diff options
Diffstat (limited to 'utils/xbox')
136 files changed, 44953 insertions, 0 deletions
diff --git a/utils/xbox/AppChooser/AppChooser.vpc b/utils/xbox/AppChooser/AppChooser.vpc new file mode 100644 index 0000000..e960987 --- /dev/null +++ b/utils/xbox/AppChooser/AppChooser.vpc @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------------- +// AppChooser.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" + +$Configuration "Debug" +{ + $Linker [$X360] + { + $AdditionalDependencies "$BASE xaudiod.lib xmediad.lib xnet.lib xonline.lib xmp.lib" + } +} + +$Configuration "Release" +{ + $Linker [$X360] + { + $AdditionalDependencies "$BASE xaudio.lib xmedia.lib xnet.lib xonline.lib xmp.lib" + } +} + +$Project "AppChooser" +{ + $Folder "Source Files" + { + $file "main.cpp" + $file "$SRCDIR\public\vgui_controls\vgui_controls.cpp" + } + + $Folder "Link Libraries" + { + $Lib appframework + $Lib mathlib + $Lib tier2 + $Lib tier3 + $Lib vtf + $Lib bitmap + $Lib vgui_controls + $Lib vgui_surfacelib + } +} diff --git a/utils/xbox/AppChooser/main.cpp b/utils/xbox/AppChooser/main.cpp new file mode 100644 index 0000000..3310ee5 --- /dev/null +++ b/utils/xbox/AppChooser/main.cpp @@ -0,0 +1,2239 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: X360 Application Chooser +// +//===========================================================================// + +#if !defined( _X360 ) +#include <windows.h> +#endif +#include "appframework/iappsystemgroup.h" +#include "appframework/appframework.h" +#include "tier0/dbg.h" +#include "tier1/interface.h" +#include "tier1/KeyValues.h" +#include "filesystem.h" +#include "vstdlib/cvar.h" +#include "filesystem_init.h" +#include "tier1/utlbuffer.h" +#include "icommandline.h" +#include "datacache/idatacache.h" +#include "datacache/imdlcache.h" +#include "studio.h" +#include "utlbuffer.h" +#include "tier2/utlstreambuffer.h" +#include "tier2/tier2.h" +#include "appframework/tier3app.h" +#include "mathlib/mathlib.h" +#include "inputsystem/iinputsystem.h" +#include "vphysics_interface.h" +#include "istudiorender.h" +#include "studio.h" +#include "vgui/IVGui.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "matsys_controls/matsyscontrols.h" +#include "vgui/ILocalize.h" +#include "vgui_controls/panel.h" +#include "vgui_controls/Label.h" +#include "vgui_controls/imagepanel.h" +#include "vgui_controls/AnimationController.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imesh.h" +#include "materialsystem/materialsystem_config.h" +#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/ishaderapi.h" +#include "materialsystem/itexture.h" +#include "filesystem/IQueuedLoader.h" +#include "xwvfile.h" +#if defined( _X360 ) +#include "hl2orange.spa.h" +#include "xbox/xbox_console.h" +#include "xbox/xbox_win32stubs.h" +#include "xbox/xbox_launch.h" +#include <xaudio.h> +#include <xmedia.h> +#include <xmp.h> +#endif +#if !defined( _X360 ) +#include "xbox/xboxstubs.h" +#endif +#include "tier0/memdbgon.h" + +#define INACTIVITY_TIMEOUT 120 + +#define MOVIE_PATH "d:\\movies" + +bool g_bActive = true; + +// user background music can force this to be zero +static float g_TargetMovieVolume = 1.0f; + +extern SpewOutputFunc_t g_DefaultSpewFunc; + +typedef void (*MovieEndCallback_t)(); + +struct game_t +{ + const wchar_t *pName; + const char *pGameDir; + bool bEnabled; +}; + +game_t g_Games[] = +{ + { L"HALF-LIFE 2", "hl2", true }, + { L"HALF-LIFE 2:\nEPISODE ONE", "episodic", true }, + { L" HALF-LIFE 2:\nEPISODE TWO", "ep2", true }, + { L"PORTAL", "portal", true }, + { L" TEAM\nFORTRESS 2", "tf", true }, +}; + +struct StartupMovie_t +{ + const char *pMovieName; + bool bUserCanSkip; +}; + +// played in order on initial startup +StartupMovie_t g_StartupMovies[] = +{ + { "valve_legalese.wmv", false }, +}; + +const char *g_DemoMovies[] = +{ + "demo.wmv", + "teaser_l4d.wmv", +}; + +class CImage : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CImage, vgui::Panel ); +public: + CImage( vgui::Panel *pParent, const char *pName, const char *pImageName ) : BaseClass( pParent, pName ) + { + m_imageID = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_imageID, pImageName, false, false ); + m_Color = Color( 255, 255, 255, 255 ); + SetPaintBackgroundEnabled( true ); + m_AspectRatio = 1.0f; + m_bLetterbox = false; + } + + CImage( vgui::Panel *pParent, const char *pName, IMaterial *pMaterial ) : BaseClass( pParent, pName ) + { + m_imageID = vgui::surface()->CreateNewTextureID(); + g_pMatSystemSurface->DrawSetTextureMaterial( m_imageID, pMaterial ); + m_Color = Color( 255, 255, 255, 255 ); + SetPaintBackgroundEnabled( true ); + m_AspectRatio = 1.0f; + m_bLetterbox = false; + } + + void SetAspectRatio( float aspectRatio, bool bLetterbox ) + { + if ( aspectRatio > 1.0f ) + { + m_AspectRatio = aspectRatio; + m_bLetterbox = bLetterbox; + } + } + + void SetColor( int r, int g, int b ) + { + // set rgb only + m_Color.SetColor( r, g, b, m_Color.a() ); + } + + void SetAlpha( int alpha ) + { + // set alpha only + alpha = clamp( alpha, 0, 255 ); + m_Color.SetColor( m_Color.r(), m_Color.g(), m_Color.b(), alpha ); + } + + int GetAlpha() const + { + return m_Color.a(); + } + + virtual void PaintBackground( void ) + { + if ( m_Color.a() != 0 ) + { + int panelWidth, panelHeight; + GetSize( panelWidth, panelHeight ); + + float s0 = 0.0f; + float s1 = 1.0f; + int y = 0; + if ( m_AspectRatio > 1.0f ) + { + if ( m_bLetterbox ) + { + // horizontal letterbox + float adjustedHeight = (float)panelWidth / m_AspectRatio; + float bandHeight = ( (float)panelHeight - adjustedHeight ) / 2; + + vgui::surface()->DrawSetColor( Color( 0, 0, 0, m_Color.a() ) ); + vgui::surface()->DrawFilledRect( 0, 0, panelWidth, bandHeight ); + vgui::surface()->DrawFilledRect( 0, panelHeight - bandHeight, panelWidth, panelHeight ); + + y = bandHeight; + panelHeight = adjustedHeight; + } + else + { + // hold the panel's height constant, determine the corresponding aspect corrected image width + float imageWidth = (float)panelHeight * m_AspectRatio; + // adjust the image width as a percentage of the panel's width + // scale and center; + s1 = (float)panelWidth / imageWidth; + s0 = ( 1 - s1 ) / 2.0f; + s1 = s0 + s1; + } + } + + vgui::surface()->DrawSetColor( m_Color ); + vgui::surface()->DrawSetTexture( m_imageID ); + vgui::surface()->DrawTexturedSubRect( 0, y, panelWidth, y+panelHeight, s0, 0.0f, s1, 1.0f ); + } + } + + int m_imageID; + Color m_Color; + float m_AspectRatio; + bool m_bLetterbox; +}; + +class CMovieImage : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CMovieImage, vgui::Panel ); +public: + + CMovieImage( vgui::Panel *pParent, const char *pName, const char *pUniqueName, int nDecodeWidth, int nDecodeHeight, float fadeDelay = 1.0f ) : BaseClass( pParent, pName ) + { + // decoupled from actual panel bounds, can be decoded at any power of two resolution + m_nDecodeWidth = nDecodeWidth; + m_nDecodeHeight = nDecodeHeight; + + char materialName[MAX_PATH]; + V_snprintf( materialName, sizeof( materialName ), "MovieMaterial_%s.vmt", pUniqueName ); + char textureName[MAX_PATH]; + V_snprintf( textureName, sizeof( textureName ), "MovieFrame_%s", pUniqueName ); + + // create a texture for use as movie frame grab + m_pTexture = g_pMaterialSystem->CreateProceduralTexture( + textureName, + TEXTURE_GROUP_OTHER, + m_nDecodeWidth, + m_nDecodeHeight, + g_pMaterialSystem->GetBackBufferFormat(), + TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY ); + + KeyValues *pVMTKeyValues = new KeyValues( "screenspace_general" ); + pVMTKeyValues->SetInt( "$ignorez", 1 ); + pVMTKeyValues->SetInt( "$linearread_basetexture", 1 ); + pVMTKeyValues->SetInt( "$X360APPCHOOSER", 1 ); + pVMTKeyValues->SetString( "$PIXSHADER", "appchooser360movie_ps20b" ); + pVMTKeyValues->SetString( "$basetexture", textureName ); + + m_pMaterial = g_pMaterialSystem->CreateMaterial( materialName, pVMTKeyValues ); + + m_imageID = vgui::surface()->CreateNewTextureID(); + g_pMatSystemSurface->DrawSetTextureMaterial( m_imageID, m_pMaterial ); + + SetPaintBackgroundEnabled( true ); + + // initially invisible + m_Color = Color( 255, 255, 255, 0 ); + + m_FadeDelay = fadeDelay; + m_pXMVPlayer = NULL; + m_bStopping = false; + m_StartTime = 0; + m_StopTime = 0; + m_pMovieEndCallback = NULL; + m_bLooped = false; + m_AspectRatio = 1.0f; + m_bLetterbox = false; + } + + void SetAspectRatio( float aspectRatio, bool bLetterbox ) + { + if ( aspectRatio > 1.0f ) + { + m_AspectRatio = aspectRatio; + m_bLetterbox = bLetterbox; + } + } + + void SetColor( int r, int g, int b ) + { + // set rgb only + m_Color.SetColor( r, g, b, m_Color.a() ); + } + + // -1 means never have any audio, otherwise set to current target + void InitUserAudioMix( bool bAudio ) + { + m_CurrentVolume = bAudio ? g_TargetMovieVolume : -1; + } + + // fade in/out based on user interaction with dashboard music system + void UpdateMovieVolume( bool bForce, float frametime = 1.0f ) + { + // m_CurrentVolume < 0 means this movie never plays audio + if ( !m_pXMVPlayer || m_CurrentVolume < 0 ) + return; + + // forced update or new volume, ramp & set + if ( bForce || g_TargetMovieVolume != m_CurrentVolume ) + { + if ( bForce ) + { + frametime = 1.0f; + } + + m_CurrentVolume = Approach( g_TargetMovieVolume, m_CurrentVolume, frametime * 0.5f ); + + // UNDONE: Under what conditions can this fail? If it fails it could cause audible pops + IXAudioSourceVoice *pVoice = NULL; + HRESULT hr = m_pXMVPlayer->GetSourceVoice( &pVoice ); + if ( !FAILED( hr ) && pVoice ) + { + pVoice->SetVolume( m_CurrentVolume ); + } + } + } + + bool StartMovieFromMemory( const void *pBuffer, int bufferSize, bool bAudio, bool bLoop, MovieEndCallback_t pMovieEndCallback = NULL ) + { + if ( m_pXMVPlayer || m_bStopping ) + { + // already started or currently stopping + return false; + } + + if ( !pBuffer || !bufferSize ) + { + return false; + } + + XMEDIA_XMV_CREATE_PARAMETERS xmvParameters; + V_memset( &xmvParameters, 0, sizeof( xmvParameters ) ); + + xmvParameters.dwFlags = XMEDIA_CREATE_CPU_AFFINITY; + if ( bLoop ) + { + xmvParameters.dwFlags |= XMEDIA_CREATE_FOR_LOOP; + m_bLooped = true; + } + if ( !bAudio ) + { + xmvParameters.dwAudioStreamId = (DWORD)XMEDIA_STREAM_ID_DONT_USE; + } + InitUserAudioMix(bAudio); + + xmvParameters.dwVideoDecoderCpu = 2; + xmvParameters.dwVideoRendererCpu = 2; + xmvParameters.dwAudioDecoderCpu = 4; + xmvParameters.dwAudioRendererCpu = 4; + xmvParameters.createType = XMEDIA_CREATE_FROM_MEMORY; + xmvParameters.createFromMemory.pvBuffer = (PVOID)pBuffer; + xmvParameters.createFromMemory.dwBufferSize = bufferSize; + + IDirect3DDevice9 *pD3DDevice = (IDirect3DDevice9 *)g_pMaterialSystem->GetD3DDevice(); + HRESULT hr = XMediaCreateXmvPlayer( pD3DDevice, &xmvParameters, &m_pXMVPlayer ); + if ( FAILED( hr ) ) + { + return false; + } + + m_pMovieEndCallback = pMovieEndCallback; + + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = m_nDecodeWidth; + rect.bottom = m_nDecodeHeight; + m_pXMVPlayer->SetRectangle( &rect ); + UpdateMovieVolume( true ); + + SetAlpha( 0 ); + m_StartTime = Plat_FloatTime() + m_FadeDelay; + m_StopTime = 0; + + return true; + } + + bool StartMovieFromFile( const char *pMovieName, bool bAudio, bool bLoop, MovieEndCallback_t pMovieEndCallback = NULL ) + { + if ( m_pXMVPlayer || m_bStopping ) + { + // already started or currently stopping + return false; + } + + XMEDIA_XMV_CREATE_PARAMETERS xmvParameters; + V_memset( &xmvParameters, 0, sizeof( xmvParameters ) ); + + xmvParameters.dwFlags = XMEDIA_CREATE_CPU_AFFINITY; + if ( bLoop ) + { + xmvParameters.dwFlags |= XMEDIA_CREATE_FOR_LOOP; + m_bLooped = true; + } + if ( !bAudio ) + { + xmvParameters.dwAudioStreamId = (DWORD)XMEDIA_STREAM_ID_DONT_USE; + } + InitUserAudioMix( bAudio ); + + char szFilename[MAX_PATH]; + V_ComposeFileName( MOVIE_PATH, pMovieName, szFilename, sizeof( szFilename ) ); + + xmvParameters.dwVideoDecoderCpu = 2; + xmvParameters.dwVideoRendererCpu = 2; + xmvParameters.dwAudioDecoderCpu = 4; + xmvParameters.dwAudioRendererCpu = 4; + xmvParameters.createType = XMEDIA_CREATE_FROM_FILE; + xmvParameters.createFromFile.szFileName = szFilename; + + IDirect3DDevice9 *pD3DDevice = (IDirect3DDevice9 *)g_pMaterialSystem->GetD3DDevice(); + HRESULT hr = XMediaCreateXmvPlayer( pD3DDevice, &xmvParameters, &m_pXMVPlayer ); + if ( FAILED( hr ) ) + { + return false; + } + + m_pMovieEndCallback = pMovieEndCallback; + + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = m_nDecodeWidth; + rect.bottom = m_nDecodeHeight; + m_pXMVPlayer->SetRectangle( &rect ); + UpdateMovieVolume( true ); + + SetAlpha( 0 ); + m_StartTime = Plat_FloatTime() + m_FadeDelay; + m_StopTime = 0; + + return true; + } + + void StopMovie() + { + if ( !m_pXMVPlayer || m_bStopping ) + { + // already stopped or currently stopping + return; + } + + m_bLooped = false; + m_bStopping = true; + m_pXMVPlayer->Stop( XMEDIA_STOP_IMMEDIATE ); + + SetAlpha( 255 ); + m_StartTime = 0; + m_StopTime = Plat_FloatTime() + m_FadeDelay; + } + + virtual void PaintBackground( void ) + { + if ( m_StartTime ) + { + // fade up goes from [0..1] and holds on 1 + float t = ( Plat_FloatTime() - m_StartTime ) * 2.0f; + t = clamp( t, 0.0f, 1.0f ); + SetAlpha( t * 255.0f ); + } + + if ( m_StopTime ) + { + // fade out goes from [1..0] and holds on 0 + float t = ( Plat_FloatTime() - m_StopTime ) * 2.0f; + t = 1.0f - clamp( t, 0.0f, 1.0f ); + SetAlpha( t * 255.0f ); + if ( m_Color.a() == 0 ) + { + if ( m_bStopping && m_pMovieEndCallback ) + { + m_pMovieEndCallback(); + } + m_bStopping = false; + } + } + + if ( m_Color.a() != 0 ) + { + int panelWidth, panelHeight; + GetSize( panelWidth, panelHeight ); + + float s0 = 0.0f; + float s1 = 1.0f; + int y = 0; + if ( m_AspectRatio > 1.0f ) + { + if ( m_bLetterbox ) + { + // horizontal letterbox + float adjustedHeight = (float)panelWidth / m_AspectRatio; + float bandHeight = ( (float)panelHeight - adjustedHeight ) / 2; + + vgui::surface()->DrawSetColor( Color( 0, 0, 0, m_Color.a() ) ); + vgui::surface()->DrawFilledRect( 0, 0, panelWidth, bandHeight ); + vgui::surface()->DrawFilledRect( 0, panelHeight - bandHeight, panelWidth, panelHeight ); + + y = bandHeight; + panelHeight = adjustedHeight; + } + else + { + // hold the panel's height constant, determine the corresponding aspect corrected image width + float imageWidth = (float)panelHeight * m_AspectRatio; + // adjust the image width as a percentage of the panel's width + // scale and center; + s1 = (float)panelWidth / imageWidth; + s0 = ( 1 - s1 ) / 2.0f; + s1 = s0 + s1; + } + } + + vgui::surface()->DrawSetColor( m_Color ); + vgui::surface()->DrawSetTexture( m_imageID ); + vgui::surface()->DrawTexturedSubRect( 0, y, panelWidth, y+panelHeight, s0, 0.0f, s1, 1.0f ); + } + } + + bool IsFullyReleased() + { + // fully stopped and released when object no longer exists + return ( m_pXMVPlayer == NULL ) && ( m_bStopping == false ); + } + + bool RenderVideoFrame() + { + if ( !m_pXMVPlayer ) + { + return false; + } + + // If RenderNextFrame does not return S_OK then the frame was not + // rendered (perhaps because it was cancelled) so a regular frame + // buffer should be rendered before calling present. + bool bRenderedFrame = true; + HRESULT hr = m_pXMVPlayer->RenderNextFrame( 0, NULL ); + if ( FAILED( hr ) || hr == XMEDIA_W_EOF ) + { + bRenderedFrame = false; + + if ( !m_bLooped ) + { + // Release the movie object + m_pXMVPlayer->Release(); + m_pXMVPlayer = NULL; + + if ( !m_bStopping ) + { + m_bStopping = true; + SetAlpha( 255 ); + m_StartTime = 0; + m_StopTime = Plat_FloatTime() + m_FadeDelay; + } + } + } + + // UNDONE: Need a frametime here. Assume it's 30fps. + // NOTE: This is only used to time audio fades, so if it's wrong by 2X it's not + // going to be noticeable. Probably fine to ship this. + UpdateMovieVolume( false, 1.0f / 30.0f ); + + // Reset our cached view of what pixel and vertex shaders are set, because + // it is no longer accurate, since XMV will have set their own shaders. + // This avoids problems when the shader cache thinks it knows what shader + // is set and it is wrong. + IDirect3DDevice9 *pD3DDevice = (IDirect3DDevice9 *)g_pMaterialSystem->GetD3DDevice(); + pD3DDevice->SetVertexShader( NULL ); + pD3DDevice->SetPixelShader( NULL ); + pD3DDevice->SetVertexDeclaration( NULL ); + pD3DDevice->SetRenderState( D3DRS_VIEWPORTENABLE, TRUE ); + + if ( bRenderedFrame ) + { + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + Rect_t rect; + rect.x = 0; + rect.y = 0; + rect.width = m_nDecodeWidth; + rect.height = m_nDecodeHeight; + pRenderContext->CopyRenderTargetToTextureEx( m_pTexture, 0, &rect ); + } + + return bRenderedFrame; + } + +private: + void SetAlpha( int alpha ) + { + // set alpha only + alpha = clamp( alpha, 0, 255 ); + m_Color.SetColor( m_Color.r(), m_Color.g(), m_Color.b(), alpha ); + } + + int m_imageID; + Color m_Color; + IXMediaXmvPlayer *m_pXMVPlayer; + ITexture *m_pTexture; + IMaterial *m_pMaterial; + bool m_bStopping; + bool m_bLooped; + float m_StartTime; + float m_StopTime; + int m_nDecodeWidth; + int m_nDecodeHeight; + float m_FadeDelay; + float m_AspectRatio; + float m_CurrentVolume; + bool m_bLetterbox; + MovieEndCallback_t m_pMovieEndCallback; +}; + +class CShadowLabel : public vgui::Label +{ + DECLARE_CLASS_SIMPLE( CShadowLabel, vgui::Label ); +public: + CShadowLabel( vgui::Panel *pParent, const char *pName, const wchar_t *pText ) : BaseClass( pParent, pName, pText ) + { + } + + virtual void Paint( void ) + { + BaseClass::Paint(); + BaseClass::Paint(); + BaseClass::Paint(); + BaseClass::Paint(); + BaseClass::Paint(); + } +}; + +class CGamePanel : public vgui::Panel +{ + DECLARE_CLASS_SIMPLE( CGamePanel, vgui::Panel ); +public: + CGamePanel( vgui::Panel *pParent, const char *pName, game_t *pGame, bool bIsWidescreen, KeyValues *pKVSettings ) : BaseClass( pParent, pName ) + { + m_bEnabled = pGame->bEnabled; + + vgui::HScheme hScheme = vgui::scheme()->GetScheme( "SourceScheme" ); + vgui::IScheme *pSourceScheme = vgui::scheme()->GetIScheme( hScheme ); + + KeyValues *pKV = pKVSettings->FindKey( "GamePanel" ); + int panelWidth = pKV->GetInt( "wide" ); + int panelHeight = pKV->GetInt( "tall" ); + SetSize( panelWidth, panelHeight ); + + // thumbnail static image + char szFilename[MAX_PATH]; + V_snprintf( szFilename, sizeof( szFilename ), "vgui/appchooser/%s", pGame->pGameDir ); + pKV = pKVSettings->FindKey( "GameImage" ); + int y = pKV->GetInt( "ypos" ); + int w = pKV->GetInt( "wide" ); + int h = pKV->GetInt( "tall" ); + int x = ( panelWidth - w ) / 2; + m_pThumbImage = new CImage( this, "GameImage", szFilename ); + SETUP_PANEL( m_pThumbImage ); + m_pThumbImage->SetBounds( x, y, w, h ); + m_pThumbImage->SetAspectRatio( bIsWidescreen ? 1.0f : 1.778f, false ); + m_pThumbImage->SetVisible( true ); + + // thumbnail movie + m_pMovieImage = new CMovieImage( this, "Movie", pGame->pGameDir, 256, 256, 0.2f ); + SETUP_PANEL( m_pMovieImage ); + m_pMovieImage->SetBounds( x, y, w, h ); + m_pMovieImage->SetVisible( true ); + V_snprintf( szFilename, sizeof( szFilename ), "%s\\thumb_%s.wmv", MOVIE_PATH, pGame->pGameDir ); + if ( !g_pFullFileSystem->ReadFile( szFilename, NULL, m_MovieBuffer ) ) + { + m_MovieBuffer.Purge(); + } + + // game title shadow + pKV = pKVSettings->FindKey( "GameTitle" ); + y = pKV->GetInt( "ypos" ); + m_pTitleShadow = new CShadowLabel( this, "GameTitle", pGame->pName ); + SETUP_PANEL( m_pTitleShadow ); + m_pTitleShadow->SetVisible( true ); + m_pTitleShadow->SetFont( pSourceScheme->GetFont( "AppChooserGameTitleFontBlur" ) ); + m_pTitleShadow->SizeToContents(); + m_pTitleShadow->SetPos( 0, y ); + m_pTitleShadow->SetWide( panelWidth ); + m_pTitleShadow->SetContentAlignment( vgui::Label::a_center ); + m_pTitleShadow->SetPaintBackgroundEnabled( false ); + m_pTitleShadow->SetFgColor( Color( 0, 0, 0, 255 ) ); + + // game title + m_pTitle = new vgui::Label( this, "GameTitle", pGame->pName ); + SETUP_PANEL( m_pTitle ); + m_pTitle->SetVisible( true ); + m_pTitle->SetFont( pSourceScheme->GetFont( "AppChooserGameTitleFont" ) ); + m_pTitle->SizeToContents(); + m_pTitle->SetPos( 0, y ); + m_pTitle->SetWide( panelWidth ); + m_pTitle->SetContentAlignment( vgui::Label::a_center ); + m_pTitle->SetPaintBackgroundEnabled( false ); + m_pTitle->SetFgColor( Color( 255, 255, 255, 255 ) ); + + // button bounds + vgui::HFont hFont = pSourceScheme->GetFont( "GameUIButtons" ); + pKV = pKVSettings->FindKey( "GameButton" ); + y = panelHeight - vgui::surface()->GetFontTall( hFont ) - pKV->GetInt( "ypos" ); + m_pButtonText = new vgui::Label( this, "GameButton", g_pVGuiLocalize->Find( "#GameUI_Icons_A_BUTTON" ) ); + SETUP_PANEL( m_pButtonText ); + m_pButtonText->SetVisible( false ); + m_pButtonText->SetFont( hFont ); + m_pButtonText->SizeToContents(); + m_pButtonText->SetPos( 0, y ); + m_pButtonText->SetWide( panelWidth ); + m_pButtonText->SetContentAlignment( vgui::Label::a_center ); + m_pButtonText->SetPaintBackgroundEnabled( false ); + m_pButtonText->SetFgColor( Color( 255, 255, 255, 255 ) ); + } + + ~CGamePanel( void ) + { + } + + void SetSelected( bool bSelected ) + { + m_pButtonText->SetVisible( m_bEnabled ? bSelected : false ); + if ( bSelected ) + { + SetBgColor( Color( 190, 115, 0, 128 ) ); + m_pThumbImage->SetColor( 255, 255, 255 ); + m_pMovieImage->SetColor( 255, 255, 255 ); + m_pTitle->SetFgColor( Color( 255, 255, 255, 255 ) ); + } + else + { + SetBgColor( Color( 160, 160, 160, 50 ) ); + m_pThumbImage->SetColor( 100, 100, 100 ); + m_pMovieImage->SetColor( 120, 120, 120 ); + m_pTitle->SetFgColor( Color( 140, 140, 140, 255 ) ); + } + } + + void StartMovie() + { + m_pMovieImage->StartMovieFromMemory( m_MovieBuffer.Base(), m_MovieBuffer.TellMaxPut(), true, true ); + } + + void StopMovie() + { + m_pMovieImage->StopMovie(); + } + + CImage *m_pThumbImage; + CMovieImage *m_pMovieImage; + CShadowLabel *m_pTitleShadow; + vgui::Label *m_pTitle; + vgui::Label *m_pButtonText; + CUtlBuffer m_MovieBuffer; + bool m_bEnabled; + int m_imageID; +}; + +//----------------------------------------------------------------------------- +// Simple XAudio wrapper to instance a sound. Provides lightweight audio feedback for ui. +// Instance this per sound. +//----------------------------------------------------------------------------- +class CXSound +{ +public: + CXSound() + { + for ( int i=0; i<ARRAYSIZE( m_pSourceVoices ); i++ ) + { + m_pSourceVoices[i] = NULL; + } + m_pXMAData = NULL; + m_nXMADataSize = 0; + m_numVoices = 0; + } + + ~CXSound() + { + Stop(); + Release(); + } + + //----------------------------------------------------------------------------- + // Setup the wave, caller can clamp the number of simultaneous playing instances + // of this sound. Useful for ui clicks to keep up with rapid input. + //----------------------------------------------------------------------------- + bool SetupWave( const char *pFilename, int numSimultaneous = 1 ) + { + CUtlBuffer buf; + if ( !g_pFullFileSystem->ReadFile( pFilename, "GAME", buf ) ) + { + Msg( "SetupWave: File '%s' not found\n", pFilename ); + return false; + } + + // only supporting xwv format + xwvHeader_t* pHeader = (xwvHeader_t *)buf.Base(); + if ( pHeader->id != XWV_ID || pHeader->version != XWV_VERSION || pHeader->format != XWV_FORMAT_XMA ) + { + Msg( "SetupWave: File '%s' has bad format\n", pFilename ); + return false; + } + + XAUDIOSOURCEVOICEINIT SourceVoiceInit = { 0 }; + SourceVoiceInit.Format.SampleType = XAUDIOSAMPLETYPE_XMA; + SourceVoiceInit.Format.NumStreams = 1; + SourceVoiceInit.MaxPacketCount = 1; + SourceVoiceInit.Format.Stream[0].SampleRate = pHeader->GetSampleRate(); + SourceVoiceInit.Format.Stream[0].ChannelCount = pHeader->channels; + + // create enough source voices to support simultaneous play of this sound + HRESULT hr; + numSimultaneous = min( numSimultaneous, ARRAYSIZE( m_pSourceVoices ) ); + for ( int i=0; i<numSimultaneous; i++ ) + { + // create the voice + hr = XAudioCreateSourceVoice( &SourceVoiceInit, &m_pSourceVoices[i] ); + if ( FAILED( hr ) ) + { + return false; + } + } + m_numVoices = numSimultaneous; + + // get the xma data + m_nXMADataSize = pHeader->dataSize; + m_pXMAData = (unsigned char *)XPhysicalAlloc( m_nXMADataSize, MAXULONG_PTR, 0, PAGE_READWRITE ); + V_memcpy( m_pXMAData, (unsigned char *)buf.Base() + pHeader->dataOffset, m_nXMADataSize ); + + return true; + } + + bool IsPlaying() + { + XAUDIOSOURCESTATE SourceState; + for ( int i=0; i<m_numVoices; i++ ) + { + m_pSourceVoices[i]->GetVoiceState( &SourceState ); + if ( SourceState & XAUDIOSOURCESTATE_STARTED ) + { + return true; + } + } + return false; + } + + void Play() + { + int numPlaying = 0; + XAUDIOSOURCESTATE SourceState; + for ( int i=0; i<m_numVoices; i++ ) + { + m_pSourceVoices[i]->GetVoiceState( &SourceState ); + if ( SourceState & XAUDIOSOURCESTATE_STARTED ) + { + numPlaying++; + } + } + if ( numPlaying >= m_numVoices ) + { + return; + } + + // find a free voice + IXAudioSourceVoice *pVoice = NULL; + for ( int i=0; i<m_numVoices; i++ ) + { + m_pSourceVoices[i]->GetVoiceState( &SourceState ); + if ( !( SourceState & XAUDIOSOURCESTATE_STARTED ) ) + { + // use the free voice + pVoice = m_pSourceVoices[i]; + break; + } + } + if ( !pVoice ) + { + // none free + return; + } + + // Set up packet + XAUDIOPACKET Packet = { 0 }; + Packet.pBuffer = m_pXMAData; + Packet.BufferSize = m_nXMADataSize; + + // Submit packet + HRESULT hr = pVoice->SubmitPacket( &Packet, XAUDIOSUBMITPACKET_DISCONTINUITY ); + if ( !FAILED( hr ) ) + { + pVoice->Start( 0 ); + } + } + + void Stop() + { + for ( int i=0; i<m_numVoices; i++ ) + { + m_pSourceVoices[i]->Stop( 0 ); + } + } + + void Release() + { + for ( int i=0; i<ARRAYSIZE( m_pSourceVoices ); i++ ) + { + if ( m_pSourceVoices[i] ) + { + m_pSourceVoices[i]->Release(); + m_pSourceVoices[i] = NULL; + } + } + if ( m_pXMAData ) + { + XPhysicalFree( m_pXMAData ); + m_pXMAData = NULL; + } + m_nXMADataSize = 0; + m_numVoices = 0; + } + +private: + IXAudioSourceVoice *m_pSourceVoices[4]; + unsigned char *m_pXMAData; + int m_nXMADataSize; + int m_numVoices; +}; + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CAppChooser : public CVguiSteamApp +{ + typedef CVguiSteamApp BaseClass; + +public: + virtual bool Create(); + virtual bool PreInit(); + virtual int Main(); + virtual void Destroy(); + + void OnSelectionPrevious(); + void OnSelectionNext(); + void OnActivateGame(); + void OnInactivityTimeout(); + void OnStopDemoMovie(); + void OnDemoMovieEnd(); + void OnStopStartupMovie(); + void Reset(); + void ResetTimeout( float timeout ); + bool IsInputEnabled() { return m_bInputEnabled; } + bool IsDemoMoviePlaying() { return m_bPlayingDemoMovie; } + bool IsStartupMoviePlaying() { return m_bPlayingStartupMovies; } + void HandleInvite( DWORD nUserId ); + +private: + const char *GetAppName() { return "AppChooser"; } + + bool CreateWindow( int width, int height, bool fullscreen ); + bool InitMaterialSystem(); + bool InitVGUI(); + void ShutdownVGUI(); + bool InitAudio(); + void ShutdownAudio(); + void FrameTick(); + void RenderScene(); + void ExitChooser(); + void EnableInput( bool bEnable ); + void StartExitingProcess(); + void SetLoadingIconPosition( bool bIsMultiplayer ); + + int m_nScreenWidth; + int m_nScreenHeight; + HWND m_hWnd; + float m_FadeInTime; + float m_FadeOutTime; + float m_StartTime; + float m_Timeout; + int m_Selection; + int m_LastSelection; + bool m_bInputEnabled; + int m_ExitingFrameCount; + float m_GameMovieStartTime; + float m_BackgroundMovieStartTime; + int m_LastBackgroundMovie; + int m_StartupMovie; + + // various operating states + bool m_bPlayingStartupMovies; + bool m_bPlayingDemoMovie; + bool m_bExiting; + + // Live invite handling + bool m_bInviteAccepted; + XNKID m_InviteSessionID; + DWORD m_nInviteUserID; + + int m_iImageID; + vgui::Panel *m_pRootPanel; + CImage *m_pPersistedImage; + CImage *m_pOverlay; + CImage *m_pFullBlack; + CMovieImage *m_pStartupMovieImage; + CMovieImage *m_pBackgroundMovie; + CMovieImage *m_pDemoMovieImage; + CGamePanel *m_pGames[ARRAYSIZE( g_Games )]; + CImage *m_pProductTitle; + CShadowLabel *m_pInstructionsShadow; + vgui::Label *m_pInstructions; + vgui::Label *m_pLoading; + CImage *m_pLoadingIcon; + CImage *m_pProductBackgrounds[ARRAYSIZE( g_Games )]; + DWORD m_iStorageDeviceID; + DWORD m_iUserIdx; + KeyValues *m_pKVSettings; + int m_DemoMovie; + + CXSound m_Click; + CXSound m_Clack; + CXSound m_Deny; +}; + +CAppChooser g_AppChooserSystem; + +//-------------------------------------------------------------------------------------- +// InitMaterialSystem +// +//-------------------------------------------------------------------------------------- +bool CAppChooser::InitMaterialSystem() +{ + RECT rect; + + MaterialSystem_Config_t config; + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, IsPC() ? true : false ); + config.SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, 0 ); + + config.m_VideoMode.m_Width = 0; + config.m_VideoMode.m_Height = 0; + config.m_VideoMode.m_Format = IMAGE_FORMAT_BGRX8888; + config.m_VideoMode.m_RefreshRate = 0; + config.dxSupportLevel = IsX360() ? 98 : 0; + + g_pMaterialSystem->ModInit(); + bool modeSet = g_pMaterialSystem->SetMode( m_hWnd, config ); + if ( !modeSet ) + { + Error( "Failed to set mode\n" ); + return false; + } + + g_pMaterialSystem->OverrideConfig( config, false ); + + GetClientRect( m_hWnd, &rect ); + m_nScreenWidth = rect.right; + m_nScreenHeight = rect.bottom; + + return true; +} + +void CAppChooser::SetLoadingIconPosition( bool bIsMultiplayer ) +{ + // matches config from matsys_interface.cpp::InitStartupScreen() + float flNormalizedX; + float flNormalizedY; + float flNormalizedSize; + if ( !bIsMultiplayer ) + { + flNormalizedX = 0.5f; + flNormalizedY = 0.86f; + flNormalizedSize = 0.1f; + } + else + { + flNormalizedX = 0.5f; + flNormalizedY = 0.9f; + flNormalizedSize = 0.1f; + } + + // matches calcs from CShaderDeviceDx8::RefreshFrontBufferNonInteractive() + float flXPos = flNormalizedX; + float flYPos = flNormalizedY; + float flHeight = flNormalizedSize; + int nSize = m_nScreenHeight * flHeight; + int x = m_nScreenWidth * flXPos - nSize * 0.5f; + int y = m_nScreenHeight * flYPos - nSize * 0.5f; + int w = nSize; + int h = nSize; + m_pLoadingIcon->SetBounds( x, y, w, h ); +} + +//----------------------------------------------------------------------------- +// Setup all our VGUI info +//----------------------------------------------------------------------------- + +bool CAppChooser::InitVGUI( void ) +{ + int x, y, w, h, g; + KeyValues *pKV; + + vgui::surface()->GetScreenSize( w, h ); + float aspectRatio = (float)w/(float)h; + bool bIsWidescreen = ( aspectRatio >= 1.7f ); + bool bIsHiDef = h > 480; + + const char *pResolutionKey = ""; + if ( bIsWidescreen ) + { + // 16:9 aspect + if ( bIsHiDef ) + { + pResolutionKey = "_hidef"; + } + else + { + pResolutionKey = "_lodef_wide"; + } + } + else + { + // 4:3 apsect + if ( bIsHiDef ) + { + pResolutionKey = "_hidef_norm"; + } + else + { + pResolutionKey = "_lodef"; + } + } + + // Start vgui + vgui::ivgui()->Start(); + vgui::ivgui()->SetSleep( false ); + + // load the scheme + vgui::scheme()->LoadSchemeFromFile( "resource/sourcescheme.res", NULL ); + vgui::HScheme hScheme = vgui::scheme()->GetScheme( "SourceScheme" ); + vgui::IScheme *pSourceScheme = vgui::scheme()->GetIScheme( hScheme ); + + m_pKVSettings = new KeyValues( "AppChooser.res" ); + if ( m_pKVSettings->LoadFromFile( g_pFullFileSystem, "resource/UI/AppChooser.res", "GAME" ) ) + { + m_pKVSettings->ProcessResolutionKeys( pResolutionKey ); + } + else + { + return false; + } + + // localization + g_pVGuiLocalize->AddFile( "resource/gameui_%language%.txt" ,"GAME", true ); + + // Init the root panel + m_pRootPanel = new vgui::Panel( NULL, "RootPanel" ); + m_pRootPanel->SetBounds( 0, 0, m_nScreenWidth, m_nScreenHeight ); + m_pRootPanel->SetPaintBackgroundEnabled( true ); + m_pRootPanel->SetVisible( true ); + vgui::surface()->SetEmbeddedPanel( m_pRootPanel->GetVPanel() ); + + // need a full pure opaque black before all panel drawing + // this fixes the top of frame xmv video render work + m_pFullBlack = new CImage( m_pRootPanel, "FullBlack", "vgui/black" ); + SETUP_PANEL( m_pFullBlack ); + m_pFullBlack->SetBounds( 0, 0, m_nScreenWidth, m_nScreenHeight ); + m_pFullBlack->SetVisible( true ); + + // all the background movies were authored for widescreen + m_pBackgroundMovie = new CMovieImage( m_pRootPanel, "Movie", "Background", m_nScreenWidth, m_nScreenHeight, 0.0f ); + SETUP_PANEL( m_pBackgroundMovie ); + m_pBackgroundMovie->SetBounds( 0, 0, m_nScreenWidth, m_nScreenHeight ); + m_pBackgroundMovie->SetAspectRatio( bIsWidescreen ? 1.0f : 1.778f, false ); + m_pBackgroundMovie->SetColor( 255, 255, 255 ); + m_pBackgroundMovie->SetVisible( true ); + + pKV = m_pKVSettings->FindKey( "Logo" ); + y = pKV->GetInt( "ypos" ); + w = pKV->GetInt( "wide" ); + h = pKV->GetInt( "tall" ); + m_pProductTitle = new CImage( m_pRootPanel, "Logo", "vgui/appchooser/orangeboxlogo" ); + SETUP_PANEL( m_pProductTitle ); + m_pProductTitle->SetBounds( ( m_nScreenWidth - w )/2, y, w, h ); + m_pProductTitle->SetVisible( true ); + + wchar_t *pString = g_pVGuiLocalize->Find( "#GameUI_AppChooser_SelectGame" ); + pKV = m_pKVSettings->FindKey( "SelectGame" ); + y = pKV->GetInt( "ypos" ); + m_pInstructionsShadow = new CShadowLabel( m_pRootPanel, "SelectGame", pString ); + SETUP_PANEL( m_pInstructionsShadow ); + m_pInstructionsShadow->SetFont( pSourceScheme->GetFont( "ChapterTitleBlur" ) ); + m_pInstructionsShadow->SizeToContents(); + m_pInstructionsShadow->SetWide( m_nScreenWidth ); + m_pInstructionsShadow->SetPos( 0, y ); + m_pInstructionsShadow->SetContentAlignment( vgui::Label::a_center ); + m_pInstructionsShadow->SetPaintBackgroundEnabled( false ); + m_pInstructionsShadow->SetFgColor( Color( 0, 0, 0, 255) ); + + m_pInstructions = new vgui::Label( m_pRootPanel, "SelectGame", pString ); + SETUP_PANEL( m_pInstructions ); + m_pInstructions->SetFont( pSourceScheme->GetFont( "ChapterTitle" ) ); + m_pInstructions->SizeToContents(); + m_pInstructions->SetWide( m_nScreenWidth ); + m_pInstructions->SetPos( 0, y ); + m_pInstructions->SetContentAlignment( vgui::Label::a_center ); + m_pInstructions->SetPaintBackgroundEnabled( false ); + m_pInstructions->SetFgColor( Color( 255, 255, 255, 255) ); + + pKV = m_pKVSettings->FindKey( "GamePanel" ); + w = pKV->GetInt( "wide" ); + g = pKV->GetInt( "gap" ); + x = ( m_nScreenWidth - ( (int)( ARRAYSIZE( g_Games ) ) * ( w + g ) - g ) ) / 2; + y = pKV->GetInt( "ypos" ); + for ( int i=0; i<ARRAYSIZE( g_Games ); i++ ) + { + m_pGames[i] = new CGamePanel( m_pRootPanel, "GamePanel", &g_Games[i], bIsWidescreen, m_pKVSettings ); + SETUP_PANEL( m_pGames[i] ); + m_pGames[i]->SetPos( x, y ); + m_pGames[i]->SetPaintBackgroundType( 2 ); + m_pGames[i]->SetSelected( false ); + x += w + g; + } + + // the product backgrounds are topmost and used as fade out materials + for ( int i=0; i<ARRAYSIZE( g_Games ); i++ ) + { + char filename[MAX_PATH]; + V_snprintf( filename, sizeof( filename ), "vgui/appchooser/background_%s%s", g_Games[i].pGameDir, bIsWidescreen ? "_widescreen" : "" ); + m_pProductBackgrounds[i] = new CImage( m_pRootPanel, "Products", filename ); + SETUP_PANEL( m_pProductBackgrounds[i] ); + m_pProductBackgrounds[i]->SetBounds( 0, 0, m_nScreenWidth, m_nScreenHeight ); + m_pProductBackgrounds[i]->SetVisible( true ); + m_pProductBackgrounds[i]->SetAlpha( 0 ); + } + + pString = g_pVGuiLocalize->Find( "#GameUI_Loading" ); + y = m_nScreenHeight / 2; + m_pLoading = new vgui::Label( m_pRootPanel, "Text", pString ); + SETUP_PANEL( m_pLoading ); + m_pLoading->SetFont( pSourceScheme->GetFont( "ChapterTitle" ) ); + m_pLoading->SizeToContents(); + m_pLoading->SetWide( m_nScreenWidth ); + m_pLoading->SetPos( 0, y ); + m_pLoading->SetContentAlignment( vgui::Label::a_center ); + m_pLoading->SetPaintBackgroundEnabled( false ); + m_pLoading->SetFgColor( Color( 255, 255, 255, 255) ); + m_pLoading->SetVisible( false ); + + m_pLoadingIcon = new CImage( m_pRootPanel, "LoadingIcon", "vgui/appchooser/loading_icon" ); + SETUP_PANEL( m_pLoadingIcon ); + SetLoadingIconPosition( false ); + m_pLoadingIcon->SetVisible( false ); + m_pLoadingIcon->SetAlpha( 0 ); + + // create back buffer cloned texture + ITexture *pTexture = NULL; + if ( XboxLaunch()->GetLaunchFlags() & LF_INTERNALLAUNCH ) + { + pTexture = g_pMaterialSystem->CreateProceduralTexture( + "PersistedTexture", + TEXTURE_GROUP_OTHER, + m_nScreenWidth, + m_nScreenHeight, + g_pMaterialSystem->GetBackBufferFormat(), + TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY ); + + // the persisted texture is in the back buffer, get it + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->CopyRenderTargetToTexture( pTexture ); + } + + // create a material to bind the persisted texture + // the fade-in material is topmost, fully opaque, and fades to transluscent on initial rendering + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetInt( "$vertexcolor", 1 ); + pVMTKeyValues->SetInt( "$vertexalpha", 1 ); + pVMTKeyValues->SetInt( "$linearwrite", 1 ); // These 2 lines are needed so that we don't lose bits of precision in + pVMTKeyValues->SetInt( "$gammacolorread", 1 ); // the dark colors due to the 360's lossy sRGB read hardware + pVMTKeyValues->SetInt( "$ignorez", 1 ); + if ( pTexture ) + { + pVMTKeyValues->SetString( "$basetexture", "PersistedTexture" ); + } + else + { + // there is no persisted texture, fade in from black + pVMTKeyValues->SetString( "$basetexture", "vgui/black" ); + } + IMaterial *pFadeInMaterial = g_pMaterialSystem->CreateMaterial( "__FadeInMaterial.vmt", pVMTKeyValues ); + + // the persisted image is either the image from the relaunch or black during first boot + m_pPersistedImage = new CImage( m_pRootPanel, "FadeInOverlay", pFadeInMaterial ); + SETUP_PANEL( m_pPersistedImage ); + m_pPersistedImage->SetBounds( 0, 0, m_nScreenWidth, m_nScreenHeight ); + m_pPersistedImage->SetVisible( true ); + m_pPersistedImage->SetAlpha( 255 ); + m_pOverlay = m_pPersistedImage; + + // full screen demo movie, use letterboxing + m_pDemoMovieImage = new CMovieImage( m_pRootPanel, "Movie", "Demo", m_nScreenWidth, m_nScreenHeight, 2.0f ); + SETUP_PANEL( m_pDemoMovieImage ); + m_pDemoMovieImage->SetBounds( 0, 0, m_nScreenWidth, m_nScreenHeight ); + m_pDemoMovieImage->SetAspectRatio( bIsWidescreen ? 1.0f : 1.778f, true ); + m_pDemoMovieImage->SetVisible( true ); + + // full screen startup movies, use letterboxing, instant start + m_pStartupMovieImage = new CMovieImage( m_pRootPanel, "Movie", "Startup", m_nScreenWidth, m_nScreenHeight, 0.0f ); + SETUP_PANEL( m_pStartupMovieImage ); + m_pStartupMovieImage->SetBounds( 0, 0, m_nScreenWidth, m_nScreenHeight ); + m_pStartupMovieImage->SetAspectRatio( bIsWidescreen ? 1.0f : 1.778f, true ); + m_pStartupMovieImage->SetVisible( true ); + + return true; +} + +//----------------------------------------------------------------------------- +// Stop VGUI +//----------------------------------------------------------------------------- +void CAppChooser::ShutdownVGUI( void ) +{ + delete m_pRootPanel; +} + +//----------------------------------------------------------------------------- +// Initialize Audio +//----------------------------------------------------------------------------- +bool CAppChooser::InitAudio() +{ + // Set up initialize parameters of XAudio Engine + // Both threads on core 2 + XAUDIOENGINEINIT EngineInit = { 0 }; + EngineInit.pEffectTable = &XAudioDefaultEffectTable; + EngineInit.ThreadUsage = XAUDIOTHREADUSAGE_THREAD4 | XAUDIOTHREADUSAGE_THREAD5; + + // Initialize the XAudio Engine + HRESULT hr = XAudioInitialize( &EngineInit ); + if ( FAILED( hr ) ) + { + Error( "Error calling XAudioInitialize\n" ); + } + + m_Click.SetupWave( "sound/ui/buttonclick.360.wav", 2 ); + m_Clack.SetupWave( "sound/ui/buttonclickrelease.360.wav", 2 ); + m_Deny.SetupWave( "sound/player/suit_denydevice.360.wav", 2 ); + + return true; +} + +void CAppChooser::ShutdownAudio() +{ + // Shut down and free XAudio resources + XAudioShutDown(); +} + +//-------------------------------------------------------------------------------------- +// Reset timeout +//-------------------------------------------------------------------------------------- +void CAppChooser::ResetTimeout( float timeout ) +{ + if ( timeout > 0 ) + { + m_Timeout = Plat_FloatTime() + timeout; + } + else + { + m_Timeout = 0; + } +} + +//-------------------------------------------------------------------------------------- +// Intialization Reset. Expected to be called once after inits. +//-------------------------------------------------------------------------------------- +void CAppChooser::Reset() +{ + // set selection to previous game or default + m_Selection = 0; + m_LastSelection = 0; + const char *pGameName = CommandLine()->ParmValue( "-game", "ep2" ); + for ( int i=0; i<ARRAYSIZE( g_Games ); i++ ) + { + if ( V_stristr( pGameName, g_Games[i].pGameDir ) ) + { + m_Selection = i; + break; + } + } + + // get the storage device + m_iStorageDeviceID = XboxLaunch()->GetStorageID(); + Msg( "Storage ID: %d", m_iStorageDeviceID ); + + // Set the user index + m_iUserIdx = XboxLaunch()->GetUserID(); + if ( g_pInputSystem ) + { + g_pInputSystem->SetPrimaryUserId( m_iUserIdx ); + } + XBX_SetPrimaryUserId( m_iUserIdx ); + Msg( "User ID: %d", m_iUserIdx ); + + m_StartTime = Plat_FloatTime(); + m_FadeInTime = 0; + m_FadeOutTime = 0; + + m_bExiting = false; + m_ExitingFrameCount = 0; + + m_bPlayingDemoMovie = false; + m_DemoMovie = 0; + + // background movie and selection startup in sync + m_LastBackgroundMovie = m_Selection; + m_BackgroundMovieStartTime = 0; + m_GameMovieStartTime = 0; + + EnableInput( true ); + + if ( !( XboxLaunch()->GetLaunchFlags() & LF_INTERNALLAUNCH ) ) + { + // first time boot + // startup movies play first, and never again + ResetTimeout( 0 ); + + m_StartupMovie = -1; + m_bPlayingStartupMovies = true; + } + else + { + // normal background startup + ResetTimeout( INACTIVITY_TIMEOUT ); + + // foreground movie starts a little staggered + m_BackgroundMovieStartTime = Plat_FloatTime(); + m_GameMovieStartTime = m_BackgroundMovieStartTime + 1.0f; + } + + // Init our invite data + m_bInviteAccepted = false; + m_nInviteUserID = XBX_INVALID_USER_ID; + memset( (void *)&m_InviteSessionID, 0, sizeof( m_InviteSessionID ) ); +} + +//-------------------------------------------------------------------------------------- +// Handle previous selection +//-------------------------------------------------------------------------------------- +void CAppChooser::OnSelectionPrevious() +{ + // backward wraparound + m_Selection = ( m_Selection + ARRAYSIZE( g_Games ) - 1 ) % ARRAYSIZE( g_Games ); + m_Click.Play(); +} + +//-------------------------------------------------------------------------------------- +// Handle next selection +//-------------------------------------------------------------------------------------- +void CAppChooser::OnSelectionNext() +{ + // forward wraparound + m_Selection = ( m_Selection + ARRAYSIZE( g_Games ) + 1 ) % ARRAYSIZE( g_Games ); + m_Click.Play(); +} + +void CAppChooser::EnableInput( bool bEnable ) +{ + m_bInputEnabled = bEnable; +} + +//-------------------------------------------------------------------------------------- +// Chooser exits +//-------------------------------------------------------------------------------------- +void CAppChooser::ExitChooser() +{ + // reset stale arguments that encode prior game + // launcher will establish correct arguments based on desired game + CommandLine()->RemoveParm( "-game" ); + CommandLine()->AppendParm( "-game", g_Games[m_Selection].pGameDir ); + + // Special command line parameter for tf. Command line args persist across + // relaunches, so remove it first in case we came from tf and are going to another game. + CommandLine()->RemoveParm( "-swapcores" ); + if ( !Q_stricmp( g_Games[m_Selection].pGameDir, "tf" ) ) + { + CommandLine()->AppendParm( "-swapcores", NULL ); + } + + int fFlags = LF_EXITFROMCHOOSER; + + // allocate the full payload + int nPayloadSize = XboxLaunch()->MaxPayloadSize(); + byte *pPayload = (byte *)stackalloc( nPayloadSize ); + V_memset( pPayload, 0, nPayloadSize ); + + // payload is at least the command line + // any user data needed must be placed AFTER the command line + const char *pCmdLine = CommandLine()->GetCmdLine(); + int nCmdLineLength = (int)strlen( pCmdLine ) + 1; + V_memcpy( pPayload, pCmdLine, min( nPayloadSize, nCmdLineLength ) ); + + // add any other data here to payload, after the command line + // ... + + XboxLaunch()->SetStorageID( m_iStorageDeviceID ); + + m_iUserIdx = XBX_GetPrimaryUserId(); + if ( m_bInviteAccepted ) + { + // A potentially different user was invited, so we need to connect them + m_iUserIdx = m_nInviteUserID; + } + XboxLaunch()->SetUserID( m_iUserIdx ); + + if ( m_bInviteAccepted ) + { + // In the case of an invitation acceptance, we need to pack extra data into the payload + fFlags |= LF_INVITERESTART; + XboxLaunch()->SetInviteSessionID( &m_InviteSessionID ); + } + + // Save out the data + bool bLaunch = XboxLaunch()->SetLaunchData( (void *)pPayload, nPayloadSize, fFlags ); + if ( bLaunch ) + { + COM_TimestampedLog( "Launching: \"%s\" Flags: 0x%8.8x", pCmdLine, XboxLaunch()->GetLaunchFlags() ); + + g_pMaterialSystem->PersistDisplay(); + ShutdownVGUI(); + ShutdownAudio(); + XBX_DisconnectConsoleMonitor(); + + XboxLaunch()->Launch(); + } +} + +//-------------------------------------------------------------------------------------- +// Handle game selection +//-------------------------------------------------------------------------------------- +void CAppChooser::OnActivateGame() +{ + if ( !m_FadeInTime || Plat_FloatTime() <= m_FadeInTime + 1.0f ) + { + // lockout user selection input until screen has stable rendering and completed its fade in + // prevents button mashing doing an immediate game selection just as the startup movies end + return; + } + + if ( !g_Games[m_Selection].bEnabled ) + { + m_Deny.Play(); + return; + } + + m_Clack.Play(); + while ( m_Clack.IsPlaying() ) + { + // let the audio complete + Sleep( 1 ); + } + + StartExitingProcess(); +} + +void CAppChooser::OnDemoMovieEnd() +{ + g_AppChooserSystem.ResetTimeout( INACTIVITY_TIMEOUT ); + m_bPlayingDemoMovie = false; +} + +void DemoMovieCallback() +{ + g_AppChooserSystem.OnDemoMovieEnd(); +} + +//-------------------------------------------------------------------------------------- +// Handle inactivity event +//-------------------------------------------------------------------------------------- +void CAppChooser::OnInactivityTimeout() +{ + // no further inactivity timeouts + ResetTimeout( 0 ); + + const char *pDemoMovieName = g_DemoMovies[m_DemoMovie]; + m_DemoMovie++; + if ( m_DemoMovie >= ARRAYSIZE( g_DemoMovies ) ) + { + // reset + m_DemoMovie = 0; + } + + m_bPlayingDemoMovie = m_pDemoMovieImage->StartMovieFromFile( pDemoMovieName, true, false, DemoMovieCallback ); + if ( !m_bPlayingDemoMovie ) + { + // try again, later + ResetTimeout( INACTIVITY_TIMEOUT ); + } +} + +//-------------------------------------------------------------------------------------- +// Handle demo stop request +//-------------------------------------------------------------------------------------- +void CAppChooser::OnStopDemoMovie() +{ + m_pDemoMovieImage->StopMovie(); +} + +//-------------------------------------------------------------------------------------- +// Handle startup stop request +//-------------------------------------------------------------------------------------- +void CAppChooser::OnStopStartupMovie() +{ + if ( m_StartupMovie >= 0 && g_StartupMovies[m_StartupMovie].bUserCanSkip ) + { + m_pStartupMovieImage->StopMovie(); + } +} + +//-------------------------------------------------------------------------------------- +// Setup the exiting context. Cannot be aborted. +//-------------------------------------------------------------------------------------- +void CAppChooser::StartExitingProcess() +{ + bool bIsMultiplayer = V_stricmp( g_Games[m_Selection].pGameDir, "tf" ) == 0; + + // stable rendering, start the fade out + m_pOverlay = m_pProductBackgrounds[m_Selection]; + + m_pLoading->SetVisible( true ); + m_pLoading->SetAlpha( 0 ); + SetLoadingIconPosition( bIsMultiplayer ); + m_pLoadingIcon->SetVisible( true ); + m_pLoadingIcon->SetAlpha( 0 ); + + m_FadeOutTime = Plat_FloatTime(); + + m_bExiting = true; + m_ExitingFrameCount = 0; + + // ensure that nothing can stop the exiting process + // otherwise the player could rapidly select a game during the fade outs + ResetTimeout( 0 ); + EnableInput( false ); +} + +//-------------------------------------------------------------------------------------- +// Handle per frame update, prior to render +//-------------------------------------------------------------------------------------- +void CAppChooser::FrameTick() +{ + if ( m_ExitingFrameCount ) + { + return; + } + + g_TargetMovieVolume = 1.0f; + BOOL bControl; + if ( ERROR_SUCCESS == XMPTitleHasPlaybackControl(&bControl) ) + { + g_TargetMovieVolume = bControl ? 1.0f : 0.0f; + } + + if ( m_FadeInTime ) + { + // fade in overlay goes from [1..0] and holds on 0 + float t = ( Plat_FloatTime() - m_FadeInTime ) * 2.0f; + t = 1.0f - clamp( t, 0.0f, 1.0f ); + m_pOverlay->SetAlpha ( t * 255.0f ); + } + + if ( m_FadeOutTime ) + { + // fade out overlay goes from [0..1] and holds on 1 + float t = ( Plat_FloatTime() - m_FadeOutTime ) * 2.0f; + t = clamp( t, 0.0f, 1.0f ); + m_pOverlay->SetAlpha ( t * 255.0f ); + } + + for ( int i=0; i<ARRAYSIZE( g_Games ); i++ ) + { + m_pGames[i]->SetSelected( false ); + } + m_pGames[m_Selection]->SetSelected( true ); + + if ( m_bExiting ) + { + m_pLoading->SetAlpha( m_pOverlay->GetAlpha() ); + m_pLoadingIcon->SetAlpha( m_pOverlay->GetAlpha() ); + if ( m_pOverlay->GetAlpha() == 255 ) + { + // exiting needs to have fade overlay fully opaque before stopping background movie + m_pBackgroundMovie->StopMovie(); + + // exiting commences after all movies full release and enough frames have swapped to ensure stability + // strict time (frame rate) cannot be trusted, must allow a non trivial amount of presents + m_ExitingFrameCount = 30; + } + } + + if ( m_bPlayingStartupMovies ) + { + if ( m_pStartupMovieImage->IsFullyReleased() ) + { + m_StartupMovie++; + if ( m_StartupMovie >= ARRAYSIZE( g_StartupMovies ) ) + { + // end of cycle + m_StartupMovie = -1; + m_bPlayingStartupMovies = false; + } + else + { + m_bPlayingStartupMovies = m_pStartupMovieImage->StartMovieFromFile( g_StartupMovies[m_StartupMovie].pMovieName, true, false ); + } + } + + if ( !m_bPlayingStartupMovies ) + { + ResetTimeout( INACTIVITY_TIMEOUT ); + m_BackgroundMovieStartTime = Plat_FloatTime(); + m_GameMovieStartTime = m_BackgroundMovieStartTime + 1.0f; + } + else + { + return; + } + } + + if ( m_bInviteAccepted ) + { + // stop attract mode + if ( m_bPlayingDemoMovie ) + { + // hint the demo movie to stop + OnStopDemoMovie(); + } + + // attract movies must finish before allowing invite + // background movies must finish before allowing invite + // starts the exiting process ONCE + if ( !m_bPlayingStartupMovies && !m_bPlayingDemoMovie && !m_bExiting ) + { + for ( int i = 0; i < ARRAYSIZE( g_Games ); i++ ) + { + if ( V_stristr( "tf", g_Games[i].pGameDir ) ) + { + // EVIL! spoof a user slection to invite only TF + m_Selection = i; + StartExitingProcess(); + + // must fixup state, invite could have happened very early, at any time, before the initial fade-in + // ensure no movies start + m_BackgroundMovieStartTime = 0; + m_GameMovieStartTime = 0; + + // hack the fade times to match the expected state + if ( !m_FadeInTime || m_FadeInTime >= Plat_FloatTime() ) + { + // can't fade out, invite occured before fade-in + // can only snap it because there is no background to fade from + m_pPersistedImage->SetAlpha( 0 ); + m_FadeInTime = 0; + m_FadeOutTime = 0; + m_pOverlay->SetAlpha( 255 ); + } + break; + } + } + } + } + + if ( m_bExiting || m_bPlayingDemoMovie || m_LastSelection != m_Selection ) + { + m_pGames[m_LastSelection]->StopMovie(); + m_LastSelection = m_Selection; + + // user can change selection very quickly + // lag the movie starting until selection settles + m_GameMovieStartTime = Plat_FloatTime() + 2.0f; + } + + if ( !m_bExiting && !m_bPlayingDemoMovie && ( m_GameMovieStartTime != 0 ) && ( Plat_FloatTime() >= m_GameMovieStartTime ) ) + { + // keep trying the current selection, it will eventually start + m_pGames[m_Selection]->StartMovie(); + if ( m_LastBackgroundMovie != m_Selection ) + { + m_pBackgroundMovie->StopMovie(); + m_LastBackgroundMovie = m_Selection; + m_BackgroundMovieStartTime = Plat_FloatTime() + 2.0f; + } + } + + // update the background movie, lags far behind any user selection + if ( !m_bExiting && !m_bPlayingDemoMovie && ( m_BackgroundMovieStartTime != 0 ) && ( Plat_FloatTime() >= m_BackgroundMovieStartTime ) ) + { + char szFilename[MAX_PATH]; + V_snprintf( szFilename, sizeof( szFilename ), "background_%s.wmv", g_Games[m_Selection].pGameDir ); + + // keep trying the current selection, it will eventually start + bool bStarted = m_pBackgroundMovie->StartMovieFromFile( + szFilename, + false, + true ); + if ( bStarted ) + { + m_LastBackgroundMovie = m_Selection; + } + } +} + +//-------------------------------------------------------------------------------------- +// Render the scene +//-------------------------------------------------------------------------------------- +void CAppChooser::RenderScene() +{ + FrameTick(); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + g_pMaterialSystem->BeginFrame( Plat_FloatTime() ); + + pRenderContext->ClearColor3ub( 0, 0, 0 ); + pRenderContext->ClearBuffers( true, true ); + pRenderContext->Flush( true ); + + // render all movies, XMV needs to hijack D3D + bool bPreviousState = g_pMaterialSystem->OwnGPUResources( false ); + { + m_pStartupMovieImage->RenderVideoFrame(); + m_pBackgroundMovie->RenderVideoFrame(); + m_pDemoMovieImage->RenderVideoFrame(); + for ( int i=0; i<ARRAYSIZE( m_pGames ); i++ ) + { + m_pGames[i]->m_pMovieImage->RenderVideoFrame(); + } + } + g_pMaterialSystem->OwnGPUResources( bPreviousState ); + + pRenderContext->Viewport( 0, 0, m_nScreenWidth, m_nScreenHeight ); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadIdentity(); + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity(); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->LoadIdentity(); + pRenderContext->Flush( true ); + + vgui::ivgui()->RunFrame(); + vgui::surface()->PaintTraverseEx( vgui::surface()->GetEmbeddedPanel() ); + + g_pMaterialSystem->EndFrame(); + g_pMaterialSystem->SwapBuffers(); + + if ( !m_FadeInTime && !m_bPlayingStartupMovies && !m_bExiting ) + { + // stable rendering, start the fade in + m_FadeInTime = Plat_FloatTime() + 1.0f; + } + + // check for timeout + if ( m_Timeout && ( Plat_FloatTime() >= m_Timeout ) ) + { + m_Timeout = 0; + OnInactivityTimeout(); + } + + if ( m_ExitingFrameCount > 1 && m_pBackgroundMovie->IsFullyReleased() && m_pGames[m_Selection]->m_pMovieImage->IsFullyReleased() ) + { + // must wait for a few frames to settle to ensure frame buffer is stable + m_ExitingFrameCount--; + if ( m_ExitingFrameCount == 1 ) + { + ExitChooser(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAppChooser::HandleInvite( DWORD nUserId ) +{ + // invites are asynchronous and could happen at any time + if ( m_bInviteAccepted ) + { + // already accepted + return; + } + + // Collect our session data + XINVITE_INFO inviteInfo; + DWORD dwError = XInviteGetAcceptedInfo( nUserId, &inviteInfo ); + if ( dwError != ERROR_SUCCESS ) + { + return; + } + + // We only care if we're asked to join an Orange Box session + if ( inviteInfo.dwTitleID != TITLEID_THE_ORANGE_BOX ) + { + return; + } + + // Store off the session ID and mark the invite as accepted internally + m_bInviteAccepted = true; + m_InviteSessionID = inviteInfo.hostInfo.sessionID; + m_nInviteUserID = nUserId; + + // must wait for the startup movies or attract mode to end + // FrameTick() will detect the invite and transition + // the user has accpeted and cannot abort the invite + EnableInput( false ); + ResetTimeout( 0 ); +} + +//-------------------------------------------------------------------------------------- +// Window Proc +//-------------------------------------------------------------------------------------- +LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) +{ + switch ( iMsg ) + { + case WM_CLOSE: + g_bActive = false; + break; + + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0L; + + case WM_LIVE_INVITE_ACCEPTED: + g_AppChooserSystem.HandleInvite( LOWORD( lParam ) ); + break; + + case WM_XCONTROLLER_KEY: + if ( !g_AppChooserSystem.IsInputEnabled() ) + { + break; + } + + if ( g_AppChooserSystem.IsStartupMoviePlaying() ) + { + // some startup movies can be aborted + switch ( wParam ) + { + case KEY_XBUTTON_A: + case KEY_XBUTTON_START: + if ( LOWORD( lParam ) ) + { + g_AppChooserSystem.OnStopStartupMovie(); + } + } + // no other input is allowed during this state + break; + } + + if ( g_AppChooserSystem.IsDemoMoviePlaying() ) + { + // demo movies can be aborted + switch ( wParam ) + { + case KEY_XBUTTON_A: + case KEY_XBUTTON_START: + if ( LOWORD( lParam ) ) + { + g_AppChooserSystem.OnStopDemoMovie(); + } + } + } + else + { + if ( LOWORD( lParam ) ) + { + g_AppChooserSystem.ResetTimeout( INACTIVITY_TIMEOUT ); + } + + switch ( wParam ) + { + case KEY_XBUTTON_LEFT: + case KEY_XSTICK1_LEFT: + if ( LOWORD( lParam ) ) + { + g_AppChooserSystem.OnSelectionPrevious(); + } + break; + + case KEY_XBUTTON_RIGHT: + case KEY_XSTICK1_RIGHT: + if ( LOWORD( lParam ) ) + { + g_AppChooserSystem.OnSelectionNext(); + } + break; + + case KEY_XBUTTON_A: + case KEY_XBUTTON_START: + if ( LOWORD( lParam ) ) + { + g_AppChooserSystem.OnActivateGame(); + } + break; + } + } + break; + } + + return DefWindowProc( hWnd, iMsg, wParam, lParam ); +} + +//-------------------------------------------------------------------------------------- +// CreateWindow +// +//-------------------------------------------------------------------------------------- +bool CAppChooser::CreateWindow( int width, int height, bool bFullScreen ) +{ + HWND hWnd; + WNDCLASSEX wndClass; + DWORD dwStyle, dwExStyle; + int x, y, sx, sy; + + if ( ( hWnd = FindWindow( GetAppName(), GetAppName() ) ) != NULL ) + { + SetForegroundWindow( hWnd ); + return true; + } + + wndClass.cbSize = sizeof( wndClass ); + wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wndClass.lpfnWndProc = ::WndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 0; + wndClass.hInstance = (HINSTANCE)GetAppInstance(); + wndClass.hIcon = 0; + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)COLOR_GRAYTEXT; + wndClass.lpszMenuName = NULL; + wndClass.lpszClassName = GetAppName(); + wndClass.hIconSm = 0; + if ( !RegisterClassEx( &wndClass ) ) + { + Error( "Window class registration failed\n" ); + return false; + } + + if ( bFullScreen ) + { + dwExStyle = WS_EX_TOPMOST; + dwStyle = WS_POPUP | WS_VISIBLE; + } + else + { + dwExStyle = 0; + dwStyle = WS_CAPTION | WS_SYSMENU; + } + + x = y = 0; + sx = width; + sy = height; + + hWnd = CreateWindowEx( + dwExStyle, + GetAppName(), // window class name + GetAppName(), // window caption + dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // window style + x, // initial x position + y, // initial y position + sx, // initial x size + sy, // initial y size + NULL, // parent window handle + NULL, // window menu handle + (HINSTANCE)GetAppInstance(),// program instance handle + NULL); // creation parameter + + if ( hWnd == NULL ) + { + return false; + } + + m_hWnd = hWnd; + + return true; +} + +//----------------------------------------------------------------------------- +// Create +//----------------------------------------------------------------------------- +bool CAppChooser::Create() +{ + AppSystemInfo_t appSystems[] = + { + { "filesystem_stdio.dll", QUEUEDLOADER_INTERFACE_VERSION }, + { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION }, + { "inputsystem.dll", INPUTSYSTEM_INTERFACE_VERSION }, + { "vgui2.dll", VGUI_IVGUI_INTERFACE_VERSION }, + { "vguimatsurface.dll", VGUI_SURFACE_INTERFACE_VERSION }, + { "", "" } + }; + + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + + SpewOutputFunc( g_DefaultSpewFunc ); + + // Add in the cvar factory + AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() ); + AddSystem( cvarModule, CVAR_INTERFACE_VERSION ); + + // vxconsole - true will block (legacy behavior) + XBX_InitConsoleMonitor( false ); + + if ( !AddSystems( appSystems ) ) + return false; + + IMaterialSystem* pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION ); + if ( !pMaterialSystem ) + { + Error( "Failed to find %s\n", MATERIAL_SYSTEM_INTERFACE_VERSION ); + return false; + } + + if ( IsX360() ) + { + IFileSystem* pFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION ); + if ( !pFileSystem ) + { + Error( "Failed to find %s\n", FILESYSTEM_INTERFACE_VERSION ); + return false; + } + pFileSystem->LoadModule( "shaderapidx9.dll" ); + } + + pMaterialSystem->SetShaderAPI( "shaderapidx9.dll" ); + + return true; +} + +//----------------------------------------------------------------------------- +// PreInit +//----------------------------------------------------------------------------- +bool CAppChooser::PreInit() +{ + if ( !BaseClass::PreInit() ) + return false; + + if ( !g_pFullFileSystem || !g_pMaterialSystem ) + { + Warning( "Unable to find required interfaces!\n" ); + return false; + } + + // Add paths... + if ( !SetupSearchPaths( NULL, false, true ) ) + { + Error( "Failed to setup search paths\n" ); + return false; + } + + // Create the main program window and our viewport + int w = 640; + int h = 480; + if ( IsX360() ) + { + w = GetSystemMetrics( SM_CXSCREEN ); + h = GetSystemMetrics( SM_CYSCREEN ); + } + + if ( !CreateWindow( w, h, false ) ) + { + ChangeDisplaySettings( 0, 0 ); + Error( "Unable to create main window\n" ); + return false; + } + + ShowWindow( m_hWnd, SW_SHOWNORMAL ); + UpdateWindow( m_hWnd ); + SetForegroundWindow( m_hWnd ); + SetFocus( m_hWnd ); + + XOnlineStartup(); + + return true; +} + + +//----------------------------------------------------------------------------- +// Destroy +//----------------------------------------------------------------------------- +void CAppChooser::Destroy() +{ + XOnlineCleanup(); +} + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +int CAppChooser::Main() +{ + if ( !InitMaterialSystem() ) + { + return 0; + } + + if ( !InitVGUI() ) + { + return 0; + } + + if ( !InitAudio() ) + { + return 0; + } + + // post initialization reset + Reset(); + + // Setup a listener for invites + XBX_NotifyCreateListener( XNOTIFY_LIVE ); + + MSG msg; + while ( g_bActive == TRUE ) + { + // Pump the XBox notifications + XBX_ProcessEvents(); + + while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + + g_pInputSystem->PollInputState(); + RenderScene(); + } + + ShutdownVGUI(); + ShutdownAudio(); + Destroy(); + + return 0; +} + +//----------------------------------------------------------------------------- +// The entry point for the application +//----------------------------------------------------------------------------- +extern "C" __declspec(dllexport) int AppChooserMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) +{ + CommandLine()->CreateCmdLine( lpCmdLine ); + + SetAppInstance( hInstance ); + + CSteamApplication steamApplication( &g_AppChooserSystem ); + steamApplication.Run(); + + return 0; +} diff --git a/utils/xbox/AppChooser/xbox/xbox.def b/utils/xbox/AppChooser/xbox/xbox.def new file mode 100644 index 0000000..66245f5 --- /dev/null +++ b/utils/xbox/AppChooser/xbox/xbox.def @@ -0,0 +1,3 @@ +LIBRARY AppChooser_360.dll +EXPORTS + AppChooserMain @1
\ No newline at end of file diff --git a/utils/xbox/FontMaker/fontmaker.cpp b/utils/xbox/FontMaker/fontmaker.cpp new file mode 100644 index 0000000..a2552af --- /dev/null +++ b/utils/xbox/FontMaker/fontmaker.cpp @@ -0,0 +1,1119 @@ +//----------------------------------------------------------------------------- +// Name: FontMaker.cpp +// +// Desc: Defines the class behaviors for the application. +// +// Hist: 09.06.02 - Revised Fontmaker sample +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- +#include "stdafx.h" +#include "FontMaker.h" +#include "Glyphs.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +CTextureFont g_Font; +extern BOOL g_bIsGlyphSelected; +extern int g_iSelectedGlyphNum; +extern GLYPH_ATTR* g_pSelectedGylph; +extern WCHAR g_cSelectedGlyph; + + + + + +//----------------------------------------------------------------------------- +// CFontMakerApp +//----------------------------------------------------------------------------- + +BEGIN_MESSAGE_MAP(CFontMakerApp, CWinApp) + //{{AFX_MSG_MAP(CFontMakerApp) + ON_COMMAND(IDM_FILE_NEWFONT, OnNewFontButton) + ON_BN_CLICKED(IDC_EFFECTSOUTLINED_CHECK, OnEffectsCheck) + ON_BN_CLICKED(IDC_EFFECTSSHADOWED_CHECK, OnEffectsCheck) + ON_BN_CLICKED(IDC_EFFECTSBLURRED_CHECK, OnEffectsCheck) + ON_BN_CLICKED(IDC_EFFECTSSCANLINES_CHECK, OnEffectsCheck) + ON_BN_CLICKED(IDC_EFFECTSANTIALIAS_CHECK, OnEffectsCheck) + ON_BN_CLICKED(IDC_GLYPHSFROMRANGE_RADIO, OnGlyphsFromRangeRadio) + ON_EN_CHANGE(IDC_GLYPHSRANGEFROM_EDIT, OnChangeGlpyhsRangeEdit) + ON_BN_CLICKED(IDC_GLYPHSFROMFILE_RADIO, OnGlyphsFromFileRadio) + ON_EN_KILLFOCUS(IDC_GLYPHSFILE_EDIT, OnChangeGlyphsFileEdit) + ON_BN_CLICKED(IDC_GLYPHSFILESELECTOR_BUTTON, OnGlyphsFileSelectorButton) + ON_BN_CLICKED(IDC_GLYPHSCUSTOM_RADIO, OnGlyphsCustom) + ON_BN_CLICKED(IDC_TEXTURESIZE_BUTTON, OnTextureSizeButton) + ON_BN_CLICKED(IDC_MAGNIFY_BUTTON, OnMagnifyButton) + ON_BN_CLICKED(IDC_GLYPH_SPECIAL, OnGlyphSpecial) + ON_UPDATE_COMMAND_UI(IDC_MAGNIFY_BUTTON, OnUpdateButton) + ON_COMMAND(IDM_FILE_LOADFONTFILE, OnLoadButton) + ON_COMMAND(IDM_FILE_SAVEFONTFILES, OnSaveButton) + ON_COMMAND(IDM_FILE_LOADFONTLAYOUT, OnLoadCustomFontButton) + ON_COMMAND(IDM_FILE_EXIT, OnExit) + ON_COMMAND(ID_APP_ABOUT, OnAbout) + ON_COMMAND(ID_HELP, OnHelp) + ON_EN_CHANGE(IDC_GLYPHSRANGETO_EDIT, OnChangeGlpyhsRangeEdit) + ON_UPDATE_COMMAND_UI(IDC_TEXTURESIZE_BUTTON, OnUpdateButton) + ON_UPDATE_COMMAND_UI(IDC_GLYPHSFILESELECTOR_BUTTON, OnUpdateButton) + ON_UPDATE_COMMAND_UI(IDM_FILE_NEWFONT, OnUpdateButton) + ON_UPDATE_COMMAND_UI(IDM_FILE_LOADFONTFILE, OnUpdateButton) + ON_UPDATE_COMMAND_UI(IDM_FILE_LOADFONTLAYOUT, OnUpdateButton) + ON_UPDATE_COMMAND_UI(IDM_FILE_SAVEFONTFILES, OnUpdateButton) + ON_UPDATE_COMMAND_UI(IDM_FILE_EXIT, OnUpdateButton) + ON_UPDATE_COMMAND_UI(ID_APP_ABOUT, OnUpdateButton) + ON_UPDATE_COMMAND_UI(ID_HELP, OnUpdateButton) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + + + +//----------------------------------------------------------------------------- +// The one and only CFontMakerApp object +//----------------------------------------------------------------------------- +CFontMakerApp theApp; + + + + +//----------------------------------------------------------------------------- +// Name: InitInstance() +// Desc: App initialization +//----------------------------------------------------------------------------- +BOOL CFontMakerApp::InitInstance() +{ + // Create the main frame window for the app + CFontMakerFrameWnd* pFrameWnd = new CFontMakerFrameWnd; + m_pMainWnd = pFrameWnd; + + // Associate the view with the frame + CCreateContext context; + context.m_pCurrentFrame = NULL; + context.m_pCurrentDoc = NULL; + context.m_pNewViewClass = RUNTIME_CLASS(CFontMakerView); + context.m_pNewDocTemplate = NULL; + + // Create the frame and load resources (menu, accelerator, etc.) + pFrameWnd->LoadFrame( IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, + NULL, &context ); + + // Call OnInitialUpdate() to be called for the view + pFrameWnd->InitialUpdateFrame( NULL, TRUE ); + + // The one and only window has been initialized, so show and update it. + m_pMainWnd->ShowWindow( SW_SHOW ); + m_pMainWnd->UpdateWindow(); + + // Load the hourglass cursor + m_hWaitCursor = LoadCursor( IDC_WAIT ); + + // Get access the the dialog controls and the view + m_pDialogBar = pFrameWnd->GetDialogBar(); + m_pView = (CFontMakerView*)pFrameWnd->GetActiveView(); + + // Initially, no font is selected + m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->SetWindowText( _T("<Choose font>") ); + m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->SetWindowText( _T("") ); + m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->SetWindowText( _T("") ); + + return TRUE; +} + + + + +//----------------------------------------------------------------------------- +// Name: OnUpdateButton() +// Desc: This function is needed to override some internal mucking with button +// states. Without it, button and menu enabling will make you crazy. +//----------------------------------------------------------------------------- +void CFontMakerApp::OnUpdateButton( CCmdUI* pCmdUI ) +{ + BOOL bEnable; + + switch( pCmdUI->m_nID ) + { + // Controls which are active all the time + case IDM_FILE_NEWFONT: + case IDM_FILE_LOADFONTLAYOUT: + case IDM_FILE_LOADFONTFILE: + case IDM_FILE_EXIT: + case ID_APP_ABOUT: + case ID_HELP: + bEnable = TRUE; + break; + + case IDC_TEXTURESIZE_BUTTON: + case IDM_FILE_SAVEFONTFILES: + case IDC_MAGNIFY_BUTTON: + bEnable = g_Font.m_hFont ? TRUE : FALSE; + if ( !bEnable ) + bEnable = g_Font.m_pCustomFilename ? TRUE : FALSE; + break; + + // Controls which are active only when a font is available + default: + bEnable = g_Font.m_hFont ? TRUE : FALSE; + break; + } + + pCmdUI->Enable( bEnable ); +} + +BOOL g_bFirstTime = TRUE; + +//----------------------------------------------------------------------------- +// Name: OnNewFontButton() +// Desc: Called when the user hits the "New Font" button, this loads the font +// and enables all the other windows controls. +//----------------------------------------------------------------------------- +void CFontMakerApp::OnNewFontButton() +{ + // Initialize the LOGFONT structure. It's static so it's state is remembered + if ( g_Font.m_LogFont.lfHeight == 0 ) + { + // first time init + strcpy( g_Font.m_LogFont.lfFaceName, "Arial" ); // Arial font for a default + g_Font.m_LogFont.lfHeight = 16; // 16 height font for a default + g_Font.m_LogFont.lfWeight = 400; // 400 = normal, 700 = bold, etc. + g_Font.m_LogFont.lfItalic = 0; // 0 = normal, 255 = italic + g_Font.m_LogFont.lfQuality = ANTIALIASED_QUALITY; + } + + // convert to point size for dialog purposes + HDC hDC = GetDC( m_pMainWnd->m_hWnd ); + // Current point size unit=1/10 pts + INT iPointSize = g_Font.m_LogFont.lfHeight * 10; + g_Font.m_LogFont.lfHeight= -MulDiv( iPointSize, GetDeviceCaps( hDC, LOGPIXELSY ), 720 ); + ReleaseDC( m_pMainWnd->m_hWnd, hDC ); + + // Create the CHOOSEFONT structure + static CHOOSEFONT cf = {0}; + cf.lStructSize = sizeof(CHOOSEFONT); + cf.lpLogFont = &g_Font.m_LogFont; + cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; + cf.nFontType = SCREEN_FONTTYPE; + + if ( 0 == ChooseFont( &cf ) ) + return; + + g_Font.m_pCustomFilename = NULL; + + // NOT using point sizes, but cell heights + g_Font.m_LogFont.lfHeight = cf.iPointSize/10; + + // Reset the selected glpyh + UpdateSelectedGlyph( FALSE ); + + if( FAILED( CalculateAndRenderGlyphs() ) ) + { + // Could not create new font + MessageBox( m_pMainWnd->m_hWnd, "Could not create the requested font!", "Error", MB_ICONERROR|MB_OK ); + return; + } + + char tempName[256]; + sprintf( tempName, "%s_%d", g_Font.m_LogFont.lfFaceName, cf.iPointSize/10 ); + + // remove any spaces in the font name + for (unsigned int i=0,j=0; i<strlen( tempName )+1; i++) + { + if ( tempName[i] != ' ' ) + { + g_Font.m_strFontName[j++] = tempName[i]; + } + } + + if ( g_bFirstTime ) + { + CString str; + + // Set font properties + m_pDialogBar->GetDlgItem( IDC_FONT_GROUPBOX )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTNAME_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTSIZE_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSOUTLINED_CHECK )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSSHADOWED_CHECK )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_BLUR_EDIT )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_SCANLINES_EDIT )->EnableWindow( TRUE ); + + if ( g_Font.m_bAntialiasEffect ) + { + ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK ))->SetCheck( TRUE ); + } + else + { + ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK ))->SetCheck( FALSE ); + } + + str.Format( "%d", g_Font.m_nBlur ); + m_pDialogBar->GetDlgItem( IDC_BLUR_EDIT )->SetWindowText( str ); + + str.Format( "%d", g_Font.m_nScanlines ); + m_pDialogBar->GetDlgItem( IDC_SCANLINES_EDIT )->SetWindowText( str ); + + str.Format( "%s", g_Font.m_LogFont.lfFaceName ); + m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->SetWindowText( str ); + if( g_Font.m_LogFont.lfItalic ) + str.Format( "Italic", g_Font.m_LogFont.lfWeight < 550 ? "" : "Bold " ); + else + str.Format( "%s", g_Font.m_LogFont.lfWeight < 550 ? "Regular" : "Bold" ); + m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->SetWindowText( str ); + str.Format( "%ld", cf.iPointSize/10 ); + m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->SetWindowText( str ); + + // Set texture properties + m_pDialogBar->GetDlgItem( IDC_TEXTURE_GROUPBOX )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTURESIZE_BUTTON )->EnableWindow( TRUE ); + + SetTextureSize( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight ); + + // Set glyph range properties + m_pDialogBar->GetDlgItem( IDC_GLYPHS_GROUPBOX )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILESELECTOR_BUTTON )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO )->EnableWindow( TRUE ); + + // Set a default range of glyphs to use + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->SetWindowText( "32" ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->SetWindowText( "127" ); + g_Font.ExtractValidGlyphsFromRange( 32, 127 ); + + m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_EDIT )->EnableWindow( TRUE ); + } + else + { + CString str; + + str.Format( "%s", g_Font.m_LogFont.lfFaceName ); + m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->SetWindowText( str ); + if ( g_Font.m_LogFont.lfItalic ) + str.Format( "Italic", g_Font.m_LogFont.lfWeight < 550 ? "" : "Bold " ); + else + str.Format( "%s", g_Font.m_LogFont.lfWeight < 550 ? "Regular" : "Bold" ); + m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->SetWindowText( str ); + str.Format( "%ld", cf.iPointSize/10 ); + m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->SetWindowText( str ); + } + + g_bFirstTime = FALSE; +} + + + + +//----------------------------------------------------------------------------- +// Name: OnGlyphsFromRangeRadio() +// Desc: User will be specifying a glyph range manually +//----------------------------------------------------------------------------- +void CFontMakerApp::OnGlyphsFromRangeRadio() +{ + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILESELECTOR_BUTTON )->EnableWindow( FALSE ); + + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO ))->SetCheck( false ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( true ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO ))->SetCheck( false ); + + OnChangeGlpyhsRangeEdit(); +} + + + + +//----------------------------------------------------------------------------- +// Name: OnChangeGlpyhsRangeEdit() +// Desc: User changed the range of glpyhs +//----------------------------------------------------------------------------- +void CFontMakerApp::OnChangeGlpyhsRangeEdit() +{ + if( NULL == g_Font.m_hFont ) + return; + + CEdit* pGlyphRangeFromEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT ); + CEdit* pGlyphRangeToEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT ); + + CString strFrom; + CString strTo; + pGlyphRangeFromEdit->GetWindowText( strFrom ); + pGlyphRangeToEdit->GetWindowText( strTo ); + + WORD wFrom = (WORD)max( 0, atoi( strFrom ) ); + WORD wTo = (WORD)min( 65535, atoi( strTo ) ); + g_Font.ExtractValidGlyphsFromRange( wFrom, wTo ); + + // Draw the new font glyphs + CalculateAndRenderGlyphs(); +} + + +void CFontMakerApp::OnGlyphsCustom() +{ + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO ))->SetCheck( false ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( false ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO ))->SetCheck( true ); +} + + +//----------------------------------------------------------------------------- +// Name: OnGlyphsFromFileRadio() +// Desc: User want to extract glyphs that are used in a text file +//----------------------------------------------------------------------------- +void CFontMakerApp::OnGlyphsFromFileRadio() +{ + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_LABEL )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_LABEL )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILESELECTOR_BUTTON )->EnableWindow( TRUE ); + + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO ))->SetCheck( true ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( false ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO ))->SetCheck( false ); + + OnChangeGlyphsFileEdit(); +} + + + + +//----------------------------------------------------------------------------- +// Name: OnChangeGlyphsFileEdit() +// Desc: Handle change in name of file to extract glyphs from +//----------------------------------------------------------------------------- +void CFontMakerApp::OnChangeGlyphsFileEdit() +{ + CEdit* pGlyphFileNameEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT ); + + CString strFileName; + pGlyphFileNameEdit->GetWindowText( strFileName ); + + if( strFileName.IsEmpty() ) + return; + + g_Font.ExtractValidGlyphsFromFile( (const TCHAR*)strFileName ); + + // Draw the new font glyphs + CalculateAndRenderGlyphs(); +} + + + + +//----------------------------------------------------------------------------- +// Name: OnGlyphsFileSelectorButton() +// Desc: Handle change in name of file to extract glyphs from +//----------------------------------------------------------------------------- +void CFontMakerApp::OnGlyphsFileSelectorButton() +{ + static TCHAR strFileName[MAX_PATH] = _T(""); + static TCHAR strFileName2[MAX_PATH] = _T(""); + static TCHAR strInitialDir[MAX_PATH] = _T("c:\\"); + + // Display the OpenFileName dialog. Then, try to load the specified file + OPENFILENAME ofn = { sizeof(OPENFILENAME), NULL, NULL, + _T("Text files (.txt)\0*.txt\0\0"), + NULL, 0, 1, strFileName, MAX_PATH, strFileName2, MAX_PATH, + strInitialDir, _T("Open Text File"), + OFN_FILEMUSTEXIST, 0, 1, NULL, 0, NULL, NULL }; + + if( TRUE == GetOpenFileName( &ofn ) ) + { + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->SetWindowText( ofn.lpstrFile); + OnChangeGlyphsFileEdit(); + } +} + + + + +//----------------------------------------------------------------------------- +// Name: OnEffectsCheck() +// Desc: User changed font rendering options +//----------------------------------------------------------------------------- +void CFontMakerApp::OnEffectsCheck() +{ + g_Font.m_bOutlineEffect = ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSOUTLINED_CHECK ))->GetCheck(); + g_Font.m_bShadowEffect = ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSSHADOWED_CHECK ))->GetCheck(); + g_Font.m_bAntialiasEffect = ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK ))->GetCheck(); + + bool bValveEffects = false; + if ( g_Font.m_bOutlineEffect || g_Font.m_bShadowEffect ) + { + m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK )->EnableWindow( false ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK )->EnableWindow( false ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK ))->SetCheck( false ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK ))->SetCheck( false ); + } + else + { + m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK )->EnableWindow( true ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK )->EnableWindow( true ); + bValveEffects = true; + } + + if ( bValveEffects && ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK ))->GetCheck() ) + { + CEdit* pBlurEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_BLUR_EDIT ); + + CString strBlur; + pBlurEdit->GetWindowText( strBlur ); + + g_Font.m_nBlur = max( 2, atoi( strBlur ) ); + + strBlur.Format( "%d", g_Font.m_nBlur ); + pBlurEdit->SetWindowText( strBlur ); + } + else + { + g_Font.m_nBlur = 0; + } + + if ( bValveEffects && ((CButton*)m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK ))->GetCheck() ) + { + CEdit* pScanlineEdit = (CEdit*)m_pDialogBar->GetDlgItem( IDC_SCANLINES_EDIT ); + + CString strScanlines; + pScanlineEdit->GetWindowText( strScanlines ); + + g_Font.m_nScanlines = max( 2, atoi( strScanlines ) ); + + strScanlines.Format( "%d", g_Font.m_nScanlines ); + pScanlineEdit->SetWindowText( strScanlines ); + } + else + { + g_Font.m_nScanlines = 0; + } + + // Draw the new font glyphs + CalculateAndRenderGlyphs(); +} + + + + +//----------------------------------------------------------------------------- +// Name: OnMagnifyButton() +// Desc: User wants to run the Windows "magnify" tool +//----------------------------------------------------------------------------- +void CFontMakerApp::OnMagnifyButton() +{ + // Run the Windows "magnify" tool + WinExec( "magnify.exe", TRUE ); +} + + + + +//----------------------------------------------------------------------------- +// Name: class CTextureSizeDlg +// Desc: Simple dialog to change the font texture size +//----------------------------------------------------------------------------- +class CTextureSizeDlg : public CDialog +{ +public: + CTextureSizeDlg(); + +// Dialog Data + //{{AFX_DATA(CTextureSizeDlg) + enum { IDD = IDD_TEXTURESIZE }; + //}}AFX_DATA + + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTextureSizeDlg) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + //{{AFX_MSG(CTextureSizeDlg) + // No message handlers + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +CTextureSizeDlg::CTextureSizeDlg() : CDialog(CTextureSizeDlg::IDD) +{ + //{{AFX_DATA_INIT(CTextureSizeDlg) + //}}AFX_DATA_INIT +} + +void CTextureSizeDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + + //{{AFX_DATA_MAP(CTextureSizeDlg) + DDX_Text( pDX, IDC_WIDTH, g_Font.m_dwTextureWidth ); + DDV_MinMaxInt( pDX, g_Font.m_dwTextureWidth, 16, 2048 ); + + DDX_Text( pDX, IDC_HEIGHT, g_Font.m_dwTextureHeight ); + DDV_MinMaxInt( pDX, g_Font.m_dwTextureHeight, 16, 2048 ); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CTextureSizeDlg, CDialog) + //{{AFX_MSG_MAP(CTextureSizeDlg) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +void CFontMakerApp::SetTextureSize( int width, int height ) +{ + g_Font.m_dwTextureWidth = width; + g_Font.m_dwTextureHeight = height; + + CString str; + str.Format( "%ld", g_Font.m_dwTextureWidth ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_STATIC )->SetWindowText( str ); + str.Format( "%ld", g_Font.m_dwTextureHeight ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_STATIC )->SetWindowText( str ); +} + +//----------------------------------------------------------------------------- +// Name: OnTextureSizeButton() +// Desc: User wants to change the font texture size +//----------------------------------------------------------------------------- +void CFontMakerApp::OnTextureSizeButton() +{ + if ( !g_Font.m_hFont && !g_Font.m_pCustomFilename ) + return; + + CTextureSizeDlg dlgTextureSize; + dlgTextureSize.DoModal(); + + SetTextureSize( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight ); + + // Draw the new font glyphs + CalculateAndRenderGlyphs(); +} + +void CFontMakerApp::InsertGlyph() +{ + CEdit* pGlyphInsert = (CEdit*)m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_EDIT ); + + CString strInsert; + pGlyphInsert->GetWindowText( strInsert ); + + WORD wGlyph = atoi( strInsert ); + if ( wGlyph < 0 ) + wGlyph = 0; + else if ( wGlyph > 65535 ) + wGlyph = 65535; + + g_Font.InsertGlyph( wGlyph ); +} + +//----------------------------------------------------------------------------- +// Name: UpdateSelectedGlyph() +// Desc: User changed (via mouse or keyboard) which glyph is selected +//----------------------------------------------------------------------------- +void CFontMakerApp::UpdateSelectedGlyph( BOOL bGlyphSelected, int iSelectedGlyph ) +{ + // Handle case where no glyph is selected + g_bIsGlyphSelected = FALSE; + g_iSelectedGlyphNum = 0; + g_pSelectedGylph = NULL; + g_cSelectedGlyph = L'\0'; + + if ( bGlyphSelected ) + { + for ( DWORD i=0; i<=g_Font.m_cMaxGlyph; i++ ) + { + if ( g_Font.m_TranslatorTable[i] == iSelectedGlyph ) + { + g_bIsGlyphSelected = TRUE; + g_iSelectedGlyphNum = iSelectedGlyph; + g_pSelectedGylph = &g_Font.m_pGlyphs[iSelectedGlyph]; + g_cSelectedGlyph = (WCHAR)i; + break; + } + } + } + + // Enable/disable/set-text-of the appropriate controls + if ( g_bIsGlyphSelected ) + { + CString str; + str.Format( "%d", g_cSelectedGlyph ); m_pDialogBar->GetDlgItem( IDC_GLYPH_VALUE_STATIC )->SetWindowText( str ); + str.Format( "%d", g_pSelectedGylph->x ); m_pDialogBar->GetDlgItem( IDC_GLYPH_X_STATIC )->SetWindowText( str ); + str.Format( "%d", g_pSelectedGylph->y ); m_pDialogBar->GetDlgItem( IDC_GLYPH_Y_STATIC )->SetWindowText( str ); + str.Format( "%d", g_pSelectedGylph->w ); m_pDialogBar->GetDlgItem( IDC_GLYPH_W_STATIC )->SetWindowText( str ); + str.Format( "%d", g_pSelectedGylph->h ); m_pDialogBar->GetDlgItem( IDC_GLYPH_H_STATIC )->SetWindowText( str ); + str.Format( "%d", g_pSelectedGylph->a ); m_pDialogBar->GetDlgItem( IDC_GLYPH_A_STATIC )->SetWindowText( str ); + str.Format( "%d", g_pSelectedGylph->b ); m_pDialogBar->GetDlgItem( IDC_GLYPH_B_STATIC )->SetWindowText( str ); + str.Format( "%d", g_pSelectedGylph->c ); m_pDialogBar->GetDlgItem( IDC_GLYPH_C_STATIC )->SetWindowText( str ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPH_SPECIAL ))->SetCheck( g_Font.m_ValidGlyphs[g_cSelectedGlyph] == 2 ); + } + else + { + CString str(""); + m_pDialogBar->GetDlgItem( IDC_GLYPH_VALUE_STATIC )->SetWindowText( str ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_X_STATIC )->SetWindowText( str ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_Y_STATIC )->SetWindowText( str ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_W_STATIC )->SetWindowText( str ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_H_STATIC )->SetWindowText( str ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_A_STATIC )->SetWindowText( str ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_B_STATIC )->SetWindowText( str ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_C_STATIC )->SetWindowText( str ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPH_SPECIAL ))->SetCheck( FALSE ); + } + + m_pDialogBar->GetDlgItem( IDC_SELECTEDGLYPH_GROUPBOX )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_VALUE_LABEL )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_X_LABEL )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_Y_LABEL )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_W_LABEL )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_H_LABEL )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_A_LABEL )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_B_LABEL )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_C_LABEL )->EnableWindow( g_bIsGlyphSelected ); + + m_pDialogBar->GetDlgItem( IDC_GLYPH_VALUE_STATIC )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_X_STATIC )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_Y_STATIC )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_W_STATIC )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_H_STATIC )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_A_STATIC )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_B_STATIC )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_C_STATIC )->EnableWindow( g_bIsGlyphSelected ); + m_pDialogBar->GetDlgItem( IDC_GLYPH_SPECIAL )->EnableWindow( g_bIsGlyphSelected ); +} + + + + +//----------------------------------------------------------------------------- +// Name: OnGlyphSpecial() +// Desc: User changed the status of the selected glyph +//----------------------------------------------------------------------------- +void CFontMakerApp::OnGlyphSpecial() +{ + if( g_bIsGlyphSelected ) + { + if( ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPH_SPECIAL ))->GetCheck() ) + g_Font.m_ValidGlyphs[g_cSelectedGlyph] = 2; + else + g_Font.m_ValidGlyphs[g_cSelectedGlyph] = 1; + + // Draw the font glyphs, which may have changed layout + CalculateAndRenderGlyphs(); + } +} + +//----------------------------------------------------------------------------- +// Name: OnLoadButton() +// Desc: User wants to load a font file +//----------------------------------------------------------------------------- +void CFontMakerApp::OnLoadButton() +{ + CHAR strVBFFileName[MAX_PATH]; + sprintf( strVBFFileName, "%s.vbf", g_Font.m_strFontName ); + + OPENFILENAME ofnVBF; // common dialog box structure + ZeroMemory( &ofnVBF, sizeof(OPENFILENAME) ); + ofnVBF.lStructSize = sizeof(OPENFILENAME); + ofnVBF.hwndOwner = m_pMainWnd->m_hWnd; + ofnVBF.lpstrFilter = "Font files (*.vbf)\0*.vbf\0\0"; + ofnVBF.nFilterIndex = 1; + ofnVBF.lpstrFile = strVBFFileName; + ofnVBF.nMaxFile = sizeof(strVBFFileName); + ofnVBF.lpstrFileTitle = NULL; + ofnVBF.nMaxFileTitle = 0; + ofnVBF.lpstrInitialDir = NULL; + ofnVBF.lpstrTitle = "Load Font (VBF) File..."; + ofnVBF.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_READONLY; + + // Display the Load dialog box for the VBF file + if ( FALSE == GetOpenFileName( &ofnVBF ) ) + return; + + if ( FAILED( g_Font.ReadFontInfoFile( strVBFFileName ) ) ) + { + m_pMainWnd->MessageBox( "Could not load the Valve bitmap font info file.", + "Error", MB_ICONERROR|MB_OK ); + return; + } +} + +//----------------------------------------------------------------------------- +// OnLoadCustomFontButton +//----------------------------------------------------------------------------- +void CFontMakerApp::OnLoadCustomFontButton() +{ + CHAR strVCFFileName[MAX_PATH]; + strVCFFileName[0] = '\0'; + + OPENFILENAME ofnVCF; // common dialog box structure + ZeroMemory( &ofnVCF, sizeof(OPENFILENAME) ); + ofnVCF.lStructSize = sizeof(OPENFILENAME); + ofnVCF.hwndOwner = m_pMainWnd->m_hWnd; + ofnVCF.lpstrFilter = "Custom Font files (*.vcf)\0*.vcf\0\0"; + ofnVCF.nFilterIndex = 1; + ofnVCF.lpstrFile = strVCFFileName; + ofnVCF.nMaxFile = sizeof(strVCFFileName); + ofnVCF.lpstrFileTitle = NULL; + ofnVCF.nMaxFileTitle = 0; + ofnVCF.lpstrInitialDir = NULL; + ofnVCF.lpstrTitle = "Load Custom Font (VCF) File..."; + ofnVCF.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_READONLY; + + // Display the Load dialog box for the VBF file + if ( FALSE == GetOpenFileName( &ofnVCF ) ) + return; + + if ( FAILED( g_Font.ReadCustomFontFile( strVCFFileName ) ) ) + { + m_pMainWnd->MessageBox( "Could not load the Valve bitmap custom font file.", + "Error", MB_ICONERROR|MB_OK ); + return; + } + + // Reset the selected glpyh + UpdateSelectedGlyph( FALSE ); + + if ( FAILED( CalculateAndRenderGlyphs() ) ) + { + // Could not create new font + MessageBox( m_pMainWnd->m_hWnd, "Could not create the requested font!", "Error", MB_ICONERROR|MB_OK ); + return; + } + + m_pDialogBar->GetDlgItem( IDC_FONT_GROUPBOX )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_FONTNAME_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTSIZE_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_FONTSTYLE_STATIC )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSOUTLINED_CHECK )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSSHADOWED_CHECK )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSBLURRED_CHECK )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSSCANLINES_CHECK )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_EFFECTSANTIALIAS_CHECK )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_BLUR_EDIT )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_SCANLINES_EDIT )->EnableWindow( FALSE ); + + CString str; + str.Format( "%s", g_Font.m_strFontName ); + m_pDialogBar->GetDlgItem( IDC_FONTNAME_STATIC )->SetWindowText( str ); + + str.Format( "%d", g_Font.m_maxCustomCharHeight ); + m_pDialogBar->GetDlgItem( IDC_FONTSIZE_STATIC )->SetWindowText( str ); + + // Set texture properties + m_pDialogBar->GetDlgItem( IDC_TEXTURE_GROUPBOX )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_LABEL )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREWIDTH_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTUREHEIGHT_STATIC )->EnableWindow( TRUE ); + m_pDialogBar->GetDlgItem( IDC_TEXTURESIZE_BUTTON )->EnableWindow( TRUE ); + + SetTextureSize( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight ); + + // Set glyph range properties + m_pDialogBar->GetDlgItem( IDC_GLYPHS_GROUPBOX )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_EDIT )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_EDIT )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGEFROM_LABEL )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSRANGETO_LABEL )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILE_EDIT )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSFILESELECTOR_BUTTON )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO )->EnableWindow( TRUE ); + + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMRANGE_RADIO ))->SetCheck( FALSE ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSFROMFILE_RADIO ))->SetCheck( FALSE ); + ((CButton*)m_pDialogBar->GetDlgItem( IDC_GLYPHSCUSTOM_RADIO ))->SetCheck( TRUE ); + + m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_LABEL )->EnableWindow( FALSE ); + m_pDialogBar->GetDlgItem( IDC_INSERTGLYPH_EDIT )->EnableWindow( FALSE ); +} + +//----------------------------------------------------------------------------- +// Name: OnSaveButton() +// Desc: User wants to save the font files +//----------------------------------------------------------------------------- +void CFontMakerApp::OnSaveButton() +{ + CHAR strTGAFileName[MAX_PATH]; + CHAR strVBFFileName[MAX_PATH]; + + if ( !g_Font.m_hFont && !g_Font.m_pCustomFilename ) + return; + + sprintf( strTGAFileName, "%s.tga", g_Font.m_strFontName ); + + OPENFILENAME ofnTGA; // common dialog box structure + ZeroMemory( &ofnTGA, sizeof(OPENFILENAME) ); + ofnTGA.lStructSize = sizeof(OPENFILENAME); + ofnTGA.hwndOwner = m_pMainWnd->m_hWnd; + ofnTGA.lpstrFilter = "Targa files (*.tga)\0*.tga\0\0"; + ofnTGA.nFilterIndex = 1; + ofnTGA.lpstrFile = strTGAFileName; + ofnTGA.nMaxFile = sizeof(strTGAFileName); + ofnTGA.lpstrFileTitle = NULL; + ofnTGA.nMaxFileTitle = 0; + ofnTGA.lpstrInitialDir = NULL; + ofnTGA.lpstrTitle = "Save Font Texture Image (TGA) File..."; + ofnTGA.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_EXPLORER; + + // Display the Save As dialog box for the TGA file + if ( FALSE == GetSaveFileName( &ofnTGA ) ) + return; + + // use the tga name, but replace the extension + CHAR *ptr; + CHAR temp[MAX_PATH]; + int len; + strcpy( temp, strTGAFileName ); + len = strlen( temp ); + if ( len > 4 && temp[len-4] == '.' ) + { + temp[len-3] = 'v'; + temp[len-2] = 'b'; + temp[len-1] = 'f'; + + // strip the path + ptr = strrchr( temp, '\\' ); + if ( ptr ) + { + strcpy( strVBFFileName, ptr+1 ); + } + else + { + strcpy( strVBFFileName, temp ); + } + } + else + { + sprintf( strVBFFileName, "%s.vbf", g_Font.m_strFontName ); + } + + // place the VBF files in the materials directory + CHAR materialsDir[MAX_PATH]; + strcpy( materialsDir, strTGAFileName ); + strlwr( materialsDir ); + ptr = strstr( materialsDir, "\\content\\hl2x\\materialsrc\\" ); + if ( ptr ) + { + // need the final dirs, skip past + CHAR *ptr2 = ptr + strlen( "\\content\\hl2x\\materialsrc\\" ); + strcpy( temp, ptr2 ); + + *ptr = '\0'; + strcat( materialsDir, "\\game\\hl2x\\materials\\" ); + strcat( materialsDir, temp ); + + // strip terminal filename + ptr = materialsDir + strlen( materialsDir ) - 1; + while ( ptr > materialsDir ) + { + if ( *ptr == '\\' ) + { + *ptr = '\0'; + break; + } + ptr--; + } + } + else + { + materialsDir[0] = '\0'; + } + + // Initialize OPENFILENAME + OPENFILENAME ofnVBF; // common dialog box structure + ZeroMemory( &ofnVBF, sizeof(OPENFILENAME) ); + ofnVBF.lStructSize = sizeof(OPENFILENAME); + ofnVBF.hwndOwner = m_pMainWnd->m_hWnd; + ofnVBF.lpstrFilter = "Font files (*.vbf)\0*.vbf\0\0"; + ofnVBF.nFilterIndex = 1; + ofnVBF.lpstrFile = strVBFFileName; + ofnVBF.nMaxFile = sizeof(strVBFFileName); + ofnVBF.lpstrFileTitle = NULL; + ofnVBF.nMaxFileTitle = 0; + ofnVBF.lpstrInitialDir = materialsDir[0] ? materialsDir : NULL; + ofnVBF.lpstrTitle = "Save Valve Bitmap Font (VBF) File..."; + ofnVBF.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_EXPLORER; + + // Display the Save As dialog box for the ABC file + if ( FALSE == GetSaveFileName( &ofnVBF ) ) + return; + + // Make sure the names are valid + if ( !lstrcmp( strVBFFileName, strTGAFileName ) ) + { + m_pMainWnd->MessageBox( "Cannot have VBF and TGA filenames be the same!\nFiles not saved.", + "Error", MB_ICONERROR|MB_OK ); + return; + } + + // Add an extension, if there was not one + if ( 0 == ofnVBF.nFileExtension ) + lstrcat( strVBFFileName, ".vbf" ); + if ( 0 == ofnTGA.nFileExtension ) + lstrcat( strTGAFileName, ".tga" ); + + // Save the valve bitmap font info file (.vbf) + if ( FAILED( g_Font.WriteFontInfoFile( strVBFFileName ) ) ) + { + m_pMainWnd->MessageBox( "Could not write the Valve bitmap font info file.", + "Error", MB_ICONERROR|MB_OK ); + return; + } + + // blur or scanline effects require special processing to ensure + // they can be used in additive mode + bool bAdditiveMode = ( g_Font.m_nBlur || g_Font.m_nScanlines ); + + // a custom font requires special processing + bool bCustomFont = g_Font.m_pCustomFilename != NULL; + + // Save the font image file (.tga) + if ( FAILED( g_Font.WriteFontImageFile( strTGAFileName, bAdditiveMode, bCustomFont ) ) ) + { + m_pMainWnd->MessageBox( "Could not write the font texture image file.", + "Error", MB_ICONERROR|MB_OK ); + } +} + + + + +//----------------------------------------------------------------------------- +// Name: OnAbout() +// Desc: Display about box +//----------------------------------------------------------------------------- +void CFontMakerApp::OnAbout() +{ + CDialog dlg(IDD_ABOUT); + dlg.DoModal(); +} + + + + +//----------------------------------------------------------------------------- +// Name: OnHelp() +// Desc: Display app help +//----------------------------------------------------------------------------- +void CFontMakerApp::OnHelp() +{ + HKEY hRegKey; + + if( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, + _T("SOFTWARE\\Microsoft\\XboxSDK"), + 0, KEY_QUERY_VALUE, &hRegKey ) ) + { + DWORD dwSize = MAX_PATH; + CHAR InstallPath[MAX_PATH]; + + if( ERROR_SUCCESS == RegQueryValueEx( hRegKey, _T("InstallPath"), NULL, + NULL, (unsigned char *)InstallPath, &dwSize ) ) + { + CString path = InstallPath; + path += _T("\\doc\\xboxsdk.chm::/xbox_jbh_tool_fontmaker.htm"); + + ::HtmlHelp( m_pMainWnd->GetSafeHwnd(), path, HH_DISPLAY_TOPIC, NULL ); + RegCloseKey( hRegKey ); + return; + } + RegCloseKey( hRegKey ); + } + + MessageBox( m_pMainWnd->GetSafeHwnd(), + "Unable to find the Xbox SDK Help file xboxsdk.chm.", + "Help file error", MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL ); +} + + + + +//----------------------------------------------------------------------------- +// Name: OnExit() +// Desc: User chose to exit the app +//----------------------------------------------------------------------------- +void CFontMakerApp::OnExit() +{ + // Send a close message to the main window + m_pMainWnd->SendMessage( WM_CLOSE ); +} + + + + +//----------------------------------------------------------------------------- +// Name: ExitInstance() +// Desc: Do some cleanup before exitting the app +//----------------------------------------------------------------------------- +int CFontMakerApp::ExitInstance() +{ + DestroyCursor( m_hWaitCursor ); + + return CWinApp::ExitInstance(); +} + + + +//----------------------------------------------------------------------------- +// Name: CalculateAndRenderGlyphs() +// Desc: User changed the status of the selected glyph +//----------------------------------------------------------------------------- +HRESULT CFontMakerApp::CalculateAndRenderGlyphs() +{ + HRESULT hr; + + // This may take some time, so display a wait cursor + HCURSOR hOldCursor = GetCursor(); + SetCursor( m_hWaitCursor ); + + // Draw the font glyphs, which may have changed layout + if( FAILED( hr = g_Font.CalculateAndRenderGlyphs() ) ) + return hr; + + // Re-select the current glyph since the font data may have changed + theApp.UpdateSelectedGlyph( g_bIsGlyphSelected, g_iSelectedGlyphNum ); + + // Inform the view of the new font glyphs + m_pView->OnNewFontGlyphs(); + + // Restore the cursor + SetCursor( hOldCursor ); + + return S_OK; +} + + + + diff --git a/utils/xbox/FontMaker/fontmaker.doc b/utils/xbox/FontMaker/fontmaker.doc Binary files differnew file mode 100644 index 0000000..f739de0 --- /dev/null +++ b/utils/xbox/FontMaker/fontmaker.doc diff --git a/utils/xbox/FontMaker/fontmaker.h b/utils/xbox/FontMaker/fontmaker.h new file mode 100644 index 0000000..43526ad --- /dev/null +++ b/utils/xbox/FontMaker/fontmaker.h @@ -0,0 +1,145 @@ +//----------------------------------------------------------------------------- +// Name: FontMaker.h +// +// Desc: Defines the class behaviors for the application. +// +// Hist: 09.06.02 - Revised Fontmaker sample +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- +#ifndef FONTMAKER_H +#define FONTMAKER_H + +#include "resource.h" +#include "BitmapFontFile.h" +#include <math.h> +#include "..\toollib\toollib.h" +#include "..\toollib\scriplib.h" +#include "..\toollib\piclib.h" + +//----------------------------------------------------------------------------- +// Name: class CFontMakerView +// Desc: The scroll view class for viewing the font texture image +//----------------------------------------------------------------------------- +class CFontMakerView : public CScrollView +{ +protected: + CFontMakerView() {} + DECLARE_DYNCREATE(CFontMakerView) + + CDC m_memDC; + +public: + VOID OnNewFontGlyphs(); + + virtual ~CFontMakerView(); + +public: + + // Overridden functions + //{{AFX_VIRTUAL(CFontMakerView) + public: + virtual void OnDraw(CDC* pDC); + virtual void OnInitialUpdate(); + protected: + //}}AFX_VIRTUAL + +protected: + // Message map functions + //{{AFX_MSG(CFontMakerView) + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + + + +//----------------------------------------------------------------------------- +// Name: class CFontMakerFrameWnd +// Desc: The main frame window class for the app, which contains the dialog bar +// full of controls and the scroll view to view the font texture image. +//----------------------------------------------------------------------------- +class CFontMakerFrameWnd : public CFrameWnd +{ +public: + CFontMakerFrameWnd() {} + virtual ~CFontMakerFrameWnd() {} + + CDialogBar m_wndDialogBar; + CDialogBar* GetDialogBar() { return &m_wndDialogBar; } + +protected: + DECLARE_DYNCREATE(CFontMakerFrameWnd) + + // Message map functions + //{{AFX_MSG(CFontMakerFrameWnd) + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + + + +//----------------------------------------------------------------------------- +// Name: class CFontMakerApp +// Desc: The main app class +//----------------------------------------------------------------------------- +class CFontMakerApp : public CWinApp +{ + CDialogBar* m_pDialogBar; + CFontMakerView* m_pView; + HCURSOR m_hWaitCursor; + +public: + CFontMakerApp() {} + ~CFontMakerApp() {} + + VOID UpdateSelectedGlyph( BOOL bGlyphSelected, int iSelectedGlyph = 0 ); + HRESULT CalculateAndRenderGlyphs(); + VOID InsertGlyph(); + + void SetTextureSize( int width, int height ); + + // Overrides + //{{AFX_VIRTUAL(CFontMakerApp) + public: + virtual BOOL InitInstance(); + virtual int ExitInstance(); + //}}AFX_VIRTUAL + + // Implementation + //{{AFX_MSG(CFontMakerApp) + afx_msg void OnNewFontButton(); + afx_msg void OnEffectsCheck(); + afx_msg void OnGlyphsFromRangeRadio(); + afx_msg void OnChangeGlpyhsRangeEdit(); + afx_msg void OnGlyphsFromFileRadio(); + afx_msg void OnChangeGlyphsFileEdit(); + afx_msg void OnGlyphsFileSelectorButton(); + afx_msg void OnTextureSizeButton(); + afx_msg void OnMagnifyButton(); + afx_msg void OnGlyphSpecial(); + afx_msg void OnUpdateButton( CCmdUI* pCmdUI ); + afx_msg void OnSaveButton(); + afx_msg void OnExit(); + afx_msg void OnAbout(); + afx_msg void OnHelp(); + afx_msg void OnGlyphsCustom(); + afx_msg void OnLoadButton(); + afx_msg void OnLoadCustomFontButton(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + + +// External reference to the unique application instance +extern CFontMakerApp theApp; + + + +#endif // FONTMAKER_H diff --git a/utils/xbox/FontMaker/fontmaker.ico b/utils/xbox/FontMaker/fontmaker.ico Binary files differnew file mode 100644 index 0000000..8046b8c --- /dev/null +++ b/utils/xbox/FontMaker/fontmaker.ico diff --git a/utils/xbox/FontMaker/fontmaker.rc b/utils/xbox/FontMaker/fontmaker.rc new file mode 100644 index 0000000..9f95362 --- /dev/null +++ b/utils/xbox/FontMaker/fontmaker.rc @@ -0,0 +1,314 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif //_WIN32\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "FontMaker.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOGBAR DIALOGEX 0, 0, 142, 418 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Font",IDC_FONT_GROUPBOX,5,5,130,142,WS_DISABLED + LTEXT "Name",IDC_FONTNAME_LABEL,10,15,24,15,SS_CENTERIMAGE | + WS_DISABLED + LTEXT "",IDC_FONTNAME_STATIC,35,15,90,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + LTEXT "Style",IDC_FONTSTYLE_LABEL,10,30,20,15,SS_CENTERIMAGE | + WS_DISABLED + LTEXT "",IDC_FONTSTYLE_STATIC,35,30,90,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + LTEXT "Size",IDC_FONTSIZE_LABEL,10,45,20,15,SS_CENTERIMAGE | + WS_DISABLED + LTEXT "",IDC_FONTSIZE_STATIC,35,45,30,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CONTROL "Outlined",IDC_EFFECTSOUTLINED_CHECK,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,10,65,42,10 + CONTROL "Shadowed",IDC_EFFECTSSHADOWED_CHECK,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,10,80,50,10 + PUSHBUTTON "Magnify...",IDC_MAGNIFY_BUTTON,75,70,50,14,WS_DISABLED + GROUPBOX "Texture properties",IDC_TEXTURE_GROUPBOX,5,149,130,40, + WS_DISABLED + LTEXT "Insert Glyph:",IDC_INSERTGLYPH_LABEL,10,375,63,10, + SS_CENTERIMAGE | WS_DISABLED + CTEXT "",IDC_TEXTUREWIDTH_STATIC,9,170,30,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CTEXT "Height",IDC_TEXTUREHEIGHT_LABEL,45,159,30,10, + SS_CENTERIMAGE | WS_DISABLED + CTEXT "",IDC_TEXTUREHEIGHT_STATIC,45,170,30,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + PUSHBUTTON "Size...",IDC_TEXTURESIZE_BUTTON,80,165,50,14, + WS_DISABLED + GROUPBOX "Glyphs",IDC_GLYPHS_GROUPBOX,5,189,130,95,WS_DISABLED + CONTROL "From range:",IDC_GLYPHSFROMRANGE_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_DISABLED | WS_GROUP,10,199,53,10 + RTEXT "From:",IDC_GLYPHSRANGEFROM_LABEL,25,215,20,15, + SS_CENTERIMAGE | WS_DISABLED + EDITTEXT IDC_GLYPHSRANGEFROM_EDIT,50,215,25,12,ES_CENTER | + ES_AUTOHSCROLL | WS_DISABLED + RTEXT "To:",IDC_GLYPHSRANGETO_LABEL,85,215,15,15, + SS_CENTERIMAGE | WS_DISABLED + EDITTEXT IDC_GLYPHSRANGETO_EDIT,105,215,25,12,ES_CENTER | + ES_AUTOHSCROLL | WS_DISABLED + CONTROL "From file:",IDC_GLYPHSFROMFILE_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_DISABLED,10,233,44,10 + EDITTEXT IDC_GLYPHSFILE_EDIT,23,245,90,12,ES_AUTOHSCROLL | + WS_DISABLED + PUSHBUTTON "...",IDC_GLYPHSFILESELECTOR_BUTTON,117,245,15,12, + WS_DISABLED + GROUPBOX "Selected Glyph",IDC_SELECTEDGLYPH_GROUPBOX,5,289,130, + 121,WS_DISABLED + CTEXT "Value",IDC_GLYPH_VALUE_LABEL,10,300,35,10, + SS_CENTERIMAGE | WS_DISABLED + CTEXT "",IDC_GLYPH_VALUE_STATIC,10,310,35,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CTEXT "A",IDC_GLYPH_A_LABEL,60,300,20,10,SS_CENTERIMAGE | + WS_DISABLED + CTEXT "x",IDC_GLYPH_X_LABEL,9,324,20,10,SS_CENTERIMAGE | + WS_DISABLED + CTEXT "y",IDC_GLYPH_Y_LABEL,35,324,20,10,SS_CENTERIMAGE | + WS_DISABLED + CTEXT "w",IDC_GLYPH_W_LABEL,65,324,20,10,SS_CENTERIMAGE | + WS_DISABLED + CTEXT "h",IDC_GLYPH_H_LABEL,89,324,20,10,SS_CENTERIMAGE | + WS_DISABLED + CTEXT "B",IDC_GLYPH_B_LABEL,85,300,20,10,SS_CENTERIMAGE | + WS_DISABLED + CTEXT "C",IDC_GLYPH_C_LABEL,110,300,20,10,SS_CENTERIMAGE | + WS_DISABLED + CONTROL "Reserved for custom bitmap",IDC_GLYPH_SPECIAL,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,10,356,104,10 + CTEXT "",IDC_GLYPH_X_STATIC,10,334,20,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CTEXT "",IDC_GLYPH_Y_STATIC,35,334,20,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CTEXT "",IDC_GLYPH_W_STATIC,65,334,20,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CTEXT "",IDC_GLYPH_H_STATIC,90,334,20,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CTEXT "",IDC_GLYPH_A_STATIC,60,310,20,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CTEXT "",IDC_GLYPH_B_STATIC,85,310,20,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CTEXT "",IDC_GLYPH_C_STATIC,110,310,20,12,SS_CENTERIMAGE | + WS_DISABLED,WS_EX_CLIENTEDGE + CONTROL "Blurred",IDC_EFFECTSBLURRED_CHECK,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,10,97,50,10 + CONTROL "ScanLines",IDC_EFFECTSSCANLINES_CHECK,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,10,114,50,10 + EDITTEXT IDC_BLUR_EDIT,65,95,25,12,ES_CENTER | ES_AUTOHSCROLL | + WS_DISABLED + EDITTEXT IDC_SCANLINES_EDIT,65,114,25,12,ES_CENTER | + ES_AUTOHSCROLL | WS_DISABLED + CONTROL "Antialias",IDC_EFFECTSANTIALIAS_CHECK,"Button", + BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,10,130,50,10 + CONTROL "Custom",IDC_GLYPHSCUSTOM_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_DISABLED | WS_GROUP,10,265,53,10 + EDITTEXT IDC_INSERTGLYPH_EDIT,10,387,35,12,ES_CENTER | + ES_AUTOHSCROLL | WS_DISABLED + CTEXT "Width",IDC_TEXTUREWIDTH_LABEL,9,159,30,10, + SS_CENTERIMAGE | WS_DISABLED +END + +IDD_TEXTURESIZE DIALOG 0, 0, 167, 49 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Texture Size" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Width",IDC_STATIC,5,5,19,15,SS_CENTERIMAGE + EDITTEXT IDC_WIDTH,35,5,40,15,ES_AUTOHSCROLL + LTEXT "Height",IDC_STATIC,5,25,25,15,SS_CENTERIMAGE + EDITTEXT IDC_HEIGHT,35,25,40,15,ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,115,5,50,14 + PUSHBUTTON "Cancel",IDCANCEL,115,25,50,14 +END + +IDD_ABOUT DIALOGEX 0, 0, 262, 123 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "About FontMaker" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,5,20,21,20 + LTEXT "Xbox Font Maker tool - Modified for Valve Software", + IDC_STATIC,36,10,222,8 + LTEXT "Version 2.0.0000.1 - Valve",IDC_STATIC,36,25,222,8 + LTEXT "Copyright(c) 2000-2003 Microsoft Corporation. All rights reserved.", + IDC_STATIC,36,40,222,8 + LTEXT "Warning: This computer program is protected by copyright law and", + IDC_STATIC,36,55,222,8 + LTEXT "international treaties. Unauthorized reproduction or distribution of", + IDC_STATIC,36,65,222,8 + LTEXT "this program, or any portion of it, may result in severe civil and", + IDC_STATIC,36,75,222,8 + LTEXT "criminal penalties, and will be prosecuted to the maximum extent", + IDC_STATIC,36,85,222,8 + LTEXT "possible under the law.",IDC_STATIC,36,95,222,8 + DEFPUSHBUTTON "OK",IDOK,204,102,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOGBAR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 135 + TOPMARGIN, 7 + BOTTOMMARGIN, 411 + END + + IDD_TEXTURESIZE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 160 + TOPMARGIN, 7 + BOTTOMMARGIN, 42 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 255 + TOPMARGIN, 7 + BOTTOMMARGIN, 68 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MAINFRAME MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "Load TTF Font...", IDM_FILE_NEWFONT + MENUITEM "Load Custom Font...", IDM_FILE_LOADFONTLAYOUT + MENUITEM "Load Compiled Font File...", IDM_FILE_LOADFONTFILE + MENUITEM SEPARATOR + MENUITEM "&Save Compiled Font...", IDM_FILE_SAVEFONTFILES + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_FILE_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "FontMaker &Help\tF1", ID_HELP + MENUITEM SEPARATOR + MENUITEM "&About FontMaker...", ID_APP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDR_MAINFRAME "FontMaker\n\nFontMa\n\n\nFontMaker.Document\nFontMa Document" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif //_WIN32 +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/utils/xbox/FontMaker/fontmaker.vpc b/utils/xbox/FontMaker/fontmaker.vpc new file mode 100644 index 0000000..8774386 --- /dev/null +++ b/utils/xbox/FontMaker/fontmaker.vpc @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------------- +// FONTMAKER.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\..\.." +$Macro OUTBINDIR "$SRCDIR\devtools\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_win_win32_base.vpc" + +$Configuration +{ + $Compiler + { + $EnableC++Exceptions "Yes (/EHsc)" + } + + $Linker + { + $AdditionalDependencies "htmlhelp.lib" + } +} + + +$Project "FontMaker" +{ + $Folder "Source Files" + { + -$File "$SRCDIR\public\tier0\memoverride.cpp" + + $File "FontMaker.cpp" + $File "FontMakerWnd.cpp" + $File "Glyphs.cpp" + $File "..\toollib\piclib.cpp" + $File "..\toollib\scriplib.cpp" + $File "Stdafx.cpp" + { + $Configuration + { + $Compiler + { + $Create/UsePrecompiledHeader "Create Precompiled Header (/Yc)" + } + } + } + + $File "..\toollib\toollib.cpp" + } + + $Folder "Resource Files" + { + $File "FontMaker.ico" + $File "FontMaker.rc" + $File "resource.h" + } + + $Folder "Header Files" + { + $File "..\..\..\public\BitmapFontFile.h" + $File "FontMaker.h" + $File "Glyphs.h" + $File "..\toollib\piclib.h" + $File "..\toollib\scriplib.h" + $File "Stdafx.h" + $File "..\toollib\toollib.h" + } +} diff --git a/utils/xbox/FontMaker/fontmakerwnd.cpp b/utils/xbox/FontMaker/fontmakerwnd.cpp new file mode 100644 index 0000000..a81a24e --- /dev/null +++ b/utils/xbox/FontMaker/fontmakerwnd.cpp @@ -0,0 +1,396 @@ +//----------------------------------------------------------------------------- +// Name: FontMakerWnd.cpp +// +// Desc: The window and scroll view class for the fontmaker app +// +// Hist: 09.06.02 - Revised Fontmaker sample +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- +#include "stdafx.h" +#include "FontMaker.h" +#include "Glyphs.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +extern CTextureFont g_Font; +BOOL g_bIsGlyphSelected = FALSE; +int g_iSelectedGlyphNum = 0; +WCHAR g_cSelectedGlyph = '\0'; +GLYPH_ATTR* g_pSelectedGylph = NULL; + +// Colors +#define COLOR_WHITE ( RGB(255,255,255) ) +#define COLOR_BLACK ( RGB( 0, 0, 0) ) +#define COLOR_BLUE ( RGB( 0, 0,255) ) +#define COLOR_RED ( RGB(255, 0, 0) ) +#define COLOR_DARKRED ( RGB(128, 0, 0) ) + +//----------------------------------------------------------------------------- +// CFontMakerFrameWnd +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNCREATE(CFontMakerFrameWnd, CFrameWnd) + +BEGIN_MESSAGE_MAP(CFontMakerFrameWnd, CFrameWnd) + //{{AFX_MSG_MAP(CFontMakerFrameWnd) + ON_WM_CREATE() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +int CFontMakerFrameWnd::OnCreate( LPCREATESTRUCT pCreateStruct ) +{ + if( CFrameWnd::OnCreate( pCreateStruct ) == -1 ) + return -1; + + // Create a docked dialog bar + EnableDocking( CBRS_ALIGN_ANY ); + if( !m_wndDialogBar.Create( this, IDD_DIALOGBAR, + CBRS_LEFT, IDD_DIALOGBAR ) ) + { + TRACE0("Failed to create DlgBar\n"); + return -1; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// CFontMakerView +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNCREATE(CFontMakerView, CScrollView) + +BEGIN_MESSAGE_MAP(CFontMakerView, CScrollView) + //{{AFX_MSG_MAP(CFontMakerView) + ON_WM_LBUTTONDOWN() + ON_WM_ERASEBKGND() + ON_WM_KEYDOWN() + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//----------------------------------------------------------------------------- +// Name: ~CFontMakerView() +// Desc: Destructor with special cleanup +//----------------------------------------------------------------------------- +CFontMakerView::~CFontMakerView() +{ + // Cleanup before exitting + m_memDC.DeleteDC(); +} + +//----------------------------------------------------------------------------- +// Name: OnInitialUpdate() +// Desc: Called when the view is created. +//----------------------------------------------------------------------------- +void CFontMakerView::OnInitialUpdate() +{ + // Set the scroll bars + CScrollView::OnInitialUpdate(); + CSize szTotal( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight ); + SetScrollSizes( MM_TEXT, szTotal ); + CPoint ptCenter( 0, 0 ); + CenterOnPoint( ptCenter ); + + // Create a secondary DC, used for drawing + m_memDC.CreateCompatibleDC( GetDC() ); +} + +//----------------------------------------------------------------------------- +// Name: OnEraseBkgnd() +// Desc: Overridden function to prevent the view from flickering during resizes +// and redraws +//----------------------------------------------------------------------------- +BOOL CFontMakerView::OnEraseBkgnd( CDC* pDC ) +{ + return TRUE; +} + +//----------------------------------------------------------------------------- +// Name: RenderSelectedGlyph() +// Desc: Highlight the selected glyph +//----------------------------------------------------------------------------- +VOID RenderSelectedGlyph( CDC* pDC ) +{ + // If no glyph is selected, return + if( FALSE == g_bIsGlyphSelected ) + return; + + HRGN rgn = CreateRectRgn( 0, 0, g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight ); + SelectClipRgn( pDC->m_hDC, rgn ); + + // Draw a higlighted background for the selected glyph + { + int x = g_pSelectedGylph->x; + int y = g_pSelectedGylph->y; + int w = g_pSelectedGylph->w; + int h = g_pSelectedGylph->h; + pDC->FillSolidRect( x, y, w, h, COLOR_DARKRED ); + } + + // Setup the DC for drawing text + pDC->SetTextColor( COLOR_WHITE ); + pDC->SelectObject( g_Font.m_hFont ); + pDC->SetTextAlign( TA_LEFT|TA_TOP ); + pDC->SetMapMode( MM_TEXT ); + pDC->SetBkMode( TRANSPARENT ); + pDC->SetBkColor( COLOR_BLUE ); + + CPen pen( PS_SOLID, 1, COLOR_RED ); + pDC->SelectObject( &pen ); + + // Render the selected glyph + GLYPH_ATTR* pGlyph = g_pSelectedGylph; + { + WCHAR c = g_cSelectedGlyph; + WCHAR str[2] = L"A"; + str[0] = c ? c : 0xffff; + + if ( g_Font.m_ValidGlyphs[c] == 2 ) + { + // Draw a square box for a placeholder for custom glyph graphics + pDC->FillSolidRect( pGlyph->x, pGlyph->y, pGlyph->w, pGlyph->h, COLOR_BLACK ); + } + else + { + int sx = pGlyph->x; + int sy = pGlyph->y; + + // Adjust ccordinates to account for the leading edge + if ( str[0] > 0x1000 ) + { + } + else + { + sx -= pGlyph->a; + + if ( g_Font.m_bOutlineEffect ) + sx -= 1; + } + + if ( g_Font.m_bOutlineEffect ) + { + sx++; + sy++; + + pDC->SetTextColor( COLOR_BLACK ); + ExtTextOutW( pDC->m_hDC, sx-1, sy-1, ETO_OPAQUE, NULL, str, 1, NULL ); + ExtTextOutW( pDC->m_hDC, sx+0, sy-1, ETO_OPAQUE, NULL, str, 1, NULL ); + ExtTextOutW( pDC->m_hDC, sx+1, sy-1, ETO_OPAQUE, NULL, str, 1, NULL ); + ExtTextOutW( pDC->m_hDC, sx-1, sy+0, ETO_OPAQUE, NULL, str, 1, NULL ); + ExtTextOutW( pDC->m_hDC, sx+1, sy+0, ETO_OPAQUE, NULL, str, 1, NULL ); + ExtTextOutW( pDC->m_hDC, sx-1, sy+1, ETO_OPAQUE, NULL, str, 1, NULL ); + ExtTextOutW( pDC->m_hDC, sx+0, sy+1, ETO_OPAQUE, NULL, str, 1, NULL ); + ExtTextOutW( pDC->m_hDC, sx+1, sy+1, ETO_OPAQUE, NULL, str, 1, NULL ); + } + + if ( g_Font.m_bShadowEffect ) + { + pDC->SetTextColor( COLOR_BLACK ); + ExtTextOutW( pDC->m_hDC, sx+2, sy+2, ETO_OPAQUE, NULL, str, 1, NULL ); + } + + // Output the letter + pDC->SetTextColor( COLOR_WHITE ); + ExtTextOutW( pDC->m_hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL ); + } + } + + // Draw a red outline around the selected glyph + { + // Create a red pen + CPen pen( PS_SOLID, 1, COLOR_RED ); + pDC->SelectObject( &pen ); + + // Draw the outline + int x1 = pGlyph->x - 1; + int y1 = pGlyph->y - 1; + int x2 = pGlyph->x + pGlyph->w; + int y2 = pGlyph->y + pGlyph->h; + + pDC->MoveTo( x1, y1 ); + pDC->LineTo( x2, y1 ); + pDC->LineTo( x2, y2 ); + pDC->LineTo( x1, y2 ); + pDC->LineTo( x1, y1 ); + } + + SelectClipRgn( pDC->m_hDC, NULL ); + DeleteObject( rgn ); +} + +//----------------------------------------------------------------------------- +// Name: OnDraw() +// Desc: Overridden draw function. Draws the font glyphs if a font is loaded, +// else just a black background. +//----------------------------------------------------------------------------- +VOID CFontMakerView::OnNewFontGlyphs() +{ + // Select the resulting bits into our memory DC + static CBitmap Bitmap; + Bitmap.DeleteObject(); + Bitmap.CreateBitmap( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight, 1, 32, g_Font.m_pBits ); + m_memDC.SelectObject( &Bitmap ); + + // Trigger the view to be re-drawn + OnUpdate(0,0,0); +} + +//----------------------------------------------------------------------------- +// Name: OnDraw() +// Desc: Overridden draw function. Draws the font glyphs if a font is loaded, +// else just a black background. +//----------------------------------------------------------------------------- +VOID CFontMakerView::OnDraw( CDC* pDC ) +{ + RECT rc; + GetClientRect( &rc ); + + // Draw the view + if ( g_Font.m_hFont == NULL && !g_Font.m_pCustomFilename ) + { + // Don't display any scroll bars + CSize sizeTotal( 0, 0 ); + SetScrollSizes( MM_TEXT, sizeTotal ); + + // Draw a black background + pDC->FillSolidRect( 0, 0, rc.right, rc.bottom, COLOR_BLACK ); + } + else + { + // Set the scroll sizes for the view + CSize sizeTotal( g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight ); + SetScrollSizes( MM_TEXT, sizeTotal ); + + // Draw the view's black areas + pDC->FillSolidRect( g_Font.m_dwTextureWidth, 0, max( (int)g_Font.m_dwTextureWidth, rc.right), g_Font.m_dwTextureHeight, COLOR_BLACK ); + pDC->FillSolidRect( 0, g_Font.m_dwTextureHeight, max( (int)g_Font.m_dwTextureWidth, rc.right), max( (int)g_Font.m_dwTextureHeight, rc.bottom), COLOR_BLACK ); + + // Display the bitmap of all the rendered glyphs + pDC->BitBlt( 0, 0, g_Font.m_dwTextureWidth, g_Font.m_dwTextureHeight, &m_memDC, 0, 0, SRCCOPY ); + + // Draw the selected glyph, if any + RenderSelectedGlyph( pDC ); + } +} + +//----------------------------------------------------------------------------- +// Name: OnLButtonDown() +// Desc: Overridden function to select a glyph when the user clicks the mouse. +//----------------------------------------------------------------------------- +void CFontMakerView::OnLButtonDown( UINT nFlags, CPoint point ) +{ + if ( !g_Font.m_hFont ) + return; + + // Correct the mouseclick point to account for the scroll position + point += GetScrollPosition(); + + // Find out which glyph, if any, is selected by the mouse click + theApp.UpdateSelectedGlyph( FALSE ); + + for( DWORD i=0; i<g_Font.m_dwNumGlyphs && g_Font.m_pGlyphs; i++ ) + { + GLYPH_ATTR* pGlyph = &g_Font.m_pGlyphs[i]; + + if ( point.x >= pGlyph->x-2 && point.x <= pGlyph->x + pGlyph->w ) + { + if ( point.y >= pGlyph->y-2 && point.y <= pGlyph->y + pGlyph->h ) + { + theApp.UpdateSelectedGlyph( TRUE, i ); + break; + } + } + } + + // Redraw the view to show the newly selected glyph + Invalidate( TRUE ); + + // Call the base class' handler + CScrollView::OnLButtonDown( nFlags, point ); +} + +//----------------------------------------------------------------------------- +// Name: OnKeyDown() +// Desc: Overridden function to select a glyph with the keyboard. +//----------------------------------------------------------------------------- +void CFontMakerView::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ) +{ + if ( !g_Font.m_hFont ) + return; + + if( g_Font.m_dwNumGlyphs > 0 ) + { + if( FALSE == g_bIsGlyphSelected ) + { + if( nChar == 37 || nChar == 38 || nChar == 39 || nChar == 40 ) // Left, right, up or down + { + // Select the first glyph + theApp.UpdateSelectedGlyph( TRUE, 0 ); + } + } + else + { + if( nChar == 37 ) // Left + theApp.UpdateSelectedGlyph( TRUE, max( 0, g_iSelectedGlyphNum-1 ) ); + else if( nChar == 39 ) // Right + theApp.UpdateSelectedGlyph( TRUE, min( (int)g_Font.m_dwNumGlyphs-1, g_iSelectedGlyphNum+1 ) ); + else if( nChar == 38 || nChar == 40 ) // Up or down + { + // Find the closest glyph above or below to move to + int x = g_pSelectedGylph->x + g_pSelectedGylph->w/2; + int y = g_pSelectedGylph->y + g_pSelectedGylph->h/2; + + if( nChar == 38 ) y -= g_pSelectedGylph->h; + if( nChar == 40 ) y += g_pSelectedGylph->h; + + for( DWORD i=0; i<g_Font.m_dwNumGlyphs; i++ ) + { + GLYPH_ATTR* pGlyph = &g_Font.m_pGlyphs[i]; + + if( x >= pGlyph->x-2 && x <= pGlyph->x + pGlyph->w ) + { + if( y >= pGlyph->y-2 && y <= pGlyph->y + pGlyph->h ) + { + theApp.UpdateSelectedGlyph( TRUE, i ); + break; + } + } + } + } + else if ( nChar == 46 ) + { + // delete a glyph + theApp.OnGlyphsCustom(); + + // mark glyph as invalid + g_Font.DeleteGlyph( g_cSelectedGlyph ); + + // reset to the first glyph + theApp.UpdateSelectedGlyph( FALSE ); + } + else if ( nChar == 45 ) + { + // insert a glyph + theApp.OnGlyphsCustom(); + + // reset to the first glyph + theApp.UpdateSelectedGlyph( FALSE ); + + theApp.InsertGlyph(); + } + } + + // Redraw the view to show the newly selected glyph + Invalidate( TRUE ); + } + + CScrollView::OnKeyDown( nChar, nRepCnt, nFlags ); +} + + + diff --git a/utils/xbox/FontMaker/glyphs.cpp b/utils/xbox/FontMaker/glyphs.cpp new file mode 100644 index 0000000..c2328ac --- /dev/null +++ b/utils/xbox/FontMaker/glyphs.cpp @@ -0,0 +1,1484 @@ +//----------------------------------------------------------------------------- +// Name: Glyphs.cpp +// +// Desc: Functions and global variables for keeping track of font glyphs +// +// Hist: 09.06.02 - Revised Fontmaker sample +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- +#include "stdafx.h" +#include "Glyphs.h" +#include "FontMaker.h" + +const COLORREF COLOR_WHITE = RGB(255,255,255); +const COLORREF COLOR_BLACK = RGB( 0, 0, 0); +const COLORREF COLOR_BLUE = RGB( 0, 0,255); + +//----------------------------------------------------------------------------- +// Name: CTextureFont() +// Desc: Constructor +//----------------------------------------------------------------------------- +CTextureFont::CTextureFont() +{ + ZeroMemory( this, sizeof( *this ) ); + + m_bIncludeNullCharacter = TRUE; + m_bAntialiasEffect = TRUE; + + // Texture info + m_dwTextureWidth = 256; + m_dwTextureHeight = 256; + + // Default glyph range + WORD wStartGlyph = 32; + WORD wEndGlyph = 255; + ExtractValidGlyphsFromRange( wStartGlyph, wEndGlyph ); +} + +//----------------------------------------------------------------------------- +// Name: ~CTextureFont() +// Desc: Destructor +//----------------------------------------------------------------------------- +CTextureFont::~CTextureFont() +{ + DestroyObjects(); + + if ( m_hFont ) + DeleteObject( m_hFont ); + + if ( m_pBits ) + delete[] m_pBits; + + m_pBits = NULL; + m_hFont = NULL; +} + +//----------------------------------------------------------------------------- +// ClearFont +//----------------------------------------------------------------------------- +void CTextureFont::ClearFont() +{ + DestroyObjects(); + + ZeroMemory( &m_LogFont, sizeof(LOGFONT) ); + + m_strFontName[0] = '\0'; + + m_hFont = NULL; + + m_dwTextureWidth = 256; + m_dwTextureHeight = 256; + + m_bAntialiasEffect = FALSE; + m_bShadowEffect = FALSE; + m_bOutlineEffect = FALSE; + m_nBlur = 0; + m_nScanlines = 0; +} + +//----------------------------------------------------------------------------- +// Name: DestroyObjects() +// Desc: Cleans up all allocated resources for the class +//----------------------------------------------------------------------------- +VOID CTextureFont::DestroyObjects() +{ + if ( m_pGlyphs ) + delete[] m_pGlyphs; + if ( m_ValidGlyphs ) + delete[] m_ValidGlyphs; + if ( m_TranslatorTable ) + delete[] m_TranslatorTable; + + if ( m_pCustomFilename ) + { + TL_Free( (void*)m_pCustomFilename ); + m_pCustomFilename = NULL; + + for (DWORD i=0; i<m_dwNumGlyphs; i++) + { + if ( m_pCustomGlyphFiles[i] ) + { + TL_Free( m_pCustomGlyphFiles[i] ); + m_pCustomGlyphFiles[i] = NULL; + } + } + } + + m_cMaxGlyph = 0; + m_dwNumGlyphs = 0; + m_pGlyphs = NULL; + m_ValidGlyphs = NULL; + m_TranslatorTable = NULL; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +HRESULT CTextureFont::InsertGlyph( WORD wGlyph ) +{ + m_cMaxGlyph = 0; + m_dwNumGlyphs = 0; + + m_ValidGlyphs[wGlyph] = 1; + + for ( DWORD c=0; c<=65535; c++ ) + { + if ( m_ValidGlyphs[c] ) + { + m_dwNumGlyphs++; + m_cMaxGlyph = (WCHAR)c; + } + } + + BuildTranslatorTable(); + theApp.CalculateAndRenderGlyphs(); + + return S_OK; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +HRESULT CTextureFont::DeleteGlyph( WORD wGlyph ) +{ + m_cMaxGlyph = 0; + m_dwNumGlyphs = 0; + + m_ValidGlyphs[wGlyph] = 0; + + for ( DWORD c=0; c<=65535; c++ ) + { + if ( m_ValidGlyphs[c] ) + { + m_dwNumGlyphs++; + m_cMaxGlyph = (WCHAR)c; + } + } + + BuildTranslatorTable(); + theApp.CalculateAndRenderGlyphs(); + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Name: ExtractValidGlyphsFromRange() +// Desc: Set global variables to indicate we will be drawing all glyphs in the +// range specified. +//----------------------------------------------------------------------------- +HRESULT CTextureFont::ExtractValidGlyphsFromRange( WORD wStartGlyph, WORD wEndGlyph ) +{ + // Cleanup any previous entries + if( m_ValidGlyphs ) + delete[] m_ValidGlyphs; + + m_cMaxGlyph = 0; + m_dwNumGlyphs = 0; + m_ValidGlyphs = NULL; + + // Allocate memory for the array of vaild glyphs + m_ValidGlyphs = new BYTE[65536]; + ZeroMemory( m_ValidGlyphs, 65536 ); + + for( DWORD c=(DWORD)wStartGlyph; c<=(DWORD)wEndGlyph; c++ ) + { + m_ValidGlyphs[c] = 1; + m_dwNumGlyphs++; + } + + m_cMaxGlyph = wEndGlyph; + + BuildTranslatorTable(); + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Name: ExtractValidGlyphsFromRange() +// Desc: Set global variables to indicate we will be drawing all glyphs that +// are present in the specified text file. +//----------------------------------------------------------------------------- +HRESULT CTextureFont::ExtractValidGlyphsFromFile( const CHAR* strFileName ) +{ + // Open the file + FILE* file = fopen( strFileName, "rb" ); + if( NULL == file ) + return E_FAIL; + + // Cleanup any previous entries + if( m_ValidGlyphs ) + delete[] m_ValidGlyphs; + + m_cMaxGlyph = 0; + m_dwNumGlyphs = 0; + m_ValidGlyphs = NULL; + + // Allocate memory for the array of vaild glyphs + m_ValidGlyphs = new BYTE[65536]; + ZeroMemory( m_ValidGlyphs, 65536 ); + + // Skip the unicode marker + BOOL bIsUnicode = (fgetwc(file) == 0xfeff) ? TRUE : FALSE; + + if( bIsUnicode == FALSE ) + rewind( file ); + + // Record which glyphs are valid + WCHAR c; + while( (WCHAR)EOF != ( c = bIsUnicode ? fgetwc(file) : fgetc(file) ) ) + { + while( c == L'\\' ) + { + c = bIsUnicode ? fgetwc(file) : fgetc(file); + + // Handle octal-coded characters + if( isdigit(c) ) + { + int code = (c - L'0'); + c = bIsUnicode ? fgetwc(file) : fgetc(file); + + if( isdigit(c) ) + { + code = code*8 + (c - L'0'); + c = bIsUnicode ? fgetwc(file) : fgetc(file); + + if( isdigit(c) ) + { + code = code*8 + (c - L'0'); + c = bIsUnicode ? fgetwc(file) : fgetc(file); + } + } + + if( m_ValidGlyphs[code] == 0 ) + { + if( code > m_cMaxGlyph ) + m_cMaxGlyph = (WCHAR)code; + + m_dwNumGlyphs++; + m_ValidGlyphs[code] = 2; + } + } + else + { + // Add the backslash character + if( L'\\' > m_cMaxGlyph ) + m_cMaxGlyph = L'\\'; + + if( m_ValidGlyphs[L'\\'] == 0 ) + { + m_dwNumGlyphs++; + m_ValidGlyphs[L'\\'] = 1; + } + } + } + + if( m_ValidGlyphs[c] == 0 ) + { + // If the character is a printable one, add it + if( c != L'\n' && c != L'\r' && c != 0xffff ) + { + m_dwNumGlyphs++; + m_ValidGlyphs[c] = 1; + + if( c > m_cMaxGlyph ) + m_cMaxGlyph = c; + } + } + } + + // Done with the file + fclose( file ); + + BuildTranslatorTable(); + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Name: BuildTranslatorTable() +// Desc: Builds a table to translate from a WCHAR to a glyph index. +//----------------------------------------------------------------------------- +HRESULT CTextureFont::BuildTranslatorTable() +{ + if ( m_TranslatorTable ) + delete[] m_TranslatorTable; + + // Insure the \0 is there + if ( m_bIncludeNullCharacter && 0 == m_ValidGlyphs[0] ) + { + m_dwNumGlyphs++; + m_ValidGlyphs[0] = 1; + } + + // Fill the string of all valid glyphs and build the translator table + m_TranslatorTable = new WORD[m_cMaxGlyph+1]; + ZeroMemory( m_TranslatorTable, sizeof(WORD)*(m_cMaxGlyph+1) ); + + if ( !m_pCustomFilename ) + { + // ttf has glyphs that are sequential + DWORD dwGlyph = 0; + for ( DWORD i=0; i<65536; i++ ) + { + if ( m_ValidGlyphs[i] ) + { + m_TranslatorTable[i] = (WORD)dwGlyph; + dwGlyph++; + } + } + } + else + { + // custom font has glyphs that are scattered + DWORD dwGlyph = 0; + for ( DWORD i=0; i<m_dwNumGlyphs; i++ ) + { + if ( !i && m_bIncludeNullCharacter ) + { + m_TranslatorTable[0] = 0; + dwGlyph++; + continue; + } + + m_TranslatorTable[m_customGlyphs[i-1]] = (WORD)dwGlyph; + dwGlyph++; + } + } + + return S_OK; +} + +void StripQuotedToken( char *pToken ) +{ + int len = strlen( pToken ); + if ( !len ) + return; + + if ( pToken[0] == '\"' && pToken[len-1] == '\"' ) + { + memcpy( pToken, pToken+1, len-1 ); + pToken[len-2] = '\0'; + } +} + + + +//----------------------------------------------------------------------------- +// ReadCustomFontFile +//----------------------------------------------------------------------------- +HRESULT CTextureFont::ReadCustomFontFile( CHAR* strFileName ) +{ + char *pToken; + char fontName[128]; + bool bSuccess; + unsigned char glyphs[256]; + char *glyphFiles[512]; + char basePath[MAX_PATH]; + int numGlyphs; + char filename[MAX_PATH]; + + bSuccess = false; + numGlyphs = 0; + + ClearFont(); + + TL_LoadScriptFile( strFileName ); + + strcpy( basePath, strFileName ); + TL_StripFilename( basePath ); + TL_AddSeperatorToPath( basePath, basePath ); + + fontName[0] = '\0'; + while ( 1 ) + { + pToken = TL_GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + StripQuotedToken( pToken ); + + // get font name + if ( !stricmp( pToken, "fontName" ) ) + { + pToken = TL_GetToken( true ); + if ( !pToken || !pToken[0] ) + goto cleanUp; + StripQuotedToken( pToken ); + strcpy( fontName, pToken ); + continue; + } + + // get glyph + if ( strlen( pToken ) != 1 ) + goto cleanUp; + glyphs[numGlyphs] = pToken[0]; + + // get glyph file + pToken = TL_GetToken( true ); + if ( !pToken || !pToken[0] ) + goto cleanUp; + StripQuotedToken( pToken ); + sprintf( filename, "%s%s", basePath, pToken ); + glyphFiles[numGlyphs] = TL_CopyString( filename ); + + numGlyphs++; + if ( numGlyphs >= 256 ) + break; + } + + if ( numGlyphs == 0 ) + goto cleanUp; + + m_pCustomFilename = TL_CopyString( strFileName ); + strcpy ( m_strFontName, fontName ); + + m_dwTextureWidth = 256; + m_dwTextureHeight = 256; + + m_ValidGlyphs = new BYTE[65536]; + ZeroMemory( m_ValidGlyphs, 65536 ); + + m_dwNumGlyphs = numGlyphs; + m_cMaxGlyph = 0; + for (int i=0; i<numGlyphs; i++) + { + m_ValidGlyphs[glyphs[i]] = 1; + + if ( m_cMaxGlyph < glyphs[i] ) + m_cMaxGlyph = glyphs[i]; + + m_customGlyphs[i] = glyphs[i]; + m_pCustomGlyphFiles[i] = glyphFiles[i]; + } + + BuildTranslatorTable(); + + bSuccess = true; + +cleanUp: + TL_FreeScriptFile(); + return bSuccess ? S_OK : E_FAIL; +} + +//----------------------------------------------------------------------------- +// Name: ReadFontInfoFile() +// Desc: Loads the font's glyph info from a file +//----------------------------------------------------------------------------- +HRESULT CTextureFont::ReadFontInfoFile( CHAR* strFileName ) +{ + BitmapFont_t bitmapFont; + + // open the info file + FILE* file = fopen( strFileName, "rb" ); + if ( NULL == file ) + return E_FAIL; + + memset( &bitmapFont, 0, sizeof( BitmapFont_t ) ); + fread( &bitmapFont, 1, sizeof( BitmapFont_t ), file ); + + if ( bitmapFont.m_id != BITMAPFONT_ID || bitmapFont.m_Version != BITMAPFONT_VERSION ) + { + return E_FAIL; + } + + theApp.SetTextureSize( bitmapFont.m_PageWidth, bitmapFont.m_PageHeight ); + + ZeroMemory( m_ValidGlyphs, 65536 ); + + m_dwNumGlyphs = 0; + m_cMaxGlyph = 0; + for (int i=0; i<256; i++) + { + if ( bitmapFont.m_TranslateTable[i] ) + { + m_ValidGlyphs[i] = 1; + m_cMaxGlyph = i; + m_dwNumGlyphs++; + } + } + BuildTranslatorTable(); + + // success + fclose( file ); + + theApp.OnGlyphsCustom(); + theApp.CalculateAndRenderGlyphs(); + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Name: WriteFontInfoFile() +// Desc: Writes the font's glyph info to a file +//----------------------------------------------------------------------------- +HRESULT CTextureFont::WriteFontInfoFile( CHAR* strFileName ) +{ + BitmapFont_t bitmapFont; + BitmapGlyph_t bitmapGlyph; + + // Create the info file + FILE* file = fopen( strFileName, "wb" ); + if ( NULL == file ) + return E_FAIL; + + bitmapFont.m_id = BITMAPFONT_ID; + bitmapFont.m_Version = BITMAPFONT_VERSION; + bitmapFont.m_PageWidth = (short)m_dwTextureWidth; + bitmapFont.m_PageHeight = (short)m_dwTextureHeight; + bitmapFont.m_Ascent = 0; + bitmapFont.m_NumGlyphs = (short)m_dwNumGlyphs; + + // generate flags + bitmapFont.m_Flags = 0; + if ( m_bAntialiasEffect ) + { + bitmapFont.m_Flags |= BF_ANTIALIASED; + } + if ( m_bShadowEffect ) + { + bitmapFont.m_Flags |= BF_DROPSHADOW; + } + if ( m_bOutlineEffect ) + { + bitmapFont.m_Flags |= BF_OUTLINED; + } + if ( m_nBlur ) + { + bitmapFont.m_Flags |= BF_BLURRED; + } + if ( m_nScanlines ) + { + bitmapFont.m_Flags |= BF_SCANLINES; + } + if ( m_LogFont.lfItalic ) + { + bitmapFont.m_Flags |= BF_ITALIC; + } + if ( m_LogFont.lfWeight > 400 ) + { + bitmapFont.m_Flags |= BF_BOLD; + } + if ( m_pCustomFilename ) + { + bitmapFont.m_Flags |= BF_CUSTOM; + } + + // determine max char width from all glyphs + bitmapFont.m_MaxCharWidth = 0; + for (unsigned int i=0; i<m_dwNumGlyphs; i++ ) + { + if ( bitmapFont.m_MaxCharWidth < m_pGlyphs[i].w ) + { + bitmapFont.m_MaxCharWidth = m_pGlyphs[i].w; + } + } + + bitmapFont.m_MaxCharHeight = 0; + for (unsigned int i=0; i<m_dwNumGlyphs; i++ ) + { + if ( bitmapFont.m_MaxCharHeight < m_pGlyphs[i].h ) + { + bitmapFont.m_MaxCharHeight = m_pGlyphs[i].h; + } + } + + // maps a char index to its actual glyph + for (int i=0; i<256; i++) + { + if ( i <= m_cMaxGlyph ) + { + bitmapFont.m_TranslateTable[i] = (unsigned char)m_TranslatorTable[i]; + } + else + { + bitmapFont.m_TranslateTable[i] = 0; + } + } + + // write out the header + fwrite( &bitmapFont, sizeof( BitmapFont_t ), 1, file ); + + // Write out the vertical padding caused by effects +// FLOAT fTopPadding = ( m_bOutlineEffect ? 1.0f : 0.0f ); +// FLOAT fBottomPadding = ( m_bOutlineEffect ? ( m_bShadowEffect ? 2.0f : 1.0f ) : ( m_bShadowEffect ? 2.0f : 0.0f ) ); +// FLOAT fFontYAdvance = fFontHeight - fTopPadding - fBottomPadding; + + // Write the glyph attributes to the file + for (unsigned int i=0; i<m_dwNumGlyphs; i++ ) + { + bitmapGlyph.x = m_pGlyphs[i].x; + bitmapGlyph.y = m_pGlyphs[i].y; + bitmapGlyph.w = m_pGlyphs[i].w; + bitmapGlyph.h = m_pGlyphs[i].h; + bitmapGlyph.a = m_pGlyphs[i].a; + bitmapGlyph.b = m_pGlyphs[i].b; + bitmapGlyph.c = m_pGlyphs[i].c; + + fwrite( &bitmapGlyph, sizeof( BitmapGlyph_t ), 1, file ); + } + + // success + fclose( file ); + return S_OK; +} + +//----------------------------------------------------------------------------- +// Name: WriteTargaFile() +// Desc: Writes 32-bit RGBA data to a .tga file +//----------------------------------------------------------------------------- +HRESULT WriteTargaFile( CHAR* strFileName, DWORD dwWidth, DWORD dwHeight, + DWORD* pRGBAData ) +{ + struct TargaHeader + { + BYTE IDLength; + BYTE ColormapType; + BYTE ImageType; + BYTE ColormapSpecification[5]; + WORD XOrigin; + WORD YOrigin; + WORD ImageWidth; + WORD ImageHeight; + BYTE PixelDepth; + BYTE ImageDescriptor; + } tga; + + // Create the file + FILE* file = fopen( strFileName, "wb" ); + if( NULL == file ) + return E_FAIL; + + // Write the TGA header + ZeroMemory( &tga, sizeof(tga) ); + tga.IDLength = 0; + tga.ImageType = 2; + tga.ImageWidth = (WORD)dwWidth; + tga.ImageHeight = (WORD)dwHeight; + tga.PixelDepth = 32; + tga.ImageDescriptor = 0x28; + fwrite( &tga, sizeof(TargaHeader), 1, file ); + + // Write the pixels + fwrite( pRGBAData, sizeof(DWORD), dwHeight*dwWidth, file ); + + // Close the file and return okay + fclose( file ); + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Name: WriteFontImageFile() +// Desc: Writes 32-bit RGBA data to a .tga file +//----------------------------------------------------------------------------- +HRESULT CTextureFont::WriteFontImageFile( CHAR* strFileName, bool bAdditiveMode, bool bCustomFont ) +{ + // Convert the bits to have an alpha channel + DWORD* pRGBAData = new DWORD[m_dwTextureWidth*m_dwTextureHeight]; + + FLOAT l; + for ( DWORD i=0; i<m_dwTextureWidth*m_dwTextureHeight; i++ ) + { + FLOAT a = ( ( 0xff000000 & m_pBits[i] ) >> 24L ) / 255.0f; + FLOAT r = ( ( 0x00ff0000 & m_pBits[i] ) >> 16L ) / 255.0f; + FLOAT g = ( ( 0x0000ff00 & m_pBits[i] ) >> 8L ) / 255.0f; + FLOAT b = ( ( 0x000000ff & m_pBits[i] ) >> 0L ) / 255.0f; + + if ( bCustomFont ) + { + if ( a == 0.0f && b == 1.0f ) + { + // pure transluscent + a = 0; + r = g = b = 0.0f; + } + + int red = (int)(r * 255.0f); + int green = (int)(g * 255.0f); + int blue = (int)(b * 255.0f); + int alpha = (int)(a * 255.0f); + + pRGBAData[i] = (alpha<<24L) | (red<<16L) | (green<<8L) | (blue<<0L); + } + else + { + if ( bAdditiveMode ) + { + // all channels should be same + if (( r != g ) || ( r != b )) + { + } + + l = r; + a = 1.0f; + } + else + { + a = r + (1-b); + if ( a ) + l = r / a; + else + l = 1; + } + + DWORD alpha = (DWORD)( a * 255.0f ); + DWORD lum = (DWORD)( l * 255.0f ); + + pRGBAData[i] = (alpha<<24L) | (lum<<16L) | (lum<<8L) | (lum<<0L); + } + } + + // Write the file + HRESULT hr = WriteTargaFile( strFileName, m_dwTextureWidth, + m_dwTextureHeight, pRGBAData ); + + // Cleanup and return + delete[] pRGBAData; + return hr; +} + +void GetBitmapBits2( HBITMAP hBitmap, int width, int height, void *pBits ) +{ + memset( pBits, 0, width*height*4 ); + + HDC hDC = CreateCompatibleDC( NULL ); + BITMAPINFO bitmapInfo = {0}; + bitmapInfo.bmiHeader.biSize = sizeof( bitmapInfo.bmiHeader ); + bitmapInfo.bmiHeader.biWidth = width; + bitmapInfo.bmiHeader.biHeight = -height; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + GetDIBits( hDC, hBitmap, 0, height, pBits, &bitmapInfo ,DIB_RGB_COLORS ); + DeleteDC( hDC ); +} + +void SetBitmapBits2( HBITMAP hBitmap, int width, int height, void *pBits ) +{ + HDC hDC = CreateCompatibleDC( NULL ); + BITMAPINFO bitmapInfo = {0}; + bitmapInfo.bmiHeader.biSize = sizeof( bitmapInfo.bmiHeader ); + bitmapInfo.bmiHeader.biWidth = width; + bitmapInfo.bmiHeader.biHeight = -height; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + SetDIBits( hDC, hBitmap, 0, height, pBits, &bitmapInfo ,DIB_RGB_COLORS ); + DeleteDC( hDC ); +} + +//----------------------------------------------------------------------------- +// SetTextureBits +// +// Blit the rect back into the bitmap +//----------------------------------------------------------------------------- +void SetTextureBits( HBITMAP hBitmap, int bitmapWidth, int bitmapHeight, int x, int y, int w, int h, unsigned char *pRGBA ) +{ + // get the enitre bitmap + unsigned char *pBitmapBits = (unsigned char *)malloc( bitmapWidth * bitmapHeight * 4); + GetBitmapBits2( hBitmap, bitmapWidth, bitmapHeight, pBitmapBits ); + + // copy into bitmap bits + unsigned char *pSrc = pRGBA; + for (int yy=y; yy<y+h; yy++) + { + if ( yy >= bitmapHeight ) + { + // past end of bitmap + break; + } + + unsigned char *pDst = pBitmapBits + (yy*bitmapWidth + x)*4; + for (int xx=0; xx<w; xx++) + { + if ( xx+x < bitmapWidth ) + { + pDst[0] = pSrc[0]; + pDst[1] = pSrc[1]; + pDst[2] = pSrc[2]; + pDst[3] = pSrc[3]; + } + pSrc += 4; + pDst += 4; + } + } + + SetBitmapBits2( hBitmap, bitmapWidth, bitmapHeight, pBitmapBits ); + + free( pBitmapBits ); +} + +//----------------------------------------------------------------------------- +// GetTextureBits +// +// Blit the rect out of the bitmap +//----------------------------------------------------------------------------- +unsigned char *GetTextureBits( HBITMAP hBitmap, int bitmapWidth, int bitmapHeight, int x, int y, int w, int h ) +{ + // get the enitre bitmap + unsigned char *pBitmapBits = new unsigned char[bitmapWidth * bitmapHeight * 4]; + GetBitmapBits2( hBitmap, bitmapWidth, bitmapHeight, pBitmapBits ); + + unsigned char *pRGBA = new unsigned char[w * h * 4]; + memset( pRGBA, 0, w*h*4 ); + + // copy out bits + unsigned char *pDst = pRGBA; + for (int yy=y; yy<y+h; yy++) + { + if ( yy >= bitmapHeight ) + { + // past last row of bitmap + break; + } + + unsigned char *pSrc = pBitmapBits + (yy*bitmapWidth + x)*4; + for (int xx=0; xx<w; xx++) + { + if ( xx + x < bitmapWidth ) + { + pDst[0] = pSrc[0]; + pDst[1] = pSrc[1]; + pDst[2] = pSrc[2]; + pDst[3] = pSrc[3]; + } + pSrc += 4; + pDst += 4; + } + } + + delete [] pBitmapBits; + return pRGBA; +} + + +int g_blur; +float *g_pGaussianDistribution; + +//----------------------------------------------------------------------------- +// Purpose: Gets the blur value for a single pixel +//----------------------------------------------------------------------------- +void GetBlurValueForPixel(unsigned char *src, int blur, float *gaussianDistribution, int srcX, int srcY, int srcWide, int srcTall, unsigned char *dest) +{ + int r = 0, g = 0, b = 0, a = 0; + + float accum = 0.0f; + + // scan the positive x direction + int maxX = min(srcX + blur, srcWide); + int minX = max(srcX - blur, 0); + for (int x = minX; x <= maxX; x++) + { + int maxY = min(srcY + blur, srcTall - 1); + int minY = max(srcY - blur, 0); + for (int y = minY; y <= maxY; y++) + { + unsigned char *srcPos = src + ((x + (y * srcWide)) * 4); + + unsigned char red = srcPos[2]; + unsigned char green = srcPos[1]; + unsigned char blue = srcPos[0]; + + // muliply by the value matrix + float weight = gaussianDistribution[x - srcX + blur]; + float weight2 = gaussianDistribution[y - srcY + blur]; + accum += (red * (weight * weight2)); + } + } + + // blurring decreased the range, for xbox kick some back + accum *= 1.30f; + + // all the values are the same for fonts, just use the calculated alpha + r = g = b = (int)accum; + + dest[0] = min(b, 255); + dest[1] = min(g, 255); + dest[2] = min(r, 255); +} + +//----------------------------------------------------------------------------- +// ApplyGaussianBlurToTexture +//----------------------------------------------------------------------------- +void ApplyGaussianBlurToTexture( int blur, int rgbaX, int rgbaY, int rgbaWide, int rgbaTall, unsigned char *rgba) +{ + // calculate our gaussian distribution for if we're blurred + if ( blur > 1 && blur != g_blur ) + { + g_blur = blur; + g_pGaussianDistribution = new float[blur * 2 + 1]; + double sigma = 0.683f * blur; + for (int x = 0; x <= (blur * 2); x++) + { + int val = x - blur; + g_pGaussianDistribution[x] = (float)((1.0 / sqrt(2.0 * 3.14 * sigma * sigma)) * pow(2.7, -1.0 * (val * val) / (2.0 * sigma * sigma))); + + // brightening factor + g_pGaussianDistribution[x] *= 1; + } + } + + // alloc a new buffer + unsigned char *src = (unsigned char *)_alloca(rgbaWide * rgbaTall * 4); + memcpy(src, rgba, rgbaWide * rgbaTall * 4); + + unsigned char *dest = rgba; + for (int y = 0; y < rgbaTall; y++) + { + for (int x = 0; x < rgbaWide; x++) + { + // scan the source pixel + GetBlurValueForPixel(src, blur, g_pGaussianDistribution, x, y, rgbaWide, rgbaTall, dest); + + // move to the next + dest += 4; + } + } +} + +//----------------------------------------------------------------------------- +// ApplyScanlineEffectToTexture +//----------------------------------------------------------------------------- +void ApplyScanlineEffectToTexture( int scanLines, int rgbaX, int rgbaY, int rgbaWide, int rgbaTall, unsigned char *rgba) +{ + if (scanLines < 2) + return; + + float scale; + scale = 0; + + // darken all the areas except the scanlines + for (int y = 0; y < rgbaTall; y++) + { + // skip the scan lines + if (y % scanLines == 0) + continue; + + DWORD *pBits = (DWORD*)&rgba[(rgbaX + ((y + rgbaY) * rgbaWide)) * 4]; + + // darken the other lines + for (int x = 0; x < rgbaWide; x++, pBits++) + { + FLOAT r = ( ( 0x00ff0000 & pBits[0] ) >> 16L ) / 255.0f; + FLOAT g = ( ( 0x0000ff00 & pBits[0] ) >> 8L ) / 255.0f; + FLOAT b = ( ( 0x000000ff & pBits[0] ) >> 0L ) / 255.0f; + + r *= scale; + g *= scale; + b *= scale; + + pBits[0] = (((int)(r * 255.0f))<<16) | (((int)(g * 255.0f))<<8) | ((int)(b * 255.0f)); + pBits[0] |= 0xFF000000; + } + } +} + + +//----------------------------------------------------------------------------- +// Name: RenderTTFGlyphs() +// Desc: Draws the list of font glyphs in the scroll view +//----------------------------------------------------------------------------- +GLYPH_ATTR* CTextureFont::RenderTTFGlyphs( HFONT hFont, HBITMAP hBitmap, + DWORD dwTextureWidth, DWORD dwTextureHeight, + BOOL bOutlineEffect, BOOL bShadowEffect, + int nScanlineEffect, int nBlurEffect, + BOOL bAntialias, + BYTE* ValidGlyphs, DWORD dwNumGlyphs ) +{ + // Create a DC + HDC hDC = CreateCompatibleDC( NULL ); + + // Associate the drawing surface + SelectObject( hDC, hBitmap ); + + // Create a clip region + HRGN rgn = CreateRectRgn( 0, 0, dwTextureWidth, dwTextureHeight ); + SelectClipRgn( hDC, rgn ); + + // Setup the DC for the font + SetTextColor( hDC, COLOR_WHITE ); + SelectObject( hDC, hFont ); + SetTextAlign( hDC, TA_LEFT|TA_TOP|TA_UPDATECP ); + SetMapMode( hDC, MM_TEXT ); + SetBkMode( hDC, TRANSPARENT ); + + if ( nScanlineEffect || nBlurEffect ) + { + SetBkColor( hDC, COLOR_BLACK ); + + if ( nBlurEffect < 2 ) + nBlurEffect = 2; + if ( nScanlineEffect < 2 ) + nScanlineEffect = 2; + } + else + { + SetBkColor( hDC, COLOR_BLUE ); + } + + // Fill the background in blue + RECT rect; + SetRect( &rect, 0, 0, dwTextureWidth, dwTextureHeight ); + ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL ); + + // Get the effective font height + WCHAR str[2] = L"A"; + SIZE size; + GetTextExtentPoint32W( hDC, str, 1, &size ); + + DWORD dwLeftOrigin = 1; + DWORD dwTopOrigin = 1; + + GLYPH_ATTR* pGlyphs = new GLYPH_ATTR[dwNumGlyphs]; + memset( pGlyphs, 0, dwNumGlyphs*sizeof( GLYPH_ATTR ) ); + + // Loop through all printable character and output them to the bitmap.. + // Meanwhile, keep track of the corresponding tex coords for each character. + DWORD x = dwLeftOrigin; + DWORD y = dwTopOrigin; + int sx; + int sy; + + int numGlyphs = 0; + + for( DWORD i=0; i<65536; i++ ) + { + if ( 0 == ValidGlyphs[i]) + continue; + + str[0] = (WCHAR)i; + + if ( i==0 && ValidGlyphs[i] == 1 ) + { + // account for unprintable, but don't render it + numGlyphs++; + continue; + } + + GetTextExtentPoint32W( hDC, str, 1, &size ); + + // Get char width a different way + int charwidth; + GetCharWidth32( hDC, str[0], str[0], &charwidth ); + + // Get the ABC widths for the letter + ABC abc; + if ( FALSE == GetCharABCWidthsW( hDC, str[0], str[0], &abc ) ) + { + abc.abcA = 0; + abc.abcB = size.cx; + abc.abcC = 0; + } + + int w = abc.abcB; + int h = size.cy; + + // Determine padding for effects + int left_padding = 0; + int right_padding = 0; + int top_padding = 0; + int bottom_padding = 0; + if ( bOutlineEffect || bShadowEffect ) + { + if ( bOutlineEffect ) + left_padding = 1; + + if ( bOutlineEffect ) + { + if ( bShadowEffect ) + right_padding = 2; + else + right_padding = 1; + } + else + { + if ( bShadowEffect ) + right_padding = 2; + else + right_padding = 0; + } + + if ( bOutlineEffect ) + top_padding = 1; + + if ( bOutlineEffect ) + { + if ( bShadowEffect ) + bottom_padding = 2; + else + bottom_padding = 1; + } + else + { + if ( bShadowEffect ) + bottom_padding = 2; + else + bottom_padding = 0; + } + } + else if ( nBlurEffect ) + { + left_padding = nBlurEffect; + right_padding = nBlurEffect; + } + + if ( ValidGlyphs[i] == 2 ) + { + // Handle special characters + // Advance to the next line, if necessary + if ( x + h + left_padding + right_padding >= (int)dwTextureWidth ) + { + x = dwLeftOrigin; + y += h + top_padding + bottom_padding + 1; + } + + sx = x; + sy = y; + + // Draw a square box for a placeholder for custom glyph graphics + w = h + left_padding + right_padding; + h = h + top_padding + bottom_padding; + + abc.abcA = 0; + abc.abcB = w; + abc.abcC = 0; + + RECT rect; + SetRect( &rect, x, y, x+w, y+h ); + SetBkColor( hDC, COLOR_BLACK ); + ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL ); + } + else + { + // Hack to adjust for Kanji + if ( str[0] > 0x1000 ) + { + w = h; + } + + // Advance to the next line, if necessary + if ( x + w + left_padding + right_padding + 1 >= (int)dwTextureWidth ) + { + x = dwLeftOrigin; + y += h + top_padding + bottom_padding + 1; + } + + sx = x; + sy = y; + + // Adjust ccordinates to account for the leading edge + if ( abc.abcA >= 0 ) + x += abc.abcA; + else + sx -= abc.abcA; + + // Hack to adjust for Kanji + if ( str[0] > 0x1000 ) + { + sx += abc.abcA; + } + + // Add padding to the width and height + w += left_padding + right_padding; + h += top_padding + bottom_padding; + abc.abcA -= left_padding; + abc.abcB += left_padding + right_padding; + abc.abcC -= right_padding; + + if ( bOutlineEffect || bShadowEffect ) + { + if ( bOutlineEffect ) + { + SetTextColor( hDC, COLOR_BLACK ); + MoveToEx( hDC, sx+0, sy+0, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + MoveToEx( hDC, sx+1, sy+0, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + MoveToEx( hDC, sx+2, sy+0, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + MoveToEx( hDC, sx+0, sy+1, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + MoveToEx( hDC, sx+2, sy+1, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + MoveToEx( hDC, sx+0, sy+2, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + MoveToEx( hDC, sx+1, sy+2, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + MoveToEx( hDC, sx+2, sy+2, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + + if ( bShadowEffect ) + { + MoveToEx( hDC, sx+3, sy+3, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + } + + // Output the letter + SetTextColor( hDC, COLOR_WHITE ); + MoveToEx( hDC, sx+1, sy+1, NULL ); ExtTextOutW( hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL ); + } + else + { + if ( bShadowEffect ) + { + SetTextColor( hDC, COLOR_BLACK ); + MoveToEx( hDC, sx+2, sy+2, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL ); + } + + // Output the letter + SetTextColor( hDC, COLOR_WHITE ); + MoveToEx( hDC, sx, sy, NULL ); ExtTextOutW( hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL ); + } + } + else if ( nBlurEffect ) + { + // blur effect + SetTextColor( hDC, COLOR_WHITE ); + MoveToEx( hDC, sx + nBlurEffect, sy, NULL ); + ExtTextOutW( hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL ); + + // apply blur effect + unsigned char *pBGRA = GetTextureBits( hBitmap, dwTextureWidth, dwTextureHeight, x, y, w, h ); + if ( pBGRA ) + { + ApplyGaussianBlurToTexture( nBlurEffect, 0, 0, w, h, pBGRA ); + SetTextureBits( hBitmap, dwTextureWidth, dwTextureHeight, x, y, w, h, pBGRA ); + delete [] pBGRA; + } + } + else + { + // normal, no effect + // Output the letter + SetTextColor( hDC, COLOR_WHITE ); + MoveToEx( hDC, sx, sy, NULL ); + ExtTextOutW( hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL ); + } + + // apply scanline effect + if ( nScanlineEffect ) + { + unsigned char *pBGRA = GetTextureBits( hBitmap, dwTextureWidth, dwTextureHeight, x, y, w, h ); + if ( pBGRA ) + { + ApplyScanlineEffectToTexture( nScanlineEffect, 0, 0, w, h, pBGRA ); + SetTextureBits( hBitmap, dwTextureWidth, dwTextureHeight, x, y, w, h, pBGRA ); + delete [] pBGRA; + } + } + + // Hack for extended characters (like Kanji) that don't seem to report + // correct ABC widths. In this case, use the width calculated from + // drawing the glyph. + if( str[0] > 0x1000 ) + { + POINT pos; + GetCurrentPositionEx( hDC, &pos ); + abc.abcB = pos.x - sx; + + if( abc.abcC < 0 ) + abc.abcB -= abc.abcC; + + w = abc.abcB; + } + } + + // Store the glyph attributes + pGlyphs[numGlyphs].x = x; + pGlyphs[numGlyphs].y = y; + pGlyphs[numGlyphs].w = w; + pGlyphs[numGlyphs].h = h; + pGlyphs[numGlyphs].a = abc.abcA; + pGlyphs[numGlyphs].b = abc.abcB; + pGlyphs[numGlyphs].c = abc.abcC; + pGlyphs[numGlyphs].fLeft = ((FLOAT)(x+0)) / dwTextureWidth; + pGlyphs[numGlyphs].fTop = ((FLOAT)(y+0)) / dwTextureHeight; + pGlyphs[numGlyphs].fRight = ((FLOAT)(x+w)) / dwTextureWidth; + pGlyphs[numGlyphs].fBottom = ((FLOAT)(y+h)) / dwTextureHeight; + numGlyphs++; + + // Advance the cursor to the next position + x += w + 1; + } + + SelectClipRgn( hDC, NULL ); + DeleteObject( rgn ); + DeleteDC( hDC ); + + return pGlyphs; +} + +//----------------------------------------------------------------------------- +// Name: RenderCustomGlyphs() +// Desc: Draws the list of font glyphs in the scroll view +//----------------------------------------------------------------------------- +GLYPH_ATTR* CTextureFont::RenderCustomGlyphs( HBITMAP hBitmap ) +{ + int i; + int w; + int h; + byte_t *pTGAPixels; + + m_maxCustomCharHeight = 0; + + // Create a DC + HDC hDC = CreateCompatibleDC( NULL ); + + // Associate the drawing surface + SelectObject( hDC, hBitmap ); + + // Create a clip region + HRGN rgn = CreateRectRgn( 0, 0, m_dwTextureWidth, m_dwTextureHeight ); + SelectClipRgn( hDC, rgn ); + + // clear the background + unsigned char *pBGRA = GetTextureBits( hBitmap, m_dwTextureWidth, m_dwTextureHeight, 0, 0, m_dwTextureWidth, m_dwTextureHeight ); + for (i=0; i<(int)(m_dwTextureHeight*m_dwTextureWidth); i++) + { + pBGRA[i*4+0] = 0xFF; + pBGRA[i*4+1] = 0x00; + pBGRA[i*4+2] = 0x00; + pBGRA[i*4+3] = 0x00; + } + SetTextureBits( hBitmap, m_dwTextureWidth, m_dwTextureHeight, 0, 0, m_dwTextureWidth, m_dwTextureHeight, pBGRA ); + + // build the glyph table + GLYPH_ATTR* pGlyphs = new GLYPH_ATTR[m_dwNumGlyphs]; + memset( pGlyphs, 0, m_dwNumGlyphs*sizeof( GLYPH_ATTR ) ); + + int x = 0; + int y = 0; + int maxHeight = 0; + + for( DWORD i=0; i<m_dwNumGlyphs; i++ ) + { + if ( !i ) + { + // account for null + continue; + } + else if ( TL_Exists( m_pCustomGlyphFiles[i-1] ) ) + { + TL_LoadTGA( m_pCustomGlyphFiles[i-1], &pTGAPixels, &w, &h ); + + // convert to expected order + for (int j=0; j<h*w; j++) + { + int r = pTGAPixels[j*4+0]; + int g = pTGAPixels[j*4+1]; + int b = pTGAPixels[j*4+2]; + + pTGAPixels[j*4+0] = b; + pTGAPixels[j*4+1] = g; + pTGAPixels[j*4+2] = r; + } + } + else + { + // build a "bad" symbol + pTGAPixels = (byte_t*)TL_Malloc( 32*32*4 ); + w = 32; + h = 32; + for (int j=0; j<32*32; j++) + { + pTGAPixels[j*4+0] = 0x00; + pTGAPixels[j*4+1] = 0x00; + pTGAPixels[j*4+2] = 0xFF; + pTGAPixels[j*4+3] = 0xFF; + } + } + + if ( m_maxCustomCharHeight < h ) + { + m_maxCustomCharHeight = h; + } + + if ( maxHeight < h ) + { + maxHeight = h; + } + + if ( x + w > (int)m_dwTextureWidth ) + { + // skip to new row + y += maxHeight; + x = 0; + maxHeight = h; + } + + SetTextureBits( hBitmap, m_dwTextureWidth, m_dwTextureHeight, x, y, w, h, pTGAPixels ); + TL_Free( pTGAPixels ); + + // Store the glyph attributes + pGlyphs[i].x = x; + pGlyphs[i].y = y; + pGlyphs[i].w = w; + pGlyphs[i].h = h; + pGlyphs[i].a = 0; + pGlyphs[i].b = w; + pGlyphs[i].c = 0; + pGlyphs[i].fLeft = ((FLOAT)(x+0)) / m_dwTextureWidth; + pGlyphs[i].fTop = ((FLOAT)(y+0)) / m_dwTextureHeight; + pGlyphs[i].fRight = ((FLOAT)(x+w)) / m_dwTextureWidth; + pGlyphs[i].fBottom = ((FLOAT)(y+h)) / m_dwTextureHeight; + + x += w; + } + + SelectClipRgn( hDC, NULL ); + DeleteObject( rgn ); + DeleteDC( hDC ); + delete [] pBGRA; + + return pGlyphs; +} + +//----------------------------------------------------------------------------- +// Name: CalculateAndRenderGlyphs() +// Desc: Draws the list of font glyphs +//----------------------------------------------------------------------------- +HRESULT CTextureFont::CalculateAndRenderGlyphs() +{ + // Create a bitmap + HBITMAP hBitmap = CreateBitmap( m_dwTextureWidth, m_dwTextureHeight, 1, 32, NULL ); + + if ( m_pGlyphs ) + delete[] m_pGlyphs; + + if ( m_pCustomFilename ) + { + m_pGlyphs = RenderCustomGlyphs( hBitmap ); + } + else + { + // Create a font + if ( m_hFont ) + { + DeleteObject( m_hFont ); + } + + if ( m_bAntialiasEffect ) + { + m_LogFont.lfQuality = ANTIALIASED_QUALITY; + } + else + { + m_LogFont.lfQuality = NONANTIALIASED_QUALITY; + } + + m_hFont = CreateFontIndirect( &m_LogFont ); + + m_pGlyphs = RenderTTFGlyphs( + m_hFont, + hBitmap, + m_dwTextureWidth, + m_dwTextureHeight, + m_bOutlineEffect, + m_bShadowEffect, + m_nScanlines, + m_nBlur, + m_bAntialiasEffect, + m_ValidGlyphs, + m_dwNumGlyphs ); + } + + // Store the resulting bits + if ( m_pBits ) + delete[] m_pBits; + m_pBits = new DWORD[ m_dwTextureWidth * m_dwTextureHeight ]; + + GetBitmapBits2( hBitmap, m_dwTextureWidth, m_dwTextureHeight, m_pBits ); + + DeleteObject( hBitmap ); + + return S_OK; +} diff --git a/utils/xbox/FontMaker/glyphs.h b/utils/xbox/FontMaker/glyphs.h new file mode 100644 index 0000000..7aaa117 --- /dev/null +++ b/utils/xbox/FontMaker/glyphs.h @@ -0,0 +1,104 @@ +//----------------------------------------------------------------------------- +// Name: Glyphs.cpp +// +// Desc: Functions and global variables for keeping track of font glyphs +// +// Hist: 09.06.02 - Revised Fontmaker sample +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- +#ifndef GLYPHS_H +#define GLYPHS_H + +//----------------------------------------------------------------------------- +// Name: struct GLYPH_ATTR +// Desc: A structure to hold attributes for one glpyh. The left, right, etc. +// values are texture coordinate offsets into the resulting texture image +// (which ends up in the .tga file). The offset, width, etc. values are +// spacing information, used when rendering the font. +//----------------------------------------------------------------------------- +struct FILE_GLYPH_ATTR +{ + FLOAT fLeft, fTop, fRight, fBottom; +}; + +struct GLYPH_ATTR : public FILE_GLYPH_ATTR +{ + int a, b, c; + int x, y, w, h; +}; + + + + +//----------------------------------------------------------------------------- +// Name: class CTextureFont +// Desc: A class to hold all information about a texture-based font +//----------------------------------------------------------------------------- +class CTextureFont +{ +public: + // current ttf font + LOGFONT m_LogFont; + HFONT m_hFont; + + BOOL m_bAntialiasEffect; + BOOL m_bShadowEffect; + BOOL m_bOutlineEffect; + int m_nBlur; + int m_nScanlines; + + // Glyph info + BYTE* m_ValidGlyphs; + WCHAR m_cMaxGlyph; + WORD* m_TranslatorTable; + BOOL m_bIncludeNullCharacter; + DWORD m_dwNumGlyphs; + GLYPH_ATTR* m_pGlyphs; + + // Texture info + DWORD m_dwTextureWidth; + DWORD m_dwTextureHeight; + DWORD* m_pBits; + + CHAR m_strFontName[MAX_PATH]; + + // current custom font + const char *m_pCustomFilename; + unsigned char m_customGlyphs[256]; + char *m_pCustomGlyphFiles[256]; + int m_maxCustomCharHeight; + +public: + HRESULT DeleteGlyph( WORD wGlyph ); + HRESULT InsertGlyph( WORD wGlyph ); + HRESULT ExtractValidGlyphsFromRange( WORD wStartGlyph, WORD wEndGlyph ); + HRESULT ExtractValidGlyphsFromFile( const CHAR* strFileName ); + HRESULT BuildTranslatorTable(); + HRESULT CalculateAndRenderGlyphs(); + HRESULT ReadCustomFontFile( CHAR* strFileName ); + HRESULT ReadFontInfoFile( CHAR* strFileName ); + HRESULT WriteFontInfoFile( CHAR* strFileName ); + HRESULT WriteFontImageFile( CHAR* strFileName, bool bAdditiveMode, bool bCustomFont ); + + VOID ClearFont(); + VOID DestroyObjects(); + + CTextureFont(); + ~CTextureFont(); + +private: + GLYPH_ATTR* RenderCustomGlyphs( HBITMAP hBitmap ); + + GLYPH_ATTR* RenderTTFGlyphs( HFONT hFont, HBITMAP hBitmap, + DWORD dwTextureWidth, DWORD dwTextureHeight, + BOOL bOutlineEffect, BOOL bShadowEffect, + int nScanlineEffect, int nBlurEffect, + BOOL bAntialias, + BYTE* ValidGlyphs, DWORD dwNumGlyphs ); +}; + + + + +#endif // GLYPHS_H diff --git a/utils/xbox/FontMaker/resource.h b/utils/xbox/FontMaker/resource.h new file mode 100644 index 0000000..d8b7060 --- /dev/null +++ b/utils/xbox/FontMaker/resource.h @@ -0,0 +1,80 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by fontmaker.rc +// +#define IDD_DIALOGBAR 103 +#define IDD_TEXTURESIZE 104 +#define IDR_MAINFRAME 128 +#define IDD_ABOUT 132 +#define IDC_GLYPHSFROMRANGE_RADIO 1007 +#define IDC_GLYPHSFROMFILE_RADIO 1008 +#define IDC_GLYPHSFILE_EDIT 1009 +#define IDC_GLYPHSFILESELECTOR_BUTTON 1010 +#define IDC_GLYPHSRANGEFROM_EDIT 1011 +#define IDC_GLYPHSRANGETO_EDIT 1012 +#define IDC_EFFECTSOUTLINED_CHECK 1013 +#define IDC_EFFECTSSHADOWED_CHECK 1014 +#define IDC_EFFECTSBLURRED_CHECK 1015 +#define IDC_EFFECTSSCANLINES_CHECK 1016 +#define IDC_BLUR_EDIT 1017 +#define IDC_SCANLINES_EDIT 1018 +#define IDC_EFFECTSANTIALIAS_CHECK 1019 +#define IDC_GLYPHSCUSTOM_RADIO 1020 +#define IDC_INSERTGLYPH_EDIT 1021 +#define IDC_GLYPH_SPECIAL 1024 +#define IDC_TEXTURESIZE_BUTTON 1026 +#define IDC_FONTNAME_STATIC 1030 +#define IDC_FONT_GROUPBOX 1031 +#define IDC_GLYPHS_GROUPBOX 1032 +#define IDC_FONTSTYLE_STATIC 1033 +#define IDC_FONTSIZE_STATIC 1034 +#define IDC_TEXTUREWIDTH_STATIC 1035 +#define IDC_TEXTURE_GROUPBOX 1036 +#define IDC_SELECTEDGLYPH_GROUPBOX 1037 +#define IDC_FONTNAME_LABEL 1038 +#define IDC_FONTSTYLE_LABEL 1039 +#define IDC_FONTSIZE_LABEL 1040 +#define IDC_INSERTGLYPH_LABEL 1041 +#define IDC_TEXTUREHEIGHT_LABEL 1042 +#define IDC_TEXTUREHEIGHT_STATIC 1043 +#define IDC_GLYPHSRANGEFROM_LABEL 1044 +#define IDC_GLYPHSRANGETO_LABEL 1045 +#define IDC_WIDTH 1046 +#define IDC_GLYPH_X_STATIC 1046 +#define IDC_TEXTUREWIDTH_LABEL 1047 +#define IDC_HEIGHT 1048 +#define IDC_GLYPH_X_LABEL 1048 +#define IDC_GLYPH_Y_LABEL 1049 +#define IDC_GLYPH_W_LABEL 1050 +#define IDC_GLYPH_H_LABEL 1051 +#define IDC_GLYPH_A_LABEL 1052 +#define IDC_GLYPH_B_LABEL 1053 +#define IDC_GLYPH_C_LABEL 1054 +#define IDC_MAGNIFY_BUTTON 1055 +#define IDC_GLYPH_VALUE_LABEL 1056 +#define IDC_USENTSCSAFECOLORS_CHECK 1057 +#define IDC_GLYPH_Y_STATIC 1061 +#define IDC_GLYPH_W_STATIC 1062 +#define IDC_GLYPH_H_STATIC 1063 +#define IDC_GLYPH_A_STATIC 1064 +#define IDC_GLYPH_B_STATIC 1065 +#define IDC_GLYPH_C_STATIC 1066 +#define IDC_GLYPH_VALUE_STATIC 1067 +#define IDM_FILE_EXIT 32778 +#define IDM_FILE_NEWFONT 32782 +#define IDM_FILE_SAVEFONTFILES 32784 +#define ID_FILE_LOADFONTFILE 32788 +#define IDM_FILE_LOADFONTFILE 32790 +#define IDM_FILE_LOADFONTLAYOUT 32792 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_3D_CONTROLS 1 +#define _APS_NEXT_RESOURCE_VALUE 133 +#define _APS_NEXT_COMMAND_VALUE 32793 +#define _APS_NEXT_CONTROL_VALUE 1058 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/utils/xbox/FontMaker/stdafx.cpp b/utils/xbox/FontMaker/stdafx.cpp new file mode 100644 index 0000000..0087258 --- /dev/null +++ b/utils/xbox/FontMaker/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// FontMaker.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + + + diff --git a/utils/xbox/FontMaker/stdafx.h b/utils/xbox/FontMaker/stdafx.h new file mode 100644 index 0000000..b57f9d4 --- /dev/null +++ b/utils/xbox/FontMaker/stdafx.h @@ -0,0 +1,27 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__797D2B31_3C16_4BE2_8C81_8C3E74DC9138__INCLUDED_) +#define AFX_STDAFX_H__797D2B31_3C16_4BE2_8C81_8C3E74DC9138__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include "tier0\wchartypes.h" +#include <afxwin.h> // MFC core and standard components +#include <afxext.h> // MFC extensions +#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include <afxcmn.h> // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__797D2B31_3C16_4BE2_8C81_8C3E74DC9138__INCLUDED_) diff --git a/utils/xbox/MakeGameData/MakeGameData.cpp b/utils/xbox/MakeGameData/MakeGameData.cpp new file mode 100644 index 0000000..91857b1 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeGameData.cpp @@ -0,0 +1,1174 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Generates a file list based on command line wildcard spec and drives +// conversion routines based on file extension. The conversion routines should be +// !!!elsewhere!!! in libraries that the game also uses at runtime to convert data. +// This tool as spec'd should just be file iteration. +// +//=====================================================================================// + +#include "MakeGameData.h" + +// MAKESCENESIMAGE is defined for the external tool. In general, it only +// supports the -pcscenes option. This gets built into MakeScenesImage.exe. + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class MakeGameDataApp : public CDefaultAppSystemGroup< CSteamAppSystemGroup > +{ +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit( ); + virtual int Main(); + virtual void PostShutdown(); +}; + +DEFINE_CONSOLE_STEAM_APPLICATION_OBJECT( MakeGameDataApp ); + +char g_szSourcePath[MAX_PATH]; +char g_targetPath[MAX_PATH]; +char g_zipPath[MAX_PATH]; +bool g_bForce; +bool g_bTest; +bool g_bMakeZip; +CXZipTool g_MasterXZip; +DiskWriteMode_t g_WriteModeForConversions; +char g_szGamePath[MAX_PATH]; +char g_szModPath[MAX_PATH]; +bool g_bModPathIsValid; +bool g_bQuiet; +bool g_bMakeScenes; +bool g_bMakeScenesPC; +bool g_bIsPlatformZip; +bool g_bUseMapList; + +IPhysicsCollision *g_pPhysicsCollision; +CSysModule *g_pPhysicsModule; + +CUtlVector< CUtlString > g_ValidMapList; +CUtlVector< errorList_t > g_errorList; + +const char *g_GameNames[] = +{ + "ep2", + "episodic", + "hl2", + "portal", + "platform", + "tf", + NULL +}; + +// all known languages +const char *g_pLanguageSuffixes[] = +{ + "_dannish", + "_dutch", + "_english", + "_finnish", + "_french", + "_german", + "_italian", + "_japanese", + "_korean", + "_koreana", + "_norwegian", + "_polish", + "_portuguese", + "_russian", + "_russion_buka", + "_schinese", + "_spanish", + "_swedish", + "_tchinese", + "_thai", +}; + +// 360 is shipping with support for only these languages +const char *g_pTargetLanguageSuffixes[] = +{ + "_english.", + "_french.", + "_german.", +}; + +// Master list of files that can go into the zip +static char *s_AllowedExtensionsInZip[] = +{ + // Explicitly lacking from this list, thus excluded from the zip + // .ain - AINs are external to the zip + // .bsp - BSPs are external to the zip + // .mp3 - MP3s aren't supported + + // Extensions with conversions + // Purposely using .360 encoding to ensure pc versions don't leak in + ".360.wav", + ".360.vtf", + ".360.mdl", + ".360.ani", + ".dx90.360.vtx", + ".360.vvd", + ".360.phy", + ".360.dat", + ".360.lst", + ".360.vcs", + ".360.image", + ".360.pcf", + + // Extensions without conversions (taken as is) + ".rc", + ".txt", + ".cfg", + ".res", + ".vfe", + ".vbf", + ".vmt", + ".raw", + ".lst", + ".bns", +}; + + + +//----------------------------------------------------------------------------- +// Determine game path +//----------------------------------------------------------------------------- +void GetGamePath() +{ + GetCurrentDirectory( sizeof( g_szGamePath ), g_szGamePath ); + + char szFullPath[MAX_PATH]; + if ( _fullpath( szFullPath, g_szGamePath, sizeof( szFullPath ) ) ) + { + strcpy( g_szGamePath, szFullPath ); + } + V_AppendSlash( g_szGamePath, sizeof( g_szGamePath ) ); + + char *pGameDir = V_stristr( g_szGamePath, "game\\" ); + if ( !pGameDir ) + { + Msg( "ERROR: Failed to determine game directory from current path. Expecting 'game' in current path." ); + exit( 1 ); + } + + // kill any trailing dirs + pGameDir[4] = '\0'; +} + +//----------------------------------------------------------------------------- +// Determine mod path +//----------------------------------------------------------------------------- +bool GetModPath() +{ + char szDirectory[MAX_PATH]; + char szLastDirectory[MAX_PATH]; + + // non destructively determine the mod directory + bool bFound = false; + szLastDirectory[0] = '\0'; + GetCurrentDirectory( sizeof( szDirectory ), szDirectory ); + while ( 1 ) + { + V_ComposeFileName( szDirectory, "gameinfo.txt", g_szModPath, sizeof( g_szModPath ) ); + struct _stat statBuf; + if ( _stat( g_szModPath, &statBuf ) != -1 ) + { + bFound = true; + V_strncpy( g_szModPath, szDirectory, sizeof( g_szModPath ) ); + break; + } + + // previous dir + V_ComposeFileName( szDirectory, "..", g_szModPath, sizeof( g_szModPath ) ); + + char fullPath[MAX_PATH]; + if ( _fullpath( fullPath, g_szModPath, sizeof( fullPath ) ) ) + { + strcpy( szDirectory, fullPath ); + } + + if ( !V_stricmp( szDirectory, szLastDirectory ) ) + { + // can back up no further + break; + } + strcpy( szLastDirectory, szDirectory ); + } + + if ( !bFound ) + { + // use current directory instead + GetCurrentDirectory( sizeof( g_szModPath ), g_szModPath ); + } + + return bFound; +} + +//----------------------------------------------------------------------------- +// Setup File system and search paths +//----------------------------------------------------------------------------- +bool SetupFileSystem() +{ + if ( g_bModPathIsValid ) + { + CFSSteamSetupInfo steamInfo; + steamInfo.m_pDirectoryName = g_szModPath; + steamInfo.m_bOnlyUseDirectoryName = true; + steamInfo.m_bToolsMode = true; + steamInfo.m_bSetSteamDLLPath = true; + steamInfo.m_bSteam = false; + if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK ) + return false; + + CFSMountContentInfo fsInfo; + fsInfo.m_pFileSystem = g_pFullFileSystem; + fsInfo.m_bToolsMode = true; + fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath; + if ( FileSystem_MountContent( fsInfo ) != FS_OK ) + return false; + + // Finally, load the search paths for the "GAME" path. + CFSSearchPathsInit searchPathsInit; + searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath; + searchPathsInit.m_pFileSystem = fsInfo.m_pFileSystem; + if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK ) + return false; + + char platform[MAX_PATH]; + Q_strncpy( platform, steamInfo.m_GameInfoPath, MAX_PATH ); + Q_StripTrailingSlash( platform ); + Q_strncat( platform, "/../platform", MAX_PATH, MAX_PATH ); + fsInfo.m_pFileSystem->AddSearchPath( platform, "PLATFORM" ); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Helper utility, read file into buffer +//----------------------------------------------------------------------------- +bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText, bool bNoOpenFailureWarning ) +{ + return scriptlib->ReadFileToBuffer( pSourceName, buffer, bText, bNoOpenFailureWarning ); +} + +//----------------------------------------------------------------------------- +// Purpose: Helper utility, Write buffer to file +//----------------------------------------------------------------------------- +bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, bool bWriteToZip, DiskWriteMode_t writeMode ) +{ + if ( g_bTest ) + return true; + + bool bSuccess = scriptlib->WriteBufferToFile( pTargetName, buffer, writeMode ); + bool bZipSuccess = true; + + if ( bSuccess && g_bMakeZip && !g_bTest && bWriteToZip ) + { + if ( !g_MasterXZip.AddBuffer( pTargetName, buffer, true ) ) + { + Msg( "WriteBufferToFile(): Error adding file %s\n", pTargetName ); + bZipSuccess = false; + } + } + + return bSuccess && bZipSuccess; +} + +//----------------------------------------------------------------------------- +// Compress data +//----------------------------------------------------------------------------- +bool CompressCallback( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer ) +{ + if ( !inputBuffer.TellPut() ) + { + // nothing to do + return false; + } + + unsigned int compressedSize; + unsigned char *pCompressedOutput = LZMA_OpportunisticCompress( (unsigned char *)inputBuffer.Base() + inputBuffer.TellGet(), inputBuffer.TellPut() - inputBuffer.TellGet(), &compressedSize ); + if ( pCompressedOutput ) + { + outputBuffer.EnsureCapacity( compressedSize ); + outputBuffer.Put( pCompressedOutput, compressedSize ); + free( pCompressedOutput ); + return true; + } + + return false; +} + + + +//----------------------------------------------------------------------------- +// Some converters need to run a final pass. +//----------------------------------------------------------------------------- +void DoPostProcessingFunctions( bool bWriteToZip ) +{ + if ( g_bMakeScenes || g_bMakeScenesPC ) + { + // scenes are converted and aggregated into one image + CreateSceneImageFile( g_szModPath, bWriteToZip, g_bMakeScenesPC, g_bQuiet, g_WriteModeForConversions ); + } + + ProcessDXSupportConfig( bWriteToZip ); +} + +//----------------------------------------------------------------------------- +// Startup any conversion modules. +//----------------------------------------------------------------------------- +bool InitConversionModules() +{ + return true; +} + +//----------------------------------------------------------------------------- +// Shutdown and cleanup any conversion modules. +//----------------------------------------------------------------------------- +void ShutdownConversionModules() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Distribute to worker function +//----------------------------------------------------------------------------- +bool CreateTargetFile( const char *pSourceName, const char *pTargetName, fileType_e fileType, bool bWriteToZip ) +{ + // resolve relative source to absolute path + // same workers use subdir name to determine conversion parameters + char fullSourcePath[MAX_PATH]; + if ( _fullpath( fullSourcePath, pSourceName, sizeof( fullSourcePath ) ) ) + { + pSourceName = fullSourcePath; + } + + // distribute to actual worker + // workers can expect exact final decorated filenames + bool bSuccess = false; + switch ( fileType ) + { + case FILETYPE_UNKNOWN: + break; + + case FILETYPE_VTF: + bSuccess = CreateTargetFile_VTF( pSourceName, pTargetName, bWriteToZip ); + break; + + case FILETYPE_WAV: + bSuccess = CreateTargetFile_WAV( pSourceName, pTargetName, bWriteToZip ); + break; + + case FILETYPE_MDL: + case FILETYPE_ANI: + case FILETYPE_VTX: + case FILETYPE_VVD: + case FILETYPE_PHY: + bSuccess = CreateTargetFile_Model( pSourceName, pTargetName, bWriteToZip ); + break; + + case FILETYPE_BSP: + bSuccess = CreateTargetFile_BSP( pSourceName, pTargetName, bWriteToZip ); + break; + + case FILETYPE_AIN: + bSuccess = CreateTargetFile_AIN( pSourceName, pTargetName, bWriteToZip ); + break; + + case FILETYPE_CCDAT: + bSuccess = CreateTargetFile_CCDAT( pSourceName, pTargetName, bWriteToZip ); + break; + + case FILETYPE_MP3: + bSuccess = CreateTargetFile_MP3( pSourceName, pTargetName, bWriteToZip ); + break; + + case FILETYPE_RESLST: + bSuccess = CreateTargetFile_RESLST( pSourceName, pTargetName, bWriteToZip ); + break; + + case FILETYPE_PCF: + bSuccess = CreateTargetFile_PCF( pSourceName, pTargetName, bWriteToZip ); + break; + + // others... + } + + return bSuccess; +} + +//----------------------------------------------------------------------------- +// Purpose: Determine file type based on source extension. Generate .360.xxx +// target name. +//----------------------------------------------------------------------------- +fileType_e ResolveFileType( const char *pSourceName, char *pTargetName, int targetNameSize ) +{ + char szFullSourcePath[MAX_PATH]; + _fullpath( szFullSourcePath, pSourceName, sizeof( szFullSourcePath ) ); + + char sourceExtension[MAX_PATH]; + V_ExtractFileExtension( pSourceName, sourceExtension, sizeof( sourceExtension ) ); + + // default unrecognized + fileType_e fileType = FILETYPE_UNKNOWN; + + if ( !V_stricmp( sourceExtension, "wav" ) ) + { + fileType = FILETYPE_WAV; + } + else if ( !V_stricmp( sourceExtension, "vtf" ) ) + { + fileType = FILETYPE_VTF; + } + else if ( !V_stricmp( sourceExtension, "mdl" ) ) + { + fileType = FILETYPE_MDL; + } + else if ( !V_stricmp( sourceExtension, "ani" ) ) + { + fileType = FILETYPE_ANI; + } + else if ( !V_stricmp( sourceExtension, "vvd" ) ) + { + fileType = FILETYPE_VVD; + } + else if ( !V_stricmp( sourceExtension, "phy" ) ) + { + fileType = FILETYPE_PHY; + } + else if ( !V_stricmp( sourceExtension, "bsp" ) ) + { + fileType = FILETYPE_BSP; + } + else if ( !V_stricmp( sourceExtension, "ain" ) ) + { + fileType = FILETYPE_AIN; + } + else if ( !V_stricmp( sourceExtension, "dat" ) ) + { + if ( V_stristr( pSourceName, "closecaption_" ) ) + { + // only want closecaption dat files, ignore all others + fileType = FILETYPE_CCDAT; + } + } + else if ( !V_stricmp( sourceExtension, "vtx" ) ) + { + if ( V_stristr( pSourceName, ".dx90" ) ) + { + // only want dx90 version, ignore all others + fileType = FILETYPE_VTX; + } + } + else if ( !V_stricmp( sourceExtension, "mp3" ) ) + { + // mp3's are already pre-converted into .360.wav + // slam the expected name here to simplify the external logic which will do the right thing + V_StripExtension( pSourceName, pTargetName, targetNameSize ); + V_strcat( pTargetName, ".360.wav", targetNameSize ); + return FILETYPE_MP3; + } + else if ( !V_stricmp( sourceExtension, "lst" ) ) + { + if ( V_stristr( szFullSourcePath, "reslists_xbox\\" ) ) + { + // only want reslists map versions, due to special processing, ignore all others + fileType = FILETYPE_RESLST; + } + } + else if ( !V_stricmp( sourceExtension, "pcf" ) ) + { + fileType = FILETYPE_PCF; + } + else if ( !V_stricmp( sourceExtension, "image" ) ) + { + if ( V_stristr( szFullSourcePath, "scenes\\" ) ) + { + // only want scene image, ignore all others + fileType = FILETYPE_SCENEIMAGE; + } + } + + if ( fileType != FILETYPE_UNKNOWN && !V_stristr( pSourceName, ".360." ) ) + { + char targetExtension[MAX_PATH]; + sprintf( targetExtension, ".360.%s", sourceExtension ); + + V_StripExtension( pSourceName, pTargetName, targetNameSize ); + V_strcat( pTargetName, targetExtension, targetNameSize ); + } + else + { + // unknown or already converted, target is same as input + V_strncpy( pTargetName, pSourceName, targetNameSize ); + } + + return fileType; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns TRUE if file is a known localized file. +//----------------------------------------------------------------------------- +bool IsLocalizedFile( const char *pFileName ) +{ + for ( int i = 0; i<ARRAYSIZE( g_pLanguageSuffixes ); i++ ) + { + if ( V_stristr( pFileName, g_pLanguageSuffixes[i] ) ) + { + // a localized file + return true; + } + } + + // not a known localized file + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns TRUE if file is a supported localization. +//----------------------------------------------------------------------------- +bool IsLocalizedFileValid( const char *pFileName, const char *pLanguageSuffix ) +{ + // file is a localized version + if ( pLanguageSuffix ) + { + if ( V_stristr( pFileName, pLanguageSuffix ) ) + { + // allow it + return true; + } + + return false; + } + + // must match the target supported languages + for ( int i = 0; i < ARRAYSIZE( g_pTargetLanguageSuffixes ); i++ ) + { + if ( V_stristr( pFileName, g_pTargetLanguageSuffixes[i] ) ) + { + // allow it + return true; + } + } + + // does not match a target language, not allowed + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Check against a list of allowed filetypes for inclusion in the zip +//----------------------------------------------------------------------------- +bool IncludeInZip( const char *pSourceName ) +{ + if ( g_bIsPlatformZip ) + { + // only allow known valid platform directories + if ( !V_stristr( pSourceName, "materials\\" ) && + !V_stristr( pSourceName, "resource\\" ) && + !V_stristr( pSourceName, "vgui\\" ) ) + { + // exclude it + return false; + } + } + + for ( int i = 0; i < ARRAYSIZE( s_AllowedExtensionsInZip ); ++i ) + { + const char *pAllowedExtension = s_AllowedExtensionsInZip[i]; + if ( !V_stristr( pSourceName, pAllowedExtension ) ) + { + continue; + } + + if ( !V_stricmp( pAllowedExtension, ".lst" ) ) + { + // only want ???_exclude.lst files + if ( V_stristr( pSourceName, "_exclude.lst" ) ) + { + return true; + } + return false; + } + + if ( !V_stricmp( pAllowedExtension, ".txt" ) || !V_stricmp( pAllowedExtension, ".360.dat" ) ) + { + if ( IsLocalizedFile( pSourceName ) && !IsLocalizedFileValid( pSourceName ) ) + { + // exclude unsupported languages + return false; + } + + if ( !V_stricmp( pAllowedExtension, ".txt" ) && V_stristr( pSourceName, "closecaption_" ) ) + { + // exclude all the closecaption_<language>.txt files + return false; + } + } + + return true; + } + + // exclude it + return false; +} + +//----------------------------------------------------------------------------- +// Returns true if map is in list, otherwise false +//----------------------------------------------------------------------------- +bool IsMapNameInList( const char *pMapName, CUtlVector< CUtlString > &mapList ) +{ + char szBaseName[MAX_PATH]; + + V_FileBase( pMapName, szBaseName, sizeof( szBaseName ) ); + V_strlower( szBaseName ); + + if ( mapList.Find( szBaseName ) != mapList.InvalidIndex() ) + { + // found + return true; + } + + // not found + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the list of valid BSPs +//----------------------------------------------------------------------------- +void BuildValidMapList( CUtlVector< CUtlString > &mapList ) +{ + char szFilename[MAX_PATH]; + V_ComposeFileName( g_szModPath, "maplist.txt", szFilename, sizeof( szFilename ) ); + + CUtlBuffer buffer; + if ( !ReadFileToBuffer( szFilename, buffer, true, true ) ) + { + return; + } + + characterset_t breakSet; + CharacterSetBuild( &breakSet, "" ); + + char szToken[MAX_PATH]; + char szMapName[MAX_PATH]; + for ( ;; ) + { + int nTokenSize = buffer.ParseToken( &breakSet, szToken, sizeof( szToken ) ); + if ( nTokenSize <= 0 ) + { + break; + } + + // reslists are pc built, filenames can be sloppy + V_FileBase( szToken, szMapName, sizeof( szMapName ) ); + V_strlower( szMapName ); + + mapList.AddToTail( szMapName ); + } +} + +#define DO_UPDATE 0x01 +#define DO_ZIP 0x02 + +//----------------------------------------------------------------------------- +// Purpose: drive the file creation +//----------------------------------------------------------------------------- +void GenerateTargetFiles( CUtlVector<fileList_t> &fileList ) +{ + char sourcePath[MAX_PATH]; + char sourceFile[MAX_PATH]; + char targetFile[MAX_PATH]; + struct _stat sourceStatBuf; + struct _stat targetStatBuf; + + strcpy( sourcePath, g_szSourcePath ); + V_StripFilename( sourcePath ); + if ( !sourcePath[0] ) + strcpy( sourcePath, "." ); + V_AppendSlash( sourcePath, sizeof( sourcePath ) ); + + // default is to update and zip + CUtlVector< int > updateList; + updateList.AddMultipleToTail( fileList.Count() ); + for ( int i=0; i<fileList.Count(); i++ ) + { + updateList[i] = DO_UPDATE|DO_ZIP; + } + int numMatches = 0; + + // build update list + for ( int i=0; i<fileList.Count(); i++ ) + { + if ( fileList[i].fileName.IsEmpty() ) + { + // ignore entries that have been culled + updateList[i] = 0; + continue; + } + + const char *ptr = fileList[i].fileName.String(); + if ( !strnicmp( ptr, ".\\", 2 ) ) + ptr += 2; + else if ( !strnicmp( ptr, sourcePath, strlen( sourcePath ) ) ) + ptr += strlen( sourcePath ); + + strcpy( sourceFile, sourcePath ); + strcat( sourceFile, ptr ); + strcpy( targetFile, g_targetPath ); + strcat( targetFile, ptr ); + + fileType_e fileType = ResolveFileType( sourceFile, targetFile, sizeof( targetFile ) ); + + // check the target name for inclusion due to extension modifications + if ( !IncludeInZip( targetFile ) ) + { + // exclude from zip + updateList[i] &= ~DO_ZIP; + } + + if ( fileType == FILETYPE_UNKNOWN ) + { + // No conversion function, can't do anything + updateList[i] &= ~DO_UPDATE; + continue; + } + else + { + // known filetype, which has a conversion + // the wildcard match may catch existing converted files, which need to be rejected + // cull exisiting conversions from the work list + // the non-converted filename is part of the same wildcard match, gets caught and resolved + // the non-converted filename will then go through the proper conversion path + if ( V_stristr( sourceFile, ".360." ) ) + { + // cull completely + updateList[i] = 0; + continue; + } + } + + if ( fileType == FILETYPE_BSP || fileType == FILETYPE_AIN || fileType == FILETYPE_RESLST ) + { + if ( g_ValidMapList.Count() && !IsMapNameInList( sourceFile, g_ValidMapList ) ) + { + // cull completely + updateList[i] = 0; + continue; + } + } + + int retVal = _stat( sourceFile, &sourceStatBuf ); + if ( retVal != 0 ) + { + // couldn't get source, skip update or zip + updateList[i] = 0; + continue; + } + + retVal = _stat( targetFile, &targetStatBuf ); + if ( retVal != 0 ) + { + // target doesn't exit, update is required + continue; + } + + // track valid candidates + numMatches++; + + if ( fileType == FILETYPE_MDL || fileType == FILETYPE_ANI || fileType == FILETYPE_VTX || fileType == FILETYPE_VVD || fileType == FILETYPE_PHY ) + { + // models are converted in a pre-pass + // let the update logic run and catch the conversions for zipping + continue; + } + + if ( !g_bForce ) + { + if ( difftime( sourceStatBuf.st_mtime, targetStatBuf.st_mtime ) <= 0 ) + { + // target is same or older, no update + updateList[i] &= ~DO_UPDATE; + } + } + } + + // cleanse and determine totals, makes succeeding logic simpler + int numWorkItems = 0; + int numFilesToUpdate = 0; + int numFilesToZip = 0; + for ( int i=0; i<fileList.Count(); i++ ) + { + if ( updateList[i] & DO_UPDATE ) + { + numFilesToUpdate++; + } + if ( g_bMakeZip && ( updateList[i] & DO_ZIP ) ) + { + numFilesToZip++; + } + else + { + updateList[i] &= ~DO_ZIP; + } + if ( updateList[i] ) + { + numWorkItems++; + } + } + + Msg( "\n" ); + Msg( "Matched %d/%d files.\n", numMatches, fileList.Count() ); + Msg( "Creating or Updating %d files.\n", numFilesToUpdate ); + if ( g_bMakeZip ) + { + Msg( "Zipping %d files.\n", numFilesToZip ); + } + + InitConversionModules(); + + if ( numFilesToZip && !g_bTest ) + { + Msg( "Creating Zip: %s\n", g_zipPath ); + if ( !g_MasterXZip.Begin( g_zipPath, XBOX_DVD_SECTORSIZE ) ) + { + Msg( "ERROR: Failed to open \"%s\" for writing.\n", g_zipPath ); + return; + } + else + { + SetupCriticalPreloadScript( g_szModPath ); + } + } + + // iterate work list + int progress = 0; + for ( int i=0; i<fileList.Count(); i++ ) + { + if ( !updateList[i] ) + { + // no update or zip needed, skip + continue; + } + + const char *ptr = fileList[i].fileName.String(); + if ( !strnicmp( ptr, ".\\", 2 ) ) + ptr += 2; + else if ( !strnicmp( ptr, sourcePath, strlen( sourcePath ) ) ) + ptr += strlen( sourcePath ); + + strcpy( sourceFile, sourcePath ); + strcat( sourceFile, ptr ); + strcpy( targetFile, g_targetPath ); + strcat( targetFile, ptr ); + + fileType_e fileType = ResolveFileType( sourceFile, targetFile, sizeof( targetFile ) ); + + if ( !g_bQuiet ) + { + Msg( "%d/%d:%s -> %s\n", progress+1, numWorkItems, sourceFile, targetFile ); + } + + bool bSuccess = true; + if ( updateList[i] & DO_UPDATE ) + { + // generate target file (and optionally zip output) + bSuccess = CreateTargetFile( sourceFile, targetFile, fileType, (updateList[i] & DO_ZIP) != 0 ); + if ( !bSuccess ) + { + // add to error list + int error = g_errorList.AddToTail(); + g_errorList[error].result = false; + g_errorList[error].fileName.Set( sourceFile ); + } + } + else if ( updateList[i] & DO_ZIP ) + { + // existing target file is zipped + CUtlBuffer targetBuffer; + bSuccess = scriptlib->ReadFileToBuffer( targetFile, targetBuffer ); + if ( bSuccess ) + { + if ( !g_bTest ) + { + bSuccess = g_MasterXZip.AddBuffer( targetFile, targetBuffer, true ); + } + } + if ( !bSuccess ) + { + // add to error list + int error = g_errorList.AddToTail(); + g_errorList[error].result = false; + g_errorList[error].fileName.Set( targetFile ); + } + } + + progress++; + } + + DoPostProcessingFunctions( !g_bTest ); + + ShutdownConversionModules(); + + if ( numFilesToZip && !g_bTest ) + { + g_MasterXZip.End(); + } + + // iterate error list + Msg( "\n" ); + for ( int i = 0; i < g_errorList.Count(); i++ ) + { + Msg( "ERROR: could not process %s\n", g_errorList[i].fileName.String() ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Spew Usage +//----------------------------------------------------------------------------- +void Usage() +{ + Msg( "usage: MakeGameData [filemask] [options]\n" ); + Msg( "options:\n" ); + Msg( "[-v] Version\n" ); + Msg( "[-q] Quiet (critical spew only)\n" ); + Msg( "[-h] [-help] [-?] Help\n" ); + Msg( "[-t targetPath] Alternate output path, will generate output at target\n" ); + Msg( "[-r] [-recurse] Recurse into source directory\n" ); + Msg( "[-f] [-force] Force update, otherwise checks timestamps\n" ); + Msg( "[-test] Skip writing to disk\n" ); + Msg( "[-z <zipname>] Generate zip file AND create or update stale conversions\n" ); + Msg( "[-zo <zipname>] Generate zip file ONLY (existing stale conversions get updated, no new conversions are written)\n" ); + Msg( "[-preloadinfo] Spew contents of preload section in zip\n" ); + Msg( "[-xmaquality <quality>] XMA Encoding quality override, [0-100]\n" ); + Msg( "[-scenes] Make 360 scene image cache.\n" ); + Msg( "[-pcscenes] Make PC scene image cache.\n" ); + Msg( "[-usemaplist] For BSP related conversions, restricts to maplist.txt.\n" ); + + exit( 1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: default output func +//----------------------------------------------------------------------------- +SpewRetval_t OutputFunc( SpewType_t spewType, char const *pMsg ) +{ + printf( pMsg ); + + if ( spewType == SPEW_ERROR ) + { + return SPEW_ABORT; + } + return ( spewType == SPEW_ASSERT ) ? SPEW_DEBUGGER : SPEW_CONTINUE; +} + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +bool MakeGameDataApp::Create() +{ + SpewOutputFunc( OutputFunc ); + + AppSystemInfo_t appSystems[] = + { + { "mdllib.dll", MDLLIB_INTERFACE_VERSION }, + { "", "" } // Required to terminate the list + }; + + AddSystem( g_pDataModel, VDATAMODEL_INTERFACE_VERSION ); + AddSystem( g_pDmSerializers, DMSERIALIZERS_INTERFACE_VERSION ); + + // Load vphysics.dll + if ( !Sys_LoadInterface( "vphysics.dll", VPHYSICS_COLLISION_INTERFACE_VERSION, &g_pPhysicsModule, (void**)&g_pPhysicsCollision ) ) + { + Msg( "Failed to load vphysics interface\n" ); + return false; + } + + bool bOk = AddSystems( appSystems ); + if ( !bOk ) + return false; + + return true; +} + +bool MakeGameDataApp::PreInit() +{ + CreateInterfaceFn factory = GetFactory(); + + ConnectTier1Libraries( &factory, 1 ); + ConnectTier2Libraries( &factory, 1 ); + + if ( !g_pFullFileSystem || !g_pDataModel || !g_pPhysicsCollision || !mdllib ) + { + Warning( "MakeGameData is missing a required interface!\n" ); + return false; + } + + return true; +} + +void MakeGameDataApp::PostShutdown() +{ + if ( g_pPhysicsModule ) + { + Sys_UnloadModule( g_pPhysicsModule ); + g_pPhysicsModule = NULL; + g_pPhysicsCollision = NULL; + } + + DisconnectTier2Libraries(); + DisconnectTier1Libraries(); +} + +//----------------------------------------------------------------------------- +// main +// +//----------------------------------------------------------------------------- +int MakeGameDataApp::Main() +{ + int argnum; + + // set the valve library printer + SpewOutputFunc( OutputFunc ); + + Msg( "\nMAKEGAMEDATA - Valve Xbox 360 Game Data Compiler (Build: %s %s)\n", __DATE__, __TIME__ ); + Msg( "(C) Copyright 1996-2006, Valve Corporation, All rights reserved.\n\n" ); + + if ( CommandLine()->FindParm( "-v" ) || CommandLine()->FindParm( "-version" ) ) + { + // spew just the version, used by batches for logging + return 0; + } + +#ifndef MAKESCENESIMAGE + if ( CommandLine()->ParmCount() < 2 || CommandLine()->FindParm( "?" ) || CommandLine()->FindParm( "-h" ) || CommandLine()->FindParm( "-help" ) ) + { + Usage(); + } +#endif // MAKESCENESIMAGE + + bool bHasFileMask = false; + + const char *pFirstArg = CommandLine()->GetParm( 1 ); + if ( pFirstArg[0] == '-' ) + { + // first arg is an option, assume *.* + strcpy( g_szSourcePath, "*.*" ); + } + else + { + strcpy( g_szSourcePath, pFirstArg ); + bHasFileMask = true; + } + + bool bRecurse = false; +#ifndef MAKESCENESIMAGE + bRecurse = CommandLine()->FindParm( "-recurse" ) || CommandLine()->FindParm( "-r" ); + g_bForce = CommandLine()->FindParm( "-force" ) || CommandLine()->FindParm( "-f" ); + g_bTest = CommandLine()->FindParm( "-test" ) != 0; + g_bQuiet = CommandLine()->FindParm( "-quiet" ) || CommandLine()->FindParm( "-q" ); + g_bMakeScenes = CommandLine()->FindParm( "-scenes" ) != 0; + g_bMakeScenesPC = CommandLine()->FindParm( "-pcscenes" ) != 0; +#else + g_bMakeScenesPC = true; +#endif // MAKESCENESIMAGE + +#ifndef MAKESCENESIMAGE + g_bUseMapList = CommandLine()->FindParm( "-usemaplist" ) != 0; +#endif // MAKESCENESIMAGE + + // Set up zip file options + g_WriteModeForConversions = WRITE_TO_DISK_ALWAYS; + argnum = CommandLine()->FindParm( "-z" ); + if ( argnum ) + { + strcpy( g_szSourcePath, "*.*" ); + g_bMakeZip = true; + g_bMakeScenes = true; + bRecurse = true; + } + else + { + argnum = CommandLine()->FindParm( "-zo" ); + if ( argnum ) + { + strcpy( g_szSourcePath, "*.*" ); + g_bMakeZip = true; + g_bMakeScenes = true; + g_WriteModeForConversions = WRITE_TO_DISK_UPDATE; + bRecurse = true; + } + } + if ( g_bMakeZip ) + { + strcat( g_zipPath, CommandLine()->GetParm( argnum + 1 ) ); + } + + // default target path is source + strcpy( g_targetPath, g_szSourcePath ); + V_StripFilename( g_targetPath ); + if ( !g_targetPath[0] ) + { + strcpy( g_targetPath, "." ); + } + + // override via command line + argnum = CommandLine()->FindParm( "-t" ); + if ( argnum ) + { + V_strcpy_safe( g_targetPath, CommandLine()->GetParm( argnum + 1 ) ); + } + V_AppendSlash( g_targetPath, sizeof( g_targetPath ) ); + + if ( CommandLine()->FindParm( "-preloadinfo" ) ) + { + g_MasterXZip.SpewPreloadInfo( g_szSourcePath ); + return 0; + } + +#ifndef MAKESCENESIMAGE + GetGamePath(); +#endif // MAKESCENESIMAGE + + g_bModPathIsValid = GetModPath(); + if ( !SetupFileSystem() ) + { + Msg( "ERROR: Failed to setup file system.\n" ); + exit( 1 ); + } + + // data model initialization + g_pDataModel->SetUndoEnabled( false ); + g_pDataModel->OnlyCreateUntypedElements( true ); + g_pDataModel->SetDefaultElementFactory( NULL ); + + g_bIsPlatformZip = g_bMakeZip && ( V_stristr( g_szModPath, "\\platform" ) != NULL ); + + // cleanup any zombie temp files left from a possible prior abort or error + scriptlib->DeleteTemporaryFiles( "mgd_*.tmp" ); + + if ( g_bMakeZip || g_bUseMapList ) + { + // zips use the map list to narrow the bsp conversion to actual shipping maps + BuildValidMapList( g_ValidMapList ); + } + + CUtlVector<fileList_t> fileList; + if ( bHasFileMask || g_bMakeZip ) + { + scriptlib->FindFiles( g_szSourcePath, bRecurse, fileList ); + } + + // model conversions require seperate pre-processing to achieve grouping + if ( !PreprocessModelFiles( fileList ) ) + { + return 0; + } + + GenerateTargetFiles( fileList ); + + return 0; +} diff --git a/utils/xbox/MakeGameData/MakeGameData.h b/utils/xbox/MakeGameData/MakeGameData.h new file mode 100644 index 0000000..c2f2004 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeGameData.h @@ -0,0 +1,165 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#pragma once + +#include <windows.h> +#include <mmreg.h> +#include <stdio.h> +#include <stdlib.h> +#include <direct.h> +#include <io.h> +#include <time.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/utime.h> +#include "tier0/dbg.h" +#include "tier0/icommandline.h" +#include "appframework/appframework.h" +#include "characterset.h" +#include "tier1/strtools.h" +#include "tier1/UtlVector.h" +#include "tier1/UtlBuffer.h" +#include "tier1/UtlString.h" +#include "tier1/UtlRBTree.h" +#include "tier1/UtlDict.h" +#include "tier1/UtlSortVector.h" +#include "tier1/UtlStringMap.h" +#include "tier1/UtlSymbol.h" +#include "tier1/KeyValues.h" +#include "tier1/lzss.h" +#include "lzma/lzma.h" +#include "datamap.h" +#include "XZipTool.h" +#include "../../common/scriplib.h" +#include "../../common/cmdlib.h" +#include "tier2/tier2.h" +#include "dmserializers/idmserializers.h" +#include "datamodel/dmattribute.h" +#include "datamodel/dmelement.h" +#include "studiobyteswap.h" +#include "studio.h" +#include "vphysics_interface.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/hardwareverts.h" +#include "optimize.h" +#include "soundchars.h" +#include "mdllib/mdllib.h" + +enum fileType_e +{ + FILETYPE_UNKNOWN = 0, + FILETYPE_WAV, + FILETYPE_VTF, + FILETYPE_MDL, + FILETYPE_ANI, + FILETYPE_VTX, + FILETYPE_VVD, + FILETYPE_PHY, + FILETYPE_BSP, + FILETYPE_AIN, + FILETYPE_CCDAT, + FILETYPE_MP3, + FILETYPE_RESLST, + FILETYPE_PCF, + FILETYPE_SCENEIMAGE +}; + +typedef struct +{ + int result; + CUtlString fileName; +} errorList_t; + +//----------------------------------------------------------------------------- +// MakeGameData.cpp +//----------------------------------------------------------------------------- + + +bool IsLocalizedFile( const char *pFileName ); +bool IsLocalizedFileValid( const char *pFileName, const char *pLanguageSuffix = NULL ); +bool CompressCallback( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer ); +bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText, bool bNoOpenFailureWarning ); +bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, bool bWriteToZip, DiskWriteMode_t writeMode ); +fileType_e ResolveFileType( const char *pSourceName, char *pTargetName, int targetNameSize ); + +extern DiskWriteMode_t g_WriteModeForConversions; +extern CXZipTool g_MasterXZip; +extern char g_szGamePath[]; +extern char g_szModPath[]; +extern bool g_bModPathIsValid; +extern const char *g_GameNames[]; +extern bool g_bForce; +extern bool g_bQuiet; +extern bool g_bMakeZip; +extern bool g_bIsPlatformZip; +extern IPhysicsCollision *g_pPhysicsCollision; +extern char g_szSourcePath[]; +extern CUtlVector< errorList_t > g_errorList; + +//----------------------------------------------------------------------------- +// MakeTextures.cpp +//----------------------------------------------------------------------------- +bool CreateTargetFile_VTF( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); +bool GetPreloadData_VTF( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ); + +//----------------------------------------------------------------------------- +// MakeScenes.cpp +//----------------------------------------------------------------------------- +bool CreateSceneImageFile( char const *pchModPath, bool bWriteToZip, bool bLittleEndian, bool bQuiet, DiskWriteMode_t eWriteModeForConversions ); + +//----------------------------------------------------------------------------- +// MakeSounds.cpp +//----------------------------------------------------------------------------- +bool CreateTargetFile_WAV( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); +bool CreateTargetFile_MP3( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); +bool GetPreloadData_WAV( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ); + +//----------------------------------------------------------------------------- +// MakeMaps.cpp +//----------------------------------------------------------------------------- +bool CreateTargetFile_BSP( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); +bool CreateTargetFile_AIN( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); +bool GetDependants_BSP( const char *pBspName, CUtlVector< CUtlString > *pList ); + +//----------------------------------------------------------------------------- +// MakeResources.cpp +//----------------------------------------------------------------------------- +bool CreateTargetFile_CCDAT( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); +bool CreateTargetFile_RESLST( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); + +//----------------------------------------------------------------------------- +// MakeModels.cpp +//----------------------------------------------------------------------------- +bool InitStudioByteSwap( void ); +void ShutdownStudioByteSwap( void ); +bool CreateTargetFile_Model( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); +bool GetDependants_MDL( const char *pModelName, CUtlVector< CUtlString > *pList ); +bool GetPreloadData_VHV( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ); +bool GetPreloadData_VTX( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ); +bool GetPreloadData_VVD( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ); +bool PreprocessModelFiles( CUtlVector<fileList_t> &fileList ); + +//----------------------------------------------------------------------------- +// MakeShaders.cpp +//----------------------------------------------------------------------------- +bool GetPreloadData_VCS( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ); + +//----------------------------------------------------------------------------- +// MakeMisc.cpp +//----------------------------------------------------------------------------- +bool ProcessDXSupportConfig( bool bWriteToZip ); + +//----------------------------------------------------------------------------- +// MakeResources.cpp +//----------------------------------------------------------------------------- +bool CreateTargetFile_PCF( const char *pSourceName, const char *pTargetName, bool bWriteToZip ); + +//----------------------------------------------------------------------------- +// MakeZip.cpp +//----------------------------------------------------------------------------- +void SetupCriticalPreloadScript( const char *pModPath ); diff --git a/utils/xbox/MakeGameData/MakeGameData.vpc b/utils/xbox/MakeGameData/MakeGameData.vpc new file mode 100644 index 0000000..315333c --- /dev/null +++ b/utils/xbox/MakeGameData/MakeGameData.vpc @@ -0,0 +1,111 @@ +//----------------------------------------------------------------------------- +// MAKEGAMEDATA.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;$SRCDIR\x360xdk\include\win32\vs2005;$SRCDIR\game\shared" + $PreprocessorDefinitions "$BASE;NO_X360_XDK" [$VS2015] + } + + $Linker + { + $AdditionalDependencies "$BASE xgraphics.lib d3d9.lib legacy_stdio_definitions.lib" + $AdditionalDependencies "$BASE xmaencoder.lib" [!$VS2015] + $AdditionalLibraryDirectories "$BASE;$SRCDIR\x360xdk\lib\win32\vs2005" + } +} + +$Project "MakeGameData" +{ + $Folder "Source Files" + { + $File "MakeGameData.cpp" + $File "MakeMaps.cpp" + $File "MakeMisc.cpp" + $File "MakeModels.cpp" + $File "MakeParticles.cpp" + $File "MakeResources.cpp" + $File "MakeScenes.cpp" + $File "MakeShaders.cpp" + $File "MakeSounds.cpp" + $File "MakeTextures.cpp" + $File "MakeZip.cpp" + + $Folder "Audio" + { + $File "imaadpcm.cpp" + $File "sound_io.cpp" + $File "resample.cpp" + } + + $Folder "Public Modules" + { + $File "$SRCDIR\common\compiledcaptionswap.cpp" + $file "$SRCDIR\common\studiobyteswap.cpp" + $File "$SRCDIR\utils\common\scriplib.cpp" + $File "$SRCDIR\public\zip_utils.cpp" + $File "$SRCDIR\public\sentence.cpp" + $File "$SRCDIR\utils\common\cmdlib.cpp" + $File "$SRCDIR\public\filesystem_helpers.cpp" + $File "$SRCDIR\public\filesystem_init.cpp" + $File "$SRCDIR\utils\common\filesystem_tools.cpp" + $File "$SRCDIR\public\interpolatortypes.cpp" + } + } + + $Folder "Header Files" + { + $File "MakeGameData.h" + $File "XZipTool.h" + $File "imaadpcm.h" + $File "resample.h" + $File "$SRCDIR\public\captioncompiler.h" + $File "$SRCDIR\common\studiobyteswap.h" + $File "$SRCDIR\utils\common\scriplib.h" + $File "$SRCDIR\public\filesystem.h" + $File "$SRCDIR\public\ibsppack.h" + $File "$SRCDIR\public\sentence.h" + $File "$SRCDIR\public\studio.h" + $File "$SRCDIR\public\tier1\utlbuffer.h" + $File "$SRCDIR\public\tier1\strtools.h" + $File "$SRCDIR\public\vphysics_interface.h" + $File "$SRCDIR\public\vstdlib\vstdlib.h" + $File "$SRCDIR\public\xwvfile.h" + $File "$SRCDIR\public\zip_utils.h" + $File "$SRCDIR\game\shared\choreoscene.h" + $File "$SRCDIR\game\shared\choreoactor.h" + $File "$SRCDIR\public\filesystem_helpers.h" + $File "$SRCDIR\public\filesystem_init.h" + $File "$SRCDIR\utils\common\filesystem_tools.h" + $File "$SRCDIR\public\interpolatortypes.h" + $File "$SRCDIR\utils\common\cmdlib.h" + $File "$SRCDIR\game\shared\choreochannel.h" + $File "$SRCDIR\game\shared\choreoevent.h" + $File "$SRCDIR\public\tier1\checksum_crc.h" + $File "$SRCDIR\public\tier2\tier2.h" + $File "$SRCDIR\common\lzma\lzma.h" + } + + $Folder "Link Libraries" + { + $Lib appframework + $Lib mathlib + $Lib vtf + $Lib tier2 + $Lib choreoobjects + $Lib bitmap + $Lib datamodel + $Lib dmserializers + $Lib $LIBCOMMON\lzma + } +} diff --git a/utils/xbox/MakeGameData/MakeMaps.cpp b/utils/xbox/MakeGameData/MakeMaps.cpp new file mode 100644 index 0000000..618e5f6 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeMaps.cpp @@ -0,0 +1,383 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: .360 Creation for all studiomdl generated files (mdl, vvd, vtx, ani, phy) +// +//=====================================================================================// + +#include "MakeGameData.h" +#include "filesystem.h" +#include "../../common/bsplib.h" +#include "ibsppack.h" +#include "vtf/vtf.h" +#include "../../game/server/ai_hull.h" +#include "zip_utils.h" + +#define AINET_VERSION_NUMBER 37 +#define MAX_NODES 1500 + +bool ReadBSPHeader( const char *pFilename, dheader_t *pHeader ) +{ + V_memset( pHeader, 0, sizeof( dheader_t ) ); + + int handle = _open( pFilename, _O_RDONLY|_O_BINARY ); + if ( handle == -1 ) + { + return false; + } + + _read( handle, pHeader, sizeof( dheader_t ) ); + close( handle ); + + return true; +} + +//----------------------------------------------------------------------------- +// Run possible lod culling fixup +//----------------------------------------------------------------------------- +bool ConvertVHV( const char *pVhvFilename, const char *pModelName, CUtlBuffer &sourceBuffer, CUtlBuffer &targetBuffer ) +{ + // find strip info from model + char vsiFilename[MAX_PATH]; + V_strncpy( vsiFilename, pModelName, sizeof( vsiFilename ) ); + V_SetExtension( vsiFilename, ".vsi", sizeof( vsiFilename ) ); + + CUtlBuffer vsiBuffer; + if ( !g_pFullFileSystem->ReadFile( vsiFilename, NULL, vsiBuffer ) ) + { + // cannot convert bsp's without model converions + Msg( "Error! Missing expected model conversion file '%s'. Cannot perform VHV fixup.\n", vsiFilename ); + return false; + } + + IMdlStripInfo *pMdlStripInfo = NULL; + if ( !mdllib->CreateNewStripInfo( &pMdlStripInfo ) ) + { + Msg( "Error! Failed to allocate strip info object\n" ); + return false; + } + + if ( !pMdlStripInfo->UnSerialize( vsiBuffer ) ) + { + Msg( "Error! Failed to unserialize strip info object '%s'\n", vsiFilename ); + pMdlStripInfo->DeleteThis(); + return false; + } + + long originalChecksum = 0; + long newChecksum = 0; + if ( !pMdlStripInfo->GetCheckSum( &originalChecksum, &newChecksum ) ) + { + Msg( "Error! Failed to get checksums from '%s'\n", vsiFilename ); + pMdlStripInfo->DeleteThis(); + return false; + } + + HardwareVerts::FileHeader_t *pVHVhdr = (HardwareVerts::FileHeader_t*)sourceBuffer.Base(); + if ( pVHVhdr->m_nChecksum != originalChecksum ) + { + // vhv file should have matching original checksums + Msg( "Error! Mismatched checksums from '%s' and '%s'\n", vsiFilename, pVhvFilename ); + pMdlStripInfo->DeleteThis(); + return false; + } + + targetBuffer.EnsureCapacity( sourceBuffer.TellMaxPut() ); + targetBuffer.Put( sourceBuffer.Base(), sourceBuffer.TellMaxPut() ); + if ( !pMdlStripInfo->StripHardwareVertsBuffer( targetBuffer ) ) + { + pMdlStripInfo->DeleteThis(); + return false; + } + + // success + pMdlStripInfo->DeleteThis(); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Generate .360 bsp +//----------------------------------------------------------------------------- +bool CreateTargetFile_BSP( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + CUtlBuffer targetBuffer; + CUtlBuffer zipBuffer; + CUtlBuffer fileBuffer; + CUtlBuffer tempBuffer; + char tempZipName[MAX_PATH]; + char tempSwapName[MAX_PATH]; + + tempZipName[0] = '\0'; + tempSwapName[0] = '\0'; + void *pPakData = NULL; + int pakSize = 0; + CXZipTool *pNewXZip = NULL; + + if ( !g_bModPathIsValid ) + { + Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" ); + return false; + } + + // Load bsppack.dll + void *pBSPPack; + CSysModule *pBSPModule; + if ( !Sys_LoadInterface( "bsppack.dll", IBSPPACK_VERSION_STRING, &pBSPModule, &pBSPPack ) ) + { + Msg( "Failed to load bsppack interface\n" ); + return false; + } + + scriptlib->MakeTemporaryFilename( g_szModPath, tempSwapName, sizeof( tempSwapName ) ); + + // Swaps the bsp directly to disk + bool bOK = ((IBSPPack*)pBSPPack)->SwapBSPFile( g_pFullFileSystem, pSourceName, tempSwapName, false, ConvertVTFTo360Format, ConvertVHV, CompressCallback ); + if ( !bOK ) + { + goto cleanUp; + } + + // get the pak file from the swapped bsp + bOK = ((IBSPPack*)pBSPPack)->GetPakFileLump( g_pFullFileSystem, tempSwapName, &pPakData, &pakSize ); + if ( !bOK ) + { + goto cleanUp; + } + + // build an xzip version of the pak file + if ( pPakData && pakSize ) + { + // mount current pak file + IZip *pOldZip = IZip::CreateZip( false, true ); + pOldZip->ParseFromBuffer( pPakData, pakSize ); + + // start a new xzip version + scriptlib->MakeTemporaryFilename( g_szModPath, tempZipName, sizeof( tempZipName ) ); + + pNewXZip = new CXZipTool; + pNewXZip->Begin( tempZipName, XBOX_DVD_SECTORSIZE ); + + // iterate each file in existing zip, add to new zip + int zipIndex = -1; + for ( ;; ) + { + char filename[MAX_PATH]; + filename[0] = '\0'; + int fileSize = 0; + zipIndex = pOldZip->GetNextFilename( zipIndex, filename, sizeof( filename ), fileSize ); + if ( zipIndex == -1 ) + { + break; + } + + fileBuffer.Purge(); + bOK = pOldZip->ReadFileFromZip( filename, false, fileBuffer ); + if ( !bOK ) + { + goto cleanUp; + } + + bOK = pNewXZip->AddBuffer( filename, fileBuffer, true ); + if ( !bOK ) + { + goto cleanUp; + } + } + + IZip::ReleaseZip( pOldZip ); + pNewXZip->End(); + + // read the new zip into memory + bOK = scriptlib->ReadFileToBuffer( tempZipName, zipBuffer ); + if ( !bOK ) + { + goto cleanUp; + } + + // replace old pak lump with new zip + bOK = ((IBSPPack*)pBSPPack)->SetPakFileLump( g_pFullFileSystem, tempSwapName, tempSwapName, zipBuffer.Base(), zipBuffer.TellMaxPut() ); + if ( !bOK ) + { + goto cleanUp; + } + } + + bOK = scriptlib->ReadFileToBuffer( tempSwapName, targetBuffer ); + if ( !bOK ) + { + goto cleanUp; + } + + // never zip, always write local file + bOK = WriteBufferToFile( pTargetName, targetBuffer, false, WRITE_TO_DISK_ALWAYS ); + +cleanUp: + if ( tempZipName[0] ) + { + _unlink( tempZipName ); + } + if ( tempSwapName[0] ) + { + _unlink( tempSwapName ); + } + + Sys_UnloadModule( pBSPModule ); + + if ( pPakData ) + { + free( pPakData ); + } + + delete pNewXZip; + + return bOK; +} + + +//----------------------------------------------------------------------------- +// Purpose: Generate .360 node graphs +//----------------------------------------------------------------------------- +bool CreateTargetFile_AIN( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + CUtlBuffer sourceBuf; + if ( !scriptlib->ReadFileToBuffer( pSourceName, sourceBuf ) ) + { + return false; + } + + // the pc ain is tied to the pc bsp and should have been generated after the bsp + char szBspName[MAX_PATH]; + char szBspPath[MAX_PATH]; + V_FileBase( pSourceName, szBspName, sizeof( szBspName ) ); + V_ExtractFilePath( pSourceName, szBspPath, sizeof( szBspPath ) ); + V_AppendSlash( szBspPath, sizeof( szBspPath ) ); + V_strncat( szBspPath, "..\\", sizeof( szBspPath ) ); + V_strncat( szBspPath, szBspName, sizeof( szBspPath ) ); + V_strncat( szBspPath, ".bsp", sizeof( szBspPath ) ); + if ( scriptlib->CompareFileTime( pSourceName, szBspPath ) < 0 ) + { + // ain has a smaller filetime, thus older than bsp + Msg( "%s: Need to regenerate PC nodegraph (stale)\n", pSourceName ); + if ( !g_bForce ) + { + return false; + } + } + + // Check the version + if ( sourceBuf.GetChar() == 'V' && sourceBuf.GetChar() == 'e' && sourceBuf.GetChar() == 'r' ) + { + Msg( "%s: Need to regenerate PC nodegraph (bad format)\n", pSourceName ); + return false; + } + + // reset + sourceBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + + // Version number + int version = sourceBuf.GetInt(); + if ( version != AINET_VERSION_NUMBER ) + { + Msg( "%s: Need to regenerate PC nodegraph (got version '%d', expected '%d')\n", pSourceName, version, AINET_VERSION_NUMBER ); + return false; + } + + // check the map revision + int mapVersion = sourceBuf.GetInt(); + dheader_t bspHeader; + if ( ReadBSPHeader( szBspPath, &bspHeader ) ) + { + if ( mapVersion != bspHeader.mapRevision ) + { + Msg( "%s: Need to regenerate PC nodegraph (ai revision '%d' does not match bsp revision '%d')\n", pSourceName, mapVersion, bspHeader.mapRevision ); + return false; + } + } + else + { + Msg( "%s: Could not find expected bsp '%s'\n", pSourceName, szBspPath ); + } + + // Nodes + int nodeCt = sourceBuf.GetInt(); + if ( nodeCt > MAX_NODES || nodeCt < 0 ) + { + Msg( "%s: Need to regenerate PC nodegraph (corrupt)\n", pSourceName ); + return false; + } + + CUtlBuffer targetBuf; + targetBuf.ActivateByteSwapping( true ); + + CByteswap swap; + swap.ActivateByteSwapping( true ); + + targetBuf.PutInt( version ); + targetBuf.PutInt( mapVersion ); + targetBuf.PutInt( nodeCt ); + + int numFloats = NUM_HULLS + 4; + for ( int node = 0; node < nodeCt; ++node ) + { + targetBuf.EnsureCapacity( targetBuf.TellPut() + numFloats * sizeof( float ) ); + swap.SwapBufferToTargetEndian<float>( (float*)targetBuf.PeekPut(), (float*)sourceBuf.PeekGet(), numFloats ); + sourceBuf.SeekGet( CUtlBuffer::SEEK_CURRENT, numFloats * sizeof( float ) ); + targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, numFloats * sizeof( float ) ); + + targetBuf.PutChar( sourceBuf.GetChar() ); + + // Align the remaining data + targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, 3 ); + + targetBuf.PutUnsignedShort( sourceBuf.GetUnsignedShort() ); + targetBuf.PutShort( sourceBuf.GetShort() ); + } + + // Node links + int totalNumLinks = sourceBuf.GetInt(); + targetBuf.PutInt( totalNumLinks ); + + for ( int link = 0; link < totalNumLinks; ++link ) + { + targetBuf.PutShort( sourceBuf.GetShort() ); + targetBuf.PutShort( sourceBuf.GetShort() ); + targetBuf.Put( sourceBuf.PeekGet(), NUM_HULLS ); + sourceBuf.SeekGet( CUtlBuffer::SEEK_CURRENT, NUM_HULLS ); + } + + // WC lookup table + targetBuf.EnsureCapacity( targetBuf.TellPut() + nodeCt * sizeof( int ) ); + swap.SwapBufferToTargetEndian<int>( (int*)targetBuf.PeekPut(), (int*)sourceBuf.PeekGet(), nodeCt ); + targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, nodeCt * sizeof( int ) ); + + // Write the file out + return WriteBufferToFile( pTargetName, targetBuf, bWriteToZip, WRITE_TO_DISK_ALWAYS ); +} + +bool GetDependants_BSP( const char *pBspName, CUtlVector< CUtlString > *pList ) +{ + if ( !g_bModPathIsValid ) + { + Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" ); + return false; + } + + // Load bsppack.dll + void *pBSPPack; + CSysModule *pBSPModule; + if ( !Sys_LoadInterface( "bsppack.dll", IBSPPACK_VERSION_STRING, &pBSPModule, &pBSPPack ) ) + { + Msg( "Failed to load bsppack interface\n" ); + return false; + } + + // 360 builds a more complete reslist that includes bsp internal files + // build full path to bsp file + char szBspFilename[MAX_PATH]; + V_ComposeFileName( g_szGamePath, pBspName, szBspFilename, sizeof( szBspFilename ) ); + + bool bOK = ((IBSPPack*)pBSPPack)->GetBSPDependants( g_pFullFileSystem, szBspFilename, pList ); + + Sys_UnloadModule( pBSPModule ); + + return bOK; +} diff --git a/utils/xbox/MakeGameData/MakeMisc.cpp b/utils/xbox/MakeGameData/MakeMisc.cpp new file mode 100644 index 0000000..d5e88de --- /dev/null +++ b/utils/xbox/MakeGameData/MakeMisc.cpp @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Conversion for general wierd files. +// +//=====================================================================================// + +#include "MakeGameData.h" + +//----------------------------------------------------------------------------- +// The DX Support file is a very fat expensive KV file, causes a run-time startup slowdown. +// Becauase it normally lives in the game\bin directory, it can't be in the zip or preloaded. +// Thus, it gets reprocessed into just the trivial 360 portion and placed into the platform.zip +// Yes, it's evil. +//----------------------------------------------------------------------------- +bool ProcessDXSupportConfig( bool bWriteToZip ) +{ + if ( !g_bIsPlatformZip ) + { + // only relevant when building platform zip, otherwise no-op + return false; + } + + const char *pConfigName = "dxsupport.cfg"; + char szTempPath[MAX_PATH]; + char szSourcePath[MAX_PATH]; + V_ComposeFileName( g_szModPath, "../bin", szTempPath, sizeof( szTempPath ) ); + V_ComposeFileName( szTempPath, pConfigName, szSourcePath, sizeof( szSourcePath ) ); + + CUtlBuffer sourceBuf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + if ( !g_pFullFileSystem->ReadFile( szSourcePath, NULL, sourceBuf ) ) + { + Msg( "Error! Couldn't open file '%s'!\n", pConfigName ); + return false; + } + + KeyValues *pKV = new KeyValues( "" ); + if ( !pKV->LoadFromBuffer( "dxsupport.cfg", sourceBuf ) ) + { + Msg( "Error! Couldn't parse config file '%s'!\n", pConfigName ); + pKV->deleteThis(); + return false; + } + + // only care about the xbox specific dxlevel 98 block + KeyValues *pXboxSubKey = NULL; + for ( KeyValues *pSubKey = pKV->GetFirstSubKey(); pSubKey != NULL && pXboxSubKey == NULL; pSubKey = pSubKey->GetNextKey() ) + { + // descend each sub block + for ( KeyValues *pKey = pSubKey->GetFirstSubKey(); pKey != NULL && pXboxSubKey == NULL; pKey = pKey->GetNextKey() ) + { + if ( !V_stricmp( pKey->GetName(), "name" ) && pKey->GetInt( (const char *)NULL ) == 98 ) + { + pXboxSubKey = pSubKey; + } + } + } + + if ( !pXboxSubKey ) + { + Msg( "Error! Couldn't find expected dxlevel 98 in config file '%s'!\n", pConfigName ); + pKV->deleteThis(); + return false; + } + + CUtlBuffer kvBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER ); + kvBuffer.Printf( "\"dxsupport\"\n" ); + kvBuffer.Printf( "{\n" ); + kvBuffer.Printf( "\t\"0\"\n" ); + kvBuffer.Printf( "\t{\n" ); + for ( KeyValues *pKey = pXboxSubKey->GetFirstSubKey(); pKey != NULL; pKey = pKey->GetNextKey() ) + { + kvBuffer.Printf( "\t\t\"%s\" \"%s\"\n", pKey->GetName(), pKey->GetString( (const char *)NULL ) ); + } + kvBuffer.Printf( "\t}\n" ); + kvBuffer.Printf( "}\n" ); + + CUtlBuffer targetBuf( 0, 0, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::CONTAINS_CRLF ); + kvBuffer.ConvertCRLF( targetBuf ); + + // only appears in zip file + bool bSuccess = WriteBufferToFile( pConfigName, targetBuf, bWriteToZip, WRITE_TO_DISK_NEVER ); + + pKV->deleteThis(); + + return bSuccess; +}
\ No newline at end of file diff --git a/utils/xbox/MakeGameData/MakeModels.cpp b/utils/xbox/MakeGameData/MakeModels.cpp new file mode 100644 index 0000000..21a14dc --- /dev/null +++ b/utils/xbox/MakeGameData/MakeModels.cpp @@ -0,0 +1,614 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: .360 Creation for all studiomdl generated files (mdl, vvd, vtx, ani, phy) +// +//=====================================================================================// + +#include "MakeGameData.h" +#include "studiobyteswap.h" +#include "studio.h" +#include "vphysics_interface.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/hardwareverts.h" +#include "optimize.h" + +//----------------------------------------------------------------------------- +// Models are already converted in a pre-pass. +//----------------------------------------------------------------------------- +bool CreateTargetFile_Model( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + // model component should be present + CUtlBuffer targetBuffer; + if ( !scriptlib->ReadFileToBuffer( pTargetName, targetBuffer ) ) + { + return false; + } + + // no conversion to write, but possibly zipped + bool bSuccess = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, WRITE_TO_DISK_NEVER ); + return bSuccess; +} + +//----------------------------------------------------------------------------- +// Load necessary dlls +//----------------------------------------------------------------------------- +bool InitStudioByteSwap( void ) +{ + StudioByteSwap::SetVerbose( false ); + StudioByteSwap::ActivateByteSwapping( true ); + StudioByteSwap::SetCollisionInterface( g_pPhysicsCollision ); + + return true; +} + +//---------------------------------------------------------------------- +// Get list of files that a model requires. +//---------------------------------------------------------------------- +bool GetDependants_MDL( const char *pModelName, CUtlVector< CUtlString > *pList ) +{ + if ( !g_bModPathIsValid ) + { + Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" ); + return false; + } + + CUtlBuffer sourceBuf; + if ( !g_pFullFileSystem->ReadFile( pModelName, "GAME", sourceBuf ) ) + { + Msg( "Error! Couldn't open file '%s'!\n", pModelName ); + return false; + } + + studiohdr_t *pStudioHdr = (studiohdr_t *)sourceBuf.Base(); + Studio_ConvertStudioHdrToNewVersion( pStudioHdr ); + if ( pStudioHdr->version != STUDIO_VERSION ) + { + Msg( "Error! Bad Model '%s', Expecting Version (%d), got (%d)\n", pModelName, STUDIO_VERSION, pStudioHdr->version ); + return false; + } + + char szOutName[MAX_PATH]; + if ( pStudioHdr->flags & STUDIOHDR_FLAGS_OBSOLETE ) + { + V_strncpy( szOutName, "materials/sprites/obsolete.vmt", sizeof( szOutName ) ); + V_FixSlashes( szOutName ); + pList->AddToTail( szOutName ); + } + else if ( pStudioHdr->textureindex != 0 ) + { + // iterate each texture + int i; + int j; + for ( i = 0; i < pStudioHdr->numtextures; i++ ) + { + // iterate through all directories until a valid material is found + bool bFound = false; + for ( j = 0; j < pStudioHdr->numcdtextures; j++ ) + { + char szPath[MAX_PATH]; + V_ComposeFileName( "materials", pStudioHdr->pCdtexture( j ), szPath, sizeof( szPath ) ); + + // should have been fixed in studiomdl + // some mdls are ending up with double slashes, borking loads + int len = strlen( szPath ); + if ( len > 2 && szPath[len-2] == '\\' && szPath[len-1] == '\\' ) + { + szPath[len-1] = '\0'; + } + + V_ComposeFileName( szPath, pStudioHdr->pTexture( i )->pszName(), szOutName, sizeof( szOutName ) ); + V_SetExtension( szOutName, ".vmt", sizeof( szOutName ) ); + + if ( g_pFullFileSystem->FileExists( szOutName, "GAME" ) ) + { + bFound = true; + break; + } + } + + if ( bFound ) + { + pList->AddToTail( szOutName ); + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Get the preload data for a vhv file +//----------------------------------------------------------------------------- +bool GetPreloadData_VHV( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ) +{ + HardwareVerts::FileHeader_t *pHeader = (HardwareVerts::FileHeader_t *)fileBufferIn.Base(); + + unsigned int version = BigLong( pHeader->m_nVersion ); + + // ensure caller's buffer is clean + // caller determines preload size, via TellMaxPut() + preloadBufferOut.Purge(); + + if ( version != VHV_VERSION ) + { + // bad version + Msg( "Can't preload: '%s', expecting version %d got version %d\n", pFilename, VHV_VERSION, version ); + return false; + } + + unsigned int nPreloadSize = sizeof( HardwareVerts::FileHeader_t ); + + preloadBufferOut.Put( fileBufferIn.Base(), nPreloadSize ); + + return true; +} + +//----------------------------------------------------------------------------- +// Get the preload data for a vtx file +//----------------------------------------------------------------------------- +bool GetPreloadData_VTX( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ) +{ + OptimizedModel::FileHeader_t *pHeader = (OptimizedModel::FileHeader_t *)fileBufferIn.Base(); + + unsigned int version = BigLong( pHeader->version ); + + // ensure caller's buffer is clean + // caller determines preload size, via TellMaxPut() + preloadBufferOut.Purge(); + + if ( version != OPTIMIZED_MODEL_FILE_VERSION ) + { + // bad version + Msg( "Can't preload: '%s', expecting version %d got version %d\n", pFilename, OPTIMIZED_MODEL_FILE_VERSION, version ); + return false; + } + + unsigned int nPreloadSize = sizeof( OptimizedModel::FileHeader_t ); + + preloadBufferOut.Put( fileBufferIn.Base(), nPreloadSize ); + + return true; +} + +//----------------------------------------------------------------------------- +// Get the preload data for a vvd file +//----------------------------------------------------------------------------- +bool GetPreloadData_VVD( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ) +{ + vertexFileHeader_t *pHeader = (vertexFileHeader_t *)fileBufferIn.Base(); + + unsigned int id = BigLong( pHeader->id ); + unsigned int version = BigLong( pHeader->version ); + + // ensure caller's buffer is clean + // caller determines preload size, via TellMaxPut() + preloadBufferOut.Purge(); + + if ( id != MODEL_VERTEX_FILE_ID ) + { + // bad version + Msg( "Can't preload: '%s', expecting id %d got id %d\n", pFilename, MODEL_VERTEX_FILE_ID, id ); + return false; + } + + if ( version != MODEL_VERTEX_FILE_VERSION ) + { + // bad version + Msg( "Can't preload: '%s', expecting version %d got version %d\n", pFilename, MODEL_VERTEX_FILE_VERSION, version ); + return false; + } + + unsigned int nPreloadSize = sizeof( vertexFileHeader_t ); + + preloadBufferOut.Put( fileBufferIn.Base(), nPreloadSize ); + + return true; +} + +bool CompressFunc( const void *pInput, int inputSize, void **pOutput, int *pOutputSize ) +{ + *pOutput = NULL; + *pOutputSize = 0; + + if ( !inputSize ) + { + // nothing to do + return false; + } + + unsigned int compressedSize; + unsigned char *pCompressedOutput = LZMA_OpportunisticCompress( (unsigned char *)pInput, inputSize, &compressedSize ); + if ( pCompressedOutput ) + { + *pOutput = pCompressedOutput; + *pOutputSize = compressedSize; + return true; + } + + return false; + +} + +//----------------------------------------------------------------------------- +// Rebuilds all of a MDL's components. +//----------------------------------------------------------------------------- +static bool GenerateModelFiles( const char *pMdlFilename ) +{ + CUtlBuffer tempBuffer; + int fileSize; + int paddedSize; + int swappedSize; + + // .mdl + CUtlBuffer mdlBuffer; + if ( !scriptlib->ReadFileToBuffer( pMdlFilename, mdlBuffer ) ) + { + return false; + } + if ( !Studio_ConvertStudioHdrToNewVersion( (studiohdr_t *)mdlBuffer.Base() )) + { + Msg("%s needs to be recompiled\n", pMdlFilename ); + } + + // .vtx + char szVtxFilename[MAX_PATH]; + V_StripExtension( pMdlFilename, szVtxFilename, sizeof( szVtxFilename ) ); + V_strncat( szVtxFilename, ".dx90.vtx", sizeof( szVtxFilename ) ); + CUtlBuffer vtxBuffer; + bool bHasVtx = ReadFileToBuffer( szVtxFilename, vtxBuffer, false, true ); + + // .vvd + char szVvdFilename[MAX_PATH]; + V_StripExtension( pMdlFilename, szVvdFilename, sizeof( szVvdFilename ) ); + V_strncat( szVvdFilename, ".vvd", sizeof( szVvdFilename ) ); + CUtlBuffer vvdBuffer; + bool bHasVvd = ReadFileToBuffer( szVvdFilename, vvdBuffer, false, true ); + + if ( bHasVtx != bHasVvd ) + { + // paired resources, either mandates the other + return false; + } + + // a .mdl file that has .vtx/.vvd gets re-processed to cull lod data + if ( bHasVtx && bHasVvd ) + { + // cull lod if needed + IMdlStripInfo *pStripInfo = NULL; + bool bResult = mdllib->StripModelBuffers( mdlBuffer, vvdBuffer, vtxBuffer, &pStripInfo ); + if ( !bResult ) + { + return false; + } + if ( pStripInfo ) + { + // .vsi + CUtlBuffer vsiBuffer; + pStripInfo->Serialize( vsiBuffer ); + pStripInfo->DeleteThis(); + + // save strip info for later processing + char szVsiFilename[MAX_PATH]; + V_StripExtension( pMdlFilename, szVsiFilename, sizeof( szVsiFilename ) ); + V_strncat( szVsiFilename, ".vsi", sizeof( szVsiFilename ) ); + WriteBufferToFile( szVsiFilename, vsiBuffer, false, WRITE_TO_DISK_ALWAYS ); + } + } + + // .ani processing may further update .mdl buffer + char szAniFilename[MAX_PATH]; + V_StripExtension( pMdlFilename, szAniFilename, sizeof( szAniFilename ) ); + V_strncat( szAniFilename, ".ani", sizeof( szAniFilename ) ); + CUtlBuffer aniBuffer; + bool bHasAni = ReadFileToBuffer( szAniFilename, aniBuffer, false, true ); + if ( bHasAni ) + { + // Some vestigal .ani files exist in the tree, only process valid .ani + if ( ((studiohdr_t*)mdlBuffer.Base())->numanimblocks != 0 ) + { + // .ani processing modifies .mdl buffer + fileSize = aniBuffer.TellPut(); + paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING; + aniBuffer.EnsureCapacity( paddedSize ); + tempBuffer.EnsureCapacity( paddedSize ); + V_StripExtension( pMdlFilename, szAniFilename, sizeof( szAniFilename ) ); + V_strncat( szAniFilename, ".360.ani", sizeof( szAniFilename ) ); + swappedSize = StudioByteSwap::ByteswapStudioFile( szAniFilename, tempBuffer.Base(), aniBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc ); + if ( swappedSize > 0 ) + { + // .ani buffer is replaced with swapped data + aniBuffer.Purge(); + aniBuffer.Put( tempBuffer.Base(), swappedSize ); + WriteBufferToFile( szAniFilename, aniBuffer, false, WRITE_TO_DISK_ALWAYS ); + } + else + { + return false; + } + } + } + + // .phy + char szPhyFilename[MAX_PATH]; + V_StripExtension( pMdlFilename, szPhyFilename, sizeof( szPhyFilename ) ); + V_strncat( szPhyFilename, ".phy", sizeof( szPhyFilename ) ); + CUtlBuffer phyBuffer; + bool bHasPhy = ReadFileToBuffer( szPhyFilename, phyBuffer, false, true ); + if ( bHasPhy ) + { + fileSize = phyBuffer.TellPut(); + paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING; + phyBuffer.EnsureCapacity( paddedSize ); + tempBuffer.EnsureCapacity( paddedSize ); + V_StripExtension( pMdlFilename, szPhyFilename, sizeof( szPhyFilename ) ); + V_strncat( szPhyFilename, ".360.phy", sizeof( szPhyFilename ) ); + swappedSize = StudioByteSwap::ByteswapStudioFile( szPhyFilename, tempBuffer.Base(), phyBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc ); + if ( swappedSize > 0 ) + { + // .phy buffer is replaced with swapped data + phyBuffer.Purge(); + phyBuffer.Put( tempBuffer.Base(), swappedSize ); + WriteBufferToFile( szPhyFilename, phyBuffer, false, WRITE_TO_DISK_ALWAYS ); + } + else + { + return false; + } + } + + if ( bHasVtx ) + { + fileSize = vtxBuffer.TellPut(); + paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING; + vtxBuffer.EnsureCapacity( paddedSize ); + tempBuffer.EnsureCapacity( paddedSize ); + V_StripExtension( pMdlFilename, szVtxFilename, sizeof( szVtxFilename ) ); + V_strncat( szVtxFilename, ".dx90.360.vtx", sizeof( szVtxFilename ) ); + swappedSize = StudioByteSwap::ByteswapStudioFile( szVtxFilename, tempBuffer.Base(), vtxBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc ); + if ( swappedSize > 0 ) + { + // .vtx buffer is replaced with swapped data + vtxBuffer.Purge(); + vtxBuffer.Put( tempBuffer.Base(), swappedSize ); + WriteBufferToFile( szVtxFilename, vtxBuffer, false, WRITE_TO_DISK_ALWAYS ); + } + else + { + return false; + } + } + + if ( bHasVvd ) + { + fileSize = vvdBuffer.TellPut(); + paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING; + vvdBuffer.EnsureCapacity( paddedSize ); + tempBuffer.EnsureCapacity( paddedSize ); + V_StripExtension( pMdlFilename, szVvdFilename, sizeof( szVvdFilename ) ); + V_strncat( szVvdFilename, ".360.vvd", sizeof( szVvdFilename ) ); + swappedSize = StudioByteSwap::ByteswapStudioFile( szVvdFilename, tempBuffer.Base(), vvdBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc ); + if ( swappedSize > 0 ) + { + // .vvd buffer is replaced with swapped data + vvdBuffer.Purge(); + vvdBuffer.Put( tempBuffer.Base(), swappedSize ); + WriteBufferToFile( szVvdFilename, vvdBuffer, false, WRITE_TO_DISK_ALWAYS ); + } + else + { + return false; + } + } + + // swap and write final .mdl + fileSize = mdlBuffer.TellPut(); + paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING; + mdlBuffer.EnsureCapacity( paddedSize ); + tempBuffer.EnsureCapacity( paddedSize ); + char szMdlFilename[MAX_PATH]; + V_StripExtension( pMdlFilename, szMdlFilename, sizeof( szMdlFilename ) ); + V_strncat( szMdlFilename, ".360.mdl", sizeof( szMdlFilename ) ); + swappedSize = StudioByteSwap::ByteswapStudioFile( szMdlFilename, tempBuffer.Base(), mdlBuffer.PeekGet(), fileSize, NULL, CompressFunc ); + if ( swappedSize > 0 ) + { + // .mdl buffer is replaced with swapped data + mdlBuffer.Purge(); + mdlBuffer.Put( tempBuffer.Base(), swappedSize ); + WriteBufferToFile( szMdlFilename, mdlBuffer, false, WRITE_TO_DISK_ALWAYS ); + } + else + { + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Returns true if specified model path has a dirty sub-component, and requires +// update. +//----------------------------------------------------------------------------- +static bool ModelNeedsUpdate( const char *pMdlSourcePath ) +{ + struct ModelExtensions_t + { + const char *pSourceExtension; + const char *pTargetExtension; + bool bSourceMustExist; // if source exists, so must target + }; + ModelExtensions_t pExtensions[] = + { + { ".mdl", ".360.mdl", true }, + { ".dx90.vtx", ".dx90.360.vtx", false }, + { ".vvd", ".360.vvd", false }, + { ".phy", ".360.phy", false }, + { ".ani", ".360.ani", false }, + // vtx/vvd generate a vsi, vsi must be fresher to be valid + { ".dx90.vtx", ".vsi", false }, + { ".vvd", ".vsi", false }, + }; + + if ( g_bForce ) + { + return true; + } + + for ( int i = 0; i < ARRAYSIZE( pExtensions ); i++ ) + { + char szSourcePath[MAX_PATH]; + struct _stat sourceStatBuf; + V_strncpy( szSourcePath, pMdlSourcePath, sizeof( szSourcePath ) ); + V_SetExtension( szSourcePath, pExtensions[i].pSourceExtension, sizeof( szSourcePath ) ); + int retVal = _stat( szSourcePath, &sourceStatBuf ); + if ( retVal != 0 ) + { + // couldn't get source + if ( pExtensions[i].bSourceMustExist ) + { + return true; + } + else + { + // source is optional + continue; + } + } + + char szTargetPath[MAX_PATH]; + struct _stat targetStatBuf; + V_strncpy( szTargetPath, pMdlSourcePath, sizeof( szTargetPath ) ); + V_SetExtension( szTargetPath, pExtensions[i].pTargetExtension, sizeof( szTargetPath ) ); + if ( _stat( szTargetPath, &targetStatBuf ) != 0 ) + { + // target doesn't exist + return true; + } + + if ( difftime( sourceStatBuf.st_mtime, targetStatBuf.st_mtime ) > 0 ) + { + // source is older (thus newer), update required + return true; + } + } + + return false; +} + +static bool ModelNamesLessFunc( CUtlString const &pLHS, CUtlString const &pRHS ) +{ + return CaselessStringLessThan( pLHS.Get(), pRHS.Get() ); +} + +//----------------------------------------------------------------------------- +// Models require specialized group handling to generate intermediate lod culled +// versions that are then used as the the source for target conversion. +//----------------------------------------------------------------------------- +bool PreprocessModelFiles( CUtlVector<fileList_t> &fileList ) +{ + if ( !InitStudioByteSwap() ) + { + return false; + } + + CUtlVector< CUtlString > updateList; + CUtlRBTree< CUtlString, int > visitedModels( 0, 0, ModelNamesLessFunc ); + + char szSourcePath[MAX_PATH]; + strcpy( szSourcePath, g_szSourcePath ); + V_StripFilename( szSourcePath ); + if ( !szSourcePath[0] ) + strcpy( szSourcePath, "." ); + V_AppendSlash( szSourcePath, sizeof( szSourcePath ) ); + + char szModelName[MAX_PATH]; + for ( int i=0; i<fileList.Count(); i++ ) + { + V_strncpy( szModelName, fileList[i].fileName.String(), sizeof( szModelName ) ); + + if ( V_stristr( szModelName, ".360." ) ) + { + // must ignore any target files + continue; + } + + // want only model related files + char *pExtension = V_stristr( szModelName, ".mdl" ); + if ( !pExtension ) + { + pExtension = V_stristr( szModelName, ".dx90.vtx" ); + if ( !pExtension ) + { + pExtension = V_stristr( szModelName, ".vvd" ); + if ( !pExtension ) + { + pExtension = V_stristr( szModelName, ".ani" ); + if ( !pExtension ) + { + pExtension = V_stristr( szModelName, ".phy" ); + if ( !pExtension ) + { + pExtension = V_stristr( szModelName, ".vsi" ); + if ( !pExtension ) + { + continue; + } + } + } + } + } + } + + *pExtension = '\0'; + V_strncat( szModelName, ".mdl", sizeof( szModelName ) ); + + if ( visitedModels.Find( szModelName ) != visitedModels.InvalidIndex() ) + { + // already processed + continue; + } + visitedModels.Insert( szModelName ); + + // resolve to full source path + const char *ptr = szModelName; + if ( !strnicmp( ptr, ".\\", 2 ) ) + ptr += 2; + else if ( !strnicmp( ptr, szSourcePath, strlen( szSourcePath ) ) ) + ptr += strlen( szSourcePath ); + char szCleanName[MAX_PATH]; + strcpy( szCleanName, szSourcePath ); + strcat( szCleanName, ptr ); + char szFullSourcePath[MAX_PATH]; + _fullpath( szFullSourcePath, szCleanName, sizeof( szFullSourcePath ) ); + + // any one dirty component generates the set of all expected files + if ( ModelNeedsUpdate( szFullSourcePath ) ) + { + int index = updateList.AddToTail(); + updateList[index].Set( szFullSourcePath ); + } + } + + Msg( "\n" ); + Msg( "Model Pre Pass: Updating %d Models.\n", updateList.Count() ); + for ( int i = 0; i < updateList.Count(); i++ ) + { + if ( !GenerateModelFiles( updateList[i].String() ) ) + { + int error = g_errorList.AddToTail(); + g_errorList[error].result = false; + g_errorList[error].fileName.Set( updateList[i].String() ); + } + } + + // iterate error list + if ( g_errorList.Count() ) + { + Msg( "\n" ); + for ( int i = 0; i < g_errorList.Count(); i++ ) + { + Msg( "ERROR: could not pre-process model: %s\n", g_errorList[i].fileName.String() ); + } + } + + return true; +} diff --git a/utils/xbox/MakeGameData/MakeParticles.cpp b/utils/xbox/MakeGameData/MakeParticles.cpp new file mode 100644 index 0000000..7e6a5f1 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeParticles.cpp @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: .360 file creation of PCF files +// +//=====================================================================================// + +#include "MakeGameData.h" + +bool CreateTargetFile_PCF( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + DmxHeader_t header; + CDmElement *pRoot; + if ( g_pDataModel->RestoreFromFile( pSourceName, NULL, NULL, &pRoot, CR_DELETE_NEW, &header ) == DMFILEID_INVALID ) + { + Msg( "CreateTargetFile_PCF: Error reading file \"%s\"!\n", pSourceName ); + return false; + } + + const char *pOutFormat = header.formatName; + if ( !g_pDataModel->FindFormatUpdater( pOutFormat ) ) + { + pOutFormat = "dmx"; + } + + CUtlBuffer binaryBuffer; + if ( !g_pDataModel->Serialize( binaryBuffer, "binary", pOutFormat, pRoot->GetHandle() ) ) + { + Msg( "CreateTargetFile_PCF: Error writing buffer\n" ); + return false; + } + + g_pDataModel->RemoveFileId( pRoot->GetFileId() ); + + WriteBufferToFile( pTargetName, binaryBuffer, bWriteToZip, g_WriteModeForConversions ); + + return true; +} diff --git a/utils/xbox/MakeGameData/MakeResources.cpp b/utils/xbox/MakeGameData/MakeResources.cpp new file mode 100644 index 0000000..3a411c3 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeResources.cpp @@ -0,0 +1,343 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: .360 file creation of miscellaneous resource and data files +// +//=====================================================================================// + +#include "MakeGameData.h" +#include "captioncompiler.h" + +//----------------------------------------------------------------------------- +// Purpose: Generate .360 compiled caption files +//----------------------------------------------------------------------------- +bool CreateTargetFile_CCDAT( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + CUtlBuffer targetBuffer; + bool bOk = false; + + if ( !scriptlib->ReadFileToBuffer( pSourceName, targetBuffer ) ) + { + return false; + } + + if ( SwapClosecaptionFile( targetBuffer.Base() ) ) + { + bOk = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, g_WriteModeForConversions ); + } + + return bOk; +} + +static bool ReslistLessFunc( CUtlString const &pLHS, CUtlString const &pRHS ) +{ + return CaselessStringLessThan( pLHS.Get(), pRHS.Get() ); +} + +//----------------------------------------------------------------------------- +// Find or Add, prevents duplicates. Returns TRUE if found. +//----------------------------------------------------------------------------- +bool FindOrAddFileToResourceList( const char *pFilename, CUtlRBTree< CUtlString, int > *pTree, bool bAdd = true ) +{ + char szOutName[MAX_PATH]; + char *pOutName; + V_strncpy( szOutName, pFilename, sizeof( szOutName ) ); + V_FixSlashes( szOutName ); + V_RemoveDotSlashes( szOutName ); + V_strlower( szOutName ); + pOutName = szOutName; + + // strip any prefixed game name + for ( int i = 0; g_GameNames[i] != NULL; i++ ) + { + size_t len = strlen( g_GameNames[i] ); + if ( !V_strnicmp( pOutName, g_GameNames[i], len ) && pOutName[len] == '\\' ) + { + // skip past game name and slash + pOutName += len+1; + break; + } + } + + if ( pTree->Find( pOutName ) != pTree->InvalidIndex() ) + { + // found + return true; + } + + if ( bAdd ) + { + pTree->Insert( pOutName ); + } + + return false; +} + +//----------------------------------------------------------------------------- +// Remove entry from dictionary, Returns TRUE if removed. +//----------------------------------------------------------------------------- +bool RemoveFileFromResourceList( const char *pFilename, CUtlRBTree< CUtlString, int > *pTree ) +{ + char szOutName[MAX_PATH]; + char *pOutName; + V_strncpy( szOutName, pFilename, sizeof( szOutName ) ); + V_FixSlashes( szOutName ); + V_RemoveDotSlashes( szOutName ); + V_strlower( szOutName ); + pOutName = szOutName; + + // strip any prefixed game name + for ( int i = 0; g_GameNames[i] != NULL; i++ ) + { + size_t len = strlen( g_GameNames[i] ); + if ( !V_strnicmp( pOutName, g_GameNames[i], len ) && pOutName[len] == '\\' ) + { + // skip past game name and slash + pOutName += len+1; + break; + } + } + + if ( pTree->Find( pOutName ) != pTree->InvalidIndex() ) + { + pTree->Remove( pOutName ); + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Generate a tree containing files from a reslist. Returns TRUE if successful. +//----------------------------------------------------------------------------- +bool LoadReslist( const char *pReslistName, CUtlRBTree< CUtlString, int > *pTree ) +{ + CUtlBuffer buffer; + if ( !scriptlib->ReadFileToBuffer( pReslistName, buffer, true ) ) + { + return false; + } + + char szBasename[MAX_PATH]; + V_FileBase( pReslistName, szBasename, sizeof( szBasename ) ); + + characterset_t breakSet; + CharacterSetBuild( &breakSet, "" ); + + // parse reslist + char szToken[MAX_PATH]; + char szBspName[MAX_PATH]; + szBspName[0] = '\0'; + for ( ;; ) + { + int nTokenSize = buffer.ParseToken( &breakSet, szToken, sizeof( szToken ) ); + if ( nTokenSize <= 0 ) + { + break; + } + + // reslists are pc built, filenames can be sloppy + V_strlower( szToken ); + V_FixSlashes( szToken ); + V_RemoveDotSlashes( szToken ); + + // can safely cull filetypes that are ignored by queued loader at runtime + bool bKeep = false; + const char *pExt = V_GetFileExtension( szToken ); + if ( !pExt ) + { + // unknown + continue; + } + else if ( !V_stricmp( pExt, "vmt" ) || + !V_stricmp( pExt, "vhv" ) || + !V_stricmp( pExt, "mdl" ) || + !V_stricmp( pExt, "raw" ) || + !V_stricmp( pExt, "wav" ) ) + { + bKeep = true; + } + else if ( !V_stricmp( pExt, "mp3" ) ) + { + // change to .wav + V_SetExtension( szToken, ".wav", sizeof( szToken ) ); + bKeep = true; + } + else if ( !V_stricmp( pExt, "bsp" ) ) + { + // reslists erroneously have multiple bsps + if ( !V_stristr( szToken, szBasename ) ) + { + // wrong one, cull it + continue; + } + else + { + // right one, save it + strcpy( szBspName, szToken ); + bKeep = true; + } + } + + if ( bKeep ) + { + FindOrAddFileToResourceList( szToken, pTree ); + } + } + + if ( !szBspName[0] ) + { + // reslist is not bsp derived, nothing more to do + return true; + } + + CUtlVector< CUtlString > bspList; + bool bOK = GetDependants_BSP( szBspName, &bspList ); + if ( !bOK ) + { + return false; + } + + // add all the bsp dependants to the resource list + for ( int i=0; i<bspList.Count(); i++ ) + { + FindOrAddFileToResourceList( bspList[i].String(), pTree ); + } + + // iterate all the models in the resource list, get all their dependents + CUtlVector< CUtlString > modelList; + for ( int i = pTree->FirstInorder(); i != pTree->InvalidIndex(); i = pTree->NextInorder( i ) ) + { + const char *pExt = V_GetFileExtension( pTree->Element( i ).String() ); + if ( !pExt || V_stricmp( pExt, "mdl" ) ) + { + continue; + } + + if ( !GetDependants_MDL( pTree->Element( i ).String(), &modelList ) ) + { + return false; + } + } + + // add all the model dependents to the resource list + for ( int i=0; i<modelList.Count(); i++ ) + { + FindOrAddFileToResourceList( modelList[i].String(), pTree ); + } + + // check for optional commentary, include wav dependencies + char szCommentaryName[MAX_PATH]; + V_ComposeFileName( g_szGamePath, szBspName, szCommentaryName, sizeof( szCommentaryName ) ); + V_StripExtension( szCommentaryName, szCommentaryName, sizeof( szCommentaryName ) ); + V_strncat( szCommentaryName, "_commentary.txt", sizeof( szCommentaryName ) ); + CUtlBuffer commentaryBuffer; + if ( ReadFileToBuffer( szCommentaryName, commentaryBuffer, true, true ) ) + { + // any single token may be quite large to due to text + char szCommentaryToken[8192]; + for ( ;; ) + { + int nTokenSize = commentaryBuffer.ParseToken( &breakSet, szCommentaryToken, sizeof( szCommentaryToken ) ); + if ( nTokenSize < 0 ) + { + break; + } + if ( nTokenSize > 0 && !V_stricmp( szCommentaryToken, "commentaryfile" ) ) + { + // get the commentary file + nTokenSize = commentaryBuffer.ParseToken( &breakSet, szCommentaryToken, sizeof( szCommentaryToken ) ); + if ( nTokenSize > 0 ) + { + // skip past sound chars + char *pName = szCommentaryToken; + while ( *pName && IsSoundChar( *pName ) ) + { + pName++; + } + char szWavFile[MAX_PATH]; + V_snprintf( szWavFile, sizeof( szWavFile ), "sound/%s", pName ); + FindOrAddFileToResourceList( szWavFile, pTree ); + } + } + } + } + + // check for optional blacklist + char szBlacklist[MAX_PATH]; + V_ComposeFileName( g_szGamePath, "reslistfixes_xbox.xsc", szBlacklist, sizeof( szBlacklist ) ); + CUtlBuffer blacklistBuffer; + if ( ReadFileToBuffer( szBlacklist, blacklistBuffer, true, true ) ) + { + for ( ;; ) + { + int nTokenSize = blacklistBuffer.ParseToken( &breakSet, szToken, sizeof( szToken ) ); + if ( nTokenSize <= 0 ) + { + break; + } + + bool bAdd; + if ( !V_stricmp( szToken, "-" ) ) + { + bAdd = false; + } + else if ( !V_stricmp( szToken, "+" ) ) + { + bAdd = true; + } + else + { + // bad syntax, skip line + Msg( "Bad Syntax, expecting '+' or '-' as first token in reslist fixup file '%s'.\n", szBlacklist ); + continue; + } + + // get entry + nTokenSize = blacklistBuffer.ParseToken( &breakSet, szToken, sizeof( szToken ) ); + if ( nTokenSize <= 0 ) + { + break; + } + + if ( bAdd ) + { + FindOrAddFileToResourceList( szToken, pTree ); + } + else + { + RemoveFileFromResourceList( szToken, pTree ); + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Generate .360 compiled reslist files +// Reslist files are processed for the unique consumption of Queued Loading. +//----------------------------------------------------------------------------- +bool CreateTargetFile_RESLST( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + bool bOK = false; + + // parse reslist + CUtlRBTree< CUtlString, int > rbTree( 0, 0, ReslistLessFunc ); + if ( !LoadReslist( pSourceName, &rbTree ) ) + { + return false; + } + + CUtlBuffer targetBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER ); + for ( int iIndex = rbTree.FirstInorder(); iIndex != rbTree.InvalidIndex(); iIndex = rbTree.NextInorder( iIndex ) ) + { + targetBuffer.PutChar( '\"' ); + targetBuffer.PutString( rbTree[iIndex].String() ); + targetBuffer.PutChar( '\"' ); + targetBuffer.PutString( "\n" ); + } + + bOK = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, g_WriteModeForConversions ); + + return bOK; +}
\ No newline at end of file diff --git a/utils/xbox/MakeGameData/MakeScenes.cpp b/utils/xbox/MakeGameData/MakeScenes.cpp new file mode 100644 index 0000000..4077978 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeScenes.cpp @@ -0,0 +1,40 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: .360 file creation of Choreo VCD files +// +//=====================================================================================// + +#include "MakeGameData.h" +#include "sceneimage.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +class CDefaultStatus : public ISceneCompileStatus +{ +public: + virtual void UpdateStatus( char const *pchSceneName, bool bQuiet, int nIndex, int nCount ) + { + if ( !bQuiet ) + { + Msg( "Scenes: Compiling: %s\n", pchSceneName ); + } + } +}; + +bool CreateSceneImageFile( char const *pchModPath, bool bWriteToZip, bool bLittleEndian, bool bQuiet, DiskWriteMode_t eWriteModeForConversions ) +{ + CUtlBuffer targetBuffer; + + const char *pFilename = bLittleEndian ? "scenes/scenes.image" : "scenes/scenes.360.image"; + + CDefaultStatus statusHelper; + + bool bSuccess = g_pSceneImage->CreateSceneImageFile( targetBuffer, pchModPath, bLittleEndian, bQuiet, &statusHelper ); + if ( bSuccess ) + { + bSuccess = WriteBufferToFile( pFilename, targetBuffer, bWriteToZip, eWriteModeForConversions ); + } + + return bSuccess; +}
\ No newline at end of file diff --git a/utils/xbox/MakeGameData/MakeScenesImage.vpc b/utils/xbox/MakeGameData/MakeScenesImage.vpc new file mode 100644 index 0000000..0361be6 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeScenesImage.vpc @@ -0,0 +1,133 @@ +//----------------------------------------------------------------------------- +// MAKESCENESIMAGE.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" + +$Macro GAMENAME "MakeScenesImage" + +$Configuration "Debug" +{ + $General + { + $OutputDirectory ".\Debug_$GAMENAME" + $IntermediateDirectory ".\Debug_$GAMENAME" + } +} + +$Configuration "Release" +{ + $General + { + $OutputDirectory ".\Release_$GAMENAME" + $IntermediateDirectory ".\Release_$GAMENAME" + } +} + +$Configuration +{ + $Compiler + { + $PreprocessorDefinitions "$BASE;MAKESCENESIMAGE" + $PreprocessorDefinitions "$BASE;NO_X360_XDK" [$VS2015] + $AdditionalIncludeDirectories "$BASE;$SRCDIR\x360xdk\include\win32\vs2005;$SRCDIR\game\shared" + } + + $Linker + { + $AdditionalDependencies "$BASE xgraphics.lib d3d9.lib legacy_stdio_definitions.lib" + $AdditionalDependencies "$BASE xmaencoder.lib" [!$VS2015] + $AdditionalLibraryDirectories "$BASE;$SRCDIR\x360xdk\lib\win32\vs2005" + } +} + +$Project "MakeScenesImage" +{ + $Folder "Source Files" + { + -$File "$SRCDIR\public\tier0\memoverride.cpp" + $File "MakeGameData.cpp" + $File "MakeMaps.cpp" + $File "MakeMisc.cpp" + $File "MakeModels.cpp" + $File "MakeParticles.cpp" + $File "MakeResources.cpp" + $File "MakeScenes.cpp" + $File "MakeShaders.cpp" + $File "MakeSounds.cpp" + $File "MakeTextures.cpp" + $File "MakeZip.cpp" + + $Folder "Audio" + { + $File "imaadpcm.cpp" + $File "sound_io.cpp" + $File "resample.cpp" + } + + $Folder "Public Modules" + { + $File "$SRCDIR\common\compiledcaptionswap.cpp" + $file "$SRCDIR\common\studiobyteswap.cpp" + $File "$SRCDIR\utils\common\scriplib.cpp" + $File "$SRCDIR\public\zip_utils.cpp" + $File "$SRCDIR\public\sentence.cpp" + $File "$SRCDIR\utils\common\cmdlib.cpp" + $File "$SRCDIR\public\filesystem_helpers.cpp" + $File "$SRCDIR\public\filesystem_init.cpp" + $File "$SRCDIR\utils\common\filesystem_tools.cpp" + $File "$SRCDIR\public\interpolatortypes.cpp" + } + } + + $Folder "Header Files" + { + $File "MakeGameData.h" + $File "XZipTool.h" + $File "imaadpcm.h" + $File "resample.h" + $File "$SRCDIR\public\captioncompiler.h" + $File "$SRCDIR\common\studiobyteswap.h" + $File "$SRCDIR\utils\common\scriplib.h" + $File "$SRCDIR\public\filesystem.h" + $File "$SRCDIR\public\ibsppack.h" + $File "$SRCDIR\public\sentence.h" + $File "$SRCDIR\public\studio.h" + $File "$SRCDIR\public\tier1\utlbuffer.h" + $File "$SRCDIR\public\tier1\strtools.h" + $File "$SRCDIR\public\vphysics_interface.h" + $File "$SRCDIR\public\vstdlib\vstdlib.h" + $File "$SRCDIR\public\xwvfile.h" + $File "$SRCDIR\public\zip_utils.h" + $File "$SRCDIR\game\shared\choreoscene.h" + $File "$SRCDIR\game\shared\choreoactor.h" + $File "$SRCDIR\public\filesystem_helpers.h" + $File "$SRCDIR\public\filesystem_init.h" + $File "$SRCDIR\utils\common\filesystem_tools.h" + $File "$SRCDIR\public\interpolatortypes.h" + $File "$SRCDIR\utils\common\cmdlib.h" + $File "$SRCDIR\game\shared\choreochannel.h" + $File "$SRCDIR\game\shared\choreoevent.h" + $File "$SRCDIR\public\tier1\checksum_crc.h" + $File "$SRCDIR\public\tier2\tier2.h" + $File "$SRCDIR\common\lzma\lzma.h" + } + + $Folder "Link Libraries" + { + $Lib appframework + $Lib mathlib + $Lib vtf + $Lib tier2 + $Lib choreoobjects + $Lib bitmap + $Lib datamodel + $Lib dmserializers + $Lib $LIBCOMMON\lzma + } +} diff --git a/utils/xbox/MakeGameData/MakeShaders.cpp b/utils/xbox/MakeGameData/MakeShaders.cpp new file mode 100644 index 0000000..25f51b4 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeShaders.cpp @@ -0,0 +1,52 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: .360 file creation of shaders +// +//=====================================================================================// + +#include "MakeGameData.h" +#include "materialsystem/shader_vcs_version.h" + +#define SHADER_FILE_THRESHOLD 32*1024 + +//----------------------------------------------------------------------------- +// Get the preload data for a vcs file +//----------------------------------------------------------------------------- +bool GetPreloadData_VCS( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ) +{ + ShaderHeader_t *pHeader = (ShaderHeader_t *)fileBufferIn.Base(); + + unsigned int version = BigLong( pHeader->m_nVersion ); + + // ensure caller's buffer is clean + // caller determines preload size, via TellMaxPut() + preloadBufferOut.Purge(); + + unsigned int nPreloadSize; + if ( fileBufferIn.TellMaxPut() <= SHADER_FILE_THRESHOLD ) + { + // include the whole file + nPreloadSize = fileBufferIn.TellMaxPut(); + } + else + { + if ( version < SHADER_VCS_VERSION_NUMBER ) + { + // not supporting old versions + return false; + } + + if ( version != SHADER_VCS_VERSION_NUMBER ) + { + // bad version + Msg( "Can't preload: '%s', expecting version %d got version %d\n", pFilename, SHADER_VCS_VERSION_NUMBER, version ); + return false; + } + + nPreloadSize = sizeof( ShaderHeader_t ) + BigLong( pHeader->m_nNumStaticCombos ) * sizeof( StaticComboRecord_t ); + } + + preloadBufferOut.Put( fileBufferIn.Base(), nPreloadSize ); + + return true; +}
\ No newline at end of file diff --git a/utils/xbox/MakeGameData/MakeSounds.cpp b/utils/xbox/MakeGameData/MakeSounds.cpp new file mode 100644 index 0000000..f0913ce --- /dev/null +++ b/utils/xbox/MakeGameData/MakeSounds.cpp @@ -0,0 +1,968 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: .360.WAV Creation +// +//=====================================================================================// + +#include "MakeGameData.h" +#ifndef NO_X360_XDK +#include <XMAEncoder.h> +#endif +#include "datamap.h" +#include "sentence.h" +#include "tier2/riff.h" +#include "resample.h" +#include "xwvfile.h" + +// all files are built for streaming compliance +// allows for fastest runtime loading path +// actual streaming or static state is determined by engine +#define XBOX_DVD_SECTORSIZE 2048 +#define XMA_BLOCK_SIZE 2048 // must be aligned to 1024 +#define MAX_CHUNKS 256 + +// [0,100] +#define XMA_HIGH_QUALITY 90 +#define XMA_DEFAULT_QUALITY 75 +#define XMA_MEDIUM_QUALITY 50 +#define XMA_LOW_QUALITY 25 + +typedef struct +{ + unsigned int id; + int size; + byte *pData; +} chunk_t; + +struct conversion_t +{ + const char *pSubDir; + int quality; + bool bForceTo22K; +}; + +// default conversion rules +conversion_t g_defaultConversionRules[] = +{ + // subdir quality 22Khz + { "", XMA_DEFAULT_QUALITY, false }, // default settings + { "weapons", XMA_DEFAULT_QUALITY, false }, + { "music", XMA_DEFAULT_QUALITY, false }, + { "vo", XMA_MEDIUM_QUALITY, false }, + { "npc", XMA_MEDIUM_QUALITY, false }, + { "ambient", XMA_DEFAULT_QUALITY, false }, + { "commentary", XMA_LOW_QUALITY, true }, + { NULL }, +}; + +// portal conversion rules +conversion_t g_portalConversionRules[] = +{ + // subdir quality 22Khz + { "", XMA_DEFAULT_QUALITY, false }, // default settings + { "commentary", XMA_LOW_QUALITY, true }, + { NULL }, +}; + +chunk_t g_chunks[MAX_CHUNKS]; +int g_numChunks; + +extern IFileReadBinary *g_pSndIO; + +//----------------------------------------------------------------------------- +// Purpose: chunk printer +//----------------------------------------------------------------------------- +void PrintChunk( unsigned int chunkName, int size ) +{ + char c[4]; + + for ( int i=0; i<4; i++ ) + { + c[i] = ( chunkName >> i*8 ) & 0xFF; + if ( !c[i] ) + c[i] = ' '; + } + + Msg( "%c%c%c%c: %d bytes\n", c[0], c[1], c[2], c[3], size ); +} + +//----------------------------------------------------------------------------- +// Purpose: which chunks are supported, false to ignore +//----------------------------------------------------------------------------- +bool IsValidChunk( unsigned int chunkName ) +{ + switch ( chunkName ) + { + case WAVE_DATA: + case WAVE_CUE: + case WAVE_SAMPLER: + case WAVE_VALVEDATA: + case WAVE_FMT: + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: align buffer +//----------------------------------------------------------------------------- +int AlignToBoundary( CUtlBuffer &buf, int alignment ) +{ + int curPosition; + int newPosition; + byte padByte = 0; + + buf.SeekPut( CUtlBuffer::SEEK_TAIL, 0 ); + curPosition = buf.TellPut(); + + if ( alignment <= 1 ) + return curPosition; + + // advance to aligned position + newPosition = AlignValue( curPosition, alignment ); + buf.EnsureCapacity( newPosition ); + + // write empty + for ( int i=0; i<newPosition-curPosition; i++ ) + { + buf.Put( &padByte, 1 ); + } + + return newPosition; +} + +//-------------------------------------------------------------------------------------- +// SampleToXMABlockOffset +// +// Description: converts from a sample index to a block index + the number of samples +// to offset from the beginning of the block. +// +// Parameters: +// dwSampleIndex: sample index to convert +// pdwSeekTable: pointer to the file's XMA2 seek table +// nEntries: number of DWORD entries in the seek table +// out_pBlockIndex: index of block where the desired sample lives +// out_pOffset: number of samples in the block before the desired sample +//-------------------------------------------------------------------------------------- +bool SampleToXMABlockOffset( DWORD dwSampleIndex, const DWORD *pdwSeekTable, DWORD nEntries, DWORD *out_pBlockIndex, DWORD *out_pOffset ) +{ + // Run through the seek table to find the block closest to the desired sample. + // Each seek table entry is the index (counting from the beginning of the file) + // of the first sample in the corresponding block, but there's no entry for the + // first block (since the index would always be zero). + bool bFound = false; + for ( DWORD i = 0; !bFound && i < nEntries; ++i ) + { + if ( dwSampleIndex < BigLong( pdwSeekTable[i] ) ) + { + *out_pBlockIndex = i; + bFound = true; + } + } + + // Calculate the sample offset by figuring out what the sample index of the first sample + // in the block is, then subtracting that from dwSampleIndex. + if ( bFound ) + { + DWORD dwStartOfBlock = (*out_pBlockIndex == 0) ? 0 : BigLong( pdwSeekTable[*out_pBlockIndex - 1] ); + *out_pOffset = dwSampleIndex - dwStartOfBlock; + } + + return bFound; +} + +//----------------------------------------------------------------------------- +// Compile and compress vdat +//----------------------------------------------------------------------------- +bool CompressVDAT( chunk_t *pChunk ) +{ + CSentence *pSentence; + + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + + buf.EnsureCapacity( pChunk->size ); + memcpy( buf.Base(), pChunk->pData, pChunk->size ); + buf.SeekPut( CUtlBuffer::SEEK_HEAD, pChunk->size ); + + pSentence = new CSentence(); + + // Make binary version of VDAT + // Throws all phonemes into one word, discards sentence memory, etc. + pSentence->InitFromDataChunk( buf.Base(), buf.TellPut() ); + pSentence->MakeRuntimeOnly(); + CUtlBuffer binaryBuffer( 0, 0, 0 ); + binaryBuffer.SetBigEndian( true ); + pSentence->CacheSaveToBuffer( binaryBuffer, CACHED_SENTENCE_VERSION_ALIGNED ); + delete pSentence; + + unsigned int compressedSize = 0; + unsigned char *pCompressedOutput = LZMA_OpportunisticCompress( (unsigned char *)binaryBuffer.Base(), + binaryBuffer.TellPut(), &compressedSize ); + if ( pCompressedOutput ) + { + if ( !g_bQuiet ) + { + Msg( "CompressVDAT: Compressed %d to %d\n", binaryBuffer.TellPut(), compressedSize ); + } + + free( pChunk->pData ); + pChunk->size = compressedSize; + pChunk->pData = pCompressedOutput; + } + else + { + // save binary VDAT as-is + free( pChunk->pData ); + pChunk->size = binaryBuffer.TellPut(); + pChunk->pData = (byte *)malloc( pChunk->size ); + memcpy( pChunk->pData, binaryBuffer.Base(), pChunk->size ); + } + + // success + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: read chunks into provided array +//----------------------------------------------------------------------------- +bool ReadChunks( const char *pFileName, int &numChunks, chunk_t chunks[MAX_CHUNKS] ) +{ + numChunks = 0; + + InFileRIFF riff( pFileName, *g_pSndIO ); + if ( riff.RIFFName() != RIFF_WAVE ) + { + return false; + } + + IterateRIFF walk( riff, riff.RIFFSize() ); + + while ( walk.ChunkAvailable() ) + { + chunks[numChunks].id = walk.ChunkName(); + chunks[numChunks].size = walk.ChunkSize(); + + int size = chunks[numChunks].size; + if ( walk.ChunkName() == WAVE_FMT && size < sizeof( WAVEFORMATEXTENSIBLE ) ) + { + // format chunks are variable and cast to different structures + // ensure the data footprint is at least the structure we want to manipulate + size = sizeof( WAVEFORMATEXTENSIBLE ); + } + + chunks[numChunks].pData = (byte *)malloc( size ); + memset( chunks[numChunks].pData, 0, size ); + + walk.ChunkRead( chunks[numChunks].pData ); + + numChunks++; + if ( numChunks >= MAX_CHUNKS ) + return false; + + walk.ChunkNext(); + } + + // success + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: promote pcm 8 bit to 16 bit pcm +//----------------------------------------------------------------------------- +void ConvertPCMDataChunk8To16( chunk_t *pFormatChunk, chunk_t *pDataChunk ) +{ + WAVEFORMATEX *pFormat = (WAVEFORMATEX*)pFormatChunk->pData; + + int sampleSize = ( pFormat->nChannels * pFormat->wBitsPerSample ) >> 3; + int sampleCount = pDataChunk->size / sampleSize; + int outputSize = sizeof( short ) * ( sampleCount * pFormat->nChannels ); + short *pOut = (short *)malloc( outputSize ); + + // in-place convert data from 8-bits to 16-bits + Convert8To16( pDataChunk->pData, pOut, sampleCount, pFormat->nChannels ); + + free( pDataChunk->pData ); + pDataChunk->pData = (byte *)pOut; + pDataChunk->size = outputSize; + + pFormat->wFormatTag = WAVE_FORMAT_PCM; + pFormat->nBlockAlign = 2 * pFormat->nChannels; + pFormat->wBitsPerSample = 16; + pFormat->nAvgBytesPerSec = 2 * pFormat->nSamplesPerSec * pFormat->nChannels; +} + +//----------------------------------------------------------------------------- +// Purpose: convert adpcm to 16 bit pcm +//----------------------------------------------------------------------------- +void ConvertADPCMDataChunkTo16( chunk_t *pFormatChunk, chunk_t *pDataChunk ) +{ + WAVEFORMATEX *pFormat = (WAVEFORMATEX*)pFormatChunk->pData; + + int sampleCount = ADPCMSampleCount( (byte *)pFormat, pDataChunk->pData, pDataChunk->size ); + int outputSize = sizeof( short ) * sampleCount * pFormat->nChannels; + short *pOut = (short *)malloc( outputSize ); + + // convert to PCM 16bit format + DecompressADPCMSamples( (byte*)pFormat, (byte*)pDataChunk->pData, pDataChunk->size, pOut ); + + free( pDataChunk->pData ); + pDataChunk->pData = (byte *)pOut; + pDataChunk->size = outputSize; + + pFormat->wFormatTag = WAVE_FORMAT_PCM; + pFormat->nBlockAlign = 2 * pFormat->nChannels; + pFormat->wBitsPerSample = 16; + pFormat->nAvgBytesPerSec = 2 * pFormat->nSamplesPerSec * pFormat->nChannels; + + pFormatChunk->size = 16; +} + +//----------------------------------------------------------------------------- +// Purpose: Decimate to 22K +//----------------------------------------------------------------------------- +void ConvertPCMDataChunk16To22K( chunk_t *pFormatChunk, chunk_t *pDataChunk ) +{ + WAVEFORMATEX *pFormat = (WAVEFORMATEX*)pFormatChunk->pData; + + if ( pFormat->nSamplesPerSec != 44100 || pFormat->wBitsPerSample != 16 || pFormat->wFormatTag != WAVE_FORMAT_PCM ) + { + // not in expected format + return; + } + + int sampleSize = ( pFormat->nChannels * pFormat->wBitsPerSample ) >> 3; + int sampleCount = pDataChunk->size / sampleSize; + short *pOut = (short *)malloc( sizeof( short ) * ( sampleCount * pFormat->nChannels ) ); + + DecimateSampleRateBy2_16( (short *)pDataChunk->pData, pOut, sampleCount, pFormat->nChannels ); + + free( pDataChunk->pData ); + pDataChunk->pData = (byte *)pOut; + pDataChunk->size = sizeof( short ) * ( sampleCount/2 * pFormat->nChannels ); + + pFormat->nSamplesPerSec = 22050; + pFormat->nBlockAlign = 2 * pFormat->nChannels; + pFormat->nAvgBytesPerSec = 2 * pFormat->nSamplesPerSec * pFormat->nChannels; +} + +//----------------------------------------------------------------------------- +// Purpose: determine loop start +//----------------------------------------------------------------------------- +int FindLoopStart( int samplerChunk, int cueChunk ) +{ + int loopStartFromCue = -1; + int loopStartFromSampler = -1; + + if ( cueChunk != -1 ) + { + struct cuechunk_t + { + unsigned int dwName; + unsigned int dwPosition; + unsigned int fccChunk; + unsigned int dwChunkStart; + unsigned int dwBlockStart; + unsigned int dwSampleOffset; + }; + struct cueRIFF_t + { + int cueCount; + cuechunk_t cues[1]; + }; + + cueRIFF_t *pCue = (cueRIFF_t *)g_chunks[cueChunk].pData; + if ( pCue->cueCount > 0 ) + { + loopStartFromCue = pCue->cues[0].dwSampleOffset; + } + } + + if ( samplerChunk != -1 ) + { + struct SampleLoop + { + unsigned int dwIdentifier; + unsigned int dwType; + unsigned int dwStart; + unsigned int dwEnd; + unsigned int dwFraction; + unsigned int dwPlayCount; + }; + + struct samplerchunk_t + { + unsigned int dwManufacturer; + unsigned int dwProduct; + unsigned int dwSamplePeriod; + unsigned int dwMIDIUnityNote; + unsigned int dwMIDIPitchFraction; + unsigned int dwSMPTEFormat; + unsigned int dwSMPTEOffset; + unsigned int cSampleLoops; + unsigned int cbSamplerData; + struct SampleLoop Loops[1]; + }; + + // assume that the loop end is the sample end + // assume that only the first loop is relevant + samplerchunk_t *pSampler = (samplerchunk_t *)g_chunks[samplerChunk].pData; + if ( pSampler->cSampleLoops > 0 ) + { + // only support normal forward loops + if ( pSampler->Loops[0].dwType == 0 ) + { + loopStartFromSampler = pSampler->Loops[0].dwStart; + } + } + } + + return ( max( loopStartFromCue, loopStartFromSampler ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: returns chunk, -1 if not found +//----------------------------------------------------------------------------- +int FindChunk( unsigned int id ) +{ + int i; + for ( i=0; i<g_numChunks; i++ ) + { + if ( g_chunks[i].id == id ) + { + return i; + } + } + + // not found + return - 1; +} + +bool EncodeAsXMA( const char *pDebugName, CUtlBuffer &targetBuff, int quality, bool bIsVoiceOver ) +{ +#ifdef NO_X360_XDK + return false; +#else + int formatChunk = FindChunk( WAVE_FMT ); + int dataChunk = FindChunk( WAVE_DATA ); + if ( formatChunk == -1 || dataChunk == -1 ) + { + // huh? these should have been pre-validated + return false; + } + + int vdatSize = 0; + int vdatChunk = FindChunk( WAVE_VALVEDATA ); + if ( vdatChunk != -1 ) + { + vdatSize = g_chunks[vdatChunk].size; + } + + int loopStart = FindLoopStart( FindChunk( WAVE_SAMPLER ), FindChunk( WAVE_CUE ) ); + + // format structure must be expected 16 bit PCM, otherwise encoder crashes + WAVEFORMATEX *pFormat = (WAVEFORMATEX *)g_chunks[formatChunk].pData; + pFormat->nAvgBytesPerSec = pFormat->nSamplesPerSec * pFormat->nChannels * 2; + pFormat->nBlockAlign = 2 * pFormat->nChannels; + pFormat->cbSize = 0; + + XMAENCODERSTREAM inputStream = { 0 }; + + WAVEFORMATEXTENSIBLE wfx; + Assert( g_chunks[formatChunk].size <= sizeof( WAVEFORMATEXTENSIBLE ) ); + memcpy( &wfx, g_chunks[formatChunk].pData, g_chunks[formatChunk].size ); + if ( g_chunks[formatChunk].size < sizeof( WAVEFORMATEXTENSIBLE ) ) + { + memset( (unsigned char*)&wfx + g_chunks[formatChunk].size, 0, sizeof( WAVEFORMATEXTENSIBLE ) - g_chunks[formatChunk].size ); + } + + memcpy( &inputStream.Format, &wfx, sizeof( WAVEFORMATEX ) ); + inputStream.pBuffer = g_chunks[dataChunk].pData; + inputStream.BufferSize = g_chunks[dataChunk].size; + if ( loopStart != -1 ) + { + // can only support a single loop point until end of file + inputStream.LoopStart = loopStart; + inputStream.LoopLength = inputStream.BufferSize / ( pFormat->nChannels * sizeof( short ) ) - loopStart; + } + + void *pXMAData = NULL; + DWORD XMADataSize = 0; + XMA2WAVEFORMAT *pXMA2Format = NULL; + DWORD XMA2FormatSize = 0; + DWORD *pXMASeekTable = NULL; + DWORD XMASeekTableSize = 0; + HRESULT hr = S_OK; + + DWORD xmaFlags = XMAENCODER_NOFILTER; + if ( loopStart != -1 ) + { + xmaFlags |= XMAENCODER_LOOP; + } + + int numAttempts = 1; + while ( numAttempts < 10 ) + { + hr = XMA2InMemoryEncoder( 1, &inputStream, quality, xmaFlags, XMA_BLOCK_SIZE/1024, &pXMAData, &XMADataSize, &pXMA2Format, &XMA2FormatSize, &pXMASeekTable, &XMASeekTableSize ); + if ( !FAILED( hr ) ) + break; + + // make small jumps + quality += 5; + if ( quality > 100 ) + quality = 100; + if ( !g_bQuiet ) + { + Msg( "XMA Encoding Error on '%s', Attempting increasing quality to %d\n", pDebugName, quality ); + } + + numAttempts++; + + pXMAData = NULL; + XMADataSize = 0; + pXMA2Format = NULL; + XMA2FormatSize = 0; + pXMASeekTable = NULL; + XMASeekTableSize = 0; + } + + if ( FAILED( hr ) ) + { + // unrecoverable + return false; + } + else if ( numAttempts > 1 ) + { + if ( !g_bQuiet ) + { + Msg( "XMA Encoding Success on '%s' at quality %d\n", pDebugName, quality ); + } + } + + DWORD loopBlock = 0; + DWORD numLeadingSamples = 0; + DWORD numTrailingSamples = 0; + + if ( loopStart != -1 ) + { + // calculate start block/offset + DWORD loopBlockStartIndex = 0; + DWORD loopBlockStartOffset = 0; + + if ( !SampleToXMABlockOffset( BigLong( pXMA2Format->LoopBegin ), pXMASeekTable, XMASeekTableSize/sizeof( DWORD ), &loopBlockStartIndex, &loopBlockStartOffset ) ) + { + // could not determine loop point, out of range of encoded samples + Msg( "XMA Loop Encoding Error on '%s', loop %d\n", pDebugName, loopStart ); + return false; + } + + loopBlock = loopBlockStartIndex; + numLeadingSamples = loopBlockStartOffset; + + if ( BigLong( pXMA2Format->LoopEnd ) < BigLong( pXMA2Format->SamplesEncoded ) ) + { + // calculate end block/offset + DWORD loopBlockEndIndex = 0; + DWORD loopBlockEndOffset = 0; + + if ( !SampleToXMABlockOffset( BigLong( pXMA2Format->LoopEnd ), pXMASeekTable, XMASeekTableSize/sizeof( DWORD ), &loopBlockEndIndex, &loopBlockEndOffset ) ) + { + // could not determine loop point, out of range of encoded samples + Msg( "XMA Loop Encoding Error on '%s', loop %d\n", pDebugName, loopStart ); + return false; + } + + if ( loopBlockEndIndex != BigLong( pXMA2Format->BlockCount ) - 1 ) + { + // end block MUST be last block + Msg( "XMA Loop Encoding Error on '%s', block end is %d/%d\n", pDebugName, loopBlockEndOffset, BigLong( pXMA2Format->BlockCount ) ); + return false; + } + + numTrailingSamples = BigLong( pXMA2Format->SamplesEncoded ) - BigLong( pXMA2Format->LoopEnd ); + } + + // check for proper encoding range + if ( loopBlock > 32767 ) + { + Msg( "XMA Loop Encoding Error on '%s', loop block exceeds 16 bits %d\n", pDebugName, loopBlock ); + return false; + } + if ( numLeadingSamples > 32767 ) + { + Msg( "XMA Loop Encoding Error on '%s', leading samples exceeds 16 bits %d\n", pDebugName, numLeadingSamples ); + return false; + } + if ( numTrailingSamples > 32767 ) + { + Msg( "XMA Loop Encoding Error on '%s', trailing samples exceeds 16 bits %d\n", pDebugName, numTrailingSamples ); + return false; + } + } + + xwvHeader_t header; + memset( &header, 0, sizeof( xwvHeader_t ) ); + + int seekTableSize = 0; + if ( vdatSize || bIsVoiceOver ) + { + // save the optional seek table only for vdat or vo + // the seek table size is expected to be derived by this calculation + seekTableSize = ( XMADataSize / XMA_BYTES_PER_PACKET ) * sizeof( int ); + if ( seekTableSize != XMASeekTableSize ) + { + Msg( "XMA Error: Unexpected seek table calculation in '%s'!", pDebugName ); + return false; + } + } + + if ( loopStart != -1 && ( vdatSize || bIsVoiceOver ) ) + { + Msg( "XMA Warning: Unexpected loop in vo data '%s'!", pDebugName ); + + // do not write the seek table for looping sounds + seekTableSize = 0; + } + + header.id = BigLong( XWV_ID ); + header.version = BigLong( XWV_VERSION ); + header.headerSize = BigLong( sizeof( xwvHeader_t ) ); + header.staticDataSize = BigLong( seekTableSize + vdatSize ); + header.dataOffset = BigLong( AlignValue( sizeof( xwvHeader_t) + seekTableSize + vdatSize, XBOX_DVD_SECTORSIZE ) ); + header.dataSize = BigLong( XMADataSize ); + + // track the XMA number of samples that will get decoded + // which is NOT the same as what the source actually encoded + header.numDecodedSamples = pXMA2Format->SamplesEncoded; + + if ( loopStart != -1 ) + { + // the loop start is in source space (now meaningless), need the loop in XMA decoding sample space + header.loopStart = pXMA2Format->LoopBegin; + } + else + { + header.loopStart = BigLong( -1 ); + } + header.loopBlock = BigShort( (unsigned short)loopBlock ); + header.numLeadingSamples = BigShort( (unsigned short)numLeadingSamples ); + header.numTrailingSamples = BigShort( (unsigned short)numTrailingSamples ); + + header.vdatSize = BigShort( (short)vdatSize ); + header.format = XWV_FORMAT_XMA; + header.bitsPerSample = 16; + header.SetSampleRate( pFormat->nSamplesPerSec ); + header.SetChannels( pFormat->nChannels ); + header.quality = quality; + header.bHasSeekTable = ( seekTableSize != 0 ); + + // output header + targetBuff.Put( &header, sizeof( xwvHeader_t ) ); + + // output optional seek table + if ( seekTableSize ) + { + // seek table is already in big-endian format + targetBuff.Put( pXMASeekTable, seekTableSize ); + } + + // output vdat + if ( vdatSize ) + { + targetBuff.Put( g_chunks[vdatChunk].pData, g_chunks[vdatChunk].size ); + } + + AlignToBoundary( targetBuff, XBOX_DVD_SECTORSIZE ); + + // write data + targetBuff.Put( pXMAData, XMADataSize ); + + // pad to EOF + AlignToBoundary( targetBuff, XBOX_DVD_SECTORSIZE ); + + free( pXMAData ); + free( pXMA2Format ); + free( pXMASeekTable ); + + // xma encoder leaves its temporary files, we'll delete + scriptlib->DeleteTemporaryFiles( "LoopStrm*" ); + scriptlib->DeleteTemporaryFiles( "EncStrm*" ); + + return true; +#endif +} + +bool EncodeAsPCM( const char *pTargetName, CUtlBuffer &targetBuff ) +{ + int formatChunk = FindChunk( WAVE_FMT ); + int dataChunk = FindChunk( WAVE_DATA ); + if ( formatChunk == -1 || dataChunk == -1 ) + { + // huh? these should have been pre-validated + return false; + } + + WAVEFORMATEX *pFormat = (WAVEFORMATEX *)g_chunks[formatChunk].pData; + if ( pFormat->wBitsPerSample != 16 ) + { + // huh? the input is expeted to be 16 bit PCM + return false; + } + + int vdatSize = 0; + int vdatChunk = FindChunk( WAVE_VALVEDATA ); + if ( vdatChunk != -1 ) + { + vdatSize = g_chunks[vdatChunk].size; + } + + chunk_t *pDataChunk = &g_chunks[dataChunk]; + + xwvHeader_t header; + memset( &header, 0, sizeof( xwvHeader_t ) ); + + int sampleSize = pFormat->nChannels * sizeof( short ); + int sampleCount = pDataChunk->size / sampleSize; + + header.id = BigLong( XWV_ID ); + header.version = BigLong( XWV_VERSION ); + header.headerSize = BigLong( sizeof( xwvHeader_t ) ); + header.staticDataSize = BigLong( vdatSize ); + header.dataOffset = BigLong( AlignValue( sizeof( xwvHeader_t) + vdatSize, XBOX_DVD_SECTORSIZE ) ); + header.dataSize = BigLong( pDataChunk->size ); + header.numDecodedSamples = BigLong( sampleCount ); + header.loopStart = BigLong( -1 ); + header.loopBlock = 0; + header.numLeadingSamples = 0; + header.numTrailingSamples = 0; + header.vdatSize = BigShort( (short)vdatSize ); + header.format = XWV_FORMAT_PCM; + header.bitsPerSample = 16; + header.SetSampleRate( pFormat->nSamplesPerSec ); + header.SetChannels( pFormat->nChannels ); + header.quality = 100; + + // output header + targetBuff.Put( &header, sizeof( xwvHeader_t ) ); + + // output vdat + if ( vdatSize ) + { + targetBuff.Put( g_chunks[vdatChunk].pData, g_chunks[vdatChunk].size ); + } + + AlignToBoundary( targetBuff, XBOX_DVD_SECTORSIZE ); + + for ( int i = 0; i < sampleCount * pFormat->nChannels; i++ ) + { + ((short *)pDataChunk->pData)[i] = BigShort( ((short *)pDataChunk->pData)[i] ); + } + + // write data + targetBuff.Put( pDataChunk->pData, pDataChunk->size ); + + // pad to EOF + AlignToBoundary( targetBuff, XBOX_DVD_SECTORSIZE ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: read source, do work, and write to target +//----------------------------------------------------------------------------- +bool CreateTargetFile_WAV( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + g_numChunks = 0; + + // resolve relative source to absolute path + char fullSourcePath[MAX_PATH]; + if ( _fullpath( fullSourcePath, pSourceName, sizeof( fullSourcePath ) ) ) + { + pSourceName = fullSourcePath; + } + + if ( !ReadChunks( pSourceName, g_numChunks, g_chunks ) ) + { + Msg( "No RIFF Chunks on '%s'\n", pSourceName ); + return false; + } + + int formatChunk = FindChunk( WAVE_FMT ); + if ( formatChunk == -1 ) + { + Msg( "RIFF Format Chunk not found on '%s'\n", pSourceName ); + return false; + } + + int dataChunk = FindChunk( WAVE_DATA ); + if ( dataChunk == -1 ) + { + Msg( "RIFF Data Chunk not found on '%s'\n", pSourceName ); + return false; + } + + // get the conversion rules + conversion_t *pConversion = g_defaultConversionRules; + if ( V_stristr( g_szModPath, "\\portal" ) ) + { + pConversion = g_portalConversionRules; + } + + // conversion rules are based on matching subdir + for ( int i=1; ;i++ ) + { + char subString[MAX_PATH]; + if ( !pConversion[i].pSubDir ) + { + // end of list + break; + } + + sprintf( subString, "\\%s\\", pConversion[i].pSubDir ); + if ( V_stristr( pSourceName, subString ) ) + { + // use matched conversion rules + pConversion = &pConversion[i]; + break; + } + } + + bool bForceTo22K = pConversion->bForceTo22K; + int quality = pConversion->quality; + + // cannot trust the localization depots to have matched their sources + // cannot allow 44K + if ( IsLocalizedFile( pSourceName ) ) + { + bForceTo22K = true; + } + + // classify strict vo from /sound/vo only + bool bIsVoiceOver = V_stristr( pSourceName, "\\sound\\vo\\" ) != NULL; + + // can override default settings + quality = CommandLine()->ParmValue( "-xmaquality", quality ); + if ( quality < 0 ) + quality = 0; + else if ( quality > 100 ) + quality = 100; + if ( !g_bQuiet ) + { + Msg( "Encoding quality: %d on '%s'\n", quality, pSourceName ); + } + + int vdatSize = 0; + int vdatChunk = FindChunk( WAVE_VALVEDATA ); + if ( vdatChunk != -1 ) + { + // compile to optimal block + if ( !CompressVDAT( &g_chunks[vdatChunk] ) ) + { + Msg( "Compress VDAT Error on '%s'\n", pSourceName ); + return false; + } + vdatSize = g_chunks[vdatChunk].size; + } + + // for safety (not trusting their decoding) and simplicity convert all data to 16 bit PCM before encoding + WAVEFORMATEX *pFormat = (WAVEFORMATEX *)g_chunks[formatChunk].pData; + if ( ( pFormat->wFormatTag == WAVE_FORMAT_PCM ) ) + { + if ( pFormat->wBitsPerSample == 8 ) + { + ConvertPCMDataChunk8To16( &g_chunks[formatChunk], &g_chunks[dataChunk] ); + } + } + else if ( pFormat->wFormatTag == WAVE_FORMAT_ADPCM ) + { + ConvertADPCMDataChunkTo16( &g_chunks[formatChunk], &g_chunks[dataChunk] ); + } + else + { + Msg( "Unknown RIFF Format on '%s'\n", pSourceName ); + return false; + } + + // optionally decimate to 22K + if ( pFormat->nSamplesPerSec == 44100 && bForceTo22K ) + { + if ( !g_bQuiet ) + { + Msg( "Converting to 22K '%s'\n", pSourceName ); + } + ConvertPCMDataChunk16To22K( &g_chunks[formatChunk], &g_chunks[dataChunk] ); + } + + CUtlBuffer targetBuff; + bool bSuccess; + + bSuccess = EncodeAsXMA( pSourceName, targetBuff, quality, bIsVoiceOver ); + if ( bSuccess ) + { + WriteBufferToFile( pTargetName, targetBuff, bWriteToZip, g_WriteModeForConversions ); + } + + // release data + for ( int i = 0; i < g_numChunks; i++ ) + { + free( g_chunks[i].pData ); + } + + return bSuccess; +} + +//----------------------------------------------------------------------------- +// Purpose: MP3's are already pre-converted into .360.wav +//----------------------------------------------------------------------------- +bool CreateTargetFile_MP3( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + CUtlBuffer targetBuffer; + + // ignore the .mp3 source, the .360.wav target should have been pre-converted, checked in, and exist + // use the expected target as the source + if ( !scriptlib->ReadFileToBuffer( pTargetName, targetBuffer ) ) + { + // the .360.wav target does not exist + // try again using a .wav version and convert from that + char wavFilename[MAX_PATH]; + V_StripExtension( pSourceName, wavFilename, sizeof( wavFilename ) ); + V_SetExtension( wavFilename, ".wav", sizeof( wavFilename ) ); + if ( scriptlib->DoesFileExist( wavFilename ) ) + { + if ( CreateTargetFile_WAV( wavFilename, pTargetName, bWriteToZip ) ) + { + return true; + } + } + + return false; + } + + // no conversion to write, but possibly zipped + bool bSuccess = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, WRITE_TO_DISK_NEVER ); + return bSuccess; +} + +//----------------------------------------------------------------------------- +// Get the preload data for a wav file +//----------------------------------------------------------------------------- +bool GetPreloadData_WAV( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ) +{ + xwvHeader_t *pHeader = ( xwvHeader_t * )fileBufferIn.Base(); + if ( pHeader->id != ( unsigned int )BigLong( XWV_ID ) || + pHeader->version != ( unsigned int )BigLong( XWV_VERSION ) || + pHeader->headerSize != BigLong( sizeof( xwvHeader_t ) ) ) + { + // bad version + Msg( "Can't preload: '%s', has bad version\n", pFilename ); + return false; + } + + // ensure caller's buffer is clean + // caller determines preload size, via TellMaxPut() + preloadBufferOut.Purge(); + unsigned int preloadSize = BigLong( pHeader->headerSize ) + BigLong( pHeader->staticDataSize ); + preloadBufferOut.Put( fileBufferIn.Base(), preloadSize ); + + return true; +} diff --git a/utils/xbox/MakeGameData/MakeTextures.cpp b/utils/xbox/MakeGameData/MakeTextures.cpp new file mode 100644 index 0000000..f267367 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeTextures.cpp @@ -0,0 +1,45 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: .360.VTF Creation +// +//=====================================================================================// + +#include "MakeGameData.h" +#include "vtf/vtf.h" + +//----------------------------------------------------------------------------- +// Purpose: Create the 360 VTF, use the library! +//----------------------------------------------------------------------------- +bool CreateTargetFile_VTF( const char *pSourceName, const char *pTargetName, bool bWriteToZip ) +{ + CUtlBuffer sourceBuffer; + CUtlBuffer targetBuffer; + + if ( !scriptlib->ReadFileToBuffer( pSourceName, sourceBuffer ) ) + { + return false; + } + + // using library conversion routine + bool bSuccess = ConvertVTFTo360Format( pSourceName, sourceBuffer, targetBuffer, CompressCallback ); + if ( bSuccess ) + { + bSuccess = WriteBufferToFile( pTargetName, targetBuffer, bWriteToZip, g_WriteModeForConversions ); + } + + return bSuccess; +} + +//----------------------------------------------------------------------------- +// Get the preload data for a vtf file +//----------------------------------------------------------------------------- +bool GetPreloadData_VTF( const char *pFilename, CUtlBuffer &fileBufferIn, CUtlBuffer &preloadBufferOut ) +{ + if ( !GetVTFPreload360Data( pFilename, fileBufferIn, preloadBufferOut ) ) + { + Msg( "Can't preload: '%s', has bad version\n", pFilename ); + return false; + } + + return true; +}
\ No newline at end of file diff --git a/utils/xbox/MakeGameData/MakeZip.cpp b/utils/xbox/MakeGameData/MakeZip.cpp new file mode 100644 index 0000000..69950b0 --- /dev/null +++ b/utils/xbox/MakeGameData/MakeZip.cpp @@ -0,0 +1,593 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "MakeGameData.h" + +static CUtlSymbolTable g_CriticalPreloadTable( 0, 32, true ); + +//----------------------------------------------------------------------------- +// Purpose: Compute preload data by file type. Calls into appropriate libraries +// to get the preload info. Libraries would use filename to generate +// the preload if there is a compilation step, otherwise the file buffer +// is a buffer loaded filename. +//----------------------------------------------------------------------------- +static bool GetPreloadBuffer( const char *pFilename, CUtlBuffer &fileBuffer, CUtlBuffer &preloadBuffer ) +{ + char fileExtension[MAX_PATH]; + Q_ExtractFileExtension( pFilename, fileExtension, sizeof( fileExtension ) ); + + // adding an entire file IS ONLY for files that are expected to be read by the game as a single read + // NOT for files that have any seek pattern + bool bAddEntireFile = false; + + // trivial small files, always add + if ( !Q_stricmp( fileExtension, "txt" ) || + !Q_stricmp( fileExtension, "dat" ) || + !Q_stricmp( fileExtension, "lst" ) || + !Q_stricmp( fileExtension, "res" ) || + !Q_stricmp( fileExtension, "vmt" ) || + !Q_stricmp( fileExtension, "cfg" ) || + !Q_stricmp( fileExtension, "bnf" ) || + !Q_stricmp( fileExtension, "rc" ) || + !Q_stricmp( fileExtension, "vbf" ) || + !Q_stricmp( fileExtension, "vfe" ) || + !Q_stricmp( fileExtension, "pcf" ) || + !Q_stricmp( fileExtension, "inf" ) ) + { + bAddEntireFile = true; + } + + // critical resources get blindly added to the preload + if ( !bAddEntireFile && ( g_CriticalPreloadTable.Find( pFilename ) != UTL_INVAL_SYMBOL ) ) + { + bAddEntireFile = true; + } + + if ( bAddEntireFile && LZMA_IsCompressed( (unsigned char *)fileBuffer.Base() ) ) + { + // sorry, not allowed to add entirely to preload if already compressed + // breaks the run-time filesystem due to inability to deliver file as-is + bAddEntireFile = false; + } + + if ( bAddEntireFile ) + { + if ( fileBuffer.TellMaxPut() >= 1*1024 ) + { + // only compress preload files of reasonable size + unsigned int compressedSize = 0; + unsigned char *pCompressedOutput = LZMA_OpportunisticCompress( (unsigned char *)fileBuffer.Base(), + fileBuffer.TellMaxPut(), &compressedSize ); + if ( pCompressedOutput ) + { + // add as compressed + preloadBuffer.EnsureCapacity( compressedSize ); + preloadBuffer.Put( pCompressedOutput, compressedSize ); + free( pCompressedOutput ); + return true; + } + } + + // add entire file to preload section + preloadBuffer.EnsureCapacity( fileBuffer.TellMaxPut() ); + preloadBuffer.Put( fileBuffer.Base(), fileBuffer.TellMaxPut() ); + return true; + } + + // Each library will fetch the optional preload data into caller's buffer + if ( !Q_stricmp( fileExtension, "wav" ) ) + { + return GetPreloadData_WAV( pFilename, fileBuffer, preloadBuffer ); + } + else if ( !Q_stricmp( fileExtension, "vtf" ) ) + { + return GetPreloadData_VTF( pFilename, fileBuffer, preloadBuffer ); + } + else if ( !Q_stricmp( fileExtension, "vcs" ) ) + { + return GetPreloadData_VCS( pFilename, fileBuffer, preloadBuffer ); + } + else if ( !Q_stricmp( fileExtension, "vhv" ) ) + { + return GetPreloadData_VHV( pFilename, fileBuffer, preloadBuffer ); + } + else if ( !Q_stricmp( fileExtension, "vtx" ) ) + { + return GetPreloadData_VTX( pFilename, fileBuffer, preloadBuffer ); + } + else if ( !Q_stricmp( fileExtension, "vvd" ) ) + { + return GetPreloadData_VVD( pFilename, fileBuffer, preloadBuffer ); + } + + // others... + return false; +} + +void SetupCriticalPreloadScript( const char *pModPath ) +{ + characterset_t breakSet; + CharacterSetBuild( &breakSet, "" ); + + // purge any prior entries + g_CriticalPreloadTable.RemoveAll(); + + // populate table + char szCriticaList[MAX_PATH]; + char szToken[MAX_PATH]; + V_ComposeFileName( pModPath, "scripts\\preload_xbox.xsc", szCriticaList, sizeof( szCriticaList ) ); + CUtlBuffer criticalListBuffer; + if ( ReadFileToBuffer( szCriticaList, criticalListBuffer, true, true ) ) + { + for ( ;; ) + { + int nTokenSize = criticalListBuffer.ParseToken( &breakSet, szToken, sizeof( szToken ) ); + if ( nTokenSize <= 0 ) + { + break; + } + + V_strlower( szToken ); + V_FixSlashes( szToken, CORRECT_PATH_SEPARATOR ); + if ( UTL_INVAL_SYMBOL == g_CriticalPreloadTable.Find( szToken ) ) + { + g_CriticalPreloadTable.AddString( szToken ); + } + } + } +} + +CXZipTool::CXZipTool() +{ + m_pZip = NULL; + m_hPreloadFile = INVALID_HANDLE_VALUE; + m_hOutputZipFile = INVALID_HANDLE_VALUE; + m_PreloadFilename[0] = '\0'; +} + +CXZipTool::~CXZipTool() +{ + Reset(); +} + +void CXZipTool::Reset() +{ + if ( m_hOutputZipFile != INVALID_HANDLE_VALUE ) + { + CloseHandle( m_hOutputZipFile ); + m_hOutputZipFile = INVALID_HANDLE_VALUE; + } + + if ( m_hPreloadFile != INVALID_HANDLE_VALUE ) + { + CloseHandle( m_hPreloadFile ); + m_hPreloadFile = INVALID_HANDLE_VALUE; + } + + if ( m_PreloadFilename[0] ) + { + DeleteFile( m_PreloadFilename ); + m_PreloadFilename[0] = '\0'; + } + + if ( m_pZip ) + { + IZip::ReleaseZip( m_pZip ); + m_pZip = NULL; + } + + m_ZipPreloadDirectoryEntries.Purge(); + m_ZipCRCList.Purge(); + m_ZipPreloadRemapEntries.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Add a file buffer to the zip +//----------------------------------------------------------------------------- +bool CXZipTool::AddBuffer( const char *pFilename, CUtlBuffer &fileBuffer, bool bDoPreload ) +{ + if ( !m_pZip ) + { + return false; + } + + // safely strip unecessary prefix, otherise pollutes CRC + if ( !strnicmp( pFilename, ".\\", 2 ) ) + { + pFilename += 2; + } + + // scan for CRC collision now, not at runtime + CRCEntry_t crcEntry; + crcEntry.fileNameCRC = HashStringCaselessConventional( pFilename ); + crcEntry.filename = pFilename; + int idx = m_ZipCRCList.Find( crcEntry ); + if ( -1 != idx ) + { + if ( !V_stricmp( pFilename, m_ZipCRCList[idx].filename.String() ) ) + { + // file has already been added, ignore as succesful + return true; + } + + Msg( "ERROR: CRC Collision: '%s' with '%s'\n", pFilename, m_ZipCRCList[idx].filename.String() ); + return false; + } + else + { + // add unique entry to lists + // must track filenames in a non-sort manner + m_ZipCRCList.Insert( crcEntry ); + } + + // default, no preload entry + unsigned short preloadDir = INVALID_PRELOAD_ENTRY; + + if ( bDoPreload ) + { + CUtlBuffer preloadBuffer; + bool bHasPreload = GetPreloadBuffer( pFilename, fileBuffer, preloadBuffer ); + int preloadSize = preloadBuffer.TellMaxPut(); + if ( bHasPreload && preloadSize > 0 ) + { + if ( m_ZipPreloadDirectoryEntries.Count() >= 65534 ) + { + Msg( "ERROR: Preload section FULL!, skipping %s\n", pFilename ); + return FALSE; + } + + // Initialize the entry header + ZIP_PreloadDirectoryEntry entry; + memset( &entry, 0, sizeof( entry ) ); + + entry.Length = preloadSize; + entry.DataOffset = SetFilePointer( m_hPreloadFile, 0, NULL, FILE_CURRENT ); + + // Add the directory entry to the preload table + preloadDir = m_ZipPreloadDirectoryEntries.AddToTail( entry ); + + // Append the preload data to the preload file + DWORD numBytesWritten; + BOOL bOK = WriteFile( m_hPreloadFile, preloadBuffer.Base(), preloadSize, &numBytesWritten, NULL ); + if ( !bOK || preloadSize != numBytesWritten ) + { + Msg( "ERROR: writing %d preload bytes of '%s'\n", preloadSize, pFilename ); + return false; + } + + if ( !g_bQuiet ) + { + // Spew it + if ( LZMA_IsCompressed( (unsigned char *)preloadBuffer.Base() ) ) + { + unsigned int actualSize = LZMA_GetActualSize( (unsigned char *)preloadBuffer.Base() ); + Msg( "Preload: '%s': Compressed:%u Actual:%u\n", pFilename, preloadSize, actualSize ); + } + else + { + Msg( "Preload: '%s': Length:%u\n", pFilename, preloadSize ); + } + } + } + } + + unsigned int fileSize = fileBuffer.TellMaxPut(); + if ( fileSize > 0 ) + { + // order in zip is sorted, not sequential + m_pZip->AddBufferToZip( pFilename, fileBuffer.Base(), fileSize, false ); + + // track the file in the zip directory to it's preload entry + // order in preload is sequential as buffers are added + preloadRemap_t remap; + remap.filename = pFilename; + remap.preloadDirIndex = preloadDir; + m_ZipPreloadRemapEntries.AddToTail( remap ); + + if ( !g_bQuiet ) + { + Msg( "File: '%s': Length:%u\n", pFilename, fileSize ); + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Load a file and add it to the zip +//----------------------------------------------------------------------------- +bool CXZipTool::AddFile( const char *pFilename, bool bDoPreload ) +{ + if ( !m_pZip ) + { + return false; + } + + FILE* pFile = fopen( pFilename, "rb" ); + if( !pFile ) + { + Msg( "ERROR: failed to open file: '%s'\n", pFilename ); + return false; + } + + // Get the length of the file + fseek( pFile, 0, SEEK_END ); + unsigned fileSize = ftell( pFile ); + fseek( pFile, 0, SEEK_SET); + + // read file to buffer + CUtlBuffer fileBuffer; + fileBuffer.EnsureCapacity( fileSize ); + fread( fileBuffer.Base(), fileSize, 1, pFile ); + fclose( pFile ); + fileBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, fileSize ); + + return AddBuffer( pFilename, fileBuffer, bDoPreload ); +} + +//----------------------------------------------------------------------------- +// Purpose: Add the preload section and save out the zip file +//----------------------------------------------------------------------------- +bool CXZipTool::End() +{ + if ( !m_pZip ) + { + return false; + } + + // Add the preload section to the zip + if ( m_ZipPreloadDirectoryEntries.Count() ) + { + CUtlBuffer sectionBuffer; + CByteswap byteSwap; + + // pc tools write 360 native data + byteSwap.ActivateByteSwapping( IsPC() ); + + // determine the preload data footprint + unsigned int preloadDataSize = SetFilePointer( m_hPreloadFile, 0, NULL, FILE_CURRENT ); + + // finalize header + m_ZipPreloadHeader.DirectoryEntries = m_ZipPreloadRemapEntries.Count(); + m_ZipPreloadHeader.PreloadDirectoryEntries = m_ZipPreloadDirectoryEntries.Count(); + + // determine the total section size ( treated as a single file inside zip ) + unsigned int sectionSize = sizeof( ZIP_PreloadHeader ) + + m_ZipPreloadHeader.PreloadDirectoryEntries * sizeof( ZIP_PreloadDirectoryEntry ) + + m_ZipPreloadHeader.DirectoryEntries * sizeof( unsigned short ) + + preloadDataSize; + sectionSize = AlignValue( sectionSize, m_ZipPreloadHeader.Alignment ); + sectionBuffer.EnsureCapacity( sectionSize ); + + // save data in order + // save the header + byteSwap.SwapFieldsToTargetEndian( &m_ZipPreloadHeader ); + sectionBuffer.Put( &m_ZipPreloadHeader, sizeof( ZIP_PreloadHeader ) ); + + // fixup and save the preload directory + for ( int i=0; i<m_ZipPreloadDirectoryEntries.Count(); i++ ) + { + ZIP_PreloadDirectoryEntry entry = m_ZipPreloadDirectoryEntries[i]; + byteSwap.SwapFieldsToTargetEndian( &entry ); + sectionBuffer.Put( &entry, sizeof( ZIP_PreloadDirectoryEntry ) ); + } + + // generate remap table + char fileName[MAX_PATH]; + int fileSize; + int zipIndex = -1; + unsigned short *pRemapTable = (unsigned short *)malloc( m_ZipPreloadRemapEntries.Count() * sizeof( unsigned short ) ); + for ( int i=0; i<m_ZipPreloadRemapEntries.Count(); i++ ) + { + // zip files get iterated in the same order they are serialized to disk + fileName[0] = '\0'; + fileSize = 0; + zipIndex = m_pZip->GetNextFilename( zipIndex, fileName, sizeof( fileName ), fileSize ); + + // find the file in the preload remap table + bool bFound = false; + int j; + for ( j=0; j<m_ZipPreloadRemapEntries.Count(); j++ ) + { + if ( !Q_stricmp( fileName, m_ZipPreloadRemapEntries[j].filename.String() ) ) + { + bFound = true; + break; + } + } + if ( !bFound ) + { + // shouldn't happen, every file in the zip has a matching preload remap entry, that is valid or marked invalid + Msg( "ERROR: file '%s' was expected to have an entry in preload table\n", fileName ); + } + + // the remap table is used to go find a file's preload data (if available) + pRemapTable[i] = m_ZipPreloadRemapEntries[j].preloadDirIndex; + } + for ( int i=0; i<m_ZipPreloadRemapEntries.Count(); i++ ) + { + unsigned short s = pRemapTable[i]; + sectionBuffer.PutShort( BigShort( s ) ); + } + free( pRemapTable ); + + // get and save preload data + void *pPreloadData = malloc( preloadDataSize ); + SetFilePointer( m_hPreloadFile, 0, NULL, FILE_BEGIN ); + DWORD numBytesRead; + BOOL bOK = ReadFile( m_hPreloadFile, pPreloadData, preloadDataSize, &numBytesRead, NULL ); + if ( !bOK || numBytesRead != preloadDataSize ) + { + Msg( "ERROR: failed to read %d bytes from temporary preload file\n", preloadDataSize ); + } + CloseHandle( m_hPreloadFile ); + m_hPreloadFile = INVALID_HANDLE_VALUE; + + sectionBuffer.Put( pPreloadData, preloadDataSize ); + free( pPreloadData ); + + // cannot have written more than was pre-calced, unless code was broken + Assert( (unsigned int)sectionBuffer.TellMaxPut() <= sectionSize ); + while( (unsigned int)sectionBuffer.TellMaxPut() < sectionSize ) + { + // pad to final alignment + sectionBuffer.PutChar( 0 ); + } + + m_pZip->AddBufferToZip( PRELOAD_SECTION_NAME, sectionBuffer.Base(), sectionBuffer.TellMaxPut(), false ); + } + else + { + // Clear the preload section placeholder + m_pZip->RemoveFileFromZip( PRELOAD_SECTION_NAME ); + } + + m_pZip->SaveToDisk( m_hOutputZipFile ); + + Reset(); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Create the zip file +//----------------------------------------------------------------------------- +bool CXZipTool::Begin( const char *pZipFileName, unsigned int alignment ) +{ + // get the volume of the target zip + char drivePath[MAX_PATH]; + _splitpath( pZipFileName, drivePath, NULL, NULL, NULL ); + + m_pZip = IZip::CreateZip( drivePath, true ); + + if ( alignment ) + { + // making an aligned zip that uses an optimized (but incompatible) format + m_pZip->ForceAlignment( true, false, alignment ); + } + + // Open the output file + m_hOutputZipFile = CreateFile( pZipFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( m_hOutputZipFile == INVALID_HANDLE_VALUE ) + { + Msg( "ERROR: failed to create zip file '%s'\n", pZipFileName ); + return false; + } + + // Create a temporary file for storing the preloaded data + scriptlib->MakeTemporaryFilename( g_szModPath, m_PreloadFilename, sizeof( m_PreloadFilename ) ); + m_hPreloadFile = CreateFile( m_PreloadFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( m_hPreloadFile == INVALID_HANDLE_VALUE ) + { + Msg( "ERROR: failed to create temporary file '%s' for preload data\n", m_PreloadFilename ); + CloseHandle( m_hOutputZipFile ); + m_hOutputZipFile = INVALID_HANDLE_VALUE; + return false; + } + memset( &m_ZipPreloadHeader, 0, sizeof( ZIP_PreloadHeader ) ); + + m_ZipPreloadHeader.Version = PRELOAD_HDR_VERSION; + m_ZipPreloadHeader.Alignment = alignment; + + // Add a placeholder for the preload section + m_pZip->AddBufferToZip( PRELOAD_SECTION_NAME, NULL, 0, false ); + preloadRemap_t remap; + remap.filename = PRELOAD_SECTION_NAME; + remap.preloadDirIndex = INVALID_PRELOAD_ENTRY; + m_ZipPreloadRemapEntries.AddToTail( remap ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Dump the preload contents +//----------------------------------------------------------------------------- +void CXZipTool::SpewPreloadInfo( const char *pZipName ) +{ + IZip *pZip = IZip::CreateZip( NULL, true ); + + HANDLE hZipFile = pZip->ParseFromDisk( pZipName ); + if ( !hZipFile ) + { + Msg( "Bad or missing zip file, failed to open '%s'\n", pZipName ); + return; + } + + CUtlBuffer preloadBuffer; + if ( !pZip->ReadFileFromZip( hZipFile, PRELOAD_SECTION_NAME, false, preloadBuffer ) ) + { + Msg( "No preload info for '%s'\n", pZipName ); + return; + } + + preloadBuffer.ActivateByteSwapping( IsPC() ); + + ZIP_PreloadHeader header; + preloadBuffer.GetObjects( &header ); + + // get the dir table + ZIP_PreloadDirectoryEntry *pDir = (ZIP_PreloadDirectoryEntry *)malloc( header.PreloadDirectoryEntries * sizeof( ZIP_PreloadDirectoryEntry ) ); + preloadBuffer.GetObjects( pDir, header.PreloadDirectoryEntries ); + + // get the remap table + unsigned short *pRemap = (unsigned short *)malloc( header.DirectoryEntries * sizeof( unsigned short ) ); + for ( unsigned int i = 0; i < header.DirectoryEntries; i++ ) + { + pRemap[i] = preloadBuffer.GetShort(); + } + + int zipIndex = -1; + int fileSize; + char fileName[MAX_PATH]; + + // iterate preload entries sequentially + CUtlDict< unsigned int, int > sizes( true ); + for ( unsigned int i = 0; i < header.DirectoryEntries; i++ ) + { + fileName[0] = '\0'; + fileSize = 0; + zipIndex = pZip->GetNextFilename( zipIndex, fileName, sizeof( fileName ), fileSize ); + + unsigned short zipPreloadDirIndex = pRemap[i]; + if ( zipPreloadDirIndex == INVALID_PRELOAD_ENTRY ) + { + continue; + } + + Msg( "Offset: 0x%8.8x Length: %5d %s (%d)\n", pDir[zipPreloadDirIndex].DataOffset, pDir[zipPreloadDirIndex].Length, fileName, fileSize ); + + // total preload sizes by extension + const char *pExt = V_GetFileExtension( fileName ); + if ( !pExt ) + { + pExt = "???"; + } + int iIndex = sizes.Find( pExt ); + if ( iIndex == sizes.InvalidIndex() ) + { + iIndex = sizes.Insert( pExt ); + sizes[iIndex] = 0; + } + sizes[iIndex] += pDir[zipPreloadDirIndex].Length; + } + + Msg( "\n" ); + Msg( "Preload Size: %.2f MB\n", (float)preloadBuffer.TellMaxPut()/(1024.0f * 1024.0f) ); + Msg( "Zip Entries: %d\n", header.DirectoryEntries ); + Msg( "Preload Entries: %d\n", header.PreloadDirectoryEntries ); + + // dump each extension's total size, necessary for debugging who is the largest contributor + for ( int i = 0; i < sizes.Count(); i++ ) + { + Msg( "Extension: '%3s' %d bytes (%.2f%s)\n", sizes.GetElementName( i ), sizes[i], (float)sizes[i]/(float)preloadBuffer.TellMaxPut() * 100.0f, "%%" ); + } + Msg( "\n" ); + + free( pRemap ); + free( pDir ); + + IZip::ReleaseZip( pZip ); +} diff --git a/utils/xbox/MakeGameData/XZipTool.h b/utils/xbox/MakeGameData/XZipTool.h new file mode 100644 index 0000000..41713cf --- /dev/null +++ b/utils/xbox/MakeGameData/XZipTool.h @@ -0,0 +1,61 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#pragma once + +#include <stdio.h> +#include "utlbuffer.h" +#include "zip_uncompressed.h" +#include "generichash.h" +#include "zip_utils.h" +#include "byteswap.h" +#include "tier1/UtlVector.h" +#include "UtlSortVector.h" + +struct CRCEntry_t +{ + unsigned int fileNameCRC; + CUtlString filename; +}; + +struct preloadRemap_t +{ + CUtlString filename; + unsigned short preloadDirIndex; +}; + +class CZipCRCLessFunc +{ +public: + bool Less( CRCEntry_t const& src1, CRCEntry_t const& src2, void *pCtx ) + { + return ( src1.fileNameCRC < src2.fileNameCRC ); + } +}; + +class CXZipTool +{ +public: + CXZipTool(); + ~CXZipTool(); + + void Reset(); + bool Begin( const char* pFileName, unsigned int alignment = 0 ); + bool End(); + bool AddBuffer( const char* pFileName, CUtlBuffer &buffer, bool bPreload = true ); + bool AddFile( const char* pFileName, bool bPreload = true ); + void SpewPreloadInfo( const char *pZipName ); + +private: + IZip *m_pZip; + char m_PreloadFilename[MAX_PATH]; + HANDLE m_hPreloadFile; + HANDLE m_hOutputZipFile; + ZIP_PreloadHeader m_ZipPreloadHeader; + CUtlVector< ZIP_PreloadDirectoryEntry > m_ZipPreloadDirectoryEntries; + CUtlSortVector< CRCEntry_t, CZipCRCLessFunc > m_ZipCRCList; + CUtlVector< preloadRemap_t > m_ZipPreloadRemapEntries; +};
\ No newline at end of file diff --git a/utils/xbox/MakeGameData/imaadpcm.cpp b/utils/xbox/MakeGameData/imaadpcm.cpp new file mode 100644 index 0000000..6648669 --- /dev/null +++ b/utils/xbox/MakeGameData/imaadpcm.cpp @@ -0,0 +1,1531 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +/*************************************************************************** + * + * Copyright (C) 2001 Microsoft Corporation. All Rights Reserved. + * + * File: imaadpcm.cpp + * Content: IMA ADPCM CODEC. + * History: + * Date By Reason + * ==== == ====== + * 04/29/01 dereks Created. + * 06/12/01 jharding Adapted for command-line encode + * + ****************************************************************************/ + +#include <stdio.h> +#include <wtypes.h> +#include <assert.h> +#include "imaadpcm.h" + +// 1/2 the range of the searchable step indices +// for a particular block when optimizing on a +// per-block basis. Widening or narrowing this +// range may produce better/worse encodings. +// Experimentation may be necessary. Higher values +// cause each block to be encoded better, but may +// produce popping in particularly fast attacks across +// blocks, while smaller values limit the number +// of encodings you consider +#define STEPINDEXSEARCHRANGE (24) + +/**************************************************************************** + * + * CImaAdpcmCodec + * + * Description: + * Object constructor. + * + * Arguments: + * (void) + * + * Returns: + * (void) + * + ****************************************************************************/ + +// +// This array is used by NextStepIndex to determine the next step index to use. +// The step index is an index to the m_asStep[] array, below. +// + +const short CImaAdpcmCodec::m_asNextStep[16] = +{ + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +// +// This array contains the array of step sizes used to encode the ADPCM +// samples. The step index in each ADPCM block is an index to this array. +// + +const short CImaAdpcmCodec::m_asStep[89] = +{ + 7, 8, 9, 10, 11, 12, 13, + 14, 16, 17, 19, 21, 23, 25, + 28, 31, 34, 37, 41, 45, 50, + 55, 60, 66, 73, 80, 88, 97, + 107, 118, 130, 143, 157, 173, 190, + 209, 230, 253, 279, 307, 337, 371, + 408, 449, 494, 544, 598, 658, 724, + 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, + 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, + 11487, 12635, 13899, 15289, 16818, 18500, 20350, + 22385, 24623, 27086, 29794, 32767 +}; + +CImaAdpcmCodec::CImaAdpcmCodec +( + void +) +{ +} + + +/**************************************************************************** + * + * ~CImaAdpcmCodec + * + * Description: + * Object destructor. + * + * Arguments: + * (void) + * + * Returns: + * (void) + * + ****************************************************************************/ + +CImaAdpcmCodec::~CImaAdpcmCodec +( + void +) +{ +} + + +/**************************************************************************** + * + * Initialize + * + * Description: + * Initializes the object. + * + * Arguments: + * LPCIMAADPCMWAVEFORMAT [in]: encoded data format. + * BOOL [in]: TRUE to initialize the object as an encoder. + * + * Returns: + * BOOL: TRUE on success. + * + ****************************************************************************/ + +BOOL +CImaAdpcmCodec::Initialize +( + LPCIMAADPCMWAVEFORMAT pwfxEncode, + CODEC_MODE cmCodecMode +) +{ + static const LPFNIMAADPCMCONVERT apfnConvert[2][2] = + { + { + DecodeM16, + DecodeS16 + }, + { + EncodeM16, + EncodeS16 + } + }; + + if(!IsValidImaAdpcmFormat(pwfxEncode)) + { + return FALSE; + } + + // + // Save the format data + // + + m_wfxEncode = *pwfxEncode; + m_cmCodecMode = cmCodecMode; + + // + // Set up the conversion function + // + + m_pfnConvert = apfnConvert[!(m_cmCodecMode == CODEC_MODE_DECODE)][m_wfxEncode.wfx.nChannels - 1]; + + // + // Initialize the stepping indices + // + + m_nStepIndexL = m_nStepIndexR = 0; + + return TRUE; +} + + +/**************************************************************************** + * + * Convert + * + * Description: + * Converts data from the source to destination format. + * + * Arguments: + * LPCVOID [in]: source buffer. + * LPVOID [out]: destination buffer. + * UINT [in]: block count. + * + * Returns: + * BOOL: TRUE on success. + * + ****************************************************************************/ + +BOOL +CImaAdpcmCodec::Convert +( + LPCVOID pvSrc, + LPVOID pvDst, + UINT cBlocks +) +{ + // Array of decoders + static const LPFNIMAADPCMCONVERT apfnDecoders[2] = + { + DecodeM16, + DecodeS16 + }; + + // Both destination and source block sizes + DWORD dwSrcBlockSize = m_wfxEncode.wfx.nChannels * m_wfxEncode.wSamplesPerBlock * sizeof(short); + DWORD dwDstBlockSize = m_wfxEncode.wfx.nBlockAlign; + + // Zero out the output + ZeroMemory( pvDst, cBlocks * dwDstBlockSize ); + + switch( m_cmCodecMode ) + { + case CODEC_MODE_DECODE: + // If we are decoding, just do it + return m_pfnConvert( (LPBYTE)pvSrc, (LPBYTE)pvDst, cBlocks, m_wfxEncode.wfx.nBlockAlign, m_wfxEncode.wSamplesPerBlock, &m_nStepIndexL, &m_nStepIndexR ); + + case CODEC_MODE_ENCODE_NORMAL: + // Normal encode + // We have some output right now, so this becomes a separate case. + // Otherwise, it would be the same as CODEC_MODE_DECODE + { + printf("Using normal encoding...\n"); + + // Allocate temporary buffers + LPBYTE pvDecoded = new BYTE[cBlocks * dwSrcBlockSize]; + if( !pvDecoded ) + return FALSE; + + // Find the decoder + LPFNIMAADPCMCONVERT pfnOppConvert; + pfnOppConvert = apfnDecoders[m_wfxEncode.wfx.nChannels - 1]; + + // Encode the stream + if( !m_pfnConvert( (LPBYTE)pvSrc, (LPBYTE)pvDst, cBlocks, m_wfxEncode.wfx.nBlockAlign, m_wfxEncode.wSamplesPerBlock, &m_nStepIndexL, &m_nStepIndexR ) ) + { + delete[] pvDecoded; + return FALSE; + } + + // Decode it back + if( !pfnOppConvert( (LPBYTE)pvDst, pvDecoded, cBlocks, m_wfxEncode.wfx.nBlockAlign, XBOX_ADPCM_SAMPLES_PER_BLOCK, &m_nStepIndexL, &m_nStepIndexR ) ) + { + delete[] pvDecoded; + return FALSE; + } + + // Report the normal difference + printf( "Difference between original and decoded streams: 0x%I64x\n", + CalcDifference( (LPBYTE)pvSrc, pvDecoded, cBlocks, cBlocks, dwSrcBlockSize ) ); + + delete[] pvDecoded; + } + break; + + case CODEC_MODE_ENCODE_OPTIMIZE_WHOLE_FILE: + // Optimize whole file encode + // Encode the file with each possible starting step index + // and pick the best one + { + printf("Using whole file encoding...\n"); + + // Allocate temporary buffers + LPBYTE pvTempDst = new BYTE[cBlocks * dwDstBlockSize]; + if(!pvTempDst) + return FALSE; + + LPBYTE pvDecoded = new BYTE[cBlocks * dwSrcBlockSize]; + if(!pvDecoded) + { + delete[] pvTempDst; + return FALSE; + } + + // Find the decoder + LPFNIMAADPCMCONVERT pfnOppConvert; + pfnOppConvert = apfnDecoders[m_wfxEncode.wfx.nChannels - 1]; + + // Keep track of the best encoding, as well as the chosen step index + ULONGLONG ullLeastDiff = (ULONGLONG)-1; + UINT uChosen = (UINT)-1; + + // Encode the entire stream with each step index and choose the best one + for( UINT i = 0; i < ARRAYSIZE(m_asStep); ++i ) + { + ZeroMemory( pvTempDst, cBlocks * dwDstBlockSize ); + ZeroMemory( pvDecoded, cBlocks * dwSrcBlockSize ); + + // Encode + m_nStepIndexL = m_nStepIndexR = i; + if( !m_pfnConvert( (LPBYTE)pvSrc, pvTempDst, cBlocks, m_wfxEncode.wfx.nBlockAlign, m_wfxEncode.wSamplesPerBlock, &m_nStepIndexL, &m_nStepIndexR ) ) + continue; + + // Decode + if( !pfnOppConvert( pvTempDst, pvDecoded, cBlocks, m_wfxEncode.wfx.nBlockAlign, XBOX_ADPCM_SAMPLES_PER_BLOCK, &m_nStepIndexL, &m_nStepIndexR ) ) + continue; + + // Diff + ULONGLONG ullDiff = CalcDifference( (LPBYTE)pvSrc, pvDecoded, cBlocks, cBlocks, dwSrcBlockSize ); + if( ullDiff < ullLeastDiff ) + { + ullLeastDiff = ullDiff; + uChosen = i; + CopyMemory( (LPBYTE)pvDst, pvTempDst, cBlocks * dwDstBlockSize ); + } + } + + // Report the optimized difference + printf( "Difference between original and decoded streams: 0x%I64x\n", ullLeastDiff ); + printf( "Step index chosen: %d\n", uChosen ); + + delete[] pvTempDst; + delete[] pvDecoded; + } + break; + + case CODEC_MODE_ENCODE_OPTIMIZE_EACH_BLOCK: + // Optimize per block encode + // Encode each block within the file with each + // possible starting step index and pick the + // best one for each block + { + printf("Using per-block encoding\n\n"); + + // Allocate temporary buffers + LPBYTE pvTempDst = new BYTE[dwDstBlockSize]; + if( !pvTempDst ) + return FALSE; + + LPBYTE pvDecoded = new BYTE[dwSrcBlockSize]; + if( !pvDecoded ) + { + delete[] pvTempDst; + return FALSE; + } + + // Find the decoder + LPFNIMAADPCMCONVERT pfnOppConvert; + pfnOppConvert = apfnDecoders[m_wfxEncode.wfx.nChannels - 1]; + + // We keep track of the best step index of the previous block + // This enables us to search a small range of values close to + // this value (the size of 2*STEPINDEXSEARCHRANGE) + // To begin, the previous block's best step index was -1. + INT iPreviousBestStepIndex = -1; + + for( UINT c = 0; c < cBlocks; ++c ) + { + ULONGLONG ullLeastDiff = (ULONGLONG)-1; + INT iThisBestStepIndex = -1; + INT iStartIndex, iStopIndex; + + // Setup the start/stop indices properly + if( iPreviousBestStepIndex == -1 ) + { + // If the previous best step index is -1, + // then we haven't yet encoded a block. Search + // through the entire range of step indices, + // rather than just in a limited range + iStartIndex = 0; + iStopIndex = ARRAYSIZE( m_asStep ); + } + else + { + // Keep the range of indices to search limited + // to around the previously chosen step index + iStartIndex = iPreviousBestStepIndex - STEPINDEXSEARCHRANGE; + iStopIndex = iPreviousBestStepIndex + STEPINDEXSEARCHRANGE + 1; + } + + // Try each step index in the searchable range and choose the best one + // for this block + for( INT i = iStartIndex; i < iStopIndex; ++i ) + { + // Don't consider anything out of range + if( i < 0 || i >= ARRAYSIZE( m_asStep ) ) + continue; + + // Zero out the temporary buffers + ZeroMemory( pvTempDst, dwDstBlockSize ); + ZeroMemory( pvDecoded, dwSrcBlockSize ); + + // Encode + m_nStepIndexL = m_nStepIndexR = i; + if( !m_pfnConvert( (LPBYTE)pvSrc + c*dwSrcBlockSize, pvTempDst, 1, m_wfxEncode.wfx.nBlockAlign, m_wfxEncode.wSamplesPerBlock, &m_nStepIndexL, &m_nStepIndexR ) ) + continue; + + // Decode + if( !pfnOppConvert( pvTempDst, pvDecoded, 1, m_wfxEncode.wfx.nBlockAlign, XBOX_ADPCM_SAMPLES_PER_BLOCK, &m_nStepIndexL, &m_nStepIndexR ) ) + continue; + + // Diff + ULONGLONG ullDiff = CalcDifference( (LPBYTE)pvSrc + c*dwSrcBlockSize, pvDecoded, 1, cBlocks, dwSrcBlockSize ); + if( ullDiff < ullLeastDiff ) + { + ullLeastDiff = ullDiff; + iThisBestStepIndex = i; + CopyMemory( (LPBYTE)pvDst + c*dwDstBlockSize, (LPBYTE)pvTempDst, dwDstBlockSize ); + } + } + + // Save the best step index for this block + iPreviousBestStepIndex = iThisBestStepIndex; + } + + delete[] pvTempDst; + delete[] pvDecoded; + + // Report on the optimized difference + pvDecoded = new BYTE[cBlocks * dwSrcBlockSize]; + pfnOppConvert( (LPBYTE)pvDst, pvDecoded, cBlocks, m_wfxEncode.wfx.nBlockAlign, XBOX_ADPCM_SAMPLES_PER_BLOCK, &m_nStepIndexL, &m_nStepIndexR ); + printf( "Difference between original and decoded streams: 0x%I64x\n", CalcDifference( (LPBYTE)pvSrc, pvDecoded, cBlocks, cBlocks, dwSrcBlockSize ) ); + + delete[] pvDecoded; + } + break; + } + + return TRUE; +} + + +/**************************************************************************** + * + * Reset + * + * Description: + * Resets the conversion operation. + * + * Arguments: + * (void) + * + * Returns: + * (void) + * + ****************************************************************************/ + +void +CImaAdpcmCodec::Reset +( + void +) +{ + // + // Reset the stepping indices + // + + m_nStepIndexL = m_nStepIndexR = 0; +} + + +/**************************************************************************** + * + * GetEncodeAlignment + * + * Description: + * Gets the alignment of an encoded buffer. + * + * Arguments: + * (void) + * + * Returns: + * WORD: alignment, in bytes. + * + ****************************************************************************/ + +WORD +CImaAdpcmCodec::GetEncodeAlignment +( + void +) +{ + return m_wfxEncode.wfx.nBlockAlign; +} + + +/**************************************************************************** + * + * GetDecodeAlignment + * + * Description: + * Gets the alignment of a decoded buffer. + * + * Arguments: + * (void) + * + * Returns: + * DWORD: alignment, in bytes. + * + ****************************************************************************/ + +WORD +CImaAdpcmCodec::GetDecodeAlignment +( + void +) +{ + return m_wfxEncode.wSamplesPerBlock * m_wfxEncode.wfx.nChannels * IMAADPCM_PCM_BITS_PER_SAMPLE / 8; +} + + +/**************************************************************************** + * + * CalculateEncodeAlignment + * + * Description: + * Calculates an encoded data block alignment based on a PCM sample + * count and an alignment multiplier. + * + * Arguments: + * WORD [in]: channel count. + * WORD [in]: PCM samples per block. + * + * Returns: + * WORD: alignment, in bytes. + * + ****************************************************************************/ + +WORD +CImaAdpcmCodec::CalculateEncodeAlignment +( + WORD nChannels, + WORD nSamplesPerBlock +) +{ + const WORD nEncodedSampleBits = nChannels * IMAADPCM_BITS_PER_SAMPLE; + const WORD nHeaderBytes = nChannels * IMAADPCM_HEADER_LENGTH; + INT nBlockAlign; + + // + // Calculate the raw block alignment that nSamplesPerBlock dictates. This + // value may include a partial encoded sample, so be sure to round up. + // + // Start with the samples-per-block, minus 1. The first sample is actually + // stored in the header. + // + + nBlockAlign = nSamplesPerBlock - 1; + + // + // Convert to encoded sample size + // + + nBlockAlign *= nEncodedSampleBits; + nBlockAlign += 7; + nBlockAlign /= 8; + + // + // The stereo encoder requires that there be at least two DWORDs to process + // + + nBlockAlign += 7; + nBlockAlign /= 8; + nBlockAlign *= 8; + + // + // Add the header + // + + nBlockAlign += nHeaderBytes; + + // We used an INT temporarily, but the final result should fit into a WORD + assert( nBlockAlign < 0xFFFF ); + return (WORD)nBlockAlign; +} + + +/**************************************************************************** + * + * CreatePcmFormat + * + * Description: + * Creates a PCM format descriptor. + * + * Arguments: + * WORD [in]: channel count. + * DWORD [in]: sampling rate. + * LPWAVEFORMATEX [out]: format descriptor. + * + * Returns: + * (void) + * + ****************************************************************************/ + +void +CImaAdpcmCodec::CreatePcmFormat +( + WORD nChannels, + DWORD nSamplesPerSec, + LPWAVEFORMATEX pwfx +) +{ + pwfx->wFormatTag = WAVE_FORMAT_PCM; + pwfx->nChannels = nChannels; + pwfx->nSamplesPerSec = nSamplesPerSec; + pwfx->nBlockAlign = nChannels * IMAADPCM_PCM_BITS_PER_SAMPLE / 8; + pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec; + pwfx->wBitsPerSample = IMAADPCM_PCM_BITS_PER_SAMPLE; +} + + +/**************************************************************************** + * + * CreateImaAdpcmFormat + * + * Description: + * Creates an IMA ADPCM format descriptor. + * + * Arguments: + * WORD [in]: channel count. + * DWORD [in]: sampling rate. + * LPIMAADPCMWAVEFORMAT [out]: format descriptor. + * + * Returns: + * (void) + * + ****************************************************************************/ + +void +CImaAdpcmCodec::CreateImaAdpcmFormat +( + WORD nChannels, + DWORD nSamplesPerSec, + WORD nSamplesPerBlock, + LPIMAADPCMWAVEFORMAT pwfx +) +{ + pwfx->wfx.wFormatTag = WAVE_FORMAT_XBOX_ADPCM; + pwfx->wfx.nChannels = nChannels; + pwfx->wfx.nSamplesPerSec = nSamplesPerSec; + pwfx->wfx.nBlockAlign = CalculateEncodeAlignment(nChannels, nSamplesPerBlock); + pwfx->wfx.nAvgBytesPerSec = nSamplesPerSec * pwfx->wfx.nBlockAlign / nSamplesPerBlock; + pwfx->wfx.wBitsPerSample = IMAADPCM_BITS_PER_SAMPLE; + pwfx->wfx.cbSize = sizeof(*pwfx) - sizeof(pwfx->wfx); + pwfx->wSamplesPerBlock = nSamplesPerBlock; +} + + +/**************************************************************************** + * + * IsValidPcmFormat + * + * Description: + * Validates a format structure. + * + * Arguments: + * LPCWAVEFORMATEX [in]: format. + * + * Returns: + * BOOL: TRUE on success. + * + ****************************************************************************/ + +BOOL +CImaAdpcmCodec::IsValidPcmFormat +( + LPCWAVEFORMATEX pwfx +) +{ + if(WAVE_FORMAT_PCM != pwfx->wFormatTag) + { + return FALSE; + } + + if((pwfx->nChannels < 1) || (pwfx->nChannels > IMAADPCM_MAX_CHANNELS)) + { + return FALSE; + } + + if(IMAADPCM_PCM_BITS_PER_SAMPLE != pwfx->wBitsPerSample) + { + return FALSE; + } + + if(pwfx->nChannels * pwfx->wBitsPerSample / 8 != pwfx->nBlockAlign) + { + return FALSE; + } + + if(pwfx->nBlockAlign * pwfx->nSamplesPerSec != pwfx->nAvgBytesPerSec) + { + return FALSE; + } + + return TRUE; +} + + +/**************************************************************************** + * + * IsValidXboxAdpcmFormat + * + * Description: + * Validates a format structure. + * + * Arguments: + * LPCIMAADPCMWAVEFORMAT [in]: format. + * + * Returns: + * BOOL: TRUE on success. + * + ****************************************************************************/ + +BOOL +CImaAdpcmCodec::IsValidImaAdpcmFormat +( + LPCIMAADPCMWAVEFORMAT pwfx +) +{ + if(WAVE_FORMAT_XBOX_ADPCM != pwfx->wfx.wFormatTag) + { + return FALSE; + } + + if(sizeof(*pwfx) - sizeof(pwfx->wfx) != pwfx->wfx.cbSize) + { + return FALSE; + } + + if((pwfx->wfx.nChannels < 1) || (pwfx->wfx.nChannels > IMAADPCM_MAX_CHANNELS)) + { + return FALSE; + } + + if(IMAADPCM_BITS_PER_SAMPLE != pwfx->wfx.wBitsPerSample) + { + return FALSE; + } + + if(CalculateEncodeAlignment(pwfx->wfx.nChannels, pwfx->wSamplesPerBlock) != pwfx->wfx.nBlockAlign) + { + return FALSE; + } + + return TRUE; +} + + +/**************************************************************************** + * + * CalcDifference + * + * Description: + * Calculates the error between two audio buffers. The error is clamped + * at (ULONGLONG)-1. Also, the error of a block acts as a percentage of + * the maximum possible contribution of a block. + * + * Arguments: + * LPBYTE [in]: First buffer + * LPBYTE [in]: Second buffer + * UINT [in]: Number of blocks-worth to compare + * UINT [in]: Total number of blocks being converted + * DWORD [in]: Size of a single block in bytes + * + * Returns: + * ULONGLONG: Difference of the two buffers + * + ****************************************************************************/ +ULONGLONG CImaAdpcmCodec::CalcDifference(LPBYTE pvBuffer1, LPBYTE pvBuffer2, UINT cBlocks, UINT cTotalBlocks, DWORD dwBlockSize) +{ + ULONGLONG ullDiff = 0; + + // Each block worth of error can contribute a maximum of this value + const ULONGLONG ullMaxBlockContribution = ( (ULONGLONG)-1 / cTotalBlocks ); + + // The maximum error in a block is + // (2^16)^2 * m_wfxEncode.wSamplesPerBlock + // = ( 1 << 32 ) * m_wfxEncode.wSamplesPerBlock + const ULONGLONG ullMaxBlockDiff = ( (ULONGLONG)1 << 32 ) * m_wfxEncode.wSamplesPerBlock; + + // Now we go through the buffers sample by sample and find the difference + // on a block-by-block basis. The factored difference of a block is + // ullBlockDiff / ullMaxBlockDiff * ullMaxBlockContribution + for( UINT i = 0; i < cBlocks; ++i ) + { + PSHORT pSamples1 = (PSHORT)(pvBuffer1 + i * dwBlockSize); + PSHORT pSamples2 = (PSHORT)(pvBuffer2 + i * dwBlockSize); + ULONGLONG ullBlockDiff = 0; + + // Find the block difference + for( UINT j = 0; j < m_wfxEncode.wSamplesPerBlock; ++j ) + { + ULONGLONG ullSampleDiff = (ULONGLONG)(pSamples2[j]) - (ULONGLONG)(pSamples1[j]); + ullBlockDiff += ( ullSampleDiff * ullSampleDiff ); + } + + // Assert that we didn't go over the maximum possible + assert( ullBlockDiff <= ullMaxBlockDiff ); + + // Add the contribution of this block to the error + ullDiff += (ULONGLONG)( ( (DOUBLE)ullBlockDiff / (DOUBLE)ullMaxBlockDiff ) * ullMaxBlockContribution ); + } + + assert( ullDiff <= cBlocks * ullMaxBlockContribution ); + + return ullDiff; +} + + +/**************************************************************************** + * + * EncodeSample + * + * Description: + * Encodes a sample. + * + * Arguments: + * int [in]: the sample to be encoded. + * LPINT [in/out]: the predicted value of the sample. + * int [in]: the quantization step size used to encode the sample. + * + * Returns: + * int: the encoded ADPCM sample. + * + ****************************************************************************/ + +int +CImaAdpcmCodec::EncodeSample +( + int nInputSample, + LPINT pnPredictedSample, + int nStepSize +) +{ + int nPredictedSample; + LONG lDifference; + int nEncodedSample; + + nPredictedSample = *pnPredictedSample; + + lDifference = nInputSample - nPredictedSample; + nEncodedSample = 0; + + if(lDifference < 0) + { + nEncodedSample = 8; + lDifference = -lDifference; + } + + if(lDifference >= nStepSize) + { + nEncodedSample |= 4; + lDifference -= nStepSize; + } + + nStepSize >>= 1; + + if(lDifference >= nStepSize) + { + nEncodedSample |= 2; + lDifference -= nStepSize; + } + + nStepSize >>= 1; + + if(lDifference >= nStepSize) + { + nEncodedSample |= 1; + lDifference -= nStepSize; + } + + if(nEncodedSample & 8) + { + nPredictedSample = nInputSample + lDifference - (nStepSize >> 1); + } + else + { + nPredictedSample = nInputSample - lDifference + (nStepSize >> 1); + } + + if(nPredictedSample > 32767) + { + nPredictedSample = 32767; + } + else if(nPredictedSample < -32768) + { + nPredictedSample = -32768; + } + + *pnPredictedSample = nPredictedSample; + + return nEncodedSample; +} + + +/**************************************************************************** + * + * DecodeSample + * + * Description: + * Decodes an encoded sample. + * + * Arguments: + * int [in]: the sample to be decoded. + * int [in]: the predicted value of the sample. + * int [i]: the quantization step size used to encode the sample. + * + * Returns: + * int: the decoded PCM sample. + * + ****************************************************************************/ + +int +CImaAdpcmCodec::DecodeSample +( + int nEncodedSample, + int nPredictedSample, + int nStepSize +) +{ + LONG lDifference; + LONG lNewSample; + + lDifference = nStepSize >> 3; + + if(nEncodedSample & 4) + { + lDifference += nStepSize; + } + + if(nEncodedSample & 2) + { + lDifference += nStepSize >> 1; + } + + if(nEncodedSample & 1) + { + lDifference += nStepSize >> 2; + } + + if(nEncodedSample & 8) + { + lDifference = -lDifference; + } + + lNewSample = nPredictedSample + lDifference; + + if((LONG)(short)lNewSample != lNewSample) + { + if(lNewSample < -32768) + { + lNewSample = -32768; + } + else + { + lNewSample = 32767; + } + } + + return (int)lNewSample; +} + + +/**************************************************************************** + * + * Conversion Routines + * + * Description: + * Converts a PCM buffer to ADPCM, or the reverse. + * + * Arguments: + * LPBYTE [in]: source buffer. + * LPBYTE [out]: destination buffer. + * UINT [in]: block count. + * UINT [in]: block alignment of the ADPCM data, in bytes. + * UINT [in]: the number of samples in each ADPCM block (not used in + * decoding). + * LPINT [in/out]: left-channel stepping index. + * LPINT [in/out]: right-channel stepping index. + * + * Returns: + * BOOL: TRUE on success. + * + ****************************************************************************/ + +BOOL +CImaAdpcmCodec::EncodeM16 +( + LPBYTE pbSrc, + LPBYTE pbDst, + UINT cBlocks, + UINT nBlockAlignment, + UINT cSamplesPerBlock, + LPINT pnStepIndexL, + LPINT +) +{ + LPBYTE pbBlock; + UINT cSamples; + int nSample; + int nStepSize; + int nEncSample1; + int nEncSample2; + int nPredSample; + int nStepIndex; + + // + // Save a local copy of the step index so we're not constantly + // dereferencing a pointer. + // + + nStepIndex = *pnStepIndexL; + + // + // Enter the main loop + // + + while(cBlocks--) + { + pbBlock = pbDst; + cSamples = cSamplesPerBlock - 1; + + // + // Block header + // + + nPredSample = *(short *)pbSrc; + pbSrc += sizeof(short); + + *(LONG *)pbBlock = MAKELONG(nPredSample, nStepIndex); + pbBlock += sizeof(LONG); + + // + // We have written the header for this block--now write the data + // chunk (which consists of a bunch of encoded nibbles). Note + // that if we don't have enough data to fill a complete byte, then + // we add a 0 nibble on the end. + // + + while(cSamples) + { + // + // Sample 1 + // + + nSample = *(short *)pbSrc; + pbSrc += sizeof(short); + cSamples--; + + nStepSize = m_asStep[nStepIndex]; + nEncSample1 = EncodeSample(nSample, &nPredSample, nStepSize); + nStepIndex = NextStepIndex(nEncSample1, nStepIndex); + + // + // Sample 2 + // + + if(cSamples) + { + nSample = *(short *)pbSrc; + pbSrc += sizeof(short); + cSamples--; + + nStepSize = m_asStep[nStepIndex]; + nEncSample2 = EncodeSample(nSample, &nPredSample, nStepSize); + nStepIndex = NextStepIndex(nEncSample2, nStepIndex); + } + else + { + nEncSample2 = 0; + } + + // + // Write out encoded byte. + // + + *pbBlock++ = (BYTE)(nEncSample1 | (nEncSample2 << 4)); + } + + // + // Skip padding + // + + pbDst += nBlockAlignment; + } + + // + // Restore the value of the step index to be used on the next buffer. + // + + *pnStepIndexL = nStepIndex; + + return TRUE; +} + + +BOOL +CImaAdpcmCodec::EncodeS16 +( + LPBYTE pbSrc, + LPBYTE pbDst, + UINT cBlocks, + UINT nBlockAlignment, + UINT cSamplesPerBlock, + LPINT pnStepIndexL, + LPINT pnStepIndexR +) +{ + LPBYTE pbBlock; + UINT cSamples; + UINT cSubSamples; + int nSample; + int nStepSize; + DWORD dwLeft; + DWORD dwRight; + int nEncSampleL; + int nPredSampleL; + int nStepIndexL; + int nEncSampleR; + int nPredSampleR; + int nStepIndexR; + UINT i; + + // + // Save a local copy of the step indices so we're not constantly + // dereferencing a pointer. + // + + nStepIndexL = *pnStepIndexL; + nStepIndexR = *pnStepIndexR; + + // + // Enter the main loop + // + + while(cBlocks--) + { + pbBlock = pbDst; + cSamples = cSamplesPerBlock - 1; + + // + // LEFT channel block header + // + + nPredSampleL = *(short *)pbSrc; + pbSrc += sizeof(short); + + *(LONG *)pbBlock = MAKELONG(nPredSampleL, nStepIndexL); + pbBlock += sizeof(LONG); + + // + // RIGHT channel block header + // + + nPredSampleR = *(short *)pbSrc; + pbSrc += sizeof(short); + + *(LONG *)pbBlock = MAKELONG(nPredSampleR, nStepIndexR); + pbBlock += sizeof(LONG); + + // + // We have written the header for this block--now write the data + // chunk. This consists of 8 left samples (one DWORD of output) + // followed by 8 right samples (also one DWORD). Since the input + // samples are interleaved, we create the left and right DWORDs + // sample by sample, and then write them both out. + // + + while(cSamples) + { + dwLeft = 0; + dwRight = 0; + + cSubSamples = min(cSamples, 8); + + for(i = 0; i < cSubSamples; i++) + { + // + // LEFT channel + // + + nSample = *(short *)pbSrc; + pbSrc += sizeof(short); + + nStepSize = m_asStep[nStepIndexL]; + + nEncSampleL = EncodeSample(nSample, &nPredSampleL, nStepSize); + + nStepIndexL = NextStepIndex(nEncSampleL, nStepIndexL); + dwLeft |= (DWORD)nEncSampleL << (4 * i); + + // + // RIGHT channel + // + + nSample = *(short *)pbSrc; + pbSrc += sizeof(short); + + nStepSize = m_asStep[nStepIndexR]; + + nEncSampleR = EncodeSample(nSample, &nPredSampleR, nStepSize); + + nStepIndexR = NextStepIndex(nEncSampleR, nStepIndexR); + dwRight |= (DWORD)nEncSampleR << (4 * i); + } + + // + // Write out encoded DWORDs. + // + + *(LPDWORD)pbBlock = dwLeft; + pbBlock += sizeof(DWORD); + + *(LPDWORD)pbBlock = dwRight; + pbBlock += sizeof(DWORD); + + cSamples -= cSubSamples; + } + + // + // Skip padding + // + + pbDst += nBlockAlignment; + } + + // + // Restore the value of the step index to be used on the next buffer. + // + + *pnStepIndexL = nStepIndexL; + *pnStepIndexR = nStepIndexR; + + return TRUE; + +} + + +BOOL +CImaAdpcmCodec::DecodeM16 +( + LPBYTE pbSrc, + LPBYTE pbDst, + UINT cBlocks, + UINT nBlockAlignment, + UINT cSamplesPerBlock, + LPINT, + LPINT +) +{ + BOOL fSuccess = TRUE; + LPBYTE pbBlock; + UINT cSamples; + BYTE bSample; + int nStepSize; + int nEncSample; + int nPredSample; + int nStepIndex; + DWORD dwHeader; + + // + // Enter the main loop + // + + while(cBlocks--) + { + pbBlock = pbSrc; + cSamples = cSamplesPerBlock - 1; + + // + // Block header + // + + dwHeader = *(LPDWORD)pbBlock; + pbBlock += sizeof(DWORD); + + nPredSample = (int)(short)LOWORD(dwHeader); + nStepIndex = (int)(BYTE)HIWORD(dwHeader); + + if(!ValidStepIndex(nStepIndex)) + { + // + // The step index is out of range - this is considered a fatal + // error as the input stream is corrupted. We fail by returning + // zero bytes converted. + // + + fSuccess = FALSE; + break; + } + + // + // Write out first sample + // + + *(short *)pbDst = (short)nPredSample; + pbDst += sizeof(short); + + // + // Enter the block loop + // + + while(cSamples) + { + bSample = *pbBlock++; + + // + // Sample 1 + // + + nEncSample = (bSample & (BYTE)0x0F); + nStepSize = m_asStep[nStepIndex]; + nPredSample = DecodeSample(nEncSample, nPredSample, nStepSize); + nStepIndex = NextStepIndex(nEncSample, nStepIndex); + + *(short *)pbDst = (short)nPredSample; + pbDst += sizeof(short); + + cSamples--; + + // + // Sample 2 + // + + if(cSamples) + { + nEncSample = (bSample >> 4); + nStepSize = m_asStep[nStepIndex]; + nPredSample = DecodeSample(nEncSample, nPredSample, nStepSize); + nStepIndex = NextStepIndex(nEncSample, nStepIndex); + + *(short *)pbDst = (short)nPredSample; + pbDst += sizeof(short); + + cSamples--; + } + } + + // + // Skip padding + // + + pbSrc += nBlockAlignment; + } + + return fSuccess; +} + + +BOOL +CImaAdpcmCodec::DecodeS16 +( + LPBYTE pbSrc, + LPBYTE pbDst, + UINT cBlocks, + UINT nBlockAlignment, + UINT cSamplesPerBlock, + LPINT, + LPINT +) +{ + BOOL fSuccess = TRUE; + LPBYTE pbBlock; + UINT cSamples; + UINT cSubSamples; + int nStepSize; + DWORD dwHeader; + DWORD dwLeft; + DWORD dwRight; + int nEncSampleL; + int nPredSampleL; + int nStepIndexL; + int nEncSampleR; + int nPredSampleR; + int nStepIndexR; + UINT i; + + // + // Enter the main loop + // + + while(cBlocks--) + { + pbBlock = pbSrc; + cSamples = cSamplesPerBlock - 1; + + // + // LEFT channel header + // + + dwHeader = *(LPDWORD)pbBlock; + pbBlock += sizeof(DWORD); + + nPredSampleL = (int)(short)LOWORD(dwHeader); + nStepIndexL = (int)(BYTE)HIWORD(dwHeader); + + if(!ValidStepIndex(nStepIndexL)) + { + // + // The step index is out of range - this is considered a fatal + // error as the input stream is corrupted. We fail by returning + // zero bytes converted. + // + + fSuccess = FALSE; + break; + } + + // + // RIGHT channel header + // + + dwHeader = *(LPDWORD)pbBlock; + pbBlock += sizeof(DWORD); + + nPredSampleR = (int)(short)LOWORD(dwHeader); + nStepIndexR = (int)(BYTE)HIWORD(dwHeader); + + if(!ValidStepIndex(nStepIndexR)) + { + // + // The step index is out of range - this is considered a fatal + // error as the input stream is corrupted. We fail by returning + // zero bytes converted. + // + + fSuccess = FALSE; + break; + } + + // + // Write out first sample + // + + *(LPDWORD)pbDst = MAKELONG(nPredSampleL, nPredSampleR); + pbDst += sizeof(DWORD); + + // + // The first DWORD contains 4 left samples, the second DWORD + // contains 4 right samples. We process the source in 8-byte + // chunks to make it easy to interleave the output correctly. + // + + while(cSamples) + { + dwLeft = *(LPDWORD)pbBlock; + pbBlock += sizeof(DWORD); + dwRight = *(LPDWORD)pbBlock; + pbBlock += sizeof(DWORD); + + cSubSamples = min(cSamples, 8); + + for(i = 0; i < cSubSamples; i++) + { + // + // LEFT channel + // + + nEncSampleL = (dwLeft & 0x0F); + nStepSize = m_asStep[nStepIndexL]; + nPredSampleL = DecodeSample(nEncSampleL, nPredSampleL, nStepSize); + nStepIndexL = NextStepIndex(nEncSampleL, nStepIndexL); + + // + // RIGHT channel + // + + nEncSampleR = (dwRight & 0x0F); + nStepSize = m_asStep[nStepIndexR]; + nPredSampleR = DecodeSample(nEncSampleR, nPredSampleR, nStepSize); + nStepIndexR = NextStepIndex(nEncSampleR, nStepIndexR); + + // + // Write out sample + // + + *(LPDWORD)pbDst = MAKELONG(nPredSampleL, nPredSampleR); + pbDst += sizeof(DWORD); + + // + // Shift the next input sample into the low-order 4 bits. + // + + dwLeft >>= 4; + dwRight >>= 4; + } + + cSamples -= cSubSamples; + } + + // + // Skip padding + // + + pbSrc += nBlockAlignment; + } + + return fSuccess; +} + + +int XboxADPCMSize( int sampleCount, int channelCount, int sampleRate ) +{ + CImaAdpcmCodec codec; + IMAADPCMWAVEFORMAT wfxEncode; + + // Create an APDCM format structure based off the source format + codec.CreateImaAdpcmFormat( (WORD)channelCount, sampleRate, XBOX_ADPCM_SAMPLES_PER_BLOCK, &wfxEncode ); + + // Calculate number of ADPCM blocks and length of ADPCM data + DWORD dwDestBlocks = sampleCount / XBOX_ADPCM_SAMPLES_PER_BLOCK; + DWORD dwDestLength = dwDestBlocks * wfxEncode.wfx.nBlockAlign; + + return dwDestLength; +} + +void Convert16ToXboxADPCM( const short *pInputBuffer, byte *pOutputBuffer, byte *pOutFormat, int sampleCount, int channelCount, int sampleRate ) +{ + CImaAdpcmCodec codec; + IMAADPCMWAVEFORMAT wfxEncode; + + // Create an APDCM format structure based off the source format + codec.CreateImaAdpcmFormat( (WORD)channelCount, sampleRate, XBOX_ADPCM_SAMPLES_PER_BLOCK, &wfxEncode ); + if ( pOutFormat ) + { + memcpy( pOutFormat, &wfxEncode, sizeof(wfxEncode) ); + } + + // Initialize the codec + if ( FALSE == codec.Initialize( &wfxEncode, CODEC_MODE_ENCODE_OPTIMIZE_EACH_BLOCK ) ) + { + printf( "Couldn't initialize codec.\n" ); + return; + } + + // Convert the data + DWORD dwDestBlocks = sampleCount / XBOX_ADPCM_SAMPLES_PER_BLOCK; + if ( FALSE == codec.Convert( (const byte *)pInputBuffer, pOutputBuffer, dwDestBlocks ) ) + return; +} diff --git a/utils/xbox/MakeGameData/imaadpcm.h b/utils/xbox/MakeGameData/imaadpcm.h new file mode 100644 index 0000000..a9fdd08 --- /dev/null +++ b/utils/xbox/MakeGameData/imaadpcm.h @@ -0,0 +1,153 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +/*************************************************************************** + * + * Copyright (C) 2001 Microsoft Corporation. All Rights Reserved. + * + * File: imaadpcm.h + * Content: IMA ADPCM CODEC. + * History: + * Date By Reason + * ==== == ====== + * 04/29/01 dereks Created. + * + ****************************************************************************/ + +#ifndef __IMAADPCM_H__ +#define __IMAADPCM_H__ + +#include <windows.h> +#include <windowsx.h> +#include <mmsystem.h> +#include <ctype.h> +#include <mmreg.h> +#include <msacm.h> + +#define XBOX_ADPCM_SAMPLES_PER_BLOCK 64 + +#define WAVE_FORMAT_XBOX_ADPCM 0x0069 + +#define IMAADPCM_BITS_PER_SAMPLE 4 +#define IMAADPCM_HEADER_LENGTH 4 + +#define IMAADPCM_MAX_CHANNELS 2 +#define IMAADPCM_PCM_BITS_PER_SAMPLE 16 + +#define NUMELMS(a) (sizeof(a) / sizeof(a[0])) + +typedef const WAVEFORMATEX *LPCWAVEFORMATEX; +typedef const IMAADPCMWAVEFORMAT *LPCIMAADPCMWAVEFORMAT; + +#ifdef __cplusplus + +// +// IMA ADPCM encoder function prototype +// + +typedef BOOL (*LPFNIMAADPCMCONVERT)(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR); + +// +// Codec mode +// + +enum CODEC_MODE +{ + CODEC_MODE_DECODE, + CODEC_MODE_ENCODE_NORMAL, + CODEC_MODE_ENCODE_OPTIMIZE_WHOLE_FILE, + CODEC_MODE_ENCODE_OPTIMIZE_EACH_BLOCK, +}; + +// +// IMA ADPCM CODEC +// + +class CImaAdpcmCodec +{ +private: + static const short m_asNextStep[16]; // Step increment array + static const short m_asStep[89]; // Step value array + IMAADPCMWAVEFORMAT m_wfxEncode; // Encoded format description + CODEC_MODE m_cmCodecMode; // Codec mode + int m_nStepIndexL; // Left-channel stepping index + int m_nStepIndexR; // Right-channel stepping index + LPFNIMAADPCMCONVERT m_pfnConvert; // Conversion function + +public: + CImaAdpcmCodec(void); + ~CImaAdpcmCodec(void); + +public: + // Initialization + BOOL Initialize(LPCIMAADPCMWAVEFORMAT pwfxEncode, CODEC_MODE cmCodecMode); + + // Size conversions + WORD GetEncodeAlignment(void); + WORD GetDecodeAlignment(void); + WORD GetSourceAlignment(void); + WORD GetDestinationAlignment(void); + + // Data conversions + BOOL Convert(LPCVOID pvSrc, LPVOID pvDst, UINT cBlocks); + void Reset(void); + + // Format descriptions + static void CreatePcmFormat(WORD nChannels, DWORD nSamplesPerSec, LPWAVEFORMATEX pwfxFormat); + static void CreateImaAdpcmFormat(WORD nChannels, DWORD nSamplesPerSec, WORD nSamplesPerBlock, LPIMAADPCMWAVEFORMAT pwfxFormat); + + static BOOL IsValidPcmFormat(LPCWAVEFORMATEX pwfxFormat); + static BOOL IsValidImaAdpcmFormat(LPCIMAADPCMWAVEFORMAT pwfxFormat); + +private: + // En/decoded data alignment + static WORD CalculateEncodeAlignment(WORD nSamplesPerBlock, WORD nChannels); + + // Data conversion functions + static BOOL EncodeM16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR); + static BOOL EncodeS16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR); + static BOOL DecodeM16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR); + static BOOL DecodeS16(LPBYTE pbSrc, LPBYTE pbDst, UINT cBlocks, UINT nBlockAlignment, UINT cSamplesPerBlock, LPINT pnStepIndexL, LPINT pnStepIndexR); + + static int EncodeSample(int nInputSample, int *nPredictedSample, int nStepSize); + static int DecodeSample(int nInputSample, int nPredictedSample, int nStepSize); + + static int NextStepIndex(int nEncodedSample, int nStepIndex); + static BOOL ValidStepIndex(int nStepIndex); + + /*static ULONGLONG CalcDifference(LPDWORD pvBuffer1, LPDWORD pvBuffer2, DWORD dwLength);*/ + ULONGLONG CalcDifference(LPBYTE pvBuffer1, LPBYTE pvBuffer2, UINT cBlocks, UINT cTotalBlocks, DWORD dwBlockSize); +}; + +__inline WORD CImaAdpcmCodec::GetSourceAlignment(void) +{ + return ( m_cmCodecMode == CODEC_MODE_DECODE ) ? GetEncodeAlignment() : GetDecodeAlignment(); +} + +__inline WORD CImaAdpcmCodec::GetDestinationAlignment(void) +{ + return ( m_cmCodecMode == CODEC_MODE_DECODE ) ? GetDecodeAlignment() : GetEncodeAlignment(); +} + +__inline int CImaAdpcmCodec::NextStepIndex(int nEncodedSample, int nStepIndex) +{ + nStepIndex += m_asNextStep[nEncodedSample]; + + if(nStepIndex < 0) + { + nStepIndex = 0; + } + else if(nStepIndex >= NUMELMS(m_asStep)) + { + nStepIndex = NUMELMS(m_asStep) - 1; + } + + return nStepIndex; +} + +__inline BOOL CImaAdpcmCodec::ValidStepIndex(int nStepIndex) +{ + return (nStepIndex >= 0) && (nStepIndex < NUMELMS(m_asStep)); +} + +#endif // __cplusplus + +#endif // __IMAADPCM_H__ diff --git a/utils/xbox/MakeGameData/resample.cpp b/utils/xbox/MakeGameData/resample.cpp new file mode 100644 index 0000000..a0ce0a7 --- /dev/null +++ b/utils/xbox/MakeGameData/resample.cpp @@ -0,0 +1,381 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// + +#include <windows.h> +#include <mmreg.h> +#include "../toollib/toollib.h" +#include "tier1/strtools.h" +#include "resample.h" + +#define clamp(a,b,c) ( (a) > (c) ? (c) : ( (a) < (b) ? (b) : (a) ) ) + +const int NUM_COEFFS = 7; +static const float g_ResampleCoefficients[NUM_COEFFS] = +{ + 0.0457281f, 0.168088f, 0.332501f, 0.504486f, 0.663202f, 0.803781f, 0.933856f +}; + + +// generates 1 output sample for 2 input samples +inline float DecimateSamplePair(float input0, float input1, const float pCoefficients[7], float xState[2], float yState[7] ) +{ + float tmp_0 = xState[0]; + float tmp_1 = xState[1]; + + xState[0] = input0; + xState[1] = input1; + + input0 = (input0 - yState[0]) * pCoefficients[0] + tmp_0; + input1 = (input1 - yState[1]) * pCoefficients[1] + tmp_1; + tmp_0 = yState[0]; + tmp_1 = yState[1]; + yState[0] = input0; + yState[1] = input1; + + input0 = (input0 - yState[2]) * pCoefficients[2] + tmp_0; + input1 = (input1 - yState[3]) * pCoefficients[3] + tmp_1; + tmp_0 = yState[2]; + tmp_1 = yState[3]; + yState[2] = input0; + yState[3] = input1; + + input0 = (input0 - yState[4]) * pCoefficients[4] + tmp_0; + input1 = (input1 - yState[5]) * pCoefficients[5] + tmp_1; + tmp_0 = yState[4]; + yState[4] = input0; + yState[5] = input1; + + input0 = (input0 - yState[6]) * pCoefficients[6] + tmp_0; + yState[6] = input0; + + return (input0 + input1); +} + +static void ExtractFloatSamples( float *pOut, const short *pInputBuffer, int sampleCount, int stride ) +{ + for ( int i = 0; i < sampleCount; i++ ) + { + pOut[i] = pInputBuffer[0] * 1.0f / 32768.0f; + pInputBuffer += stride; + } +} + +static void ExtractShortSamples( short *pOut, const float *pInputBuffer, float scale, int sampleCount, int stride ) +{ + for ( int i = 0; i < sampleCount; i++ ) + { + int sampleOut = (int)(pInputBuffer[i] * scale); + sampleOut = clamp( sampleOut, -32768, 32767 ); + + pOut[0] = (short)(sampleOut); + pOut += stride; + } +} + +struct decimatestate_t +{ + float xState[2]; + float yState[7]; +}; +void DecimateSampleBlock( float *pInOut, int sampleCount ) +{ + decimatestate_t block; + int outCount = sampleCount >> 1; + int pos = 0; + memset( &block, 0, sizeof(block) ); + do + { + float input0 = pInOut[pos*2+0]; + float input1 = pInOut[pos*2+1]; + pInOut[pos] = DecimateSamplePair( input0, input1, g_ResampleCoefficients, block.xState, block.yState ); + pos++; + } while( pos < outCount ); +} + +void DecimateSampleRateBy2_16( const short *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount ) +{ + float *pTmpBuf = new float[sampleCount]; + for ( int i = 0; i < channelCount; i++ ) + { + ExtractFloatSamples( pTmpBuf, pInputBuffer+i, sampleCount, channelCount ); + DecimateSampleBlock( pTmpBuf, sampleCount ); + ExtractShortSamples( pOutputBuffer+i, pTmpBuf, 0.5f * 32768.0f, sampleCount>>1, channelCount ); + } + delete [] pTmpBuf; +} + + +struct adpcmstate_t +{ + const ADPCMWAVEFORMAT *pFormat; + const ADPCMCOEFSET *pCoefficients; + int blockSize; +}; + +static int error_sign_lut[] = { 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1 }; +static int error_coefficients_lut[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 }; + +void ParseADPCM( adpcmstate_t &out, const byte *pFormatChunk ) +{ + out.pFormat = (const ADPCMWAVEFORMAT *)pFormatChunk; + if ( out.pFormat ) + { + out.pCoefficients = out.pFormat->aCoef; + + // number of bytes for samples + out.blockSize = ((out.pFormat->wSamplesPerBlock - 2) * out.pFormat->wfx.nChannels ) / 2; + // size of channel header + out.blockSize += 7 * out.pFormat->wfx.nChannels; + } +} + +void DecompressBlockMono( const adpcmstate_t &state, short *pOut, const char *pIn, int count ) +{ + int pred = *pIn++; + int co1 = state.pCoefficients[pred].iCoef1; + int co2 = state.pCoefficients[pred].iCoef2; + + // read initial delta + int delta = *((short *)pIn); + pIn += 2; + + // read initial samples for prediction + int samp1 = *((short *)pIn); + pIn += 2; + + int samp2 = *((short *)pIn); + pIn += 2; + + // write out the initial samples (stored in reverse order) + *pOut++ = (short)samp2; + *pOut++ = (short)samp1; + + // subtract the 2 samples in the header + count -= 2; + + // this is a toggle to read nibbles, first nibble is high + int high = 1; + + int error, sample=0; + + // now process the block + while ( count ) + { + // read the error nibble from the input stream + if ( high ) + { + sample = (unsigned char) (*pIn++); + // high nibble + error = sample >> 4; + // cache low nibble for next read + sample = sample & 0xf; + // Next read is from cache, not stream + high = 0; + } + else + { + // stored in previous read (low nibble) + error = sample; + // next read is from stream + high = 1; + } + // convert to signed with LUT + int errorSign = error_sign_lut[error]; + + // interpolate the new sample + int predSample = (samp1 * co1) + (samp2 * co2); + // coefficients are fixed point 8-bit, so shift back to 16-bit integer + predSample >>= 8; + + // Add in current error estimate + predSample += (errorSign * delta); + + // Correct error estimate + delta = (delta * error_coefficients_lut[error]) >> 8; + // Clamp error estimate + if ( delta < 16 ) + delta = 16; + + // clamp + if ( predSample > 32767L ) + predSample = 32767L; + else if ( predSample < -32768L ) + predSample = -32768L; + + // output + *pOut++ = (short)predSample; + // move samples over + samp2 = samp1; + samp1 = predSample; + + count--; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Decode a single block of stereo ADPCM audio +// Input : *pOut - 16-bit output buffer +// *pIn - ADPCM encoded block data +// count - number of sample pairs to decode +//----------------------------------------------------------------------------- +void DecompressBlockStereo( const adpcmstate_t &state, short *pOut, const char *pIn, int count ) +{ + int pred[2], co1[2], co2[2]; + int i; + + for ( i = 0; i < 2; i++ ) + { + pred[i] = *pIn++; + co1[i] = state.pCoefficients[pred[i]].iCoef1; + co2[i] = state.pCoefficients[pred[i]].iCoef2; + } + + int delta[2], samp1[2], samp2[2]; + + for ( i = 0; i < 2; i++, pIn += 2 ) + { + // read initial delta + delta[i] = *((short *)pIn); + } + + // read initial samples for prediction + for ( i = 0; i < 2; i++, pIn += 2 ) + { + samp1[i] = *((short *)pIn); + } + for ( i = 0; i < 2; i++, pIn += 2 ) + { + samp2[i] = *((short *)pIn); + } + + // write out the initial samples (stored in reverse order) + *pOut++ = (short)samp2[0]; // left + *pOut++ = (short)samp2[1]; // right + *pOut++ = (short)samp1[0]; // left + *pOut++ = (short)samp1[1]; // right + + // subtract the 2 samples in the header + count -= 2; + + // this is a toggle to read nibbles, first nibble is high + int high = 1; + + int error, sample=0; + + // now process the block + while ( count ) + { + for ( i = 0; i < 2; i++ ) + { + // read the error nibble from the input stream + if ( high ) + { + sample = (unsigned char) (*pIn++); + // high nibble + error = sample >> 4; + // cache low nibble for next read + sample = sample & 0xf; + // Next read is from cache, not stream + high = 0; + } + else + { + // stored in previous read (low nibble) + error = sample; + // next read is from stream + high = 1; + } + // convert to signed with LUT + int errorSign = error_sign_lut[error]; + + // interpolate the new sample + int predSample = (samp1[i] * co1[i]) + (samp2[i] * co2[i]); + // coefficients are fixed point 8-bit, so shift back to 16-bit integer + predSample >>= 8; + + // Add in current error estimate + predSample += (errorSign * delta[i]); + + // Correct error estimate + delta[i] = (delta[i] * error_coefficients_lut[error]) >> 8; + // Clamp error estimate + if ( delta[i] < 16 ) + delta[i] = 16; + + // clamp + if ( predSample > 32767L ) + predSample = 32767L; + else if ( predSample < -32768L ) + predSample = -32768L; + + // output + *pOut++ = (short)predSample; + // move samples over + samp2[i] = samp1[i]; + samp1[i] = predSample; + } + count--; + } +} + +int ADPCMSampleCountShortBlock( const adpcmstate_t &state, int shortBlockSize ) +{ + if ( shortBlockSize < 8 ) + return 0; + + int sampleCount = state.pFormat->wSamplesPerBlock; + + // short block?, fixup sample count (2 samples per byte, divided by number of channels per sample set) + sampleCount -= ((state.blockSize - shortBlockSize) * 2) / state.pFormat->wfx.nChannels; + return sampleCount; +} + +int ADPCMSampleCount( const byte *pFormatChunk, const byte *pDataChunk, int dataSize ) +{ + adpcmstate_t state; + ParseADPCM( state, pFormatChunk ); + int numBlocks = dataSize / state.blockSize; + int mod = dataSize % state.blockSize; + return numBlocks * state.pFormat->wSamplesPerBlock + ADPCMSampleCountShortBlock(state, mod); +} + +void DecompressADPCMSamples( const byte *pFormatChunk, const byte *pDataChunk, int dataSize, short *pOutputBuffer ) +{ + adpcmstate_t state; + ParseADPCM( state, pFormatChunk ); + + while ( dataSize > 0 ) + { + int block = dataSize; + int sampleCount = state.pFormat->wSamplesPerBlock; + if ( block > state.blockSize ) + { + block = state.blockSize; + } + else + { + sampleCount = ADPCMSampleCountShortBlock( state, block ); + } + if ( state.pFormat->wfx.nChannels == 1 ) + { + DecompressBlockMono( state, pOutputBuffer, (const char *)pDataChunk, sampleCount ); + } + else + { + DecompressBlockStereo( state, pOutputBuffer, (const char *)pDataChunk, sampleCount ); + } + pOutputBuffer += sampleCount * state.pFormat->wfx.nChannels; + dataSize -= block; + pDataChunk += block; + } +} + +void Convert8To16( const byte *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount ) +{ + for ( int i = 0; i < sampleCount*channelCount; i++ ) + { + unsigned short signedSample = (byte)((int)((unsigned)pInputBuffer[i]) - 128); + pOutputBuffer[i] = (short) (signedSample | (signedSample<<8)); + } +} + diff --git a/utils/xbox/MakeGameData/resample.h b/utils/xbox/MakeGameData/resample.h new file mode 100644 index 0000000..8382d7d --- /dev/null +++ b/utils/xbox/MakeGameData/resample.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef RESAMPLE_H +#define RESAMPLE_H +#ifdef _WIN32 +#pragma once +#endif + +void DecimateSampleRateBy2_16( const short *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount ); +void DecompressADPCMSamples( const byte *pFormatChunk, const byte *pDataChunk, int dataSize, short *pOutputBuffer ); +int ADPCMSampleCount( const byte *pFormatChunk, const byte *pDataChunk, int dataSize ); +void Convert8To16( const byte *pInputBuffer, short *pOutputBuffer, int sampleCount, int channelCount ); + +#endif // RESAMPLE_H diff --git a/utils/xbox/MakeGameData/sound_io.cpp b/utils/xbox/MakeGameData/sound_io.cpp new file mode 100644 index 0000000..44e0323 --- /dev/null +++ b/utils/xbox/MakeGameData/sound_io.cpp @@ -0,0 +1,68 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +/***************************************************************************** + SOUND_IO.CPP + + IO class for RIFF +*****************************************************************************/ +#include "../toollib/toollib.h" +#include "tier2/riff.h" + +//----------------------------------------------------------------------------- +// Purpose: Implements Audio IO on the engine's COMMON filesystem +//----------------------------------------------------------------------------- +class COM_IOReadBinary : public IFileReadBinary +{ +public: + int open( const char *pFileName ); + int read( void *pOutput, int size, int file ); + void seek( int file, int pos ); + unsigned int tell( int file ); + unsigned int size( int file ); + void close( int file ); +}; + + +int COM_IOReadBinary::open( const char *pFileName ) +{ + int hFile = -1; + + _sopen_s( &hFile, pFileName, _O_RDONLY|_O_BINARY, _SH_DENYWR, _S_IREAD ); + + return hFile; +} + +int COM_IOReadBinary::read( void *pOutput, int size, int file ) +{ + return _read( file, pOutput, size ); +} + +void COM_IOReadBinary::seek( int file, int pos ) +{ + _lseek( file, pos, SEEK_SET ); +} + +unsigned int COM_IOReadBinary::tell( int file ) +{ + return _lseek( file, 0, SEEK_CUR ); +} + +unsigned int COM_IOReadBinary::size( int file ) +{ + long pos; + long length; + + pos = _lseek( file, 0, SEEK_CUR ); + length = _lseek( file, 0, SEEK_END ); + _lseek( file, pos, SEEK_SET ); + + return length; +} + +void COM_IOReadBinary::close( int file ) +{ + _close( file ); +} + +static COM_IOReadBinary io; +IFileReadBinary *g_pSndIO = &io; + diff --git a/utils/xbox/Test360/TriangleASM.cpp b/utils/xbox/Test360/TriangleASM.cpp new file mode 100644 index 0000000..7610661 --- /dev/null +++ b/utils/xbox/Test360/TriangleASM.cpp @@ -0,0 +1,981 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//-------------------------------------------------------------------------------------- +// TriangleASM.cpp +// +// Hijacked from samples, assimilated into valve app. +//-------------------------------------------------------------------------------------- + +#include "tier0\platform.h" +#if !defined( _X360 ) +#include <windows.h> +#endif +#include "appframework\iappsystemgroup.h" +#include "appframework\appframework.h" +#include "tier0\dbg.h" +#include "tier1\interface.h" +#include "filesystem.h" +#include "vstdlib\cvar.h" +#include "filesystem_init.h" +#include "tier1/utlbuffer.h" +#include "icommandline.h" +#include "datacache\idatacache.h" +#include "datacache\imdlcache.h" +#include "studio.h" +#include "utlbuffer.h" +#include "tier2\utlstreambuffer.h" +#include "tier2\tier2.h" +#include "tier3\tier3.h" +#include "mathlib/mathlib.h" +#include "inputsystem\iinputsystem.h" +#include "vphysics_interface.h" +#include "istudiorender.h" +#include "studio.h" +#include "tier1\KeyValues.h" +#include "vgui\IVGui.h" +#include "vguimatsurface\imatsystemsurface.h" +#include "matsys_controls\matsyscontrols.h" +#include "vgui\ILocalize.h" +#include "vgui_controls\panel.h" +#include "vgui_controls\label.h" +#if defined( _X360 ) +#include "xbox\xbox_console.h" +#include "xbox\xbox_win32stubs.h" +#endif +#include "materialsystem\imaterialsystem.h" +#include "materialsystem\imesh.h" +#include "materialsystem\materialsystem_config.h" +#include "materialsystem\MaterialSystemUtil.h" +#include "materialsystem\ishaderapi.h" +#if !defined( _X360 ) +#include "xbox\xboxstubs.h" +#endif +#include "bone_setup.h" +#include "tier0\memdbgon.h" + +bool g_bActive = true; + +extern SpewOutputFunc_t g_DefaultSpewFunc; + +// These must be turned on in order.... +#define USE_FILESYSTEM +#define USE_MATERIALSYSTEM +#define USE_VPHYSICS + +// Note: VPHYSICS is just used via the datacache to load a model's physics collision mesh + +// These can be turned on in any order +#define USE_INPUTSYSTEM +#define USE_VGUI +#define USE_STUDIORENDER + +#pragma warning(disable:4189) // local variable is initialized but not referenced + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CTest360App : public CDefaultAppSystemGroup<CSteamAppSystemGroup> +{ +public: + virtual bool Create(); + virtual bool PreInit(); + virtual int Main(); + virtual void Destroy(); + +private: + const char *GetAppName() { return "TEST360"; } + void RenderScene(); + bool CreateMainWindow( int width, int height, bool fullscreen ); + +#if defined( USE_MATERIALSYSTEM ) + bool SetupMaterialSystem(); +#endif + +#if defined( USE_STUDIORENDER ) + bool SetupStudioRender(); + bool LoadModel( const char *pModelName ); + matrix3x4_t* SetUpBones( studiohdr_t *pStudioHdr, const matrix3x4_t &modelMatrix ); +#endif + +#if defined( USE_VGUI ) + int InitializeVGUI( void ); + void ShutdownVGUI( void ); +#endif + + IPhysicsCollision *m_pCollision; + IMaterialSystem *m_pMaterialSystem; + IFileSystem *m_pFileSystem; + int m_nWidth; + int m_nHeight; + float m_fAspect; + float m_NearClip; + float m_FarClip; + float m_fov; + HWND m_hWnd; + studiohdr_t *m_pStudioHdr; + studiohwdata_t *m_pStudioHWData; + int m_nLod; + float m_flTime; + float m_flPlaybackRate; + vgui::Panel *m_pMainPanel; +}; + + +static float g_yaw; +static float g_horizontalPan; +static float g_verticalPan; +static float g_zoom; +static int g_sequence; +static bool g_bWireframe; + +DEFINE_WINDOWED_STEAM_APPLICATION_OBJECT( CTest360App ); + +#if defined( USE_MATERIALSYSTEM ) +static void MaterialSystem_Warning( const char *fmt, ... ) +{ + va_list argptr; + char msg[2048]; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof ( msg ), fmt, argptr ); + va_end( argptr ); + + OutputDebugString( msg ); +} +#endif + +#if defined( USE_MATERIALSYSTEM ) +static void MaterialSystem_Warning( char *fmt, ... ) +{ + va_list argptr; + char msg[2048]; + + va_start( argptr, fmt ); + Q_vsnprintf( msg, sizeof( msg ), fmt, argptr ); + va_end( argptr ); + + OutputDebugString( msg ); +} +#endif + +virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const +{ + if ( numincludemodels == 0 ) + return NULL; + return g_pMDLCache->GetVirtualModelFast( this, (MDLHandle_t)virtualModel ); +} +byte *studiohdr_t::GetAnimBlock( int i ) const +{ + return g_pMDLCache->GetAnimBlock( (MDLHandle_t)virtualModel, i ); +} +int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const +{ + return g_pMDLCache->GetAutoplayList( (MDLHandle_t)virtualModel, pOut ); +} +const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const +{ + return g_pMDLCache->GetStudioHdr( (MDLHandle_t)cache ); +} + +#if defined( USE_STUDIORENDER ) +matrix3x4_t* CTest360App::SetUpBones( studiohdr_t *pStudioHdr, const matrix3x4_t &shapeToWorld ) +{ + // Default to middle of the pose parameter range + float pPoseParameter[MAXSTUDIOPOSEPARAM]; + for ( int i = 0; i < MAXSTUDIOPOSEPARAM; ++i ) + { + pPoseParameter[i] = 0.5f; + } + + CStudioHdr studioHdr( pStudioHdr, g_pMDLCache ); + + int nFrameCount = Studio_MaxFrame( &studioHdr, g_sequence, pPoseParameter ); + if ( nFrameCount == 0 ) + { + nFrameCount = 1; + } + float flCycle = ( m_flTime * m_flPlaybackRate ) / nFrameCount; + + // FIXME: We're always wrapping; may want to determing if we should clamp + flCycle -= (int)(flCycle); + + int boneMask = BONE_USED_BY_VERTEX_AT_LOD( m_nLod ); + + Vector pos[MAXSTUDIOBONES]; + Quaternion q[MAXSTUDIOBONES]; + + IBoneSetup boneSetup( &studioHdr, boneMask, pPoseParameter ); + boneSetup.InitPose( pos, q ); + boneSetup.AccumulatePose( pos, q, g_sequence, flCycle, 1.0f, m_flTime, NULL ); + + // FIXME: Try enabling this? +// CalcAutoplaySequences( pStudioHdr, NULL, pos, q, pPoseParameter, BoneMask( ), flTime ); + + // Root transform + matrix3x4_t rootToWorld, temp; + + MatrixCopy( shapeToWorld, rootToWorld ); + + matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( studioHdr.numbones() ); + for ( int i = 0; i < studioHdr.numbones(); i++ ) + { + // If it's not being used, fill with NAN for errors + if ( !(studioHdr.pBone( i )->flags & boneMask) ) + { + int j, k; + for (j = 0; j < 3; j++) + { + for (k = 0; k < 4; k++) + { + pBoneToWorld[i][j][k] = VEC_T_NAN; + } + } + continue; + } + + matrix3x4_t boneMatrix; + QuaternionMatrix( q[i], boneMatrix ); + MatrixSetColumn( pos[i], 3, boneMatrix ); + + if (studioHdr.pBone(i)->parent == -1) + { + ConcatTransforms (rootToWorld, boneMatrix, pBoneToWorld[i]); + } + else + { + ConcatTransforms (pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[i] ); + } + } + return pBoneToWorld; +} +#endif + +//-------------------------------------------------------------------------------------- +// LoadModel +// +//-------------------------------------------------------------------------------------- +#if defined( USE_STUDIORENDER ) +bool CTest360App::LoadModel( const char* pModelName ) +{ + MDLHandle_t hMdl = g_pMDLCache->FindMDL( pModelName ); + + m_pStudioHdr = g_pMDLCache->GetStudioHdr( hMdl ); + + g_pMDLCache->GetVertexData( hMdl ); + g_pMDLCache->FinishPendingLoads(); + + g_pMDLCache->GetHardwareData( hMdl ); + g_pMDLCache->FinishPendingLoads(); + + m_pStudioHWData = g_pMDLCache->GetHardwareData( hMdl ); + + g_sequence = 0; + m_nLod = 0; + m_flPlaybackRate = 30.0; + g_yaw = 0; + g_zoom = -100; + g_horizontalPan = 0; + g_verticalPan = -30; + + return true; +} +#endif + +//-------------------------------------------------------------------------------------- +// SetupMaterialSystem +// +//-------------------------------------------------------------------------------------- +#if defined( USE_MATERIALSYSTEM ) +bool CTest360App::SetupMaterialSystem() +{ + RECT rect; + + MaterialSystem_Config_t config; + config.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, IsPC() ? true : false ); + config.SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, 0 ); + + config.m_VideoMode.m_Width = 0; + config.m_VideoMode.m_Height = 0; + config.m_VideoMode.m_Format = IMAGE_FORMAT_BGRX8888; + config.m_VideoMode.m_RefreshRate = 0; + config.dxSupportLevel = IsX360() ? 98 : 0; + + bool modeSet = m_pMaterialSystem->SetMode( m_hWnd, config ); + if ( !modeSet ) + { + Error( "Failed to set mode\n" ); + return false; + } + + m_pMaterialSystem->OverrideConfig( config, false ); + + GetClientRect( m_hWnd, &rect ); + m_nWidth = rect.right; + m_nHeight = rect.bottom; + m_fAspect = (float)m_nWidth/(float)m_nHeight; + + m_NearClip = 8.0f; + m_FarClip = 28400.0f; + m_fov = 90; + + return true; +} +#endif + +//-------------------------------------------------------------------------------------- +// SetupStudioRender +// +//-------------------------------------------------------------------------------------- +#if defined( USE_STUDIORENDER ) +bool CTest360App::SetupStudioRender() +{ + StudioRenderConfig_t config; + memset( &config, 0, sizeof(config) ); + + config.bEyeMove = false; + config.bTeeth = true; + config.bEyes = true; + config.bFlex = true; + + config.fEyeShiftX = 0.0f; + config.fEyeShiftY = 0.0f; + config.fEyeShiftZ = 0.0f; + config.fEyeSize = 0.0f; + + config.bNoHardware = false; + config.bNoSoftware = false; + + config.bSoftwareSkin = false; + config.bSoftwareLighting = false; + + config.drawEntities = true; + config.bWireframe = false; + config.SetNormals( false ); + config.SetTangentFrame( false ); + config.skin = 0; + + config.fullbright = 0; + config.pConDPrintf = MaterialSystem_Warning; + config.pConPrintf = MaterialSystem_Warning; + + config.bShowEnvCubemapOnly = false; + + g_pStudioRender->UpdateConfig( config ); + + return true; +} +#endif + +//-------------------------------------------------------------------------------------- +// Render a model using the MaterialSystem +//-------------------------------------------------------------------------------------- +void CTest360App::RenderScene() +{ + m_flTime = Plat_FloatTime(); + +#if defined( USE_MATERIALSYSTEM ) + CMatRenderContextPtr pRenderContext( m_pMaterialSystem ); + m_pMaterialSystem->BeginFrame(); +#endif + +#if defined( USE_STUDIORENDER ) + g_pStudioRender->BeginFrame(); +#endif + +#if defined( USE_MATERIALSYSTEM ) + pRenderContext->ClearColor3ub( 0, 0, 0 ); + pRenderContext->ClearBuffers( true, true ); +#endif + +#if defined( USE_STUDIORENDER ) + pRenderContext->Viewport( 0, 0, m_nWidth, m_nHeight ); + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->LoadIdentity(); + pRenderContext->PerspectiveX( m_fov, m_fAspect, m_NearClip, m_FarClip ); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->LoadIdentity(); + pRenderContext->Translate( g_horizontalPan, g_verticalPan, g_zoom ); + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->LoadIdentity(); + + g_pStudioRender->SetLocalLights( 0, NULL ); + pRenderContext->SetAmbientLight( 1.0, 1.0, 1.0 ); + + QAngle angles; + angles[YAW] = 0; + angles[PITCH] = -90 + g_yaw; + angles[ROLL] = -90; + + matrix3x4_t cameraMatrix; + AngleMatrix( angles, cameraMatrix ); + + static Vector white[6] = + { + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + Vector( 1.0, 1.0, 1.0 ), + }; + g_pStudioRender->SetAmbientLightColors( white ); + + matrix3x4_t *pBoneToWorld = SetUpBones( m_pStudioHdr, cameraMatrix ); + + Vector modelOrigin( 0, 0, 0 ); + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + + DrawModelInfo_t modelInfo; + memset( &modelInfo, 0, sizeof( modelInfo ) ); + modelInfo.m_pStudioHdr = m_pStudioHdr; + modelInfo.m_pHardwareData = m_pStudioHWData; + modelInfo.m_Decals = STUDIORENDER_DECAL_INVALID; + modelInfo.m_Skin = 0; + modelInfo.m_Body = 0; + modelInfo.m_HitboxSet = 0; + modelInfo.m_pClientEntity = NULL; + modelInfo.m_Lod = 0; + modelInfo.m_ppColorMeshes = NULL; + + int drawFlags = 0; + if ( g_bWireframe ) + { + drawFlags |= STUDIORENDER_DRAW_WIREFRAME; + } + + g_pStudioRender->DrawModel( NULL, modelInfo, pBoneToWorld, modelOrigin, drawFlags ); + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PopMatrix(); +#endif + +#if defined( USE_MATERIALSYSTEM ) + pRenderContext->Flush( true ); +#endif + +#if defined( USE_VGUI ) + vgui::ivgui()->RunFrame(); + vgui::surface()->PaintTraverseEx( vgui::surface()->GetEmbeddedPanel() ); +#endif + +#if defined( USE_STUDIORENDER ) + g_pStudioRender->EndFrame(); +#endif + +#if defined( USE_MATERIALSYSTEM ) + m_pMaterialSystem->EndFrame(); + m_pMaterialSystem->SwapBuffers(); +#endif +} + +//-------------------------------------------------------------------------------------- +// Window Proc +//-------------------------------------------------------------------------------------- +LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) +{ + switch ( iMsg ) + { + case WM_CLOSE: + g_bActive = false; + break; + + case WM_DESTROY: + PostQuitMessage( 0 ); + return 0L; + + case WM_XCONTROLLER_INSERTED: + Msg( "Port %d: Gamepad Activated\n", wParam ); + break; + + case WM_XCONTROLLER_UNPLUGGED: + Msg( "Port %d: Gamepad Unplugged\n", wParam ); + break; + + case WM_XCONTROLLER_KEY: + // wParam == key + // HIWORD( lParam ) = port + // LOWWORD( lParam ) = sample + Msg( "Port %d: Button %d %s\n", HIWORD( lParam ), wParam, LOWORD( lParam ) ? "Pressed" : "Released" ); + switch ( wParam ) + { + case XK_BUTTON_RTRIGGER: + if ( LOWORD( lParam ) ) + { + g_zoom++; + } + break; + + case XK_BUTTON_LTRIGGER: + if ( LOWORD( lParam ) ) + { + g_zoom--; + } + break; + + case XK_BUTTON_DOWN: + if ( LOWORD( lParam ) ) + { + g_verticalPan += 2; + } + break; + + case XK_BUTTON_UP: + if ( LOWORD( lParam ) ) + { + g_verticalPan -= 2; + } + break; + + case XK_BUTTON_LEFT: + if ( LOWORD( lParam ) ) + { + g_horizontalPan += 2; + } + break; + + case XK_BUTTON_RIGHT: + if ( LOWORD( lParam ) ) + { + g_horizontalPan -= 2; + } + break; + + case XK_STICK2_LEFT: + if ( LOWORD( lParam ) ) + { + g_yaw += 5; + } + break; + + case XK_STICK2_RIGHT: + if ( LOWORD( lParam ) ) + { + g_yaw -= 5; + } + break; + + case XK_BUTTON_A: + if ( LOWORD( lParam ) ) + { + g_sequence++; + } + break; + + case XK_BUTTON_B: + if ( LOWORD( lParam ) ) + { + g_sequence--; + if ( g_sequence < 0 ) + g_sequence = 0; + } + break; + + case XK_BUTTON_Y: + if ( LOWORD( lParam ) ) + { + g_bWireframe ^= 1; + } + break; + } + break; + + case WM_KEYDOWN: + switch ( wParam ) + { + case 'O': + g_zoom++; + break; + + case 'P': + g_zoom--; + break; + + case 'W': + g_verticalPan += 2; + break; + + case 'S': + g_verticalPan -= 2; + break; + + case 'A': + g_horizontalPan += 2; + break; + + case 'D': + g_horizontalPan -= 2; + break; + + case 'N': + g_sequence--; + if ( g_sequence < 0 ) + g_sequence = 0; + break; + + case 'M': + g_sequence++; + break; + } + break; + } + + return DefWindowProc( hWnd, iMsg, wParam, lParam ); +} + +//-------------------------------------------------------------------------------------- +// CreateMainWindow +// +//-------------------------------------------------------------------------------------- +bool CTest360App::CreateMainWindow( int width, int height, bool fullscreen ) +{ + HWND hwnd; + WNDCLASSEX wndclass; + DWORD dwStyle, dwExStyle; + int x, y, sx, sy; + + if ( ( hwnd = FindWindow( GetAppName(), GetAppName() ) ) != NULL ) + { + SetForegroundWindow( hwnd ); + return true; + } + + wndclass.cbSize = sizeof (wndclass); + wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wndclass.lpfnWndProc = ::WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = (HINSTANCE)GetAppInstance(); + wndclass.hIcon = 0; + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)COLOR_GRAYTEXT; + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = GetAppName(); + wndclass.hIconSm = 0; + + if ( !RegisterClassEx( &wndclass ) ) + { + Error( "Window class registration failed\n" ); + return false; + } + + if ( fullscreen ) + { + dwExStyle = WS_EX_TOPMOST; + dwStyle = WS_POPUP | WS_VISIBLE; + } + else + { + dwExStyle = 0; + dwStyle = WS_CAPTION | WS_SYSMENU; + } + + x = y = 0; + sx = width; + sy = height; + + hwnd = CreateWindowEx( + dwExStyle, + GetAppName(), // window class name + GetAppName(), // window caption + dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, // window style + x, // initial x position + y, // initial y position + sx, // initial x size + sy, // initial y size + NULL, // parent window handle + NULL, // window menu handle + (HINSTANCE)GetAppInstance(),// program instance handle + NULL); // creation parameter + + if ( hwnd == NULL ) + { + ChangeDisplaySettings( 0, 0 ); + Error( "Window creation failed\n" ); + return false; + } + + m_hWnd = hwnd; + + return true; +} + +//----------------------------------------------------------------------------- +// Create +//----------------------------------------------------------------------------- +bool CTest360App::Create() +{ + AppSystemInfo_t appSystems[] = + { +#if defined( USE_STUDIORENDER ) + { "datacache.dll", DATACACHE_INTERFACE_VERSION }, + { "datacache.dll", MDLCACHE_INTERFACE_VERSION }, +#endif +#if defined( USE_MATERIALSYSTEM ) + { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION }, +#endif +#if defined( USE_STUDIORENDER ) + { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION }, +#endif +#if defined( USE_INPUTSYSTEM ) + { "inputsystem.dll", INPUTSYSTEM_INTERFACE_VERSION }, +#endif +#if defined( USE_VGUI ) + { "vgui2.dll", VGUI_IVGUI_INTERFACE_VERSION }, + { "vguimatsurface.dll", VGUI_SURFACE_INTERFACE_VERSION }, +#endif +#if defined( USE_STUDIORENDER ) + { "vphysics.dll", VPHYSICS_INTERFACE_VERSION }, +#endif + { "", "" } + }; + + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + + SpewOutputFunc( g_DefaultSpewFunc ); + +#if defined( USE_FILESYSTEM ) + // Add in the cvar factory + AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() ); + AddSystem( cvarModule, VENGINE_CVAR_INTERFACE_VERSION ); +#endif + +#if defined( _X360 ) + // vxconsole - true will block (legacy behavior) + XBX_InitConsoleMonitor( false ); +#endif + + if ( !AddSystems( appSystems ) ) + return false; + +#if defined( USE_FILESYSTEM ) + m_pFileSystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION ); + if ( !m_pFileSystem ) + { + Error( "Failed to find %s\n", FILESYSTEM_INTERFACE_VERSION ); + return false; + } +#endif + +#if defined( USE_VPHYSICS ) + m_pCollision = (IPhysicsCollision*)FindSystem( VPHYSICS_COLLISION_INTERFACE_VERSION ); + if ( !m_pCollision ) + { + Error( "Failed to find %s\n", VPHYSICS_COLLISION_INTERFACE_VERSION ); + return false; + } +#endif + +#if defined( USE_MATERIALSYSTEM ) + m_pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION ); + if ( !m_pMaterialSystem ) + { + Error( "Failed to find %s\n", MATERIAL_SYSTEM_INTERFACE_VERSION ); + return false; + } +#if defined( _X360 ) + m_pFileSystem->LoadModule( "shaderapidx9.dll" ); +#endif + m_pMaterialSystem->SetShaderAPI( "shaderapidx9.dll" ); +#endif + + return true; +} + +//----------------------------------------------------------------------------- +// PreInit +//----------------------------------------------------------------------------- +bool CTest360App::PreInit() +{ +#if defined( USE_FILESYSTEM ) + // Add paths... + if ( !SetupSearchPaths( NULL, false, true ) ) + { + Error( "Failed to setup search paths\n" ); + return false; + } +#endif + + CreateInterfaceFn factory = GetFactory(); + ConnectTier1Libraries( &factory, 1 ); + ConnectTier2Libraries( &factory, 1 ); + ConnectTier3Libraries( &factory, 1 ); + + // Create the main program window and our viewport + int w = 640; + int h = 480; + if ( IsX360() ) + { + w = GetSystemMetrics( SM_CXSCREEN ); + h = GetSystemMetrics( SM_CYSCREEN ); + } + if ( !CreateMainWindow( w, h, false ) ) + { + ChangeDisplaySettings( 0, 0 ); + Error( "Unable to create main window\n" ); + return false; + } + + ShowWindow( m_hWnd, SW_SHOWNORMAL ); + UpdateWindow( m_hWnd ); + SetForegroundWindow( m_hWnd ); + SetFocus( m_hWnd ); + + return true; +} + +//----------------------------------------------------------------------------- +// Destroy +//----------------------------------------------------------------------------- +void CTest360App::Destroy() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Setup all our VGUI info +//----------------------------------------------------------------------------- +#if defined( USE_VGUI ) + +static CreateInterfaceFn s_pFactoryList[3]; + +void *VGuiFactory( const char *pName, int *pReturnCode ) +{ + for ( int i = 0; i < ARRAYSIZE( s_pFactoryList ); ++i ) + { + void *pInterface = s_pFactoryList[i]( pName, pReturnCode ); + if ( pInterface ) + return pInterface; + } + return NULL; +} + +int CTest360App::InitializeVGUI( void ) +{ + s_pFactoryList[0] = Sys_GetFactory( m_pFileSystem->LoadModule( "filesystem_stdio" ) ); + s_pFactoryList[1] = Sys_GetFactory( m_pFileSystem->LoadModule( "vguimatsurface" ) ); + s_pFactoryList[2] = Sys_GetFactory( m_pFileSystem->LoadModule( "vgui2" ) ); + int factorycount = ARRAYSIZE( s_pFactoryList ); + + if ( !vgui::VGui_InitInterfacesList( "test360", s_pFactoryList, factorycount ) ) + return 3; + + vgui::ivgui()->Connect( VGuiFactory ); + vgui::ivgui()->Init(); + + vgui::ivgui()->SetSleep(false); + + // Init the surface + vgui::Panel *pPanel = new vgui::Panel( NULL, "TopPanel" ); + pPanel->SetBounds( 0, 0, m_nWidth, m_nHeight ); + pPanel->SetPaintBackgroundEnabled( false ); + pPanel->SetVisible(true); + + vgui::surface()->SetEmbeddedPanel(pPanel->GetVPanel()); + + // load the scheme + vgui::scheme()->LoadSchemeFromFile( "resource/clientscheme.res", NULL ); + + // localization + //vgui::localize()->AddFile( "resource/vgui_%language%.txt" ); + + // Start vgui + vgui::ivgui()->Start(); + + // add a panel + m_pMainPanel = new vgui::Panel( pPanel, "MainPanel" ); + SETUP_PANEL( m_pMainPanel ); + m_pMainPanel->SetBounds( 30, 30, 200, 100 ); + m_pMainPanel->SetBgColor( Color(255,255,0,255) ); + + // add text + vgui::Label *pLabel = new vgui::Label( m_pMainPanel, "Text", L"" ); + SETUP_PANEL( pLabel ); + + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); +// vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "BudgetLabel" ); +// pLabel->SetFont( hFont ); + pLabel->SetText( L"This is text" ); + + pLabel->SetFgColor( Color(0,0,0,255) ); + + return 0; +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: Stop VGUI +//----------------------------------------------------------------------------- +#if defined( USE_VGUI ) +void CTest360App::ShutdownVGUI( void ) +{ + delete m_pMainPanel; + + // Shutdown + vgui::surface()->Shutdown(); +} +#endif + +//----------------------------------------------------------------------------- +// Main +//----------------------------------------------------------------------------- +int CTest360App::Main() +{ +#if defined( USE_MATERIALSYSTEM ) + if ( !SetupMaterialSystem() ) + { + return 0; + } +#endif + +#if defined( USE_STUDIORENDER ) + if ( !SetupStudioRender() ) + { + return 0; + } +#endif + +#if defined( USE_VGUI ) + int ret = InitializeVGUI(); + if ( ret != 0 ) + return ret; +#endif + + const char *pArgVal; + const char* pModelName = "models\\alyx.mdl"; + if ( CommandLine()->CheckParm( "-model", &pArgVal ) ) + { + pModelName = pArgVal; + } + +#if defined( USE_STUDIORENDER ) + // the easiest model to load - no anims + //const char* pModelName = "models\\items\\item_item_crate.mdl"; + if ( !LoadModel( pModelName ) ) + { + return 0; + } +#endif + + MSG msg; + while ( g_bActive == TRUE ) + { + while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + +#if defined( USE_INPUTSYSTEM ) + g_pInputSystem->PollInputState(); +#endif + RenderScene(); + } + +#if defined( USE_VGUI ) + ShutdownVGUI(); +#endif + + return 0; +} diff --git a/utils/xbox/dumpobj/dumpobj.cpp b/utils/xbox/dumpobj/dumpobj.cpp new file mode 100644 index 0000000..e074d25 --- /dev/null +++ b/utils/xbox/dumpobj/dumpobj.cpp @@ -0,0 +1,407 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +/***************************************************************************** + DUMPOBJ.CPP + +*****************************************************************************/ +#include "..\toollib\toollib.h" + +typedef struct section_s +{ + int size; + char* name; + section_s* nextPtr; +} section_t; + +typedef struct obj_s +{ + char* filename; + section_t* sectionPtr; + obj_s* nextPtr; +} obj_t; + +obj_t* g_obj_head; +char g_sectionName[128]; +bool g_bVerbose; + +typedef struct +{ + char* filename; + int size; +} entry_t; + +/*********************************************************** + _SortCallback + +***********************************************************/ +int _SortCallback(const void *a, const void *b) +{ + entry_t* aPtr; + entry_t* bPtr; + + aPtr = (entry_t*)a; + bPtr = (entry_t*)b; + + return (aPtr->size-bPtr->size); +} + +/*********************************************************** + FreeInfo + +***********************************************************/ +void FreeInfo() +{ + obj_t* objPtr; + obj_t* nextObjPtr; + section_t* sectionPtr; + section_t* nextSectionPtr; + + objPtr = g_obj_head; + while (objPtr) + { + nextObjPtr = objPtr->nextPtr; + sectionPtr = objPtr->sectionPtr; + while (sectionPtr) + { + nextSectionPtr = sectionPtr->nextPtr; + + TL_Free(sectionPtr->name); + TL_Free(sectionPtr); + + sectionPtr = nextSectionPtr; + } + + TL_Free(objPtr->filename); + TL_Free(objPtr); + + objPtr = nextObjPtr; + } +} + +/*********************************************************** + AnalyzeData + +***********************************************************/ +void AnalyzeData() +{ + obj_t* objPtr; + section_t* sectionPtr; + char* sections[128]; + int totals[128]; + int numSections; + int i; + int index; + int numEntries; + entry_t* entries; + int total; + + printf("\n"); + + memset(totals, 0, sizeof(totals)); + + // determine unique sections + numSections = 0; + objPtr = g_obj_head; + while (objPtr) + { + sectionPtr = objPtr->sectionPtr; + while (sectionPtr) + { + for (i=0; i<numSections; i++) + { + if (!stricmp(sections[i],sectionPtr->name)) + break; + } + if (i >= numSections) + { + // add it + sections[numSections] = sectionPtr->name; + numSections++; + assert(numSections < 128); + + index = numSections-1; + } + else + index = i; + + totals[index] += sectionPtr->size; + + sectionPtr = sectionPtr->nextPtr; + } + objPtr = objPtr->nextPtr; + } + + if (g_sectionName[0]) + { + // dump only matching section + printf("Section: %s\n", g_sectionName); + printf("-------------------------\n"); + + // tally entries + numEntries = 0; + objPtr = g_obj_head; + while (objPtr) + { + sectionPtr = objPtr->sectionPtr; + while (sectionPtr) + { + if (!stricmp(g_sectionName, sectionPtr->name)) + numEntries++; + sectionPtr = sectionPtr->nextPtr; + } + objPtr = objPtr->nextPtr; + } + + // fill entries + if (numEntries) + { + entries = (entry_t*)TL_Malloc(numEntries*sizeof(entry_t)); + numEntries = 0; + objPtr = g_obj_head; + while (objPtr) + { + sectionPtr = objPtr->sectionPtr; + while (sectionPtr) + { + if (!stricmp(g_sectionName, sectionPtr->name)) + { + entries[numEntries].size = sectionPtr->size; + entries[numEntries].filename = objPtr->filename; + numEntries++; + } + sectionPtr = sectionPtr->nextPtr; + } + objPtr = objPtr->nextPtr; + } + + // sort + qsort(entries, numEntries, sizeof(entry_t), _SortCallback); + + // display results + int total = 0; + for (i=0; i<numEntries; i++) + { + printf("%8d %s\n", entries[i].size, entries[i].filename); + total += entries[i].size; + } + printf("-------------------------\n"); + printf("%8d Total\n", total); + + TL_Free(entries); + } + } + else + { + // dump all sections + printf("Sections:\n"); + printf("---------\n"); + total = 0; + for (i=0; i<numSections; i++) + { + printf("%8d %s\n", totals[i], sections[i]); + total += totals[i]; + } + printf("---------\n"); + printf("%8d\n", total); + } +} + + +/*********************************************************** + LocalExec + +***********************************************************/ +int LocalExec(const char* batfilename, const char* arg1) +{ + intptr_t pid; + int errcode; + const char* args[8]; + + args[0] = batfilename; + args[1] = arg1; + args[2] = NULL; + + pid = _spawnvp(P_NOWAIT, batfilename, args); + _cwait(&errcode, pid, 0); + + return (errcode); +} + +/***************************************************************************** + GetInfo + +*****************************************************************************/ +void GetInfo(char* objFilename, char* batFilename, char* logFilename) +{ + char buff[TL_MAXPATH]; + int size; + char name[128]; + char* ptr; + int errcode; + char* token; + obj_t* objPtr; + section_t* sectionPtr; + + if (g_bVerbose) + printf("%s\n", objFilename); + + ptr = objFilename; + if (!strnicmp(objFilename,".\\",2)) + { + ptr += 2; + + getcwd(buff, sizeof(buff)); + TL_AddSeperatorToPath(buff, buff); + + strcat(buff, ptr); + } + else + strcpy(buff, objFilename); + + // exec the batch file with the obj file + errcode = LocalExec(batFilename, buff); + if (errcode) + { + printf("Failed on %s\n", buff); + return; + } + + // add new object node + objPtr = (obj_t*)TL_Malloc(sizeof(obj_t)); + objPtr->filename = (char*)TL_Malloc((int)strlen(objFilename)+1); + strcpy(objPtr->filename, objFilename); + + // link it in + objPtr->nextPtr = g_obj_head; + g_obj_head = objPtr; + + // read the results + TL_LoadScriptFile(logFilename); + + while (1) + { + token = TL_GetToken(true); + if (!token || !token[0]) + break; + + if (!stricmp(token, "summary")) + break; + else + TL_SkipRestOfLine(); + } + + while (1) + { + token = TL_GetToken(true); + if (!token || !token[0]) + break; + sscanf(token, "%x", &size); + + token = TL_GetToken(true); + if (!token || !token[0]) + break; + strcpy(name, token); + + // add new section node + sectionPtr = (section_t*)TL_Malloc(sizeof(section_t)); + sectionPtr->name = (char*)TL_Malloc((int)strlen(name)+1); + strcpy(sectionPtr->name, name); + sectionPtr->size = size; + + // link it in + sectionPtr->nextPtr = objPtr->sectionPtr; + objPtr->sectionPtr = sectionPtr; + } + + TL_FreeScriptFile(); +} + +/***************************************************************************** + Usage + +*****************************************************************************/ +void Usage(void) +{ + printf("usage: dumpobj <*.obj> [-s section] [-r] [-v]\n"); + exit(-1); +} + +/***************************************************************************** + main + +*****************************************************************************/ +int main(int argc, char* argv[]) +{ + tlfile_t** filelist; + int filecount; + int i; + int recurse; + int section; + FILE* fp; + char* vcvarsPath; + char batFilename[TL_MAXPATH]; + char txtFilename[TL_MAXPATH]; + + batFilename[0] = '\0'; + txtFilename[0] = '\0'; + + TL_Setup("DUMPOBJ",argc,argv); + + // find critical path to vcvars32.bat + vcvarsPath = "c:\\Program Files\\Microsoft Visual Studio .Net 2003\\Vc7\\bin\\vcvars32.bat"; + if (!TL_Exists(vcvarsPath)) + TL_Error("Cannot find: %s\n", vcvarsPath); + + if (argc < 2) + Usage(); + + recurse = TL_CheckParm("r"); + filecount = TL_FindFiles2(argv[1], recurse != 0, &filelist); + + g_bVerbose = TL_CheckParm("v") != 0; + + section = TL_CheckParm("s"); + if (section && section+1 < argc) + strcpy(g_sectionName, argv[section+1]); + else + g_sectionName[0] = '\0'; + + strcpy(batFilename,"c:\\"); + TL_TempFilename(batFilename); + TL_ReplaceDosExtension(batFilename, ".bat"); + + strcpy(txtFilename,"c:\\"); + TL_TempFilename(txtFilename); + TL_ReplaceDosExtension(txtFilename, ".txt"); + + if (filecount) + { + // create bat file + fp = fopen(batFilename, "wt+"); + if (!fp) + TL_Error("Could not open bat file '%s'", batFilename); + + fprintf(fp, "@echo off\n"); + fprintf(fp, "@call \"%s\" > nul: \n", vcvarsPath); + fprintf(fp, "@dumpbin %%1 > %s\n", txtFilename); + fclose(fp); + } + + for (i=0; i<filecount; i++) + GetInfo(filelist[i]->filename, batFilename, txtFilename); + + if (filecount) + AnalyzeData(); + + if (filecount) + { + FreeInfo(); + unlink(batFilename); + unlink(txtFilename); + } + + TL_FreeFileList(filecount,filelist); + + TL_End(false); + + return (0); +}
\ No newline at end of file diff --git a/utils/xbox/dumpobj/dumpobj.vcproj b/utils/xbox/dumpobj/dumpobj.vcproj new file mode 100644 index 0000000..2227140 --- /dev/null +++ b/utils/xbox/dumpobj/dumpobj.vcproj @@ -0,0 +1,156 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="dumpobj" + ProjectGUID="{620FC3E4-31D4-49F4-A66C-089A543FB140}" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + MinimalRebuild="TRUE" + BasicRuntimeChecks="3" + RuntimeLibrary="5" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="FALSE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool" + CommandLine="if exist $(TargetPath) copy $(TargetPath) c:\bin_utils\$(TargetFileName)" + Outputs="c:\bin_utils\$(TargetFileName)"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/dumpobj.exe" + LinkIncremental="2" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/dumpobj.pdb" + SubSystem="1" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="4" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="FALSE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool" + CommandLine="if exist ..\..\..\..\game\bin\"$(TargetName)".exe attrib -r ..\..\..\..\game\bin\"$(TargetName)".exe +if exist "$(TargetPath)" copy "$(TargetPath)" ..\..\..\..\game\bin +" + Outputs="..\..\..\..\game\bin\$(TargetName).exe"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/dumpobj.exe" + LinkIncremental="1" + GenerateDebugInformation="TRUE" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + <File + RelativePath=".\dumpobj.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\toollib\scriplib.cpp"> + </File> + <File + RelativePath="..\toollib\toollib.cpp"> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + <File + RelativePath="..\toollib\scriplib.h"> + </File> + <File + RelativePath="..\toollib\toollib.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/utils/xbox/makephx/makephx.cpp b/utils/xbox/makephx/makephx.cpp new file mode 100644 index 0000000..8473005 --- /dev/null +++ b/utils/xbox/makephx/makephx.cpp @@ -0,0 +1,359 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "stdafx.h" +#include "physdll.h" +#include "vphysics/constraints.h" +#include "tier0/icommandline.h" +#include "filesystem_tools.h" +#include "simplify.h" +#include "keyvalues.h" +#include "studio.h" + +IPhysicsCollision *physcollision = NULL; +IPhysicsSurfaceProps *physprops = NULL; + +int g_TotalOut = 0; +int g_TotalCompress = 0; +bool g_bRecursive = false; +bool g_bQuiet = false; + +KeyValues *g_pModelConfig = NULL; + +void InitFilesystem( const char *pPath ) +{ + CmdLib_InitFileSystem( pPath ); + // This bit of hackery allows us to access files on the harddrive + g_pFullFileSystem->AddSearchPath( "", "LOCAL", PATH_ADD_TO_HEAD ); +} + +static bool LoadSurfaceProps( const char *pMaterialFilename ) +{ + if ( !physprops ) + return false; + + FileHandle_t fp = g_pFileSystem->Open( pMaterialFilename, "rb", TOOLS_READ_PATH_ID ); + if ( fp == FILESYSTEM_INVALID_HANDLE ) + return false; + + int len = g_pFileSystem->Size( fp ); + char *pText = new char[len+1]; + g_pFileSystem->Read( pText, len, fp ); + g_pFileSystem->Close( fp ); + + pText[len]=0; + + physprops->ParseSurfaceData( pMaterialFilename, pText ); + + delete[] pText; + + return true; +} + +void LoadSurfacePropsAll() +{ + // already loaded + if ( physprops->SurfacePropCount() ) + return; + + const char *SURFACEPROP_MANIFEST_FILE = "scripts/surfaceproperties_manifest.txt"; + KeyValues *manifest = new KeyValues( SURFACEPROP_MANIFEST_FILE ); + if ( manifest->LoadFromFile( g_pFileSystem, SURFACEPROP_MANIFEST_FILE, "GAME" ) ) + { + for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() ) + { + if ( !Q_stricmp( sub->GetName(), "file" ) ) + { + // Add + LoadSurfaceProps( sub->GetString() ); + continue; + } + } + } + + manifest->deleteThis(); +} +void InitVPhysics() +{ + CreateInterfaceFn physicsFactory = GetPhysicsFactory(); + physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL ); + physprops = (IPhysicsSurfaceProps *)physicsFactory( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, NULL ); + LoadSurfacePropsAll(); +} + +struct phyfile_t +{ + phyheader_t header; + vcollide_t collide; + int fileSize; +}; + +void LoadPHYFile(phyfile_t *pOut, const char *name) +{ + memset( pOut, 0, sizeof(*pOut) ); + FileHandle_t file = g_pFullFileSystem->Open( name, "rb" ); + if ( !file ) + return; + + g_pFullFileSystem->Read( &pOut->header, sizeof(pOut->header), file ); + if ( pOut->header.size != sizeof(pOut->header) || pOut->header.solidCount <= 0 ) + return; + + pOut->fileSize = g_pFullFileSystem->Size( file ); + + char *buf = (char *)_alloca( pOut->fileSize ); + g_pFullFileSystem->Read( buf, pOut->fileSize, file ); + g_pFullFileSystem->Close( file ); + + physcollision->VCollideLoad( &pOut->collide, pOut->header.solidCount, (const char *)buf, pOut->fileSize ); +} + + +void OverrideDefaultsForModel( const char *keyname, simplifyparams_t ¶ms ) +{ + KeyValues *pKeys = g_pModelConfig; + while ( pKeys ) + { + if ( !Q_stricmp( pKeys->GetName(), keyname ) ) + { + for ( KeyValues *pData = pKeys->GetFirstSubKey(); pData; pData = pData->GetNextKey() ) + { + if ( !Q_stricmp( pData->GetName(), "tolerance" ) ) + { + params.tolerance = pData->GetFloat(); + if (!g_bQuiet) + { + Msg("%s: tolerance set to %.2f\n", keyname, params.tolerance ); + } + } + else if ( !Q_stricmp( pData->GetName(), "addAABB" ) ) + { + params.addAABBToSimplifiedHull = pData->GetInt() ? true : false; + if (!g_bQuiet) + { + Msg("%s: AABB %s\n", keyname, params.addAABBToSimplifiedHull ? "on" : "off" ); + } + } + else if ( !Q_stricmp( pData->GetName(), "singleconvex" ) ) + { + params.forceSingleConvex = pData->GetInt() ? true : false; + if (!g_bQuiet) + { + Msg("%s: Forced to single convex\n", keyname ); + } + } + else if ( !Q_stricmp( pData->GetName(), "mergeconvex" ) ) + { + params.mergeConvexTolerance = pData->GetFloat(); + params.mergeConvexElements = params.mergeConvexTolerance > 0 ? true : false; + if (!g_bQuiet) + { + Msg("%s: Merge convex %.2f\n", keyname, params.mergeConvexTolerance ); + } + } + } + return; + } + pKeys = pKeys->GetNextKey(); + } +} + +bool HasMultipleBones( const char *pFilename ) +{ + char outName[1024]; + studiohdr_t hdr; + Q_strncpy( outName, pFilename, sizeof(outName) ); + Q_SetExtension( outName, ".mdl", sizeof(outName) ); + FileHandle_t fp = g_pFileSystem->Open( outName, "rb", TOOLS_READ_PATH_ID ); + if ( fp == FILESYSTEM_INVALID_HANDLE ) + return false; + + g_pFileSystem->Read( &hdr, sizeof(hdr), fp ); + g_pFileSystem->Close( fp ); + if ( hdr.numbones > 1 ) + return true; + return false; +} + +void WritePHXFile( const char *pName, const phyfile_t &file ) +{ + if ( file.header.size != sizeof(file.header) || file.collide.solidCount <= 0 ) + return; + + CUtlBuffer out; + + char outName[1024]; + Q_snprintf( outName, sizeof(outName), "%s", pName ); + Q_SetExtension( outName, ".phx", sizeof(outName) ); + + simplifyparams_t params; + params.Defaults(); + params.tolerance = (file.collide.solidCount > 1) ? 4.0f : 2.0f; + // single solids constraint to AABB for placement help + params.addAABBToSimplifiedHull = (file.collide.solidCount == 1) ? true : false; + params.mergeConvexElements = true; + params.mergeConvexTolerance = 0.025f; + Q_FixSlashes(outName); + Q_strlower(outName); + char *pSearch = Q_strstr( outName,"models\\" ); + if ( pSearch ) + { + char keyname[1024]; + pSearch += strlen("models\\"); + Q_StripExtension( pSearch, keyname, sizeof(keyname) ); + OverrideDefaultsForModel( keyname, params ); + } + out.Put( &file.header, sizeof(file.header) ); + int outSize = 0; + bool bStoreSolidNames = file.collide.solidCount > 1 ? true : false; + bStoreSolidNames = bStoreSolidNames || HasMultipleBones(outName); + + vcollide_t *pNewCollide = ConvertVCollideToPHX( &file.collide, params, &outSize, false, bStoreSolidNames); + g_TotalOut += file.fileSize; + for ( int i = 0; i < pNewCollide->solidCount; i++ ) + { + int collideSize = physcollision->CollideSize( pNewCollide->solids[i] ); + out.PutInt( collideSize ); + char *pMem = new char[collideSize]; + physcollision->CollideWrite( pMem, pNewCollide->solids[i] ); + out.Put( pMem, collideSize ); + delete[] pMem; + } + + if (!g_bQuiet) + { + Msg("%s Compressed %d (%d text) to %d (%d text)\n", outName, file.fileSize, file.collide.descSize, out.TellPut(), pNewCollide->descSize ); + } + out.Put( pNewCollide->pKeyValues, pNewCollide->descSize ); + g_TotalCompress += out.TellPut(); + +#if 0 + //Msg("OLD:\n-----------------------------------\n%s\n", file.collide.pKeyValues ); + CPackedPhysicsDescription *pPacked = physcollision->CreatePackedDesc( pNewCollide->pKeyValues, pNewCollide->descSize ); + Msg("NEW:\n-----------------------------------\n" ); + for ( int i = 0; i < pPacked->m_solidCount; i++ ) + { + solid_t solid; + pPacked->GetSolid( &solid, i ); + Msg("index %d\n", solid.index ); + Msg("name %s\n", solid.name ); + Msg("mass %.2f\n", solid.params.mass ); + Msg("surfaceprop %s\n", solid.surfaceprop); + Msg("damping %.2f\n", solid.params.damping ); + Msg("rotdamping %.2f\n", solid.params.rotdamping ); + Msg("drag %.2f\n", solid.params.dragCoefficient ); + Msg("inertia %.2f\n", solid.params.inertia ); + Msg("volume %.2f\n", solid.params.volume ); + } +#endif + DestroyPHX( pNewCollide ); + if ( !g_pFullFileSystem->WriteFile( outName, NULL, out ) ) + Warning("Can't write file: %s\n", outName ); +} + +void UnloadPHYFile( phyfile_t *pFile ) +{ + physcollision->VCollideUnload( &pFile->collide ); + pFile->header.size = 0; +} + +void MakeFilename( char *pDest, int destSize, const char *pPathname, const char *pFilenameExt ) +{ + Q_strncpy(pDest, pPathname, destSize); + Q_AppendSlash(pDest, destSize); + Q_strncat(pDest, pFilenameExt, destSize); +} + +void MakeDirname( char *pDest, int destSize, const char *pPathname, const char *pSubdir ) +{ + MakeFilename(pDest, destSize , pPathname, pSubdir); +} + +int main( int argc, char *argv[] ) +{ + if ( argc < 2 ) + { + Msg("Usage:\nmakephx [options] <FILESPEC>\ne.g. makephx [-r] *.phy\n"); + return 0; + } + + CommandLine()->CreateCmdLine( argc, argv ); + g_bRecursive = CommandLine()->FindParm("-r") > 0 ? true : false; + g_bQuiet = CommandLine()->FindParm("-quiet") > 0 ? true : false; + InitFilesystem( "*.*" ); + InitVPhysics(); + // disable automatic packing, we want to do this ourselves. + physcollision->SetPackOnLoad( false ); + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false ); + InstallSpewFunction(); + + g_pModelConfig = new KeyValues("config"); + g_pModelConfig->LoadFromFile( g_pFullFileSystem, "phx.cfg", "GAME" ); + g_TotalOut = 0; + g_TotalCompress = 0; + FileFindHandle_t handle; + char fullpath[1024], currentFile[1024], dirName[1024], nameext[256]; + strcpy( fullpath, argv[argc-1] ); + strcpy( fullpath, ExpandPath( fullpath ) ); + strcpy( fullpath, ExpandArg( fullpath ) ); + Q_strncpy(dirName, fullpath, sizeof(dirName)); + Q_StripFilename(dirName); + Q_strncpy(nameext, fullpath + strlen(dirName)+1, sizeof(nameext)); + CUtlVector< const char * > directoryList; + directoryList.AddToTail( strdup(dirName) ); + int current = 0; + int count = 0; + do + { + if ( g_bRecursive ) + { + MakeFilename( currentFile, sizeof(currentFile), directoryList[current], "*.*" ); + const char *pFilename = g_pFullFileSystem->FindFirst( currentFile, &handle ); + while ( pFilename ) + { + if ( pFilename[0] != '.' && g_pFullFileSystem->FindIsDirectory( handle ) ) + { + MakeDirname( currentFile, sizeof(currentFile), directoryList[current], pFilename ); + directoryList.AddToTail(strdup(currentFile)); + } + pFilename = g_pFullFileSystem->FindNext( handle ); + } + g_pFullFileSystem->FindClose( handle ); + } + + MakeFilename(currentFile, sizeof(currentFile), directoryList[current], nameext); + const char *pFilename = g_pFullFileSystem->FindFirst( currentFile, &handle ); + while ( pFilename ) + { + phyfile_t phy; + MakeFilename(currentFile, sizeof(currentFile), directoryList[current], pFilename); + LoadPHYFile( &phy, currentFile ); + if ( phy.collide.isPacked || phy.collide.solidCount < 1 ) + { + Msg("%s is not a valid PHY file\n", currentFile ); + } + else + { + WritePHXFile( currentFile, phy ); + count++; + } + UnloadPHYFile( &phy ); + pFilename = g_pFullFileSystem->FindNext( handle ); + } + g_pFullFileSystem->FindClose( handle ); + current++; + } while( current < directoryList.Count() ); + + if ( count ) + { + if (!g_bQuiet) + { + Msg("\n------\nTotal %s, %s\nSaved %s\n", Q_pretifymem( g_TotalOut ), Q_pretifymem( g_TotalCompress ), Q_pretifymem( g_TotalOut - g_TotalCompress ) ); + Msg("%.2f%% savings\n", ((float)(g_TotalOut-g_TotalCompress) / (float)g_TotalOut) * 100.0f ); + } + } + else + { + Msg("No files found in %s!\n", directoryList[current] ); + } + + return 0; +} diff --git a/utils/xbox/makephx/makephx.vcproj b/utils/xbox/makephx/makephx.vcproj new file mode 100644 index 0000000..90df4a1 --- /dev/null +++ b/utils/xbox/makephx/makephx.vcproj @@ -0,0 +1,300 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="makephx" + ProjectGUID="{FD9038D2-A941-4B5E-8E35-4205E650F120}" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="..\..\..\..\game\bin\" + IntermediateDirectory="Debug" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\..\public;..\..\common;..\..\..\public\tier1" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + MinimalRebuild="TRUE" + BasicRuntimeChecks="3" + RuntimeLibrary="5" + UsePrecompiledHeader="3" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/makephx.exe" + LinkIncremental="2" + IgnoreDefaultLibraryNames="LIBC,LIBCD" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/makephx.pdb" + SubSystem="1" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool" + Description="Write enable target file" + CommandLine="attrib -r ..\..\..\..\game\bin\makephx.exe"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory=".\Release" + IntermediateDirectory="Release" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\..\public;..\..\common;..\..\..\public\tier1" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="4" + UsePrecompiledHeader="3" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool" + CommandLine="if exist ..\..\..\..\game\bin\"$(TargetName)".exe attrib -r ..\..\..\..\game\bin\"$(TargetName)".exe +if exist "$(TargetPath)" copy "$(TargetPath)" ..\..\..\..\game\bin" + Outputs="..\..\..\..\game\bin\$(TargetName).exe"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/makephx.exe" + LinkIncremental="1" + IgnoreDefaultLibraryNames="LIBC,LIBCD" + GenerateDebugInformation="TRUE" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool" + Description="Write enable target file" + CommandLine="attrib -r ..\..\..\..\game\bin\makephx.exe"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + <File + RelativePath=".\makephx.cpp"> + </File> + <File + RelativePath=".\phxfile.cpp"> + </File> + <File + RelativePath=".\simplify.cpp"> + </File> + <File + RelativePath=".\stdafx.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1"/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + <File + RelativePath="..\..\..\public\vphysics\constraints.h"> + </File> + <File + RelativePath="..\..\..\public\filesystem.h"> + </File> + <File + RelativePath="..\..\..\public\filesystem_helpers.h"> + </File> + <File + RelativePath="..\..\..\public\filesystem_init.h"> + </File> + <File + RelativePath="..\..\..\public\vstdlib\ICommandLine.h"> + </File> + <File + RelativePath="..\..\..\public\tier1\KeyValues.h"> + </File> + <File + RelativePath="..\..\..\public\mathlib\mathlib.h"> + </File> + <File + RelativePath=".\phxfile.h"> + </File> + <File + RelativePath=".\stdafx.h"> + </File> + <File + RelativePath="..\..\..\public\vstdlib\strtools.h"> + </File> + <File + RelativePath="..\..\..\public\vcollide.h"> + </File> + <File + RelativePath="..\..\..\public\vcollide_parse.h"> + </File> + <File + RelativePath="..\..\..\public\vphysics_interface.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + </Filter> + <Filter + Name="common" + Filter=""> + <File + RelativePath="..\..\common\cmdlib.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\public\filesystem_helpers.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\public\filesystem_init.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\common\filesystem_tools.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\common\physdll.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + </Filter> + <File + RelativePath="..\..\..\lib\public\mathlib.lib"> + </File> + <File + RelativePath=".\ReadMe.txt"> + </File> + <File + RelativePath="..\..\..\lib\public\tier0.lib"> + </File> + <File + RelativePath="..\..\..\lib\public\tier1.lib"> + </File> + <File + RelativePath="..\..\..\lib\public\tier2.lib"> + </File> + <File + RelativePath="..\..\..\lib\public\vstdlib.lib"> + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/utils/xbox/makephx/phx.cpp b/utils/xbox/makephx/phx.cpp new file mode 100644 index 0000000..5a292b2 --- /dev/null +++ b/utils/xbox/makephx/phx.cpp @@ -0,0 +1,215 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "cmdlib.h" +#include "mathlib/mathlib.h" +#include "tier1/strtools.h" +#include "physdll.h" +#include "phyfile.h" +#include "phxfile.h" +#include "utlvector.h" +#include "utlbuffer.h" +#include "vphysics_interface.h" +#include "vcollide_parse.h" +#include "vphysics/constraints.h" +#include "tier0/icommandline.h" +#include "filesystem_tools.h" +#include "simplify.h" +#include "mathlib/compressed_vector.h" +#include "keyvalues.h" + +IPhysicsCollision *physcollision = NULL; +IPhysicsSurfaceProps *physprops = NULL; + +int g_TotalOut = 0; +int g_TotalCompress = 0; + +void InitFilesystem( const char *pPath ) +{ + CmdLib_InitFileSystem( pPath ); + //FileSystem_Init( ".", 0, FS_INIT_COMPATIBILITY_MODE ); + // This bit of hackery allows us to access files on the harddrive + g_pFullFileSystem->AddSearchPath( "", "LOCAL", PATH_ADD_TO_HEAD ); +} + +static bool LoadSurfaceProps( const char *pMaterialFilename ) +{ + if ( !physprops ) + return false; + + // already loaded + if ( physprops->SurfacePropCount() ) + return false; + + FileHandle_t fp = g_pFileSystem->Open( pMaterialFilename, "rb", TOOLS_READ_PATH_ID ); + if ( fp == FILESYSTEM_INVALID_HANDLE ) + return false; + + int len = g_pFileSystem->Size( fp ); + char *pText = new char[len+1]; + g_pFileSystem->Read( pText, len, fp ); + g_pFileSystem->Close( fp ); + + pText[len]=0; + + physprops->ParseSurfaceData( pMaterialFilename, pText ); + + delete[] pText; + + return true; +} + +void LoadSurfacePropsAll() +{ + const char *SURFACEPROP_MANIFEST_FILE = "scripts/surfaceproperties_manifest.txt"; + KeyValues *manifest = new KeyValues( SURFACEPROP_MANIFEST_FILE ); + if ( manifest->LoadFromFile( g_pFileSystem, SURFACEPROP_MANIFEST_FILE, "GAME" ) ) + { + for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() ) + { + if ( !Q_stricmp( sub->GetName(), "file" ) ) + { + // Add + LoadSurfaceProps( sub->GetString() ); + continue; + } + } + } + + manifest->deleteThis(); +} +void InitVPhysics() +{ + CreateInterfaceFn physicsFactory = GetPhysicsFactory(); + physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL ); + physprops = (IPhysicsSurfaceProps *)physicsFactory( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, NULL ); + LoadSurfacePropsAll(); +} + +struct phyfile_t +{ + phyheader_t header; + vcollide_t collide; + int fileSize; +}; + +void LoadPHYFile(phyfile_t *pOut, const char *name) +{ + memset( pOut, 0, sizeof(*pOut) ); + FileHandle_t file = g_pFullFileSystem->Open( name, "rb" ); + if ( !file ) + return; + + g_pFullFileSystem->Read( &pOut->header, sizeof(pOut->header), file ); + if ( pOut->header.size != sizeof(pOut->header) || pOut->header.solidCount <= 0 ) + return; + + pOut->fileSize = g_pFullFileSystem->Size( file ); + + char *buf = (char *)_alloca( pOut->fileSize ); + g_pFullFileSystem->Read( buf, pOut->fileSize, file ); + g_pFullFileSystem->Close( file ); + + physcollision->VCollideLoad( &pOut->collide, pOut->header.solidCount, (const char *)buf, pOut->fileSize ); +} + + + +void WritePHXFile( const char *pName, const phyfile_t &file ) +{ + if ( file.header.size != sizeof(file.header) || file.collide.solidCount <= 0 ) + return; + + CUtlBuffer out; + + char outName[1024]; + Q_snprintf( outName, sizeof(outName), "%s", pName ); + Q_SetExtension( outName, ".phx", sizeof(outName) ); + + out.Put( &file.header, sizeof(file.header) ); + int outSize = 0; + float tolerance = (file.collide.solidCount > 1) ? 3.0f : 7.0f; + + vcollide_t *pNewCollide = ConvertVCollideToPHX( &file.collide, tolerance, &outSize, false ); + g_TotalOut += file.fileSize; + for ( int i = 0; i < pNewCollide->solidCount; i++ ) + { + int collideSize = physcollision->CollideSize( pNewCollide->solids[i] ); + out.PutInt( collideSize ); + char *pMem = new char[collideSize]; + physcollision->CollideWrite( pMem, pNewCollide->solids[i] ); + out.Put( pMem, collideSize ); + delete[] pMem; + } + + Msg("%s Compressed %d (%d text) to %d (%d text)\n", outName, file.fileSize, file.collide.descSize, out.TellPut(), pNewCollide->descSize ); + out.Put( pNewCollide->pKeyValues, pNewCollide->descSize ); + g_TotalCompress += out.TellPut(); + + Msg("OLD:\n-----------------------------------\n%s\n", file.collide.pKeyValues ); + CPackedPhysicsDescription *pPacked = physcollision->CreatePackedDesc( pNewCollide->pKeyValues, pNewCollide->descSize ); + Msg("NEW:\n-----------------------------------\n" ); + for ( int i = 0; i < pPacked->m_solidCount; i++ ) + { + solid_t solid; + pPacked->GetSolid( &solid, i ); + Msg("index %d\n", solid.index ); + Msg("name %s\n", solid.name ); + Msg("mass %.2f\n", solid.params.mass ); + Msg("surfaceprop %s\n", solid.surfaceprop); + Msg("damping %.2f\n", solid.params.damping ); + Msg("rotdamping %.2f\n", solid.params.rotdamping ); + Msg("drag %.2f\n", solid.params.dragCoefficient ); + Msg("inertia %.2f\n", solid.params.inertia ); + Msg("volume %.2f\n", solid.params.volume ); + } + + if ( !g_pFullFileSystem->WriteFile( outName, NULL, out ) ) + Error("Error writing %s\n", outName ); +} + +void UnloadPHYFile( phyfile_t *pFile ) +{ + physcollision->VCollideUnload( &pFile->collide ); + pFile->header.size = 0; +} + +int main( int argc, char *argv[] ) +{ + CommandLine()->CreateCmdLine( argc, argv ); + InstallSpewFunction(); + InitFilesystem( argv[argc-1] ); + InitVPhysics(); + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false ); + + g_TotalOut = 0; + g_TotalCompress = 0; + FileFindHandle_t handle; + char fullpath[1024], filebase[1024]; + strcpy( fullpath, argv[argc-1] ); + strcpy( fullpath, ExpandPath( fullpath ) ); + strcpy( fullpath, ExpandArg( fullpath ) ); + Q_FileBase(fullpath, filebase, sizeof(filebase)); + + const char *pFilename = g_pFullFileSystem->FindFirst( argv[argc-1], &handle ); + while ( pFilename ) + { +#if 0 + if ( g_pFullFileSystem->FindIsDirectory( handle ) ) + { + } +#endif + g_pFullFileSystem->RelativePathToFullPath( pFilename, NULL, filebase, sizeof( filebase ) ); + + phyfile_t phy; + strcpy( filebase, ExpandPath( filebase ) ); + strcpy( filebase, ExpandArg( filebase ) ); + LoadPHYFile( &phy, filebase ); + WritePHXFile( filebase, phy ); + UnloadPHYFile( &phy ); + pFilename = g_pFullFileSystem->FindNext( handle ); + } + g_pFullFileSystem->FindClose( handle ); + Msg("Total %s, %s\nSaved %s\n", Q_pretifymem( g_TotalOut ), Q_pretifymem( g_TotalCompress ), Q_pretifymem( g_TotalOut - g_TotalCompress ) ); + Msg("%.2f%% savings\n", ((float)(g_TotalOut-g_TotalCompress) / (float)g_TotalOut) * 100.0f ); + + return 0; +} diff --git a/utils/xbox/makephx/phxfile.cpp b/utils/xbox/makephx/phxfile.cpp new file mode 100644 index 0000000..304e87e --- /dev/null +++ b/utils/xbox/makephx/phxfile.cpp @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "stdafx.h" +#include "simplify.h" + +extern IPhysicsCollision *physcollision; + +vcollide_t *ConvertVCollideToPHX( const vcollide_t *pCollideIn, const simplifyparams_t ¶ms, int *pSize, bool bStoreSurfaceprops, bool bStoreSolidNames ) +{ + Assert( !pCollideIn->isPacked ); + vcollide_t *pCollideOut = new vcollide_t; + pCollideOut->solids = new CPhysCollide *[pCollideIn->solidCount]; + pCollideOut->solidCount = pCollideIn->solidCount; + *pSize = 0; + + for ( int i = 0; i < pCollideIn->solidCount; i++ ) + { + Assert( pCollideIn->solids[i] ); + pCollideOut->solids[i] = SimplifyCollide( pCollideIn->solids[i], i, params ); + Assert( pCollideOut->solids[i] ); + int collideSize = physcollision->CollideSize( pCollideOut->solids[i] ); + *pSize += collideSize; + } + int packedTextSize; + pCollideOut->pKeyValues = (char *)physcollision->PackVCollideText( pCollideIn->pKeyValues, &packedTextSize, bStoreSolidNames, bStoreSurfaceprops ); + pCollideOut->isPacked = true; + pCollideOut->descSize = packedTextSize; + *pSize += packedTextSize; + + return pCollideOut; +} + + +void DestroyPHX( vcollide_t *pCollide ) +{ + for ( int i = 0; i < pCollide->solidCount; i++ ) + { + physcollision->DestroyCollide( pCollide->solids[i] ); + } + delete[] pCollide->solids; + physcollision->DestroyVCollideText( pCollide->pKeyValues ); + delete pCollide; +} diff --git a/utils/xbox/makephx/phxfile.h b/utils/xbox/makephx/phxfile.h new file mode 100644 index 0000000..cb4f2dc --- /dev/null +++ b/utils/xbox/makephx/phxfile.h @@ -0,0 +1,18 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef PHXFILE_H +#define PHXFILE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "simplify.h" +// convert a vcollide to packed/simplified format +vcollide_t *ConvertVCollideToPHX( const vcollide_t *pCollideIn, const simplifyparams_t ¶ms, int *pSize, bool bStoreSurfaceprops, bool bStoreSolidNames ); +void DestroyPHX( vcollide_t *pCollide ); + +#endif // PHXFILE_H diff --git a/utils/xbox/makephx/simplify.cpp b/utils/xbox/makephx/simplify.cpp new file mode 100644 index 0000000..897fccf --- /dev/null +++ b/utils/xbox/makephx/simplify.cpp @@ -0,0 +1,453 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "stdafx.h" +#include "simplify.h" +extern IPhysicsCollision *physcollision; + +extern bool g_bQuiet; + +const float DIST_EPSILON = 1.0f / 32.0f; +// this is the list of candidate planes that will be added one by one to the convex hull +// until none of the surface lies outside the tolerance +struct planetest_t +{ + Vector normal; + float dist; + int inUse; + float bestDist; + void Init( int axis, float sign, float _dist, bool _inUse = false ) + { + memset( this, 0, sizeof(*this) ); + normal[axis] = sign; + dist = sign*_dist; + inUse = _inUse; + bestDist = -1; + } + void Init( const Vector &a, const Vector &b, const Vector &c, bool _inUse = false ) + { + Vector e0 = b-a; + Vector e1 = c-a; + normal = CrossProduct( e1, e0 ); + VectorNormalize( normal ); + dist = DotProduct( normal, a ); + inUse = _inUse; + bestDist = -1; + } +}; + +CPhysConvex *ConvertPlaneListToConvex( CUtlVector<planetest_t> &list ) +{ + float temp[4 * 2048]; + struct listplane_t + { + float plane[4]; + }; + + int planeCount = 0; + listplane_t *pList = (listplane_t *)temp; + for ( int i = 0; i < list.Count(); i++ ) + { + if ( list[i].inUse ) + { + list[i].normal.CopyToArray( pList[planeCount].plane ); + pList[planeCount].plane[3] = list[i].dist; + planeCount++; + } + } + + return physcollision->ConvexFromPlanes( temp, planeCount, 0.25f ); +} + +Vector BoxSupport( const Vector &dir, const Vector &mins, const Vector &maxs ) +{ + Vector out; + for ( int i = 0; i < 3; i++ ) + { + out[i] = (dir[i] >= 0) ? maxs[i] : mins[i]; + } + return out; +} + +struct convexoptimize_t +{ + CUtlVector<planetest_t> list; + float targetTolerance; + + void InitPlanes( CPhysCollide *pCollide, bool addAABBToSimplifiedHull ) + { + Vector mins, maxs; + physcollision->CollideGetAABB( &mins, &maxs, pCollide, vec3_origin, vec3_angle ); + if ( !addAABBToSimplifiedHull ) + { + mins -= Vector(targetTolerance,targetTolerance,targetTolerance); + maxs += Vector(targetTolerance,targetTolerance,targetTolerance); + } + int i; + for ( i = 0; i < 3; i++ ) + { + planetest_t &elem = list[list.AddToTail()]; + elem.Init( i, 1.0f, maxs[i], true ); + planetest_t &elem2 = list[list.AddToTail()]; + elem2.Init( i, -1.0f, mins[i], true ); + } + ICollisionQuery *pQuery = physcollision->CreateQueryModel( pCollide ); + Vector triVerts[3]; + for ( i = 0; i < pQuery->TriangleCount(0); i++ ) + { + pQuery->GetTriangleVerts( 0, i, triVerts ); + planetest_t &elem = list[list.AddToTail()]; + elem.Init( triVerts[0], triVerts[1], triVerts[2], false ); + elem.bestDist = DotProduct( elem.normal, BoxSupport(elem.normal, mins, maxs) ) - elem.dist; + } + physcollision->DestroyQueryModel( pQuery ); + } + + CPhysConvex *ConvertToConvex() + { + return ::ConvertPlaneListToConvex( list ); + } + + int FindBestPlane( float dist ) + { + int best = -1; + for ( int i = 6; i < list.Count(); i++ ) + { + if ( list[i].inUse ) + continue; + if ( dist >= list[i].bestDist ) + continue; + dist = list[i].bestDist; + best = i; + } + return best; + } + + bool AddBestPlane() + { + convertconvexparams_t params; + params.Defaults(); + CPhysConvex *pConvex = ConvertPlaneListToConvex( list ); + CPhysCollide *pCurrentCollide = physcollision->ConvertConvexToCollideParams( &pConvex, 1, params ); + int bestIndex = -1; + float bestDist = 0; + while ( true ) + { + if ( bestIndex >= 0 ) + { + list[bestIndex].inUse = true; + } + int test = FindBestPlane( bestDist ); + if ( test < 0 ) + break; + if ( bestIndex >= 0 ) + { + list[bestIndex].inUse = false; + } + Vector dir = list[test].normal; + Vector point = physcollision->CollideGetExtent( pCurrentCollide, vec3_origin, vec3_angle, dir ); + float before = DotProduct( dir, point ); + list[test].inUse = true; + pConvex = ConvertToConvex(); + list[test].inUse = false; + CPhysCollide *pCollide = physcollision->ConvertConvexToCollideParams( &pConvex, 1, params ); + Vector p2 = physcollision->CollideGetExtent( pCollide, vec3_origin, vec3_angle, dir ); + physcollision->DestroyCollide( pCollide ); + float after = DotProduct( dir, p2 ); + list[test].bestDist = fabs(before-after); + if ( list[test].bestDist > bestDist ) + { + bestDist = list[test].bestDist; + bestIndex = test; + } + } + physcollision->DestroyCollide( pCurrentCollide ); + + if ( bestIndex >= 0 && bestDist >= targetTolerance ) + { + list[bestIndex].inUse = true; + return true; + } + + return false; + } +}; + +CPhysConvex *SimplifyConvexFromVerts( Vector **verts, int vertCount, bool addAABBToSimplifiedHull, float tolerance, int index ) +{ + CPhysConvex *pConvex = physcollision->ConvexFromVerts( verts, vertCount ); + float targetVolume = physcollision->ConvexVolume( pConvex ); + // can't simplify this polyhedron + if ( vertCount <= 8 ) + return pConvex; + + convexoptimize_t opt; + memset( &opt, 0, sizeof(opt)); + opt.targetTolerance = tolerance; + convertconvexparams_t params; + params.Defaults(); + CPhysCollide *pRef = physcollision->ConvertConvexToCollideParams( &pConvex, 1, params ); + opt.InitPlanes( pRef, addAABBToSimplifiedHull ); + physcollision->DestroyCollide( pRef ); + + // Simplify until you hit the tolerance + int i; + for ( i = 0; i < vertCount; i++ ) + { + if ( !opt.AddBestPlane() ) + break; + } + + // Create the output shape + pConvex = opt.ConvertToConvex(); + float currentVolume = physcollision->ConvexVolume( pConvex ); + //Msg("%d iterations, for convex %d\n", i, index ); + + return pConvex; +} + +inline int AddVert( Vector **ppVerts, int vertCount, const Vector &newVert ) +{ + for ( int i = 0; i < vertCount; i++ ) + { + if ( fabs(ppVerts[i]->x - newVert.x) < DIST_EPSILON && + fabs(ppVerts[i]->y - newVert.y) < DIST_EPSILON && + fabs(ppVerts[i]->z - newVert.z) < DIST_EPSILON ) + return vertCount; + } + *ppVerts[vertCount] = newVert; + return vertCount+1; +} + +void BuildSingleConvex( CPhysConvex **convexListOut, ICollisionQuery *pQuery, Vector **ppVerts, const simplifyparams_t ¶ms ) +{ + int vertCount = 0; + for ( int i = 0; i < pQuery->ConvexCount(); i++ ) + { + Vector v[3]; + for ( int j = 0; j < pQuery->TriangleCount(i); j++ ) + { + pQuery->GetTriangleVerts( i, j, v ); + vertCount = AddVert( ppVerts, vertCount, v[0] ); + vertCount = AddVert( ppVerts, vertCount, v[1] ); + vertCount = AddVert( ppVerts, vertCount, v[2] ); + } + } + convexListOut[0] = SimplifyConvexFromVerts( ppVerts, vertCount, params.addAABBToSimplifiedHull, params.tolerance, 0 ); + physcollision->SetConvexGameData( convexListOut[0], pQuery->GetGameData( 0 ) ); +} + +void SimplifyConvexElements( CPhysConvex **convexListOut, ICollisionQuery *pQuery, Vector **ppVerts, const simplifyparams_t ¶ms ) +{ + for ( int i = 0; i < pQuery->ConvexCount(); i++ ) + { + int vertCount = 0; + Vector v[3]; + for ( int j = 0; j < pQuery->TriangleCount(i); j++ ) + { + pQuery->GetTriangleVerts( i, j, v ); + vertCount = AddVert( ppVerts, vertCount, v[0] ); + vertCount = AddVert( ppVerts, vertCount, v[1] ); + vertCount = AddVert( ppVerts, vertCount, v[2] ); + } + convexListOut[i] = SimplifyConvexFromVerts( ppVerts, vertCount, params.addAABBToSimplifiedHull, params.tolerance, i ); + physcollision->SetConvexGameData( convexListOut[i], pQuery->GetGameData( i ) ); + } +} + +struct mergeconvex_t +{ + byte mergeCount; + byte list[255]; +}; + +void MergeElems( CUtlVector<mergeconvex_t> &elems, int index0, int index1 ) +{ + Assert( index0 < index1 ); + for (int i = 0; i < elems[index1].mergeCount; i++) + { + elems[index0].list[i+elems[index0].mergeCount] = elems[index1].list[i]; + } + elems[index0].mergeCount += elems[index1].mergeCount; + elems.FastRemove(index1); +} + +int VertsForElem( ICollisionQuery *pQuery, Vector **ppVerts, const mergeconvex_t &elems0, int vertCount ) +{ + for ( int i = 0; i < elems0.mergeCount; i++ ) + { + int convexId = elems0.list[i]; + Vector v[3]; + for ( int j = 0; j < pQuery->TriangleCount(convexId); j++ ) + { + pQuery->GetTriangleVerts( convexId, j, v ); + vertCount = AddVert( ppVerts, vertCount, v[0] ); + vertCount = AddVert( ppVerts, vertCount, v[1] ); + vertCount = AddVert( ppVerts, vertCount, v[2] ); + } + } + return vertCount; +} + +void PlanesForElem( ICollisionQuery *pQuery, CUtlVector<float> &planes, const mergeconvex_t &elem0 ) +{ + for ( int i = 0; i < elem0.mergeCount; i++ ) + { + int convexId = elem0.list[i]; + Vector v[3]; + for ( int j = 0; j < pQuery->TriangleCount(convexId); j++ ) + { + pQuery->GetTriangleVerts( convexId, j, v ); + Vector e0 = v[1]-v[0]; + Vector e1 = v[2]-v[0]; + Vector normal = CrossProduct( e1, e0 ); + VectorNormalize( normal ); + float dist = DotProduct( normal, v[0] ); + planes.AddToTail( normal.x ); + planes.AddToTail( normal.y ); + planes.AddToTail( normal.z ); + planes.AddToTail( dist ); + } + } +} + +float ConvexVolumeFromPlanes( CUtlVector<float> &planes ) +{ + CPhysConvex *pConvex = planes.Count() ? physcollision->ConvexFromPlanes( planes.Base(), planes.Count()/4, DIST_EPSILON ) : NULL; + float volume = 0; + if ( pConvex ) + { + volume = physcollision->ConvexVolume(pConvex); + physcollision->ConvexFree(pConvex); + } + return volume; +} + +float MergedDeltaVolume( ICollisionQuery *pQuery, Vector **ppVerts, const mergeconvex_t &elem0, const mergeconvex_t &elem1 ) +{ + // build vert list + int vertCount = VertsForElem( pQuery, ppVerts, elem0, 0 ); + // merge in next element + vertCount = VertsForElem( pQuery, ppVerts, elem1, vertCount); + CPhysConvex *pConvex = physcollision->ConvexFromVerts( ppVerts, vertCount ); + float finalVolume = physcollision->ConvexVolume(pConvex); + physcollision->ConvexFree(pConvex); + + CUtlVector<float> planes; + PlanesForElem( pQuery, planes, elem0 ); + float vol0 = ConvexVolumeFromPlanes( planes ); + planes.RemoveAll(); + PlanesForElem( pQuery, planes, elem1 ); + float vol1 = ConvexVolumeFromPlanes( planes ); + PlanesForElem( pQuery, planes, elem0 ); + + float volInt = ConvexVolumeFromPlanes( planes ); + + return finalVolume - (vol0+vol1-volInt); +} + +int MergeAndSimplifyConvexElements( CPhysConvex **convexListOut, const CPhysCollide *pCollideIn, ICollisionQuery *pQuery, Vector **ppVerts, const simplifyparams_t ¶ms ) +{ + Assert( pQuery->ConvexCount() < 256 ); + if ( pQuery->ConvexCount() > 256 ) + { + SimplifyConvexElements(convexListOut, pQuery, ppVerts, params); + return pQuery->ConvexCount(); + } + + CUtlVector<mergeconvex_t> elems; + int i; + elems.EnsureCount(pQuery->ConvexCount()); + float totalVolume = physcollision->CollideVolume( (CPhysCollide *)pCollideIn ); + for ( i = 0; i < pQuery->ConvexCount(); i++ ) + { + elems[i].mergeCount = 1; + elems[i].list[0] = i; + } +loop: + for ( i = 0; i < elems.Count(); i++ ) + { + for ( int j = i+1; j < elems.Count(); j++ ) + { + float volume = fabs(MergedDeltaVolume( pQuery, ppVerts, elems[i], elems[j] )); + volume /= totalVolume; + if ( volume < params.mergeConvexTolerance ) + { + MergeElems( elems, i, j ); + goto loop; + } + } + } + + for ( i = 0; i < elems.Count(); i++ ) + { + int vertCount = VertsForElem( pQuery, ppVerts, elems[i], 0 ); + convexListOut[i] = SimplifyConvexFromVerts( ppVerts, vertCount, params.addAABBToSimplifiedHull, params.tolerance, i ); + physcollision->SetConvexGameData( convexListOut[i], pQuery->GetGameData( elems[i].list[0] ) ); + } + return elems.Count(); +} + +CPhysCollide *SimplifyCollide( CPhysCollide *pCollideIn, int indexIn, const simplifyparams_t ¶ms ) +{ + int sizeIn = physcollision->CollideSize( pCollideIn ); + ICollisionQuery *pQuery = physcollision->CreateQueryModel( pCollideIn ); + int maxVertCount = 0; + int i; + for ( i = pQuery->ConvexCount(); --i >= 0; ) + { + int vertCount = pQuery->TriangleCount(i)*3; + maxVertCount += vertCount; + } + + Vector **ppVerts = new Vector *[maxVertCount]; + Vector *verts = new Vector[maxVertCount]; + for ( i = 0; i < maxVertCount; i++ ) + { + ppVerts[i] = &verts[i]; + } + + int outputConvexCount = params.forceSingleConvex ? 1 : pQuery->ConvexCount(); + CPhysConvex **convexList = new CPhysConvex *[outputConvexCount]; + if ( params.forceSingleConvex ) + { + BuildSingleConvex( convexList, pQuery, ppVerts, params ); + } + else if ( params.mergeConvexElements && pQuery->ConvexCount() > 1 ) + { + outputConvexCount = MergeAndSimplifyConvexElements( convexList, pCollideIn, pQuery, ppVerts, params ); + if ( !g_bQuiet && pQuery->ConvexCount() != outputConvexCount) + { + Msg("Simplified %d to %d elements\n", pQuery->ConvexCount(), outputConvexCount ); + } + } + else + { + SimplifyConvexElements( convexList, pQuery, ppVerts, params ); + } + convertconvexparams_t params; + params.Defaults(); + params.buildOuterConvexHull = true; + params.buildDragAxisAreas = false; + + CPhysCollide *pCollideOut = physcollision->ConvertConvexToCollideParams( convexList, outputConvexCount, params ); + + // copy the drag axis areas from the source + Vector dragAxisAreas = physcollision->CollideGetOrthographicAreas( pCollideIn ); + physcollision->CollideSetOrthographicAreas( pCollideOut, dragAxisAreas ); + + physcollision->DestroyQueryModel( pQuery ); + delete[] convexList; + delete[] verts; + delete[] ppVerts; + + if ( physcollision->CollideSize(pCollideOut) >= sizeIn ) + { + // make a copy of the input collide + physcollision->DestroyCollide(pCollideOut); + char *pBuf = new char[sizeIn]; + physcollision->CollideWrite( pBuf, pCollideIn ); + pCollideOut = physcollision->UnserializeCollide( pBuf, sizeIn, indexIn ); + delete[] pBuf; + } + return pCollideOut; +} + diff --git a/utils/xbox/makephx/simplify.h b/utils/xbox/makephx/simplify.h new file mode 100644 index 0000000..acf2625 --- /dev/null +++ b/utils/xbox/makephx/simplify.h @@ -0,0 +1,38 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef SIMPLIFY_H +#define SIMPLIFY_H +#pragma once + +struct simplifyparams_t +{ + float tolerance; + bool addAABBToSimplifiedHull; + bool forceSingleConvex; + bool mergeConvexElements; + float mergeConvexTolerance; + + void Defaults() + { + tolerance = 1.0f; + addAABBToSimplifiedHull = false; + forceSingleConvex = false; + mergeConvexElements = false; + mergeConvexTolerance = 0.f; + } +}; + +extern CPhysCollide *SimplifyCollide( CPhysCollide *pCollideIn, int index, const simplifyparams_t ¶ms ); + +#endif // SIMPLIFY_H diff --git a/utils/xbox/makephx/stdafx.cpp b/utils/xbox/makephx/stdafx.cpp new file mode 100644 index 0000000..c4c1f62 --- /dev/null +++ b/utils/xbox/makephx/stdafx.cpp @@ -0,0 +1,9 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// stdafx.cpp : source file that includes just the standard includes +// makephx.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/utils/xbox/makephx/stdafx.h b/utils/xbox/makephx/stdafx.h new file mode 100644 index 0000000..db4423e --- /dev/null +++ b/utils/xbox/makephx/stdafx.h @@ -0,0 +1,20 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + + +#include "cmdlib.h" +#include "mathlib/mathlib.h" +#include "vphysics_interface.h" +#include "tier1/strtools.h" +#include "phyfile.h" +#include "phxfile.h" +#include "utlvector.h" +#include "utlbuffer.h" +#include "vcollide_parse.h" + +// TODO: reference additional headers your program requires here diff --git a/utils/xbox/makephx/util.cpp b/utils/xbox/makephx/util.cpp new file mode 100644 index 0000000..cb5e879 --- /dev/null +++ b/utils/xbox/makephx/util.cpp @@ -0,0 +1,41 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include "mathlib/mathlib.h" +#include "util.h" +#include "tier1/strtools.h" + +void UTIL_StringToFloatArray( float *pVector, int count, const char *pString ) +{ + char *pstr, *pfront, tempString[128]; + int j; + + Q_strncpy( tempString, pString, sizeof(tempString) ); + pstr = pfront = tempString; + + for ( j = 0; j < count; j++ ) // lifted from pr_edict.c + { + pVector[j] = atof( pfront ); + + // skip any leading whitespace + while ( *pstr && *pstr <= ' ' ) + pstr++; + + // skip to next whitespace + while ( *pstr && *pstr > ' ' ) + pstr++; + + if (!*pstr) + break; + + pstr++; + pfront = pstr; + } + for ( j++; j < count; j++ ) + { + pVector[j] = 0; + } +} + +void UTIL_StringToVector( float *pVector, const char *pString ) +{ + UTIL_StringToFloatArray( pVector, 3, pString ); +} diff --git a/utils/xbox/makephx/util.h b/utils/xbox/makephx/util.h new file mode 100644 index 0000000..8d389a3 --- /dev/null +++ b/utils/xbox/makephx/util.h @@ -0,0 +1,16 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef UTIL_H +#define UTIL_H +#ifdef _WIN32 +#pragma once +#endif + +extern void UTIL_StringToFloatArray( float *pVector, int count, const char *pString ); +extern void UTIL_StringToVector( float *pVector, const char *pString ); + +#endif // UTIL_H diff --git a/utils/xbox/makexvcd/cbase.h b/utils/xbox/makexvcd/cbase.h new file mode 100644 index 0000000..d374bb7 --- /dev/null +++ b/utils/xbox/makexvcd/cbase.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef CBASE_H +#define CBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "basetypes.h" + +// This is just a dummy file to make this tool compile +#include "ai_activity.h" +#include "UtlVector.h" + +#endif // CBASE_H diff --git a/utils/xbox/makexvcd/makexvcd.cpp b/utils/xbox/makexvcd/makexvcd.cpp new file mode 100644 index 0000000..fcb1459 --- /dev/null +++ b/utils/xbox/makexvcd/makexvcd.cpp @@ -0,0 +1,933 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: vcd_sound_check.cpp : Defines the entry point for the console application. +// +//=============================================================================// +#include <stdio.h> +#include <windows.h> +#include "tier0/dbg.h" +#include "tier1/utldict.h" +#include "filesystem.h" +#include "FileSystem_Tools.h" +#include "tier1/KeyValues.h" +#include "cmdlib.h" +#include "scriplib.h" +#include "vstdlib/random.h" +#include "choreoscene.h" +#include "choreoevent.h" +#include "iscenetokenprocessor.h" +#include "tier1/utlbuffer.h" +#include "tier1/checksum_crc.h" +#include "pacifier.h" +#include "SceneCache.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "ModelSoundsCache.h" +#include "Datacache/imdlcache.h" +#include "datacache/idatacache.h" +#include "studio.h" +#include "appframework/appframework.h" +#include "tier0/icommandline.h" +#include "istudiorender.h" +#include "materialsystem/imaterialsystem.h" +#include "vphysics_interface.h" +#include "icvar.h" +#include "vstdlib/cvar.h" +#include "eventlist.h" + +// #define TESTING 1 + + +bool uselogfile = false; +bool modelsoundscache = false; +bool scenecache = false; +bool virtualmodel = false; +bool buildxcds = false; + +struct AnalysisData +{ + CUtlSymbolTable symbols; +}; + +static AnalysisData g_Analysis; + +static char g_szCurrentGameDir[ 512 ]; + +IFileSystem *filesystem = NULL; +IMDLCache *g_pMDLCache = NULL; +ISoundEmitterSystemBase *soundemitterbase = NULL; + +static CUniformRandomStream g_Random; +IUniformRandomStream *random = &g_Random; + +static bool spewed = false; + +static CUtlCachedFileData< CSceneCache > g_SceneCache( "scene.cache", SCENECACHE_VERSION, 0, UTL_CACHED_FILE_USE_FILESIZE ); +static CUtlCachedFileData< CModelSoundsCache > g_ModelSoundsCache( "modelsounds.cache", MODELSOUNDSCACHE_VERSION, 0, UTL_CACHED_FILE_USE_FILESIZE ); + +//----------------------------------------------------------------------------- +// FIXME: This trashy glue code is really not acceptable. Figure out a way of making it unnecessary. +//----------------------------------------------------------------------------- +const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *pModelName ) const +{ + MDLHandle_t handle = g_pMDLCache->FindMDL( pModelName ); + *cache = (void*)handle; + return g_pMDLCache->GetStudioHdr( handle ); +} + +virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const +{ + return g_pMDLCache->GetVirtualModel( (MDLHandle_t)virtualModel ); +} + +byte *studiohdr_t::GetAnimBlock( int i ) const +{ + return g_pMDLCache->GetAnimBlock( (MDLHandle_t)virtualModel, i ); +} + +int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const +{ + return g_pMDLCache->GetAutoplayList( (MDLHandle_t)virtualModel, pOut ); +} + +const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const +{ + return g_pMDLCache->GetStudioHdr( (MDLHandle_t)cache ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Helper for parsing scene data file +//----------------------------------------------------------------------------- +class CSceneTokenProcessor : public ISceneTokenProcessor +{ +public: + const char *CurrentToken( void ); + bool GetToken( bool crossline ); + bool TokenAvailable( void ); + void Error( const char *fmt, ... ); +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const char +//----------------------------------------------------------------------------- +const char *CSceneTokenProcessor::CurrentToken( void ) +{ + return token; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : crossline - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CSceneTokenProcessor::GetToken( bool crossline ) +{ + return ::GetToken( crossline ) ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CSceneTokenProcessor::TokenAvailable( void ) +{ + return ::TokenAvailable() ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *fmt - +// ... - +//----------------------------------------------------------------------------- +void CSceneTokenProcessor::Error( const char *fmt, ... ) +{ + char string[ 2048 ]; + va_list argptr; + va_start( argptr, fmt ); + Q_vsnprintf( string, sizeof(string), fmt, argptr ); + va_end( argptr ); + + Warning( "%s", string ); + Assert(0); +} + +static CSceneTokenProcessor g_TokenProcessor; + +SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg ) +{ + spewed = true; + + printf( "%s", pMsg ); + OutputDebugString( pMsg ); + + if ( type == SPEW_ERROR ) + { + printf( "\n" ); + OutputDebugString( "\n" ); + } + + return SPEW_CONTINUE; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : depth - +// *fmt - +// ... - +//----------------------------------------------------------------------------- +void vprint( int depth, const char *fmt, ... ) +{ + char string[ 8192 ]; + va_list va; + va_start( va, fmt ); + vsprintf( string, fmt, va ); + va_end( va ); + + FILE *fp = NULL; + + if ( uselogfile ) + { + fp = fopen( "log.txt", "ab" ); + } + + while ( depth-- > 0 ) + { + printf( " " ); + OutputDebugString( " " ); + if ( fp ) + { + fprintf( fp, " " ); + } + } + + ::printf( "%s", string ); + OutputDebugString( string ); + + if ( fp ) + { + char *p = string; + while ( *p ) + { + if ( *p == '\n' ) + { + fputc( '\r', fp ); + } + fputc( *p, fp ); + p++; + } + fclose( fp ); + } +} + +void logprint( char const *logfile, const char *fmt, ... ) +{ + char string[ 8192 ]; + va_list va; + va_start( va, fmt ); + vsprintf( string, fmt, va ); + va_end( va ); + + FILE *fp = NULL; + static bool first = true; + if ( first ) + { + first = false; + fp = fopen( logfile, "wb" ); + } + else + { + fp = fopen( logfile, "ab" ); + } + if ( fp ) + { + char *p = string; + while ( *p ) + { + if ( *p == '\n' ) + { + fputc( '\r', fp ); + } + fputc( *p, fp ); + p++; + } + fclose( fp ); + } +} + + +void Con_Printf( const char *fmt, ... ) +{ + va_list args; + static char output[1024]; + + va_start( args, fmt ); + vprintf( fmt, args ); + vsprintf( output, fmt, args ); + + vprint( 0, output ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void printusage( void ) +{ + vprint( 0, "usage: makexvcd [options] -game gamedir\n\ + \t-v = verbose output\n\ + \t-m = rebuild modelsounds.cache\n\ + \t-x = rebuild .xcd files\n\ + \t-s = rebuild scene.cache\n\ + \t-z = rebuild virtualmodel.cache (xbox only)\n\ + \t-l = log to file log.txt\n\ + \ne.g.: makexvcd -s -m -game episodic\n" ); + + // Exit app + exit( 1 ); +} + +void BuildFileList_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *extension ) +{ + WIN32_FIND_DATA wfd; + + char directory[ 256 ]; + char filename[ 256 ]; + HANDLE ff; + + Q_snprintf( directory, sizeof( directory ), "%s\\*.*", dir ); + +#if defined( TESTING ) + if ( files.Count() > 100 ) + return; +#endif + + if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE ) + return; + + int extlen = strlen( extension ); + + do + { +#if defined( TESTING ) + if ( files.Count() > 100 ) + return; +#endif + if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + + if ( wfd.cFileName[ 0 ] == '.' ) + continue; + + // Recurse down directory + Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName ); + BuildFileList_R( files, filename, extension ); + } + else + { + int len = strlen( wfd.cFileName ); + if ( len > extlen ) + { + if ( !stricmp( &wfd.cFileName[ len - extlen ], extension ) ) + { + char filename[ MAX_PATH ]; + Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName ); + _strlwr( filename ); + + Q_FixSlashes( filename ); + + CUtlSymbol sym = g_Analysis.symbols.AddString( filename ); + files.AddToTail( sym ); + + if ( !( files.Count() % 3000 ) ) + { + vprint( 0, "...found %i .%s files\n", files.Count(), extension ); + } + } + } + } + } while ( FindNextFile( ff, &wfd ) ); +} + +void BuildFileList( char const *basedir, CUtlVector< CUtlSymbol >& files, char const *rootdir, char const *extension ) +{ + files.RemoveAll(); + char root[ 512 ]; + Q_snprintf( root, sizeof( root ), "%s\\%s", basedir, rootdir ); + BuildFileList_R( files, root, extension ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CheckLogFile( void ) +{ + if ( uselogfile ) + { + _unlink( "log.txt" ); + vprint( 0, " Outputting to log.txt\n" ); + } +} + +void PrintHeader() +{ + vprint( 0, "Valve Software - CompileVCD.exe (%s)\n", __DATE__ ); + vprint( 0, "--- Binary .vcd compiler ---\n" ); +} + +//----------------------------------------------------------------------------- +// Purpose: For each .wav file in the list, see if any vcd file in the list references it +// First build an index of .wav to .vcd mappings, then search wav list and print results +// Input : vcdfiles - +// wavfiles - +//----------------------------------------------------------------------------- + +struct VCDList +{ + VCDList() + { + } + + VCDList( const VCDList& src ) + { + int c = src.vcds.Count(); + for ( int i = 0 ; i < c; i++ ) + { + vcds.AddToTail( src.vcds[ i ] ); + } + } + + VCDList& operator =( const VCDList& src ) + { + if ( this == &src ) + return *this; + + int c = src.vcds.Count(); + for ( int i = 0 ; i < c; i++ ) + { + vcds.AddToTail( src.vcds[ i ] ); + } + + return *this; + } + + CUtlVector< CUtlSymbol > vcds; +}; + +void AppendDisposition( CUtlVector< CUtlSymbol >& disposition, char const *fmt, ... ) +{ + char string[ 2048 ]; + va_list argptr; + va_start( argptr, fmt ); + _vsnprintf( string, sizeof( string ), fmt, argptr ); + va_end( argptr ); + + CUtlSymbol sym; + sym = string; + disposition.AddToTail( sym ); +} + +CChoreoScene *BlockingLoadScene( char const *vcdname ) +{ + // Load the .vcd + char scenefile[ MAX_PATH ]; + Q_snprintf( scenefile, sizeof( scenefile ), "%s\\%s", g_szCurrentGameDir, vcdname ); + + LoadScriptFile( scenefile ); + + CChoreoScene *scene = ChoreoLoadScene( scenefile, NULL, &g_TokenProcessor, Con_Printf ); + return scene; +} + +void ProcessVCD( char const *vcdname, CUtlVector< CUtlSymbol >& disposition ) +{ + if ( verbose ) + { + vprint( 0, "Processing '%s'\n", vcdname ); + } + + bool rebuild = false; + + FileHandle_t fh = filesystem->Open( vcdname, "rb", "GAME" ); + if ( fh == FILESYSTEM_INVALID_HANDLE ) + { + Error( "Couldn't open '%s' for reading.", vcdname ); + return; + } + + size_t bufSize = filesystem->Size( fh ); + char *buffer = new char[ bufSize + 1 ]; + filesystem->Read( buffer, bufSize, fh ); + filesystem->Close( fh ); + buffer[ bufSize ] = 0; + + CRC32_t crc; + CRC32_Init( &crc ); + CRC32_ProcessBuffer( &crc, buffer, bufSize ); + CRC32_Final( &crc ); + + delete[] buffer; + + // Now load the file as a binary if it exists... + char binfile[ 512 ]; + Q_strncpy( binfile, vcdname, sizeof( binfile ) ); + Q_SetExtension( binfile, ".xcd", sizeof( binfile ) ); + + if ( buildxcds ) + { + fh = filesystem->Open( binfile, "rb", "GAME" ); + if ( fh == FILESYSTEM_INVALID_HANDLE ) + { + AppendDisposition( disposition, "Built '%s'\n", binfile ); + rebuild = true; + } + else + { + // Read the first bit of data and check + char crcdata[ 12 ]; + filesystem->Read( crcdata, sizeof( crcdata ), fh ); + filesystem->Close( fh ); + + CUtlBuffer buf; + buf.Put( crcdata, sizeof( crcdata ) ); + + CRC32_t fileCRC = 0; + if ( !CChoreoScene::GetCRCFromBuffer( buf, (unsigned int &)fileCRC ) ) + { + AppendDisposition( disposition, "Rebuilt '%s' due to version change\n", binfile ); + rebuild = true; + } + else + { + if ( fileCRC != crc ) + { + AppendDisposition( disposition, "Rebuilt '%s' due to crc change\n", binfile ); + rebuild = true; + } + } + } + } + + // Validate the scene cache + g_SceneCache.RebuildItem( vcdname + strlen( g_szCurrentGameDir ) + 1 ); + + if ( !rebuild ) + return; + + // Remove current binary + if ( filesystem->FileExists( binfile, "GAME" ) ) + { + _unlink( binfile ); + } + + // Load the .vcd + LoadScriptFile( (char *)vcdname ); + + CChoreoScene *scene = ChoreoLoadScene( vcdname, NULL, &g_TokenProcessor, Con_Printf ); + if ( scene ) + { + scene->SaveBinary( binfile, NULL, crc ); + + delete scene; + } +} + +void CompileVCDs( CUtlVector< CUtlSymbol >& vcds ) +{ + CUtlVector< CUtlSymbol > disposition; + + StartPacifier( "CompileVCDs" ); + int i; + int c = vcds.Count(); + for ( i = 0 ; i < c; ++i ) + { + UpdatePacifier( (float)i / (float)c ); + ProcessVCD( g_Analysis.symbols.String( vcds[ i ] ), disposition ); + } + EndPacifier(); + + if ( verbose ) + { + c = disposition.Count(); + for ( i = 0; i < c; ++i ) + { + Warning( "%s", disposition[ i ].String() ); + } + } +} + +static CUtlMap< CStudioHdr *, MDLHandle_t > g_ModelMap( 0, 0, DefLessFunc( CStudioHdr * ) ); + +CStudioHdr *ModelSoundsCache_LoadModel( char const *filename ) +{ + MDLHandle_t handle = g_pMDLCache->FindMDL( filename ); + + CStudioHdr *studioHdr = new CStudioHdr( g_pMDLCache->GetStudioHdr( handle ), g_pMDLCache ); + + g_ModelMap.Insert( studioHdr, handle ); + + if ( studioHdr->IsValid() ) + return studioHdr; + return NULL; +} + +void ModelSoundsCache_FinishModel( CStudioHdr *hdr ) +{ + int idx = g_ModelMap.Find( hdr ); + if ( idx != g_ModelMap.InvalidIndex() ) + { + g_pMDLCache->Release( g_ModelMap[ idx ] ); + g_ModelMap.RemoveAt( idx ); + } + delete hdr; +} + +void ModelSoundsCache_PrecacheScriptSound( const char *soundname ) +{ +} + +void ProcessMDL( char const *mdlname, CUtlVector< CUtlSymbol >& disposition ) +{ + if ( verbose ) + { + vprint( 0, "Processing '%s'\n", mdlname ); + } + + if ( Q_stristr( mdlname, "ghostanim" ) ) + { + int n =3 ; + } + // Validate the model sounds cache + g_ModelSoundsCache.RebuildItem( mdlname + strlen( g_szCurrentGameDir ) + 1 ); +} + +void CompileMDLs( CUtlVector< CUtlSymbol >& mdls ) +{ + CUtlVector< CUtlSymbol > disposition; + + StartPacifier( "CompileMDLs" ); + int i; + int c = mdls.Count(); + for ( i = 0 ; i < c; ++i ) + { + UpdatePacifier( (float)i / (float)c ); + ProcessMDL( g_Analysis.symbols.String( mdls[ i ] ), disposition ); + } + EndPacifier(); + + c = disposition.Count(); + for ( i = 0; i < c; ++i ) + { + Warning( "%s", disposition[ i ].String() ); + } +} + + +//----------------------------------------------------------------------------- +// The application object +//----------------------------------------------------------------------------- +class CMakeCachesApp : public CSteamAppSystemGroup +{ +public: + // Methods of IApplication + virtual bool Create(); + virtual bool PreInit(); + virtual int Main(); + virtual void PostShutdown(); + virtual void Destroy(); + +private: + // Sets up the search paths + bool SetupSearchPaths(); +}; + +bool CMakeCachesApp::Create() +{ + SpewOutputFunc( SpewFunc ); + SpewActivate( "makexvcd", 2 ); + + // Add in the cvar factory + AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() ); + AddSystem( cvarModule, VENGINE_CVAR_INTERFACE_VERSION ); + + AppSystemInfo_t appSystems[] = + { + { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION }, + { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION }, + { "vphysics.dll", VPHYSICS_INTERFACE_VERSION }, + { "datacache.dll", DATACACHE_INTERFACE_VERSION }, + { "datacache.dll", MDLCACHE_INTERFACE_VERSION }, + { "datacache.dll", STUDIO_DATA_CACHE_INTERFACE_VERSION }, + { "soundemittersystem.dll", SOUNDEMITTERSYSTEM_INTERFACE_VERSION }, + + { "", "" } // Required to terminate the list + }; + + if ( !AddSystems( appSystems ) ) + return false; + + g_pFileSystem = filesystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION ); + g_pMDLCache = (IMDLCache*)FindSystem( MDLCACHE_INTERFACE_VERSION ); + soundemitterbase = (ISoundEmitterSystemBase*)FindSystem(SOUNDEMITTERSYSTEM_INTERFACE_VERSION); + g_pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION ); + + if ( !soundemitterbase || !g_pMDLCache || !filesystem || !g_pMaterialSystem ) + { + Error("Unable to load required library interface!\n"); + } + + g_pMaterialSystem->SetShaderAPI( "shaderapiempty.dll" ); + + return true; +} + +void CMakeCachesApp::Destroy() +{ + g_pFileSystem = filesystem = NULL; + soundemitterbase = NULL; + g_pMDLCache = NULL; +} + +//----------------------------------------------------------------------------- +// Sets up the game path +//----------------------------------------------------------------------------- +bool CMakeCachesApp::SetupSearchPaths() +{ + CFSSteamSetupInfo steamInfo; + steamInfo.m_pDirectoryName = NULL; + steamInfo.m_bOnlyUseDirectoryName = false; + steamInfo.m_bToolsMode = true; + steamInfo.m_bSetSteamDLLPath = true; + steamInfo.m_bSteam = filesystem->IsSteam(); + if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK ) + return false; + + CFSMountContentInfo fsInfo; + fsInfo.m_pFileSystem = filesystem; + fsInfo.m_bToolsMode = true; + fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath; + + if ( FileSystem_MountContent( fsInfo ) != FS_OK ) + return false; + + // Finally, load the search paths for the "GAME" path. + CFSSearchPathsInit searchPathsInit; + searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath; + searchPathsInit.m_pFileSystem = fsInfo.m_pFileSystem; + if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK ) + return false; + + char platform[MAX_PATH]; + Q_strncpy( platform, steamInfo.m_GameInfoPath, MAX_PATH ); + Q_StripTrailingSlash( platform ); + Q_strncat( platform, "/../platform", MAX_PATH, MAX_PATH ); + + fsInfo.m_pFileSystem->AddSearchPath( platform, "PLATFORM" ); + + // Set gamedir. + Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), steamInfo.m_GameInfoPath ); + Q_AppendSlash( gamedir, sizeof( gamedir ) ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Init, shutdown +//----------------------------------------------------------------------------- +bool CMakeCachesApp::PreInit( ) +{ + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false ); + filesystem->SetWarningFunc( Warning ); + + // Add paths... + if ( !SetupSearchPaths() ) + return false; + + return true; +} + +void CMakeCachesApp::PostShutdown() +{ +} + +//----------------------------------------------------------------------------- +// main application +//----------------------------------------------------------------------------- +int CMakeCachesApp::Main() +{ + for ( int i=1 ; i<CommandLine()->ParmCount() ; i++) + { + if ( CommandLine()->GetParm( i )[ 0 ] == '-' ) + { + switch( CommandLine()->GetParm( i )[ 1 ] ) + { + case 'l': + uselogfile = true; + break; + case 'v': + verbose = true; + break; + case 'g': // -game + ++i; + break; + case 'm': + modelsoundscache = true; + break; + case 's': + scenecache = true; + break; + case 'x': + buildxcds = true; + break; + case 'z': + virtualmodel = true; + break; + default: + printusage(); + break; + } + } + } + + if ( CommandLine()->ParmCount() < 2 || ( i != CommandLine()->ParmCount() ) ) + { + PrintHeader(); + printusage(); + } + + CheckLogFile(); + + PrintHeader(); + + vprint( 0, " Compiling binary .vcd files to .xvcd ...\n" ); + + char vcddir[ 256 ]; + char modelsdir[ 256 ]; + Q_snprintf( vcddir, sizeof( vcddir ), "scenes", CommandLine()->GetParm( i - 1 ) ); + Q_snprintf( modelsdir, sizeof( modelsdir ), "models", CommandLine()->GetParm( i - 1 ) ); + if ( !strstr( vcddir, "scenes" ) ) + { + vprint( 0, ".vcd dir %s looks invalid (format: u:/game/hl2/scenes)\n", vcddir ); + return 0; + } + if ( !strstr( modelsdir, "models" ) ) + { + vprint( 0, ".mdl dir %s looks invalid (format: u:/game/hl2/models)\n", modelsdir ); + return 0; + } + + char binaries[MAX_PATH]; + Q_strncpy( binaries, gamedir, MAX_PATH ); + Q_StripTrailingSlash( binaries ); + Q_strncat( binaries, "/../bin", MAX_PATH, MAX_PATH ); + + filesystem->AddSearchPath( binaries, "EXECUTABLE_PATH"); + + soundemitterbase->ModInit(); + + // Delete the scene cache file + if ( scenecache ) filesystem->RemoveFile( "scene.cache", "MOD" ); + if ( modelsoundscache ) filesystem->RemoveFile( "modelsounds.cache", "MOD" ); + if ( virtualmodel ) filesystem->RemoveFile( "virtualmodel.cache", "MOD" ); + + CUtlSymbolTable pathStrings; + CUtlVector< CUtlSymbol > searchList; + char searchPaths[ 512 ]; + filesystem->GetSearchPath( "GAME", true, searchPaths, sizeof( searchPaths ) ); + + // We want to walk them in reverse order so newer files are "overrides" for older ones, so we add them to a list in reverse order + for ( char *path = strtok( searchPaths, ";" ); path; path = strtok( NULL, ";" ) ) + { + char dir[ 512 ]; + Q_strncpy( dir, path, sizeof( dir ) ); + Q_FixSlashes( dir ); + Q_strlower( dir ); + Q_StripTrailingSlash( dir ); + + CUtlSymbol sym = pathStrings.AddString( dir ); + // Push them on head so we can walk them in reverse order + searchList.AddToHead( sym ); + } + + if ( scenecache ) + { + g_SceneCache.Init(); + } + if ( modelsoundscache ) + { + g_ModelSoundsCache.Init(); + + g_pMDLCache->InitPreloadData( true ); + } + + EventList_RegisterSharedEvents(); + + for ( int sp = 0; sp < searchList.Count(); ++sp ) + { + char const *basedir = pathStrings.String( searchList[ sp ] ); + Q_strncpy( g_szCurrentGameDir, basedir, sizeof( g_szCurrentGameDir ) ); + + vprint( 0, "Processing gamedir %s\n", basedir ); + + if ( scenecache ) + { + vprint( 1, "Building list of .vcd files\n" ); + CUtlVector< CUtlSymbol > vcdfiles; + BuildFileList( basedir, vcdfiles, vcddir, ".vcd" ); + vprint( 1, "found %i .vcd files\n", vcdfiles.Count() ); + + CompileVCDs( vcdfiles ); + } + + if ( modelsoundscache ) + { + vprint( 1, "Building list of .mdl files\n" ); + CUtlVector< CUtlSymbol > mdlfiles; + BuildFileList( basedir, mdlfiles, modelsdir, ".mdl" ); + vprint( 1, "found %i .mdl files\n", mdlfiles.Count() ); + + CompileMDLs( mdlfiles ); + } + } + + if ( scenecache ) + { + if ( g_SceneCache.IsDirty() ) + { + g_SceneCache.Save(); + } + g_SceneCache.Shutdown(); + } + + if ( modelsoundscache ) + { + if ( g_ModelSoundsCache.IsDirty() ) + { + g_ModelSoundsCache.Save(); + } + g_ModelSoundsCache.Shutdown(); + + g_pMDLCache->ShutdownPreloadData(); + } + + soundemitterbase->ModShutdown(); + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : argc - +// argv[] - +// Output : int +//----------------------------------------------------------------------------- +int main( int argc, char* argv[] ) +{ + CommandLine()->CreateCmdLine( argc, argv ); + + CMakeCachesApp sceneManagerApp; + CSteamApplication steamApplication( &sceneManagerApp ); + int nRetVal = steamApplication.Run(); + + return nRetVal; +}
\ No newline at end of file diff --git a/utils/xbox/makexvcd/makexvcd.vcproj b/utils/xbox/makexvcd/makexvcd.vcproj new file mode 100644 index 0000000..c90784c --- /dev/null +++ b/utils/xbox/makexvcd/makexvcd.vcproj @@ -0,0 +1,497 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="makexvcd" + ProjectGUID="{36C1181C-9B10-48CB-956A-059A284C9F8B}" + RootNamespace="makexvcd" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="../../../public;../../../public/tier1;../../common;../../../game_shared;./" + PreprocessorDefinitions="MAKEXVCD" + MinimalRebuild="TRUE" + BasicRuntimeChecks="3" + RuntimeLibrary="5" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool" + CommandLine="if exist ..\..\..\..\game\bin\"$(TargetName)".exe attrib -r ..\..\..\..\game\bin\"$(TargetName)".exe +if exist "$(TargetPath)" copy "$(TargetPath)" ..\..\..\..\game\bin +" + Outputs="..\..\..\..\game\bin\$(TargetName).exe"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/makexvcd.exe" + LinkIncremental="2" + IgnoreDefaultLibraryNames="LIBCMT,LIBCMTD" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/makexvcd.pdb" + SubSystem="1" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="../../../public;../../../public/tier1;../../common;../../../game_shared;./" + PreprocessorDefinitions="MAKEXVCD" + RuntimeLibrary="4" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool" + CommandLine="if exist ..\..\..\..\game\bin\"$(TargetName)".exe attrib -r ..\..\..\..\game\bin\"$(TargetName)".exe +if exist "$(TargetPath)" copy "$(TargetPath)" ..\..\..\..\game\bin +" + Outputs="..\..\..\..\game\bin\$(TargetName).exe"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/makexvcd.exe" + LinkIncremental="1" + IgnoreDefaultLibraryNames="LIBCMT,LIBCMTD" + GenerateDebugInformation="TRUE" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> + <File + RelativePath=".\makexvcd.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + <File + RelativePath=".\cbase.h"> + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> + </Filter> + <Filter + Name="Shared Code" + Filter=""> + <File + RelativePath="..\..\..\game_shared\activitylist.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\activitylist.h"> + </File> + <File + RelativePath="..\..\..\game_shared\animation.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\animation.h"> + </File> + <File + RelativePath="..\..\..\public\tier1\checksum_crc.h"> + </File> + <File + RelativePath="..\..\..\game_shared\choreoactor.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\choreoactor.h"> + </File> + <File + RelativePath="..\..\..\game_shared\choreochannel.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\choreochannel.h"> + </File> + <File + RelativePath="..\..\..\game_shared\choreoevent.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\choreoevent.h"> + </File> + <File + RelativePath="..\..\..\game_shared\choreoscene.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\choreoscene.h"> + </File> + <File + RelativePath="..\..\common\cmdlib.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\common\cmdlib.h"> + </File> + <File + RelativePath="..\..\..\game_shared\eventlist.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\eventlist.h"> + </File> + <File + RelativePath="..\..\..\public\filesystem_helpers.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\public\filesystem_helpers.h"> + </File> + <File + RelativePath="..\..\..\public\filesystem_init.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\public\filesystem_init.h"> + </File> + <File + RelativePath="..\..\common\filesystem_tools.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\common\filesystem_tools.h"> + </File> + <File + RelativePath="..\..\..\public\interpolatortypes.cpp"> + </File> + <File + RelativePath="..\..\..\public\interpolatortypes.h"> + </File> + <File + RelativePath="..\..\..\public\mathlib\mathlib.h"> + </File> + <File + RelativePath="..\..\..\game_shared\ModelSoundsCache.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\ModelSoundsCache.h"> + </File> + <File + RelativePath="..\..\common\pacifier.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\common\pacifier.h"> + </File> + <File + RelativePath="..\..\..\game_shared\SceneCache.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\game_shared\SceneCache.h"> + </File> + <File + RelativePath="..\..\common\scriplib.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\common\scriplib.h"> + </File> + <File + RelativePath="..\..\..\public\stringregistry.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + <File + RelativePath="..\..\..\public\stringregistry.h"> + </File> + <File + RelativePath="..\..\..\public\studio.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0"/> + </FileConfiguration> + </File> + </Filter> + <File + RelativePath="..\..\..\lib\public\appframework.lib"> + </File> + <File + RelativePath="..\..\..\lib\public\mathlib.lib"> + </File> + <File + RelativePath="..\..\..\lib\public\tier0.lib"> + </File> + <File + RelativePath="..\..\..\lib\public\tier1.lib"> + </File> + <File + RelativePath="..\..\..\lib\public\tier2.lib"> + </File> + <File + RelativePath="..\..\..\lib\public\vstdlib.lib"> + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/utils/xbox/toollib/piclib.cpp b/utils/xbox/toollib/piclib.cpp new file mode 100644 index 0000000..fc0101a --- /dev/null +++ b/utils/xbox/toollib/piclib.cpp @@ -0,0 +1,557 @@ +#include "toollib.h" +#include "piclib.h" + +byte_t* g_tgabuffer; +byte_t* g_tgabuffptr; + +/***************************************************************************** + TL_LoadPCX + +*****************************************************************************/ +void TL_LoadPCX(char* filename, byte_t** pic, byte_t** palette, int* width, int* height) +{ + byte_t* raw; + pcx_t* pcx; + int x; + int y; + int len; + int databyte; + int runlength; + byte_t* out; + byte_t* pix; + + // load the file + len = TL_LoadFile(filename,(void **)&raw); + + // parse the PCX file + pcx = (pcx_t*)raw; + raw = &pcx->data; + + pcx->xmin = TL_LittleShort(pcx->xmin); + pcx->ymin = TL_LittleShort(pcx->ymin); + pcx->xmax = TL_LittleShort(pcx->xmax); + pcx->ymax = TL_LittleShort(pcx->ymax); + pcx->hres = TL_LittleShort(pcx->hres); + pcx->vres = TL_LittleShort(pcx->vres); + pcx->bytes_per_line = TL_LittleShort(pcx->bytes_per_line); + pcx->palette_type = TL_LittleShort(pcx->palette_type); + + if (pcx->manufacturer != 0x0a || + pcx->version != 5 || + pcx->encoding != 1 || + pcx->bits_per_pixel != 8 || + pcx->xmax >= 640 || + pcx->ymax >= 480) + TL_Error("Bad pcx file %s",filename); + + if (palette) + { + *palette = (byte_t*)TL_Malloc(768); + memcpy(*palette,(byte_t*)pcx + len - 768,768); + } + + if (width) + *width = pcx->xmax+1; + + if (height) + *height = pcx->ymax+1; + + if (!pic) + return; + + out = (byte_t*)TL_Malloc((pcx->ymax+1)*(pcx->xmax+1)); + *pic = out; + pix = out; + + for (y=0; y<=pcx->ymax; y++, pix += pcx->xmax+1) + { + for (x=0; x<=pcx->xmax; ) + { + databyte = *raw++; + + if((databyte & 0xC0) == 0xC0) + { + runlength = databyte & 0x3F; + databyte = *raw++; + } + else + runlength = 1; + + while (runlength-- > 0) + pix[x++] = databyte; + } + } + + if (raw - (byte_t *)pcx > len) + TL_Error("PCX file %s was malformed",filename); + + TL_Free(pcx); +} + +/***************************************************************************** + TL_SavePCX + +*****************************************************************************/ +void TL_SavePCX(char* filename, byte_t* data, int width, int height, byte_t* palette) +{ + int i; + int j; + int length; + pcx_t* pcx; + byte_t* pack; + + pcx = (pcx_t*)TL_Malloc(width*height*2+1000); + + pcx->manufacturer = 0x0A; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = TL_LittleShort((short)(width-1)); + pcx->ymax = TL_LittleShort((short)(height-1)); + pcx->hres = TL_LittleShort((short)width); + pcx->vres = TL_LittleShort((short)height); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = TL_LittleShort((short)width); + pcx->palette_type = TL_LittleShort(2); // not a grey scale + + // pack the image + pack = &pcx->data; + + for (i=0; i<height; i++) + { + for (j=0; j<width; j++) + { + if ((*data & 0xc0) != 0xC0) + *pack++ = *data++; + else + { + *pack++ = 0xC1; + *pack++ = *data++; + } + } + } + + // write the palette + *pack++ = 0x0C; + for (i=0; i<768; i++) + *pack++ = *palette++; + + // write output file + length = pack - (byte_t*)pcx; + TL_SaveFile(filename,pcx,length); + + TL_Free(pcx); +} + +/***************************************************************************** + TGA_GetByte + +*****************************************************************************/ +byte_t TGA_GetByte(void) +{ + return (*g_tgabuffptr++); +} + +/***************************************************************************** + TGA_GetShort + +*****************************************************************************/ +short TGA_GetShort(void) +{ + byte_t msb; + byte_t lsb; + + lsb = g_tgabuffptr[0]; + msb = g_tgabuffptr[1]; + + g_tgabuffptr += 2; + + return ((msb<<8)|lsb); +} + +/***************************************************************************** + TL_LoadTGA + +*****************************************************************************/ +void TL_LoadTGA(char* name, byte_t** pixels, int* width, int* height) +{ + int columns; + int rows; + int numPixels; + byte_t* pixbuf; + int row; + int column; + byte_t* targa_rgba; + tga_t targa_header; + byte_t red; + byte_t green; + byte_t blue; + byte_t alphabyte; + byte_t packetHeader; + byte_t packetSize; + byte_t j; + + TL_LoadFile(name,(void**)&g_tgabuffer); + g_tgabuffptr = g_tgabuffer; + + /* load unaligned tga data */ + targa_header.id_length = TGA_GetByte(); + targa_header.colormap_type = TGA_GetByte(); + targa_header.image_type = TGA_GetByte(); + targa_header.colormap_index = TGA_GetShort(); + targa_header.colormap_length = TGA_GetShort(); + targa_header.colormap_size = TGA_GetByte(); + targa_header.x_origin = TGA_GetShort(); + targa_header.y_origin = TGA_GetShort(); + targa_header.width = TGA_GetShort(); + targa_header.height = TGA_GetShort(); + targa_header.pixel_size = TGA_GetByte(); + targa_header.attributes = TGA_GetByte(); + + if (targa_header.image_type != 2 && targa_header.image_type != 10) + TL_Error("TL_LoadTGA: %s - Only type 2 and 10 targa RGB images supported",name); + + if ((targa_header.colormap_type != 0) || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) + TL_Error("TL_LoadTGA: %s - Only 32 or 24 bit images supported (no colormaps)",name); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + targa_rgba = (byte_t*)TL_Malloc(numPixels*4); + *pixels = targa_rgba; + + if (targa_header.id_length != 0) + { + // skip TARGA image comment + g_tgabuffptr += targa_header.id_length; + } + + if (targa_header.image_type==2) + { + // Uncompressed, RGB images + for (row=rows-1; row>=0; row--) + { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column<columns; column++) + { + switch (targa_header.pixel_size) + { + case 24: + blue = TGA_GetByte(); + green = TGA_GetByte(); + red = TGA_GetByte(); + alphabyte = 255; + break; + + case 32: + blue = TGA_GetByte(); + green = TGA_GetByte(); + red = TGA_GetByte(); + alphabyte = TGA_GetByte(); + break; + } + + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + + } + } + } + else if (targa_header.image_type==10) + { + // Runlength encoded RGB images + for (row=rows-1; row>=0; row--) + { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column<columns; ) + { + packetHeader = TGA_GetByte(); + packetSize = 1 + (packetHeader & 0x7f); + if (packetHeader & 0x80) + { + // run-length packet + switch (targa_header.pixel_size) + { + case 24: + blue = TGA_GetByte(); + green = TGA_GetByte(); + red = TGA_GetByte(); + alphabyte = 255; + break; + + case 32: + blue = TGA_GetByte(); + green = TGA_GetByte(); + red = TGA_GetByte(); + alphabyte = TGA_GetByte(); + break; + } + + for(j=0; j<packetSize; j++) + { + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + column++; + + if (column==columns) + { + // run spans across rows + column=0; + if (row>0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else + { + // non run-length packet + for(j=0; j<packetSize; j++) + { + switch (targa_header.pixel_size) + { + case 24: + blue = TGA_GetByte(); + green = TGA_GetByte(); + red = TGA_GetByte(); + alphabyte = 255; + break; + + case 32: + blue = TGA_GetByte(); + green = TGA_GetByte(); + red = TGA_GetByte(); + alphabyte = TGA_GetByte(); + break; + } + + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + column++; + + if (column == columns) + { + // pixel packet run spans across rows + column=0; + if (row>0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } +breakOut:; + } + } + + TL_Free(g_tgabuffer); +} + +/***************************************************************************** + TL_SaveTGA + + Saves TGA. Supports r/w 16/24/32 bpp. +*****************************************************************************/ +void TL_SaveTGA(char* filename, byte_t* pixels, int width, int height, int sbpp, int tbpp) +{ + int handle; + tga_t tga; + unsigned short rgba5551; + unsigned long rgba8888; + int r; + int g; + int b; + int x; + int y; + int a; + byte_t* tgabuffer; + byte_t* tgabufferptr; + byte_t* rawbufferptr; + byte_t* tempbuffer; + byte_t* tempbufferptr; + int bytesperpixel; + + // all source is upsampled into easy 32 bit rgba8888 + // and downsampled into tga buffer + tempbuffer = (byte_t*)TL_Malloc(width*height*4); + + if (sbpp == 16) + { + /* source is 16 bit rgba */ + rawbufferptr = pixels; + for (y=0; y<height; y++) + { + tempbufferptr = tempbuffer + y*width*4; + for (x=0; x<width; x++) + { + rgba5551 = *(unsigned short*)rawbufferptr; + r = (rgba5551 & 0xF800)>>11; + g = (rgba5551 & 0x07C0)>>6; + b = (rgba5551 & 0x003E)>>1; + a = (rgba5551 & 0x01); + tempbufferptr[0] = (byte_t)(b * (255.0/31.0)); + tempbufferptr[1] = (byte_t)(g * (255.0/31.0)); + tempbufferptr[2] = (byte_t)(r * (255.0/31.0)); + tempbufferptr[3] = (byte_t)(a * 255.0); + + rawbufferptr += sizeof(unsigned short); + tempbufferptr += 4; + } + } + } + else if (sbpp == 24) + { + /* source is 24 bit rgba */ + rawbufferptr = pixels; + for (y=0; y<height; y++) + { + tempbufferptr = tempbuffer + y*width*4; + for (x=0; x<width; x++) + { + tempbufferptr[0] = rawbufferptr[0]; + tempbufferptr[1] = rawbufferptr[1]; + tempbufferptr[2] = rawbufferptr[2]; + tempbufferptr[3] = 255; + + rawbufferptr += 3; + tempbufferptr += 4; + } + } + } + else if (sbpp == 32) + { + /* source is 32 bit rgba */ + memcpy(tempbuffer,pixels,width*height*4); + } + else + TL_Error("TL_SaveTGA: cannot handle source %d bits per pixel",sbpp); + + if (tbpp == 16) + bytesperpixel = 2; + else if (tbpp == 24) + bytesperpixel = 3; + else if (tbpp == 32) + bytesperpixel = 4; + else + TL_Error("TL_SaveTGA: cannot handle target %d bits per pixel",tbpp); + + handle = TL_SafeOpenWrite(filename); + + /* write the targa header */ + tga.id_length = 0; + tga.colormap_type = 0; + tga.image_type = 2; + tga.colormap_index = 0; + tga.colormap_length = 0; + tga.colormap_size = 0; + tga.x_origin = 0; + tga.y_origin = 0; + tga.width = width; + tga.height = height; + tga.pixel_size = tbpp; + tga.attributes = 0; + + TL_SafeWrite(handle,&tga.id_length,sizeof(tga.id_length)); + TL_SafeWrite(handle,&tga.colormap_type,sizeof(tga.colormap_type)); + TL_SafeWrite(handle,&tga.image_type,sizeof(tga.image_type)); + TL_SafeWrite(handle,&tga.colormap_index,sizeof(tga.colormap_index)); + TL_SafeWrite(handle,&tga.colormap_length,sizeof(tga.colormap_length)); + TL_SafeWrite(handle,&tga.colormap_size,sizeof(tga.colormap_size)); + TL_SafeWrite(handle,&tga.x_origin,sizeof(tga.x_origin)); + TL_SafeWrite(handle,&tga.y_origin,sizeof(tga.y_origin)); + TL_SafeWrite(handle,&tga.width,sizeof(tga.width)); + TL_SafeWrite(handle,&tga.height,sizeof(tga.height)); + TL_SafeWrite(handle,&tga.pixel_size,sizeof(tga.pixel_size)); + TL_SafeWrite(handle,&tga.attributes,sizeof(tga.attributes)); + + /* tga images are upside down left to right - !@#$% */ + tgabuffer = (byte_t*)TL_Malloc(width*height*bytesperpixel); + + /* source is 32 bit rgba */ + rawbufferptr = tempbuffer; + for (y=height-1; y>=0; y--) + { + tgabufferptr = tgabuffer + y*width*bytesperpixel; + for (x=0; x<width; x++) + { + switch (bytesperpixel) + { + case 2: + break; + + case 3: + rgba8888 = TL_BigLong(*(unsigned long*)rawbufferptr); + r = (rgba8888 & 0xFF000000)>>24; + g = (rgba8888 & 0x00FF0000)>>16; + b = (rgba8888 & 0x0000FF00)>>8; + + tgabufferptr[0] = b; + tgabufferptr[1] = g; + tgabufferptr[2] = r; + break; + + case 4: + rgba8888 = TL_BigLong(*(unsigned long*)rawbufferptr); + r = (rgba8888 & 0xFF000000)>>24; + g = (rgba8888 & 0x00FF0000)>>16; + b = (rgba8888 & 0x0000FF00)>>8; + a = rgba8888 & 0xFF; + + tgabufferptr[0] = b; + tgabufferptr[1] = g; + tgabufferptr[2] = r; + tgabufferptr[3] = a; + break; + } + + rawbufferptr += 4; + tgabufferptr += bytesperpixel; + } + } + + TL_SafeWrite(handle,tgabuffer,width*height*bytesperpixel); + close(handle); + + TL_Free(tempbuffer); + TL_Free(tgabuffer); +} + +/***************************************************************************** + TL_LoadImage + + Loads an image based on extension. +*****************************************************************************/ +void TL_LoadImage(char* name, byte_t** pixels, byte_t** palette, int* width, int* height) +{ + char ext[16]; + + TL_GetExtension(name,ext); + if (!stricmp(ext,"pcx")) + TL_LoadPCX(name,pixels,palette,width,height); + else if (!stricmp(ext,"tga")) + { + TL_LoadTGA(name,pixels,width,height); + *palette = NULL; + } + else + TL_Error("TL_LoadImage: unknown image extension %s",ext); +} + diff --git a/utils/xbox/toollib/piclib.h b/utils/xbox/toollib/piclib.h new file mode 100644 index 0000000..346d94c --- /dev/null +++ b/utils/xbox/toollib/piclib.h @@ -0,0 +1,61 @@ +#ifndef _PICLIB_H_ +#define _PICLIB_H_ + +typedef enum +{ + ms_none, + ms_mask, + ms_transcolor, + ms_lasso +} +mask_t; + +typedef enum +{ + cm_none, + cm_rle1 +} +compress_t; + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; +} pcx_t; + +typedef struct +{ + unsigned char id_length; + unsigned char colormap_type; + unsigned char image_type; + unsigned char pad1; // not in file + unsigned short colormap_index; + unsigned short colormap_length; + unsigned char colormap_size; + unsigned char pad2; // not in file + unsigned short x_origin; + unsigned short y_origin; + unsigned short width; + unsigned short height; + unsigned char pixel_size; + unsigned char attributes; +} tga_t; + +extern void TL_LoadPCX(char* filename, byte_t** picture, byte_t** palette, int* width, int* height); +extern void TL_SavePCX(char* filename, byte_t* data, int width, int height, byte_t* palette); +extern void TL_LoadTGA(char* name, byte_t** pixels, int* width, int* height); +extern void TL_SaveTGA(char* filename, byte_t* pixels, int width, int height, int sbpp, int tbpp); +extern void TL_LoadImage(char* name, byte_t** pixels, byte_t** palette, int* width, int* height); + +#endif diff --git a/utils/xbox/toollib/scriplib.cpp b/utils/xbox/toollib/scriplib.cpp new file mode 100644 index 0000000..e674673 --- /dev/null +++ b/utils/xbox/toollib/scriplib.cpp @@ -0,0 +1,264 @@ +#include "toollib.h" + +char g_tl_token[MAXTOKEN]; +char* g_tl_scriptbuff; +char* g_tl_scriptptr; +char* g_tl_scriptendptr; +int g_tl_scriptsize; +int g_tl_scriptline; +bool g_tl_endofscript; +bool g_tl_tokenready; +int g_tl_oldscriptline; +char* g_tl_oldscriptptr; + +/***************************************************************************** + TL_FreeScriptFile + +*****************************************************************************/ +void TL_FreeScriptFile(void) +{ + if (g_tl_scriptbuff) + { + TL_Free(g_tl_scriptbuff); + g_tl_scriptbuff = NULL; + } +} + +/***************************************************************************** + TL_LoadScriptFile + +*****************************************************************************/ +void TL_LoadScriptFile(const char* filename) +{ + g_tl_scriptsize = TL_LoadFile(filename,(void **)&g_tl_scriptbuff); + + TL_ResetParser(); +} + +/***************************************************************************** + TL_SetScriptData + +*****************************************************************************/ +void TL_SetScriptData(char* data, int length) +{ + g_tl_scriptbuff = data; + g_tl_scriptsize = length; + + TL_ResetParser(); +} + +/***************************************************************************** + TL_UnGetToken + +*****************************************************************************/ +void TL_UnGetToken(void) +{ + g_tl_tokenready = true; +} + +/***************************************************************************** + TL_GetToken + +*****************************************************************************/ +char* TL_GetToken(bool crossline) +{ + char* tokenptr; + + if (g_tl_tokenready) + { + g_tl_tokenready = false; + return (g_tl_token); + } + + g_tl_token[0] = '\0'; + + if (g_tl_scriptptr >= g_tl_scriptendptr) + { + if (!crossline) + TL_Error("TL_GetToken: Line %d is incomplete",g_tl_scriptline); + + g_tl_endofscript = true; + return (NULL); + } + +skipspace: + while (*g_tl_scriptptr <= ' ') + { + if (g_tl_scriptptr >= g_tl_scriptendptr) + { + if (!crossline) + TL_Error("GetToken: Line %i is incomplete",g_tl_scriptline); + + g_tl_endofscript = true; + return (NULL); + } + + if (*g_tl_scriptptr++ == '\n') + { + if (!crossline) + TL_Error("GetToken: Line %i is incomplete",g_tl_scriptline); + + g_tl_scriptline++; + } + } + + if (g_tl_scriptptr >= g_tl_scriptendptr) + { + if (!crossline) + TL_Error("GetToken: Line %i is incomplete",g_tl_scriptline); + + g_tl_endofscript = true; + return (NULL); + } + + // skip commented line + if ((g_tl_scriptptr[0] == ';') || (g_tl_scriptptr[0] == '/' && g_tl_scriptptr[1] == '/')) + { + if (!crossline) + TL_Error("GetToken: Line %i is incomplete",g_tl_scriptline); + + while (*g_tl_scriptptr++ != '\n') + { + if (g_tl_scriptptr >= g_tl_scriptendptr) + { + g_tl_endofscript = true; + return (NULL); + } + } + + g_tl_scriptline++; + goto skipspace; + } + + tokenptr = g_tl_token; + if (g_tl_scriptptr[0] == '\"' && g_tl_scriptptr[1]) + { + // copy quoted token + do + { + *tokenptr++ = *g_tl_scriptptr++; + if (g_tl_scriptptr == g_tl_scriptendptr) + break; + + if (tokenptr == &g_tl_token[MAXTOKEN]) + TL_Error("GetToken: Token too large on line %i",g_tl_scriptline); + } + while (*g_tl_scriptptr >= ' ' && *g_tl_scriptptr != '\"'); + + if (g_tl_scriptptr[0] == '\"') + *tokenptr++ = *g_tl_scriptptr++; + } + else + { + // copy token + while (*g_tl_scriptptr > ' ' && *g_tl_scriptptr != ';' && *g_tl_scriptptr != '\"') + { + *tokenptr++ = *g_tl_scriptptr++; + if (g_tl_scriptptr == g_tl_scriptendptr) + break; + + if (tokenptr == &g_tl_token[MAXTOKEN]) + TL_Error("GetToken: Token too large on line %i",g_tl_scriptline); + } + } + + *tokenptr = '\0'; + + return (g_tl_token); +} + +/***************************************************************************** + TL_SkipRestOfLine + +*****************************************************************************/ +void TL_SkipRestOfLine(void) +{ + while (*g_tl_scriptptr++ != '\n') + { + if (g_tl_scriptptr >= g_tl_scriptendptr) + { + break; + } + } + + g_tl_scriptline++; +} + +/***************************************************************************** + TL_TokenAvailable + + Returns (TRUE) if token available on line. +*****************************************************************************/ +bool TL_TokenAvailable (void) +{ + char* ptr; + + ptr = g_tl_scriptptr; + while (*ptr <= ' ') + { + if (ptr >= g_tl_scriptendptr) + { + g_tl_endofscript = true; + return (false); + } + + if (*ptr++ == '\n') + return (false); + } + + return (true); +} + + +/***************************************************************************** + TL_EndOfScript + + Returns (TRUE) at end of script +*****************************************************************************/ +bool TL_EndOfScript(void) +{ + if (g_tl_scriptptr >= g_tl_scriptendptr) + { + g_tl_endofscript = true; + return (true); + } + + return (false); +} + +/***************************************************************************** + TL_ResetParser + +*****************************************************************************/ +void TL_ResetParser(void) +{ + g_tl_scriptptr = g_tl_scriptbuff; + g_tl_scriptendptr = g_tl_scriptptr + g_tl_scriptsize; + g_tl_scriptline = 1; + g_tl_endofscript = false; + g_tl_tokenready = false; +} + +/***************************************************************************** + TL_SaveParser + +*****************************************************************************/ +void TL_SaveParser(void) +{ + g_tl_oldscriptline = g_tl_scriptline; + g_tl_oldscriptptr = g_tl_scriptptr; +} + +/***************************************************************************** + TL_RestoreParser + +*****************************************************************************/ +void TL_RestoreParser(void) +{ + g_tl_scriptline = g_tl_oldscriptline; + g_tl_scriptptr = g_tl_oldscriptptr; +} + + + + diff --git a/utils/xbox/toollib/scriplib.h b/utils/xbox/toollib/scriplib.h new file mode 100644 index 0000000..292a16c --- /dev/null +++ b/utils/xbox/toollib/scriplib.h @@ -0,0 +1,28 @@ +#ifndef _SCRIPLIB_H_ +#define _SCRIPLIB_H_ + +#define MAXTOKEN 128 + +extern void TL_LoadScriptFile(const char* filename); +extern void TL_SetScriptData(char* data, int length); +extern void TL_FreeScriptFile(void); +extern char* TL_GetToken(bool crossline); +extern char* TL_GetQuotedToken(bool crossline); +extern void TL_UnGetToken(void); +extern bool TL_TokenAvailable(void); +extern void TL_SaveParser(void); +extern void TL_RestoreParser(void); +extern void TL_ResetParser(void); +extern void TL_SkipRestOfLine(void); +extern bool TL_EndOfScript(void); +extern char* TL_GetRawToken(void); + +extern char g_tl_token[MAXTOKEN]; +extern char* g_tl_scriptbuffer; +extern char* g_tl_scriptptr; +extern char* g_tl_scriptendptr; +extern int g_tl_scriptsize; // ydnar +extern int g_tl_scriptline; +extern bool g_tl_endofscript; + +#endif diff --git a/utils/xbox/toollib/toollib.cpp b/utils/xbox/toollib/toollib.cpp new file mode 100644 index 0000000..998bf91 --- /dev/null +++ b/utils/xbox/toollib/toollib.cpp @@ -0,0 +1,1322 @@ +#include "toollib.h" + +#ifdef _DEBUG +#define HEAP_CHECK +#endif + +int g_tl_argc; +char** g_tl_argv; +int g_tl_byteorder; +int g_tl_dircount; +char** g_tl_dirlist; +int g_tl_start; +int g_tl_abort; +bool g_tl_quiet; + +#pragma warning(disable:4311) +#pragma warning(disable:4267) + +/***************************************************************************** + TL_Setup + +*****************************************************************************/ +void TL_Setup(char* appname, int argc, char** argv) +{ + const char* buildStr; + + g_tl_argc = argc; + g_tl_argv = argv; + + g_tl_quiet = (TL_CheckParm("q") > 0) || (TL_CheckParm("quiet") > 0) || (TL_CheckParm("noheader") > 0); + + if (appname) + { + TL_printf("\n%s \n",appname); +#ifdef _DEBUG + buildStr = "Debug Build"; +#else + buildStr = "Release Build"; +#endif + TL_printf("%s - %s %s\n\n", buildStr, __DATE__, __TIME__); + } + + g_tl_abort = TL_CheckParm("abort"); + g_tl_start = TL_CPUCount(); +} + +/***************************************************************************** + TL_End + +*****************************************************************************/ +void TL_End(bool showtime) +{ + int end; + + if (showtime && !g_tl_quiet) + { + end = TL_CPUCount(); + TL_printf("\n%f seconds.\n",TL_CPUTime(g_tl_start,end)); + } +} + +/***************************************************************************** + TL_Error + +*****************************************************************************/ +void TL_Error(char* error, ...) +{ + va_list argptr; + + va_start(argptr,error); + vprintf(error,argptr); + va_end(argptr); + + printf("\n"); + +#if !defined( _X360 ) + __asm + { + int 3; + } +#endif + + if (g_tl_abort) + abort(); + + exit(-1); +} + +/***************************************************************************** + TL_CheckParm + + Returns the argument number (1 to argc-1) or 0 if not present +*****************************************************************************/ +int TL_CheckParm(char* check) +{ + int i; + char* parm; + + for (i=1; i<g_tl_argc; i++) + { + parm = g_tl_argv[i]; + + if (!isalpha(*parm)) + if (!*++parm) + continue; + + if (!stricmp(check,parm)) + return (i); + } + + return (0); +} + +/***************************************************************************** + TL_SafeRead + +*****************************************************************************/ +void TL_SafeRead(int handle, void* buffer, long count) +{ + if (_read(handle,buffer,count) != count) + TL_Error("SafeRead(): read failure"); +} + +/***************************************************************************** + TL_SafeOpenRead + +*****************************************************************************/ +int TL_SafeOpenRead(const char* filename) +{ + int handle; + + handle = _open(filename,_O_RDONLY|_O_BINARY); + if (handle == -1) + TL_Error("TL_SafeOpenRead(): Error opening %s: %s",filename,strerror(errno)); + + return (handle); +} + +/***************************************************************************** + TL_SafeOpenWrite + +*****************************************************************************/ +int TL_SafeOpenWrite(const char* filename) +{ + int handle; + + handle = _open(filename,_O_RDWR|_O_BINARY|_O_CREAT|_O_TRUNC,0666); + if (handle == -1) + TL_Error("TL_SafeOpenWrite(): Error opening %s: %s",filename,strerror(errno)); + + return (handle); +} + +/***************************************************************************** + TL_SafeWrite + +*****************************************************************************/ +void TL_SafeWrite(int handle, void* buffer, long count) +{ + int status; + + status = _write(handle,buffer,count); + if (status != count) + TL_Error("TL_SafeWrite(): write failure %d, errno=%d",status,errno); +} + +/***************************************************************************** + TL_SafeClose + +*****************************************************************************/ +void TL_SafeClose(int handle, int touch) +{ + // ensure date and time of modification get set + if (touch) + _futime(handle,NULL); + + close(handle); +} + +/***************************************************************************** + TL_Malloc + +*****************************************************************************/ +void* TL_Malloc(int size) +{ + void* ptr; + int newsize; + + newsize = size + sizeof(tlmem_t); + newsize = (newsize + 3) & ~3; + + ptr = malloc(newsize); + if (!ptr) + TL_Error("TL_Malloc(): failure for %lu bytes",size); + + memset(ptr,0,newsize); + + ((tlmem_t*)ptr)->id = TL_MEMID; + ((tlmem_t*)ptr)->size = size; + + return ((byte_t*)ptr + sizeof(tlmem_t)); +} + +/***************************************************************************** + TL_Free + +*****************************************************************************/ +void TL_Free(void* ptr) +{ + tlmem_t* memptr; + + if (!ptr) + TL_Error("TL_Free(): null pointer"); + + memptr = (tlmem_t*)((byte_t*)ptr - sizeof(tlmem_t)); + + if (((u32)memptr) & 3) + TL_Error("TL_Free(): bad pointer %8.8x",ptr); + + if (memptr->id != TL_MEMID) + TL_Error("TL_Free(): corrupted pointer %8.8x",ptr); + + memptr->id = 0; + memptr->size = 0; + + free(memptr); + +#ifdef HEAP_CHECK + if (_heapchk() != _HEAPOK) + TL_Error("TL_Free(): heap corrupted"); +#endif +} + +bool TL_Check(void* ptr) +{ + tlmem_t* memptr; + + if (!ptr) + return false; + + memptr = (tlmem_t*)((byte_t*)ptr - sizeof(tlmem_t)); + + if (((u32)memptr) & 3) + return false; + + if (memptr->id != TL_MEMID) + return false; + + return true; +} + +/***************************************************************************** + TL_Realloc + +*****************************************************************************/ +void* TL_Realloc(void* ptr, int newsize) +{ + int len; + tlmem_t* oldmemptr; + void* newptr; + + if (!ptr) + { + newptr = TL_Malloc(newsize); + return (newptr); + } + + oldmemptr = (tlmem_t*)((byte_t*)ptr - sizeof(tlmem_t)); + + if ((u32)oldmemptr & 3) + TL_Error("TL_Realloc(): bad pointer %8.8x",ptr); + + if (oldmemptr->id != TL_MEMID) + TL_Error("TL_Realloc(): corrupted pointer %8.8x",ptr); + + newptr = TL_Malloc(newsize); + + len = TL_min(newsize,oldmemptr->size); + + memcpy(newptr,ptr,len); + + TL_Free(ptr); + + return (newptr); +} + +/***************************************************************************** + TL_strncpyz + + Copy up to (N) bytes including appending null. +*****************************************************************************/ +void TL_strncpyz(char* dst, char* src, int n) +{ + if (n <= 0) + return; + + if (n > 1) + strncpy(dst,src,n-1); + + dst[n-1] = '\0'; +} + +/***************************************************************************** + TL_strncatz + + Concatenate up to dstsize bytes including appending null. +*****************************************************************************/ +void TL_strncatz(char* dst, char* src, int dstsize) +{ + int len; + + if (dstsize <= 0) + return; + + len = (int)strlen(dst); + + TL_strncpyz(dst+len,src,dstsize-len); +} + +/***************************************************************************** + TL_LoadFile + +*****************************************************************************/ +long TL_LoadFile(const char* filename, void** bufferptr) +{ + int handle; + long length; + char* buffer; + + handle = TL_SafeOpenRead(filename); + length = TL_FileLength(handle); + buffer = (char*)TL_Malloc(length+1); + TL_SafeRead(handle,buffer,length); + close(handle); + + // for parsing + buffer[length] = '\0'; + + *bufferptr = (void*)buffer; + + return (length); +} + +/***************************************************************************** + TL_TouchFile + +*****************************************************************************/ +void TL_TouchFile(char* filename) +{ + int h; + + h = _open(filename,_O_RDWR|_O_BINARY,0666); + if (h < 0) + return; + + _futime(h,NULL); + _close(h); +} + +/***************************************************************************** + TL_SaveFile + +*****************************************************************************/ +void TL_SaveFile(char* filename, void* buffer, long count) +{ + int handle; + + handle = TL_SafeOpenWrite(filename); + TL_SafeWrite(handle,buffer,count); + + TL_SafeClose(handle,true); +} + +/***************************************************************************** + TL_FileLength + +*****************************************************************************/ +long TL_FileLength(int handle) +{ + long pos; + long length; + + pos = lseek(handle,0,SEEK_CUR); + length = lseek(handle,0,SEEK_END); + lseek(handle,pos,SEEK_SET); + + return (length); +} + +/***************************************************************************** + TL_StripFilename + + Removes filename from path. +*****************************************************************************/ +void TL_StripFilename(char* path) +{ + int length; + + length = (int)strlen(path)-1; + while ((length > 0) && (path[length] != '\\') && (path[length] != '/') && (path[length] != ':')) + length--; + + /* leave possible seperator */ + if (!length) + path[0] = '\0'; + else + path[length+1] = '\0'; +} + +/***************************************************************************** + TL_StripExtension + + Removes extension from path. +*****************************************************************************/ +void TL_StripExtension(char* path) +{ + int length; + + length = (int)strlen(path)-1; + while (length > 0 && path[length] != '.') + length--; + + if (length && path[length] == '.') + path[length] = 0; +} + +/***************************************************************************** + TL_StripPath + + Removes path from full path. +*****************************************************************************/ +void TL_StripPath(char* path, char* dest) +{ + char* src; + + src = path + strlen(path); + while ((src != path) && (*(src-1) != '\\') && (*(src-1) != '/') && (*(src-1) != ':')) + src--; + + strcpy(dest,src); +} + +/***************************************************************************** + TL_GetExtension + + Gets any extension from the full path. +*****************************************************************************/ +void TL_GetExtension(char* path, char* dest) +{ + char* src; + + src = path + strlen(path) - 1; + + // back up until a . or the start + while (src != path && *(src-1) != '.') + src--; + + if (src == path) + { + *dest = '\0'; // no extension + return; + } + + strcpy(dest,src); +} + +/***************************************************************************** + TL_DefaultPath + + Adds basepath to head of path. +*****************************************************************************/ +void TL_DefaultPath(char* path, char* basepath) +{ + char temp[TL_MAXPATH]; + char* ptr; + char ch; + + if (path[0] == '\\') + { + // path is absolute + return; + } + + ptr = path; + while (1) + { + ch = *ptr++; + if (!ch) + break; + + if (ch == ':') + { + // path has a device - must be absolute + return; + } + } + + // place basepath at head of path + // do intermediate copy to preserve any arg wierdness + strcpy(temp,path); + strcpy(path,basepath); + strcat(path,temp); +} + +/***************************************************************************** + TL_AddSeperatorToPath + +*****************************************************************************/ +void TL_AddSeperatorToPath(char* inpath, char* outpath) +{ + int len; + + strcpy(outpath,inpath); + + len = (int)strlen(outpath); + if (outpath[len-1] != '\\') + { + outpath[len] = '\\'; + outpath[len+1] = '\0'; + } +} + +/***************************************************************************** + TL_DefaultExtension + + Adds extension a path that has no extension. +*****************************************************************************/ +void TL_DefaultExtension(char* path, char* extension, bool bForce) +{ + char* src; + + if ( !bForce && path[0] ) + { + src = path + strlen(path) - 1; + while ((src != path) && (*src != '\\') && (*src != '/')) + { + if (*src == '.') + return; + src--; + } + } + + strcat(path,extension); +} + +/***************************************************************************** + TL_ReplaceDosExtension + + Handles files of the form xxxx.xxxxxxx.xxxxx.zzz +*****************************************************************************/ +void TL_ReplaceDosExtension(char* path, char* extension) +{ + int len; + + len = (int)strlen(path); + if (!len) + return; + + if (path[len-1] == '.') + { + path[len-1] = '\0'; + strcat(path,extension); + return; + } + + if (len-4 > 0 && path[len-4] == '.') + path[len-4] = '\0'; + + strcat(path,extension); +} + +/***************************************************************************** + TL_ReplaceExtension + + Replaces any extension found after '.' +*****************************************************************************/ +void TL_ReplaceExtension(const char* inPath, const char* extension, char* outPath) +{ + int len; + char* src; + + if (outPath != inPath) + strcpy(outPath, inPath); + + len = (int)strlen(outPath); + if (!len) + return; + + if (outPath[len-1] == '.') + { + outPath[len-1] = '\0'; + strcat(outPath, extension); + return; + } + + src = outPath + len - 1; + while ((src != outPath) && (*src != '\\') && (*src != '/')) + { + if (*src == '.') + { + *src = '\0'; + break; + } + src--; + } + + strcat(outPath, extension); +} + +/***************************************************************************** + TL_TempFilename + + Builds a temporary filename at specified path. +*****************************************************************************/ +void TL_TempFilename(char* path) +{ + int len; + + len = (int)strlen(path); + if (len) + { + /* tack on appending seperator */ + if (path[len-1] != '\\') + { + path[len] = '\\'; + path[len+1] = '\0'; + } + } + + strcat(path,tmpnam(NULL)); +} + +/***************************************************************************** + TL_AlignFile + + TL_Aligns data in file to any boundary. +*****************************************************************************/ +int TL_AlignFile(int handle, int align) +{ + int i; + int pos; + int empty; + int count; + + empty = 0; + pos = lseek(handle,0,SEEK_CUR); + count = ((pos+align-1)/align)*align - pos; + + for (i=0; i<count; i++) + TL_SafeWrite(handle,&empty,1); + + return (pos+count); +} + +/***************************************************************************** + TL_GetByteOrder + + Gets byte ordering, true is bigendian. +*****************************************************************************/ +int TL_GetByteOrder(void) +{ + return (g_tl_byteorder); +} + +/***************************************************************************** + TL_SetByteOrder + + Sets byte ordering, true is bigendian. +*****************************************************************************/ +void TL_SetByteOrder(int flag) +{ + g_tl_byteorder = flag; +} + +/***************************************************************************** + TL_LongSwap + + Swap according to set state. +*****************************************************************************/ +long TL_LongSwap(long l) +{ + if (!g_tl_byteorder) + return (l); + + return (TL_BigLong(l)); +} + +/***************************************************************************** + TL_ShortSwap + + Swap according to set state. +*****************************************************************************/ +short TL_ShortSwap(short s) +{ + if (!g_tl_byteorder) + return (s); + + return (TL_BigShort(s)); +} + +/***************************************************************************** + TL_BigShort + + Converts native short to big endian +*****************************************************************************/ +short TL_BigShort(short l) +{ + byte_t b1; + byte_t b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +/***************************************************************************** + TL_LittleShort + + Converts native short to little endian +*****************************************************************************/ +short TL_LittleShort(short l) +{ + return (l); +} + +/***************************************************************************** + TL_BigLong + + Converts native long to big endian +*****************************************************************************/ +long TL_BigLong(long l) +{ + byte_t b1; + byte_t b2; + byte_t b3; + byte_t b4; + + b1 = (byte_t)(l&255); + b2 = (byte_t)((l>>8)&255); + b3 = (byte_t)((l>>16)&255); + b4 = (byte_t)((l>>24)&255); + + return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4; +} + +/***************************************************************************** + TL_LittleLong + + Converts native long to little endian +*****************************************************************************/ +long TL_LittleLong(long l) +{ + return (l); +} + +/***************************************************************************** + TL_BigFloat + + Converts native float to big endian +*****************************************************************************/ +float TL_BigFloat(float f) +{ + union + { + float f; + byte_t b[4]; + } dat1,dat2; + + dat1.f = f; + dat2.b[0] = dat1.b[3]; + dat2.b[1] = dat1.b[2]; + dat2.b[2] = dat1.b[1]; + dat2.b[3] = dat1.b[0]; + + return (dat2.f); +} + +/***************************************************************************** + TL_Exists + + Returns TRUE if file exists. +*****************************************************************************/ +bool TL_Exists(const char* filename) +{ + FILE* test; + + if (!filename || !filename[0]) + return (false); + + if ((test = fopen(filename,"rb")) == NULL) + return (false); + + fclose(test); + + return (true); +} + +/***************************************************************************** + TL_FileTime + + Returns a file's time and data word. +*****************************************************************************/ +u32 TL_FileTime(char* filename) +{ + struct _finddata_t finddata; + intptr_t h; + + h = _findfirst(filename, &finddata); + if (h == -1) + return (0); + + _findclose(h); + + return (finddata.time_write); +} + +/***************************************************************************** + TL_SortNames + +*****************************************************************************/ +int TL_SortNames(const void *a, const void *b) +{ + return (strcmp(*((char **)a), *((char **)b))); +} + +/***************************************************************************** + TL_FindFiles + +*****************************************************************************/ +int TL_FindFiles(char* filemask, char*** filenames) +{ + struct _finddata_t finddata; + intptr_t h; + char sourcepath[TL_MAXPATH]; + int count; + int len; + char** names = NULL; + char* ptr; + + h = _findfirst(filemask,&finddata); + if (h == -1) + return (0); + + TL_strncpyz(sourcepath,filemask,TL_MAXPATH); + TL_StripFilename(sourcepath); + if (!sourcepath[0]) + strcpy(sourcepath,".\\"); + else + { + len = (int)strlen(sourcepath); + if (sourcepath[len-1] != '\\') + TL_strncatz(sourcepath,"\\",TL_MAXPATH); + } + + count = 0; + do + { + if (finddata.attrib & _A_SUBDIR) + continue; + + if (!count) + names = (char**)TL_Malloc(sizeof(char*)); + else + names = (char**)TL_Realloc(names,(count+1)*sizeof(char*)); + + ptr = (char*)TL_Malloc(TL_MAXPATH); + + names[count] = ptr; + TL_strncpyz(names[count],sourcepath,TL_MAXPATH); + TL_strncatz(names[count],finddata.name,TL_MAXPATH); + + count++; + } + while (!_findnext(h,&finddata)); + + _findclose(h); + + // ascending sort the names + qsort(names,count,sizeof(char*),TL_SortNames); + + *filenames = names; + return (count); +} + +/***************************************************************************** + TL_GetFileList + +*****************************************************************************/ +int TL_GetFileList(char* dirpath, char* pattern, tlfile_t*** filelist) +{ + struct _finddata_t finddata; + char sourcepath[TL_MAXPATH]; + char fullpath[TL_MAXPATH]; + char* filename; + intptr_t h; + int filecount; + int finddirs; + int len; + + filecount = 0; + + strcpy(sourcepath,dirpath); + len = (int)strlen(sourcepath); + + if (!len) + strcpy(sourcepath,".\\"); + else if (sourcepath[len-1] != '\\') + { + sourcepath[len] = '\\'; + sourcepath[len+1] = '\0'; + } + + strcpy(fullpath,sourcepath); + + if (pattern[0] == '\\' && pattern[1] == '\0') + { + // find directories + finddirs = true; + strcat(fullpath,"*"); + } + else + { + finddirs = false; + strcat(fullpath,pattern); + } + + h = _findfirst(fullpath,&finddata); + if (h == -1) + return (0); + + do + { + // dos attribute complexities i.e. _A_NORMAL is 0 + if (finddirs) + { + // skip non dirs + if (!(finddata.attrib & _A_SUBDIR)) + continue; + } + else + { + // skip dirs + if (finddata.attrib & _A_SUBDIR) + continue; + } + + if (!stricmp(finddata.name,".")) + continue; + + if (!stricmp(finddata.name,"..")) + continue; + + if (!filecount) + *filelist = (tlfile_t**)TL_Malloc(sizeof(tlfile_t*)); + else + *filelist = (tlfile_t**)TL_Realloc(*filelist,(filecount+1)*sizeof(tlfile_t*)); + + (*filelist)[filecount] = (tlfile_t*)TL_Malloc(sizeof(tlfile_t)); + + len = (int)strlen(sourcepath) + (int)strlen(finddata.name) + 1; + filename = (char*)TL_Malloc(len); + + strcpy(filename,sourcepath); + strcat(filename,finddata.name); + + (*filelist)[filecount]->filename = filename; + (*filelist)[filecount]->time_write = finddata.time_write; + + filecount++; + } + while (!_findnext(h,&finddata)); + + _findclose(h); + + return (filecount); +} + +/***************************************************************************** + _RecurseFileTree + +*****************************************************************************/ +void _RecurseFileTree(char* dirpath, int depth) +{ + tlfile_t** filelist; + int numfiles; + int i; + int len; + + // recurse from source directory + numfiles = TL_GetFileList(dirpath,"\\",&filelist); + if (!numfiles) + { + // add directory name to search tree + if (!g_tl_dircount) + g_tl_dirlist = (char**)TL_Malloc(sizeof(char*)); + else + g_tl_dirlist = (char**)TL_Realloc(g_tl_dirlist,(g_tl_dircount+1)*sizeof(char*)); + + len = (int)strlen(dirpath); + g_tl_dirlist[g_tl_dircount] = (char*)TL_Malloc(len+1); + strcpy(g_tl_dirlist[g_tl_dircount],dirpath); + + g_tl_dircount++; + return; + } + + for (i=0; i<numfiles; i++) + { + // form new path name + _RecurseFileTree(filelist[i]->filename,depth+1); + } + + g_tl_dirlist = (char**)TL_Realloc(g_tl_dirlist,(g_tl_dircount+1)*sizeof(char*)); + + len = (int)strlen(dirpath); + g_tl_dirlist[g_tl_dircount] = (char*)TL_Malloc(len+1); + strcpy(g_tl_dirlist[g_tl_dircount],dirpath); + + g_tl_dircount++; +} + +/***************************************************************************** + TL_BuildFileTree + +*****************************************************************************/ +int TL_BuildFileTree(char* dirpath, char*** dirlist) +{ + g_tl_dircount = 0; + g_tl_dirlist = NULL; + + _RecurseFileTree(dirpath,0); + + *dirlist = g_tl_dirlist; + return (g_tl_dircount); +} + +/***************************************************************************** + TL_FindFiles2 + +*****************************************************************************/ +int TL_FindFiles2(char* filemask, bool recurse, tlfile_t*** filelist) +{ + char dirpath[TL_MAXPATH]; + char pattern[TL_MAXPATH]; + char** dirlist; + tlfile_t*** templists; + tlfile_t** list; + int* numfiles; + int numoutfiles; + int count; + int numdirs; + int i; + int j; + int k; + + // get path only + strcpy(dirpath,filemask); + TL_StripFilename(dirpath); + + // get pattern only + TL_StripPath(filemask,pattern); + + numoutfiles = 0; + + if (recurse) + { + // get the tree + numdirs = TL_BuildFileTree(dirpath,&dirlist); + if (numdirs) + { + templists = (tlfile_t***)TL_Malloc(numdirs * sizeof(tlfile_t**)); + numfiles = (int*)TL_Malloc(numdirs * sizeof(int)); + + // iterate each directory found + for (i=0; i<numdirs; i++) + numfiles[i] = TL_GetFileList(dirlist[i],pattern,&templists[i]); + + // count all the files + numoutfiles = 0; + for (i=0; i<numdirs; i++) + numoutfiles += numfiles[i]; + + // allocate single list + if (numoutfiles) + { + *filelist = (tlfile_t**)TL_Malloc(numoutfiles*sizeof(tlfile_t*)); + + k = 0; + for (i=0; i<numdirs; i++) + { + count = numfiles[i]; + list = templists[i]; + for (j=0; j<count; j++,k++) + { + (*filelist)[k] = list[j]; + } + } + } + + // free the directory lists + for (i=0; i<numdirs; i++) + { + TL_Free(dirlist[i]); + + if (numfiles[i]) + TL_Free(templists[i]); + } + + TL_Free(dirlist); + TL_Free(templists); + TL_Free(numfiles); + } + } + else + { + numoutfiles = TL_GetFileList(dirpath,pattern,filelist); + } + + return (numoutfiles); +} + +/***************************************************************************** + TL_FreeFileList + +*****************************************************************************/ +void TL_FreeFileList(int count, tlfile_t** filelist) +{ + int i; + + for (i=0; i<count; i++) + { + TL_Free(filelist[i]->filename); + TL_Free(filelist[i]); + } + + if (count) + TL_Free(filelist); +} + +/***************************************************************************** + TL_CPUCount + +*****************************************************************************/ +int TL_CPUCount(void) +{ + int time; + + time = clock(); + + return (time); +} + +/***************************************************************************** + TL_CPUTime + +*****************************************************************************/ +double TL_CPUTime(int start, int stop) +{ + double duration; + + duration = (double)(stop - start)/CLOCKS_PER_SEC; + + return (duration); +} + +/***************************************************************************** + TL_CreatePath + +*****************************************************************************/ +void TL_CreatePath(const char* inPath) +{ + char* ptr; + char dirPath[TL_MAXPATH]; + + // prime and skip to first seperator + strcpy(dirPath, inPath); + ptr = strchr(dirPath, '\\'); + while (ptr) + { + ptr = strchr(ptr+1, '\\'); + if (ptr) + { + *ptr = '\0'; + mkdir(dirPath); + *ptr = '\\'; + } + } +} + +/***************************************************************************** + TL_Warning + +*****************************************************************************/ +void TL_Warning(const char* format, ...) +{ + char msg[4096]; + va_list argptr; + + if (g_tl_quiet) + return; + + va_start(argptr, format); + vsprintf(msg, format, argptr); + va_end(argptr); + + printf("WARNING: %s", msg); +} + +/***************************************************************************** + TL_printf + +*****************************************************************************/ +void TL_printf(const char* format, ...) +{ + char msg[4096]; + va_list argptr; + + if (g_tl_quiet) + return; + + va_start(argptr, format); + vsprintf(msg, format, argptr); + va_end(argptr); + + printf(msg); +} + +//----------------------------------------------------------------------------- +// TL_IsWildcardMatch +// +// See if a string matches a wildcard specification that uses * or ? +//----------------------------------------------------------------------------- +bool TL_IsWildcardMatch( const char *wildcardString, const char *stringToCheck, bool caseSensitive ) +{ + char wcChar; + char strChar; + + // use the starMatchesZero variable to determine whether an asterisk + // matches zero or more characters ( TRUE ) or one or more characters + // ( FALSE ) + bool starMatchesZero = true; + + while ( ( strChar = *stringToCheck ) && ( wcChar = *wildcardString ) ) + { + // we only want to advance the pointers if we successfully assigned + // both of our char variables, so we'll do it here rather than in the + // loop condition itself + *stringToCheck++; + *wildcardString++; + + // if this isn't a case-sensitive match, make both chars uppercase + // ( thanks to David John Fielder ( Konan ) at http://innuendo.ev.ca + // for pointing out an error here in the original code ) + if ( !caseSensitive ) + { + wcChar = toupper( wcChar ); + strChar = toupper( strChar ); + } + + // check the wcChar against our wildcard list + switch ( wcChar ) + { + // an asterisk matches zero or more characters + case '*' : + // do a recursive call against the rest of the string, + // until we've either found a match or the string has + // ended + if ( starMatchesZero ) + *stringToCheck--; + + while ( *stringToCheck ) + { + if ( TL_IsWildcardMatch( wildcardString, stringToCheck++, caseSensitive ) ) + return true; + } + + break; + + // a question mark matches any single character + case '?' : + break; + + // if we fell through, we want an exact match + default : + if ( wcChar != strChar ) + return false; + break; + } + } + + // if we have any asterisks left at the end of the wildcard string, we can + // advance past them if starMatchesZero is TRUE ( so "blah*" will match "blah" ) + while ( ( *wildcardString ) && ( starMatchesZero ) ) + { + if ( *wildcardString == '*' ) + wildcardString++; + else + break; + } + + // if we got to the end but there's still stuff left in either of our strings, + // return false; otherwise, we have a match + if ( ( *stringToCheck ) || ( *wildcardString ) ) + return false; + else + return true; +} + +//----------------------------------------------------------------------------- +// TL_CopyString +// +//----------------------------------------------------------------------------- +char *TL_CopyString( const char* pString ) +{ + int size = strlen( pString ) + 1; + char *pNewString = (char *)TL_Malloc( size ); + memcpy( pNewString, pString, size ); + + return pNewString; +} + diff --git a/utils/xbox/toollib/toollib.h b/utils/xbox/toollib/toollib.h new file mode 100644 index 0000000..c62886a --- /dev/null +++ b/utils/xbox/toollib/toollib.h @@ -0,0 +1,114 @@ +#ifndef _TOOLLIB_H_ +#define _TOOLLIB_H_ + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/utime.h> +#include <string.h> +#include <io.h> +#include <direct.h> +#include <process.h> +#include <dos.h> +#include <stdarg.h> +#include <conio.h> +#include <math.h> +#include <limits.h> +#include <malloc.h> +#include <errno.h> +#include <time.h> +#include <assert.h> +#include <share.h> + +#define TL_MAXPATH 128 +#define TL_MEMID 0x44434241 + +typedef unsigned char byte_t; +typedef unsigned int rgba_t; +typedef unsigned int abgr_t; +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned long u32; +typedef signed long s32; + +typedef struct +{ + int id; + int size; +} tlmem_t; + +typedef struct +{ + char* filename; + time_t time_write; +} tlfile_t; + +#include "scriplib.h" + +#define TL_max(a,b) ((a) > (b) ? (a) : (b)) +#define TL_min(a,b) ((a) < (b) ? (a) : (b)) + +extern void TL_Setup(char* appname, int argc, char** argv); +extern void TL_End(bool showtime); +extern void TL_Error(char* error, ...); +extern int TL_CheckParm(char* check); +extern void TL_strncpyz(char* dst, char* src, int n); +extern void TL_strncatz(char* dst, char* src, int dstsize); +extern void* TL_Malloc(int size); +extern void* TL_Realloc(void* ptr, int newsize); +extern void TL_Free(void* ptr); +extern int TL_SafeOpenRead(const char* filename); +extern int TL_SafeOpenWrite(const char* filename); +extern void TL_SafeRead(int handle, void* buffer, long count); +extern void TL_SafeWrite(int handle, void* buffer, long count); +extern void TL_SafeClose(int handle, int touch); +extern long TL_LoadFile(const char* filename, void** bufferptr); +extern void TL_SaveFile(char* filename, void* buffer, long count); +extern void TL_TouchFile(char* filename); +extern long TL_FileLength(int handle); +extern void TL_StripPath(char* path, char* dest); +extern void TL_StripExtension(char* path); +extern void TL_StripFilename(char* path); +extern void TL_GetExtension(char* path, char* dest); +extern void TL_DefaultPath(char* path, char* basepath); +extern void TL_AddSeperatorToPath(char* inpath, char* outpath); +extern void TL_DefaultExtension(char* path, char* extension, bool bForce = false); +extern void TL_TempFilename(char* path); +extern int TL_AlignFile(int handle, int align); +extern int TL_GetByteOrder(void); +extern void TL_SetByteOrder(int flag); +extern long TL_LongSwap(long l); +extern short TL_ShortSwap(short s); +extern short TL_LittleShort(short l); +extern short TL_BigShort(short l); +extern long TL_LittleLong(long l); +extern long TL_BigLong(long l); +extern float TL_BigFloat(float f); +extern bool TL_Exists(const char* filename); +extern u32 TL_FileTime(char* filename); +extern void TL_ReplaceDosExtension(char* path, char* extension); +extern void TL_ReplaceExtension(const char* inPath, const char* extension, char* outPath); +extern int TL_CPUCount(void); +extern double TL_CPUTime(int start, int stop); +extern int TL_BuildFileTree(char* dirpath, char*** dirlist); +extern int TL_GetFileList(char* dirpath, char* pattern, tlfile_t*** filelist); +extern int TL_FindFiles(char* filemask, char*** filenames); +extern int TL_FindFiles2(char* filemask, bool recurse, tlfile_t*** filelist); +extern void TL_FreeFileList(int count, tlfile_t** filelist); +extern void TL_CreatePath(const char* inPath); +extern void TL_printf(const char* format, ...); +extern void TL_Warning(const char* format, ...); +extern bool TL_IsWildcardMatch( const char *wildcardString, const char *stringToCheck, bool caseSensitive ); +extern char *TL_CopyString( const char* pString ); +extern bool TL_Check(void* ptr); + +extern int g_argc; +extern char** g_argv; + +#endif diff --git a/utils/xbox/vxbdm/console.cpp b/utils/xbox/vxbdm/console.cpp new file mode 100644 index 0000000..8ff746a --- /dev/null +++ b/utils/xbox/vxbdm/console.cpp @@ -0,0 +1,763 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Xbox console link +// +//=====================================================================================// + +#include "xbox/xbox_console.h" +#include "xbox/xbox_vxconsole.h" +#include "tier0/threadtools.h" +#include "tier0/tslist.h" +#include "tier0/ICommandLine.h" +#include "tier0/memdbgon.h" + +// all redirecting funneled here, stop redirecting in this module only +#undef OutputDebugStringA + +#pragma comment( lib, "xbdm.lib" ) + +struct DebugString_t +{ + unsigned int color; + char *pString; +}; + +#define XBX_DBGCOMMANDPREFIX "XCMD" +#define XBX_DBGRESPONSEPREFIX "XACK" +#define XBX_DBGPRINTPREFIX "XPRT" +#define XBX_DBGCOLORPREFIX "XCLR" + +#define XBX_MAX_RCMDLENGTH 256 +#define XBX_MAX_MESSAGE 2048 + +CThreadFastMutex g_xbx_dbgChannelMutex; +CThreadFastMutex g_xbx_dbgCommandHandlerMutex; +static char g_xbx_dbgRemoteBuf[XBX_MAX_RCMDLENGTH]; +static HANDLE g_xbx_dbgValidEvent; +static HANDLE g_xbx_dbgCmdCompleteEvent; +bool g_xbx_bUseVXConsoleOutput = true; +bool g_xbx_bDoSyncOutput; +static ThreadHandle_t g_xbx_hDebugThread; +CTSQueue<DebugString_t> g_xbx_DebugStringQueue; +extern CInterlockedInt g_xbx_numProfileCounters; +extern unsigned int g_xbx_profileCounters[]; +extern char g_xbx_profileName[]; +int g_xbx_freeMemory; + +_inline bool XBX_NoXBDM() { return false; } + +static CXboxConsole XboxConsole; + +DLL_EXPORT IXboxConsole *GetConsoleInterface() +{ + return &XboxConsole; +} + +//----------------------------------------------------------------------------- +// Low level string output. +// Input string should be stack based, can get clobbered. +//----------------------------------------------------------------------------- +static void OutputStringToDevice( unsigned int color, char *pString, bool bRemoteValid ) +{ + if ( !bRemoteValid ) + { + // local debug only + OutputDebugStringA( pString ); + return; + } + + // remote debug valid + // non pure colors don't translate well - find closest pure hue + unsigned int bestColor = color; + int r = ( bestColor & 0xFF ); + int g = ( bestColor >> 8 ) & 0xFF; + int b = ( bestColor >> 16 ) & 0xFF; + if ( ( r && r != 255 ) || ( g && g != 255 ) || ( b && b != 255 ) ) + { + int r0, g0, b0; + unsigned int minDist = 0xFFFFFFFF; + for ( int i=0; i<8; i++ ) + { + r0 = g0 = b0 = 0; + if ( i&4 ) + r0 = 255; + if ( i&2 ) + g0 = 255; + if ( i&1 ) + b0 = 255; + unsigned int d = ( r-r0 )*( r-r0 ) + ( g-g0 )*( g-g0 ) + ( b-b0 )*( b-b0 ); + if ( minDist > d ) + { + minDist = d; + bestColor = XMAKECOLOR( r0, g0, b0 ); + } + } + } + + // create color string + char colorString[16]; + sprintf( colorString, XBX_DBGCOLORPREFIX "[%8.8x]", bestColor ); + + // chunk line out, for each cr + char strBuffer[XBX_MAX_RCMDLENGTH]; + char *pStart = pString; + char *pEnd = pStart + strlen( pStart ); + char *pNext; + while ( pStart < pEnd ) + { + pNext = strchr( pStart, '\n' ); + if ( !pNext ) + pNext = pEnd; + else + *pNext = '\0'; + + int length = _snprintf( strBuffer, XBX_MAX_RCMDLENGTH, "%s!%s%s", XBX_DBGPRINTPREFIX, colorString, pStart ); + if ( length == -1 ) + { + strBuffer[sizeof( strBuffer )-1] = '\0'; + } + // Send the string + DmSendNotificationString( strBuffer ); + + // advance past cr + pStart = pNext+1; + } +} + +//----------------------------------------------------------------------------- +// XBX_IsConsoleConnected +// +//----------------------------------------------------------------------------- +bool CXboxConsole::IsConsoleConnected() +{ + bool bConnected; + + if ( g_xbx_dbgValidEvent == NULL ) + { + // init was never called + return false; + } + + AUTO_LOCK_FM( g_xbx_dbgChannelMutex ); + + bConnected = ( WaitForSingleObject( g_xbx_dbgValidEvent, 0 ) == WAIT_OBJECT_0 ); + + return bConnected; +} + +//----------------------------------------------------------------------------- +// Output string to listening console. Queues output for slave thread. +// Needs to be lightweight. +//----------------------------------------------------------------------------- +void CXboxConsole::DebugString( unsigned int color, const char* pFormat, ... ) +{ + if ( XBX_NoXBDM() ) + return; + + va_list args; + char szStringBuffer[XBX_MAX_MESSAGE]; + int length; + + // resolve string + va_start( args, pFormat ); + length = _vsnprintf( szStringBuffer, sizeof( szStringBuffer ), pFormat, args ); + if ( length == -1 ) + { + szStringBuffer[sizeof( szStringBuffer ) - 1] = '\0'; + } + va_end( args ); + + if ( !g_xbx_bDoSyncOutput ) + { + // queue string for delayed output + DebugString_t debugString; + debugString.color = color; + debugString.pString = strdup( szStringBuffer ); + g_xbx_DebugStringQueue.PushItem( debugString ); + } + else + { + bool bRemoteValid = g_xbx_bUseVXConsoleOutput && XBX_IsConsoleConnected(); + OutputStringToDevice( color, szStringBuffer, bRemoteValid ); + } +} + +//----------------------------------------------------------------------------- +// Waits for debug queue to drain. +//----------------------------------------------------------------------------- +void CXboxConsole::FlushDebugOutput() +{ + while ( g_xbx_DebugStringQueue.Count() != 0 ) + { + Sleep( 1 ); + } +} + +//----------------------------------------------------------------------------- +// _xdbg_strlen +// +// Critical section safe. +//----------------------------------------------------------------------------- +int _xdbg_strlen( const CHAR* str ) +{ + const CHAR* strEnd = str; + + while( *strEnd ) + strEnd++; + + return strEnd - str; +} + +//----------------------------------------------------------------------------- +// _xdbg_tolower +// +// Critical section safe. +//----------------------------------------------------------------------------- +inline CHAR _xdbg_tolower( CHAR ch ) +{ + if( ch >= 'A' && ch <= 'Z' ) + return ch - ( 'A' - 'a' ); + else + return ch; +} + +//----------------------------------------------------------------------------- +// _xdbg_strnicmp +// +// Critical section safe. +//----------------------------------------------------------------------------- +BOOL _xdbg_strnicmp( const CHAR* str1, const CHAR* str2, int n ) +{ + while ( ( _xdbg_tolower( *str1 ) == _xdbg_tolower( *str2 ) ) && *str1 && n > 0 ) + { + --n; + ++str1; + ++str2; + } + return ( !n || _xdbg_tolower( *str1 ) == _xdbg_tolower( *str2 ) ); +} + +//----------------------------------------------------------------------------- +// _xdbg_strcpy +// +// Critical section safe. +//----------------------------------------------------------------------------- +VOID _xdbg_strcpy( CHAR* strDest, const CHAR* strSrc ) +{ + while ( ( *strDest++ = *strSrc++ ) != 0 ); +} + +//----------------------------------------------------------------------------- +// _xdbg_strcpyn +// +// Critical section safe. +//----------------------------------------------------------------------------- +VOID _xdbg_strcpyn( CHAR* strDest, const CHAR* strSrc, int numChars ) +{ + while ( numChars>0 && ( *strDest++ = *strSrc++ ) != 0 ) + numChars--; +} + +//----------------------------------------------------------------------------- +// _xdbg_gettoken +// +// Critical section safe. +//----------------------------------------------------------------------------- +void _xdbg_gettoken( CHAR** tokenStream, CHAR* token, int tokenSize ) +{ + int c; + int len; + CHAR* data; + + len = 0; + + // skip prefix whitespace + data = *tokenStream; + while ( ( c = *data ) <= ' ' ) + { + if ( !c ) + goto cleanUp; + data++; + } + + // parse a token + do + { + if ( len < tokenSize ) + token[len++] = c; + + data++; + c = *data; + } while ( c > ' ' ); + + if ( len >= tokenSize ) + len = 0; + +cleanUp: + token[len] = '\0'; + *tokenStream = data; +} + +//----------------------------------------------------------------------------- +// _xdbg_tokenize +// +// Critical section safe. +//----------------------------------------------------------------------------- +int _xdbg_tokenize( CHAR* tokenStream, CHAR** tokens, int maxTokens ) +{ + char token[64]; + + // tokenize stream into seperate tokens + int numTokens = 0; + while ( 1 ) + { + tokens[numTokens++] = tokenStream; + if ( numTokens >= maxTokens ) + break; + + _xdbg_gettoken( &tokenStream, token, sizeof( token ) ); + if ( !tokenStream[0] || !token[0] ) + break; + + *tokenStream = '\0'; + tokenStream++; + } + return ( numTokens ); +} + +//----------------------------------------------------------------------------- +// _xdbg_findtoken +// +// Critical section safe. Returns -1 if not found +//----------------------------------------------------------------------------- +int _xdbg_findtoken( CHAR** tokens, int numTokens, CHAR* token ) +{ + int i; + int len; + + len = _xdbg_strlen( token ); + for ( i=0; i<numTokens; i++ ) + { + if ( _xdbg_strnicmp( tokens[i], token, len ) ) + return i; + } + + // not found + return -1; +} + +//----------------------------------------------------------------------------- +// _DebugCommandHandler +// +//----------------------------------------------------------------------------- +HRESULT __stdcall _DebugCommandHandler( const CHAR* strCommand, CHAR* strResponse, DWORD dwResponseLen, PDM_CMDCONT pdmcc ) +{ + CHAR buff[256]; + CHAR* args[8]; + int numArgs; + + AUTO_LOCK_FM( g_xbx_dbgCommandHandlerMutex ); + + // skip over the command prefix and the exclamation mark + strCommand += _xdbg_strlen( XBX_DBGCOMMANDPREFIX ) + 1; + + if ( strCommand[0] == '\0' ) + { + // just a ping + goto cleanUp; + } + + // get command and optional arguments + _xdbg_strcpyn( buff, strCommand, sizeof( buff ) ); + numArgs = _xdbg_tokenize( buff, args, sizeof( args )/sizeof( CHAR* ) ); + + if ( _xdbg_strnicmp( args[0], "__connect__", 11 ) ) + { + if ( numArgs > 1 && atoi( args[1] ) == VXCONSOLE_PROTOCOL_VERSION ) + { + // initial connect - respond that we're connected + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Connected To Application.", dwResponseLen ); + SetEvent( g_xbx_dbgValidEvent ); + + // notify convar system to send its commands + // allows vxconsole to re-connect during game + _xdbg_strcpy( g_xbx_dbgRemoteBuf, "getcvars" ); + XBX_QueueEvent( XEV_REMOTECMD, ( int )g_xbx_dbgRemoteBuf, 0, 0 ); + } + else + { + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Rejecting Connection: Wrong Protocol Version.", dwResponseLen ); + } + goto cleanUp; + } + + if ( _xdbg_strnicmp( args[0], "__disconnect__", 14 ) ) + { + // respond that we're disconnected + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Disconnected.", dwResponseLen ); + ResetEvent( g_xbx_dbgValidEvent ); + goto cleanUp; + } + + if ( _xdbg_strnicmp( args[0], "__complete__", 12 ) ) + { + // remote server has finished command - respond to acknowledge + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen ); + + // set the complete event - allows expected synchronous calling mechanism + SetEvent( g_xbx_dbgCmdCompleteEvent ); + goto cleanUp; + } + + if ( _xdbg_strnicmp( args[0], "__memory__", 10 ) ) + { + // get a current stat of available memory + MEMORYSTATUS stat; + GlobalMemoryStatus( &stat ); + g_xbx_freeMemory = stat.dwAvailPhys; + + if ( _xdbg_findtoken( args, numArgs, "quiet" ) > 0 ) + { + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen ); + } + else + { + // 32 MB is reserved and fixed by OS, so not reporting + _snprintf( strResponse, dwResponseLen, XBX_DBGRESPONSEPREFIX "Available: %.2f MB, Used: %.2f MB, Free: %.2f MB", + stat.dwTotalPhys/( 1024.0f*1024.0f ) - 32.0f, + ( stat.dwTotalPhys - stat.dwAvailPhys )/( 1024.0f*1024.0f ) - 32.0f, + stat.dwAvailPhys/( 1024.0f*1024.0f ) ); + } + goto cleanUp; + } + + if ( g_xbx_dbgRemoteBuf[0] ) + { + // previous command still pending + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Cannot execute: Previous command still pending", dwResponseLen ); + } + else + { + // add the command to the event queue to be processed by main app + _xdbg_strcpy( g_xbx_dbgRemoteBuf, strCommand ); + XBX_QueueEvent( XEV_REMOTECMD, ( int )g_xbx_dbgRemoteBuf, 0, 0 ); + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen ); + } + +cleanUp: + return XBDM_NOERR; +} + +//----------------------------------------------------------------------------- +// XBX_SendRemoteCommand +// +//----------------------------------------------------------------------------- +void CXboxConsole::SendRemoteCommand( const char *pCommand, bool async ) +{ + char cmdString[XBX_MAX_RCMDLENGTH]; + + if ( XBX_NoXBDM() || !IsConsoleConnected() ) + return; + + AUTO_LOCK_FM( g_xbx_dbgChannelMutex ); + + _snprintf( cmdString, sizeof( cmdString ), "%s!%s", XBX_DBGCOMMANDPREFIX, pCommand ); + HRESULT hr = DmSendNotificationString( cmdString ); + if ( FAILED( hr ) ) + { + XBX_Error( "XBX_SendRemoteCommand: failed on %s", cmdString ); + } + + // wait for command completion + if ( !async ) + { + DWORD timeout; + if ( !strnicmp( pCommand, "Assert()", 8 ) ) + { + // the assert is waiting for user to make selection + timeout = INFINITE; + } + else + { + // no vxconsole operation should take this long + timeout = 15000; + } + + if ( WaitForSingleObject( g_xbx_dbgCmdCompleteEvent, timeout ) == WAIT_TIMEOUT ) + { + // we have no choice but to dump core + DmCrashDump( false ); + } + } +} + +//----------------------------------------------------------------------------- +// Handle delayed VXConsole transactions +// +//----------------------------------------------------------------------------- +static unsigned _DebugThreadFunc( void *pParam ) +{ + while ( 1 ) + { + Sleep( 10 ); + + if ( !g_xbx_DebugStringQueue.Count() && !g_xbx_numProfileCounters && !g_xbx_freeMemory ) + { + continue; + } + + if ( g_xbx_numProfileCounters ) + { + // build and send asynchronously + char dbgCommand[XBX_MAX_RCMDLENGTH]; + _snprintf( dbgCommand, sizeof( dbgCommand ), "SetProfileData() %s 0x%8.8x", g_xbx_profileName, g_xbx_profileCounters ); + XBX_SendRemoteCommand( dbgCommand, true ); + + // mark as sent + g_xbx_numProfileCounters = 0; + } + + if ( g_xbx_freeMemory ) + { + // build and send asynchronously + char dbgCommand[XBX_MAX_RCMDLENGTH]; + _snprintf( dbgCommand, sizeof( dbgCommand ), "FreeMemory() 0x%8.8x", g_xbx_freeMemory ); + XBX_SendRemoteCommand( dbgCommand, true ); + + // mark as sent + g_xbx_freeMemory = 0; + } + + bool bRemoteValid = g_xbx_bUseVXConsoleOutput && XBX_IsConsoleConnected(); + while ( 1 ) + { + DebugString_t debugString; + if ( !g_xbx_DebugStringQueue.PopItem( &debugString ) ) + { + break; + } + + OutputStringToDevice( debugString.color, debugString.pString, bRemoteValid ); + free( debugString.pString ); + } + } + + return 0; +} + +//----------------------------------------------------------------------------- +// XBX_InitConsoleMonitor +// +//----------------------------------------------------------------------------- +void CXboxConsole::InitConsoleMonitor( bool bWaitForConnect ) +{ + if ( XBX_NoXBDM() ) + return; + + // create our events + g_xbx_dbgValidEvent = CreateEvent( XBOX_DONTCARE, TRUE, FALSE, NULL ); + g_xbx_dbgCmdCompleteEvent = CreateEvent( XBOX_DONTCARE, FALSE, FALSE, NULL ); + + // register our command handler with the debug monitor + HRESULT hr = DmRegisterCommandProcessor( XBX_DBGCOMMANDPREFIX, _DebugCommandHandler ); + if ( FAILED( hr ) ) + { + XBX_Error( "XBX_InitConsoleMonitor: failed to register command processor" ); + } + + // user can have output bypass slave thread + g_xbx_bDoSyncOutput = CommandLine()->FindParm( "-syncoutput" ) != 0; + + // create a slave thread to do delayed VXConsole transactions + ThreadId_t threadID; + g_xbx_hDebugThread = CreateSimpleThread( _DebugThreadFunc, NULL, &threadID, 16*1024 ); + ThreadSetDebugName( threadID, "DebugThread" ); + ThreadSetAffinity( g_xbx_hDebugThread, XBOX_PROCESSOR_5 ); + + if ( bWaitForConnect ) + { + XBX_DebugString( XBX_CLR_DEFAULT, "Waiting For VXConsole Connection...\n" ); + WaitForSingleObject( g_xbx_dbgValidEvent, INFINITE ); + } +} + +//----------------------------------------------------------------------------- +// Sends a disconnect signal to possibly attached VXConsole. +//----------------------------------------------------------------------------- +void CXboxConsole::DisconnectConsoleMonitor() +{ + if ( XBX_NoXBDM() ) + return; + + // caller is trying to safely stop vxconsole traffic, disconnect must be synchronous + XBX_SendRemoteCommand( "Disconnect()", false ); +} + +bool CXboxConsole::GetXboxName( char *pName, unsigned *pLength ) +{ + return ( DmGetXboxName( pName, (DWORD *)pLength ) == XBDM_NOERR ); +} + +void CXboxConsole::CrashDump( bool b ) +{ + DmCrashDump(b); +} + +//----------------------------------------------------------------------------- +// Walk to a specific module and dump size info +//----------------------------------------------------------------------------- +int CXboxConsole::DumpModuleSize( const char *pName ) +{ + HRESULT error; + PDM_WALK_MODULES pWalkMod = NULL; + DMN_MODLOAD modLoad; + int size = 0; + + // iterate and find match + do + { + error = DmWalkLoadedModules( &pWalkMod, &modLoad ); + if ( XBDM_NOERR == error && !stricmp( modLoad.Name, pName ) ) + { + Msg( "0x%8.8x, %5.2f MB, %s\n", modLoad.BaseAddress, modLoad.Size/( 1024.0f*1024.0f ), modLoad.Name ); + size = modLoad.Size; + error = XBDM_ENDOFLIST; + } + } + while ( XBDM_NOERR == error ); + DmCloseLoadedModules( pWalkMod ); + + if ( error != XBDM_ENDOFLIST ) + { + Warning( "DmWalkLoadedModules() failed.\n" ); + } + + return size; +} + +//----------------------------------------------------------------------------- +// 360 spew sizes of dll modules +//----------------------------------------------------------------------------- +char const* HACK_stristr( char const* pStr, char const* pSearch ) // hack because moved code from above vstdlib +{ + AssertValidStringPtr(pStr); + AssertValidStringPtr(pSearch); + + if (!pStr || !pSearch) + return 0; + + char const* pLetter = pStr; + + // Check the entire string + while (*pLetter != 0) + { + // Skip over non-matches + if (tolower((unsigned char)*pLetter) == tolower((unsigned char)*pSearch)) + { + // Check for match + char const* pMatch = pLetter + 1; + char const* pTest = pSearch + 1; + while (*pTest != 0) + { + // We've run off the end; don't bother. + if (*pMatch == 0) + return 0; + + if (tolower((unsigned char)*pMatch) != tolower((unsigned char)*pTest)) + break; + + ++pMatch; + ++pTest; + } + + // Found a match! + if (*pTest == 0) + return pLetter; + } + + ++pLetter; + } + + return 0; +} + +void CXboxConsole::DumpDllInfo( const char *pBasePath ) +{ + // Directories containing dlls + static char *dllDirs[] = + { + "bin", + "hl2\\bin", + "tf\\bin", + "portal\\bin", + "episodic\\bin" + }; + + char binPath[MAX_PATH]; + char dllPath[MAX_PATH]; + char searchPath[MAX_PATH]; + + HMODULE hModule; + WIN32_FIND_DATA wfd; + HANDLE hFind; + + Msg( "Dumping Module Sizes...\n" ); + + for ( int i = 0; i < ARRAYSIZE( dllDirs ); ++i ) + { + int totalSize = 0; + + _snprintf( binPath, sizeof( binPath ), "%s\\%s", pBasePath, dllDirs[i] ); + _snprintf( searchPath, sizeof( binPath ), "%s\\*.dll", binPath ); + + // show the directory we're searching + Msg( "\nDirectory: %s\n\n", binPath ); + + // Start the find and check for failure. + hFind = FindFirstFile( searchPath, &wfd ); + if ( INVALID_HANDLE_VALUE == hFind ) + { + Warning( "No Files Found.\n" ); + } + else + { + // Load and unload each dll individually. + do + { + if ( !HACK_stristr( wfd.cFileName, "_360.dll" ) ) + { + // exclude explicit pc dlls + // FindFirstFile does not support a spec mask of *_360.dll on the Xbox HDD + continue; + } + + _snprintf( dllPath, sizeof( dllPath ), "%s\\%s", binPath, wfd.cFileName ); + hModule = LoadLibrary( dllPath ); + if ( hModule ) + { + totalSize += DumpModuleSize( wfd.cFileName ); + FreeLibrary( hModule ); + } + else + { + Warning( "Failed to load: %s\n", dllPath ); + } + } + while( FindNextFile( hFind, &wfd ) ); + + FindClose( hFind ); + + Msg( "Total Size: %.2f MB\n", totalSize/( 1024.0f*1024.0f ) ); + } + } +} + +void CXboxConsole::OutputDebugString( const char *p ) +{ + ::OutputDebugStringA( p ); +} + +bool CXboxConsole::IsDebuggerPresent() +{ + return ( DmIsDebuggerPresent() != 0 ); +} diff --git a/utils/xbox/vxbdm/rcommands.cpp b/utils/xbox/vxbdm/rcommands.cpp new file mode 100644 index 0000000..83b9cea --- /dev/null +++ b/utils/xbox/vxbdm/rcommands.cpp @@ -0,0 +1,320 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Xbox Remote Commands +// +//=====================================================================================// + +#include "xbox/xbox_console.h" +#include "xbox/xbox_vxconsole.h" +#include "tier0/tslist.h" +#include "tier0/memdbgon.h" + +CInterlockedInt g_xbx_numProfileCounters; +unsigned int g_xbx_profileCounters[XBX_MAX_PROFILE_COUNTERS]; +char g_xbx_profileName[32]; + +//----------------------------------------------------------------------------- +// XBX_rSetProfileAttributes +// +// Expose profile counters attributes to the console. +//----------------------------------------------------------------------------- +int CXboxConsole::SetProfileAttributes( const char *pProfileName, int numCounters, const char *names[], unsigned int colors[] ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrProfile_t* profileList; + + if ( numCounters > XBX_MAX_PROFILE_COUNTERS ) + { + numCounters = XBX_MAX_PROFILE_COUNTERS; + } + + profileList = new xrProfile_t[numCounters]; + memset( profileList, 0, numCounters*sizeof( xrProfile_t ) ); + + for ( int i=0; i<numCounters; i++ ) + { + strncpy( profileList[i].labelString, names[i], sizeof( profileList[i].labelString ) ); + profileList[i].labelString[sizeof( profileList[i].labelString ) - 1] = '\0'; + + profileList[i].color = colors[i]; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "SetProfile() %s 0x%8.8x 0x%8.8x 0x%8.8x", pProfileName, numCounters, profileList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete[] profileList; + + return ( retVal ); +} + +//----------------------------------------------------------------------------- +// XBX_rSetProfileData +// +// Expose profile counters to the console. Expected to be called once per game frame. +//----------------------------------------------------------------------------- +void CXboxConsole::SetProfileData( const char *pProfileName, int numCounters, unsigned int *pCounters ) +{ + static unsigned int lastTime = 0; + unsigned int time; + + // not faster than 10Hz + time = GetTickCount(); + if ( time - lastTime < 100 ) + { + return; + } + + if ( g_xbx_numProfileCounters == 0 ) + { + _snprintf( g_xbx_profileName, sizeof( g_xbx_profileName ), pProfileName ); + + if ( numCounters > XBX_MAX_PROFILE_COUNTERS ) + { + numCounters = XBX_MAX_PROFILE_COUNTERS; + } + memcpy( g_xbx_profileCounters, pCounters, numCounters * sizeof( unsigned int ) ); + + // mark for sending + g_xbx_numProfileCounters = numCounters; + + lastTime = time; + } +} + +//----------------------------------------------------------------------------- +// XBX_rMemDump +// +// Send signal to remote console to read mempry dump in specified filename. +//----------------------------------------------------------------------------- +int CXboxConsole::MemDump( const char *pDumpFileName ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + + _snprintf( dbgCommand, sizeof( dbgCommand ), "MemDump() %s", pDumpFileName ); + XBX_SendRemoteCommand( dbgCommand, true ); + + return 0; +} + +//----------------------------------------------------------------------------- +// XBX_rTimeStampLog +// +// Send time stamp to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::TimeStampLog( float time, const char *pString ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrTimeStamp_t timeStamp; + MEMORYSTATUS stat; + static int lastMemoryStamp = 0; + static float lastTimeStamp = 0; + + // get current available memory + GlobalMemoryStatus( &stat ); + + if ( !lastTimeStamp || time < lastTimeStamp ) + { + // first entry or restart, reset stamps + lastMemoryStamp = stat.dwAvailPhys; + lastTimeStamp = time; + } + + timeStamp.time = time; + timeStamp.deltaTime = time - lastTimeStamp; + timeStamp.memory = stat.dwAvailPhys; + timeStamp.deltaMemory = stat.dwAvailPhys - lastMemoryStamp; + + strncpy( timeStamp.messageString, pString, sizeof( timeStamp.messageString ) ); + timeStamp.messageString[sizeof( timeStamp.messageString ) - 1] = '\0'; + + _snprintf( dbgCommand, sizeof( dbgCommand ), "TimeStampLog() 0x%8.8x 0x%8.8x", &timeStamp, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + lastTimeStamp = time; + lastMemoryStamp = stat.dwAvailPhys; + + return retVal; +} + +//----------------------------------------------------------------------------- +// XBX_rMaterialList +// +// Send material list to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::MaterialList( int nMaterials, const xMaterialList_t* pXMaterialList ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrMaterial_t* pRemoteList; + + pRemoteList = new xrMaterial_t[nMaterials]; + memset( pRemoteList, 0, nMaterials*sizeof( xrMaterial_t ) ); + + for ( int i=0; i<nMaterials; i++ ) + { + strncpy( pRemoteList[i].nameString, pXMaterialList[i].pName, sizeof( pRemoteList[i].nameString ) ); + pRemoteList[i].nameString[sizeof( pRemoteList[i].nameString ) - 1] = '\0'; + + strncpy( pRemoteList[i].shaderString, pXMaterialList[i].pShaderName, sizeof( pRemoteList[i].shaderString ) ); + pRemoteList[i].shaderString[sizeof( pRemoteList[i].shaderString ) - 1] = '\0'; + + pRemoteList[i].refCount = pXMaterialList[i].refCount; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "MaterialList() 0x%8.8x 0x%8.8x 0x%8.8x", nMaterials, pRemoteList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete [] pRemoteList; + + return retVal; +} + +//----------------------------------------------------------------------------- +// XBX_rTextureList +// +// Send texture list to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::TextureList( int nTextures, const xTextureList_t* pXTextureList ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrTexture_t* pRemoteList; + + pRemoteList = new xrTexture_t[nTextures]; + memset( pRemoteList, 0, nTextures*sizeof( xrTexture_t ) ); + + for ( int i=0; i<nTextures; i++ ) + { + strncpy( pRemoteList[i].nameString, pXTextureList[i].pName, sizeof( pRemoteList[i].nameString ) ); + pRemoteList[i].nameString[sizeof( pRemoteList[i].nameString ) - 1] = '\0'; + + strncpy( pRemoteList[i].groupString, pXTextureList[i].pGroupName, sizeof( pRemoteList[i].groupString ) ); + pRemoteList[i].groupString[sizeof( pRemoteList[i].groupString ) - 1] = '\0'; + + strncpy( pRemoteList[i].formatString, pXTextureList[i].pFormatName, sizeof( pRemoteList[i].formatString ) ); + pRemoteList[i].formatString[sizeof( pRemoteList[i].formatString ) - 1] = '\0'; + + pRemoteList[i].size = pXTextureList[i].size; + pRemoteList[i].width = pXTextureList[i].width; + pRemoteList[i].height = pXTextureList[i].height; + pRemoteList[i].depth = pXTextureList[i].depth; + pRemoteList[i].numLevels = pXTextureList[i].numLevels; + pRemoteList[i].binds = pXTextureList[i].binds; + pRemoteList[i].refCount = pXTextureList[i].refCount; + pRemoteList[i].sRGB = pXTextureList[i].sRGB; + pRemoteList[i].edram = pXTextureList[i].edram; + pRemoteList[i].procedural = pXTextureList[i].procedural; + pRemoteList[i].fallback = pXTextureList[i].fallback; + pRemoteList[i].final = pXTextureList[i].final; + pRemoteList[i].failed = pXTextureList[i].failed; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "TextureList() 0x%8.8x 0x%8.8x 0x%8.8x", nTextures, pRemoteList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete [] pRemoteList; + + return ( retVal ); +} + +//----------------------------------------------------------------------------- +// XBX_rSoundList +// +// Send sound list to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::SoundList( int nSounds, const xSoundList_t* pXSoundList ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrSound_t* pRemoteList; + + pRemoteList = new xrSound_t[nSounds]; + memset( pRemoteList, 0, nSounds*sizeof( xrSound_t ) ); + + for ( int i=0; i<nSounds; i++ ) + { + strncpy( pRemoteList[i].nameString, pXSoundList[i].name, sizeof( pRemoteList[i].nameString ) ); + pRemoteList[i].nameString[sizeof( pRemoteList[i].nameString ) - 1] = '\0'; + + strncpy( pRemoteList[i].formatString, pXSoundList[i].formatName, sizeof( pRemoteList[i].formatString ) ); + pRemoteList[i].formatString[sizeof( pRemoteList[i].formatString ) - 1] = '\0'; + + pRemoteList[i].rate = pXSoundList[i].rate; + pRemoteList[i].bits = pXSoundList[i].bits; + pRemoteList[i].channels = pXSoundList[i].channels; + pRemoteList[i].looped = pXSoundList[i].looped; + pRemoteList[i].dataSize = pXSoundList[i].dataSize; + pRemoteList[i].numSamples = pXSoundList[i].numSamples; + pRemoteList[i].streamed = pXSoundList[i].streamed; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "SoundList() 0x%8.8x 0x%8.8x 0x%8.8x", nSounds, pRemoteList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete [] pRemoteList; + + return ( retVal ); +} + +//----------------------------------------------------------------------------- +// XBX_rMapInfo +// +// Send signal to remote console with various info +//----------------------------------------------------------------------------- +int CXboxConsole::MapInfo( const xMapInfo_t *pXMapInfo ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrMapInfo_t xrMapInfo; + + memcpy( xrMapInfo.position, pXMapInfo->position, 3 * sizeof( float ) ); + memcpy( xrMapInfo.angle, pXMapInfo->angle, 3 * sizeof( float ) ); + + strncpy( xrMapInfo.mapPath, pXMapInfo->mapPath, sizeof( xrMapInfo.mapPath ) ); + xrMapInfo.mapPath[sizeof( xrMapInfo.mapPath ) - 1] = '\0'; + + strncpy( xrMapInfo.savePath, pXMapInfo->savePath, sizeof( xrMapInfo.savePath ) ); + xrMapInfo.savePath[sizeof( xrMapInfo.savePath ) - 1] = '\0'; + + xrMapInfo.build = pXMapInfo->build; + xrMapInfo.skill = pXMapInfo->skill; + + _snprintf( dbgCommand, sizeof( dbgCommand ), "MapInfo() 0x%8.8x 0x%8.8x", &xrMapInfo, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + return retVal; +} + +//----------------------------------------------------------------------------- +// XBX_rAddCommands +// +// Expose commands to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::AddCommands( int numCommands, const char* commands[], const char* help[] ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrCommand_t* cmdList; + + cmdList = new xrCommand_t[numCommands]; + memset( cmdList, 0, numCommands*sizeof( xrCommand_t ) ); + + for ( int i=0; i<numCommands; i++ ) + { + strncpy( cmdList[i].nameString, commands[i], sizeof( cmdList[i].nameString ) ); + cmdList[i].nameString[sizeof( cmdList[i].nameString ) - 1] = '\0'; + + strncpy( cmdList[i].helpString, help[i], sizeof( cmdList[i].helpString ) ); + cmdList[i].helpString[sizeof( cmdList[i].helpString ) - 1] = '\0'; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "AddCommands() 0x%8.8x 0x%8.8x 0x%8.8x", numCommands, cmdList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete [] cmdList; + + return ( retVal ); +} + diff --git a/utils/xbox/vxbdm/vxbdm.vpc b/utils/xbox/vxbdm/vxbdm.vpc new file mode 100644 index 0000000..65c74e7 --- /dev/null +++ b/utils/xbox/vxbdm/vxbdm.vpc @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// vxbdm.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_dll_x360_base.vpc" + +$Configuration +{ + $Xbox360ImageConversion + { + // General + $ExportByName "Yes" + } +} + +$Project +{ + $Folder "Link Libraries" + { + -$File "$SRCDIR\lib\public\tier1_360.lib" + -$File "$SRCDIR\lib\public\vstdlib_360.lib" + } +} + +$Project "vxbdm" +{ + $Folder "Source Files" + { + $file "console.cpp" + $File "rcommands.cpp" + } +} diff --git a/utils/xbox/vxbdm/xbox/xbox.def b/utils/xbox/vxbdm/xbox/xbox.def new file mode 100644 index 0000000..3c64bf8 --- /dev/null +++ b/utils/xbox/vxbdm/xbox/xbox.def @@ -0,0 +1,3 @@ +LIBRARY vxbdm_360.dll +EXPORTS + GetConsoleInterface @1
\ No newline at end of file diff --git a/utils/xbox/vxconsole/assert_dialog.cpp b/utils/xbox/vxconsole/assert_dialog.cpp new file mode 100644 index 0000000..9abcd35 --- /dev/null +++ b/utils/xbox/vxconsole/assert_dialog.cpp @@ -0,0 +1,155 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// ASSERT_DIALOG.CPP +// +// Handle Remote Assert(). +//=====================================================================================// +#include "vxconsole.h" + +AssertAction_t g_AssertAction = ASSERT_ACTION_BREAK; +static const char * g_AssertInfo = "Assert Info Not Available."; +bool g_AssertDialogActive = false; + +//----------------------------------------------------------------------------- +// AssertDialogProc +// +//----------------------------------------------------------------------------- +int CALLBACK AssertDialogProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + switch( uMsg ) + { + case WM_INITDIALOG: + { + SetWindowText( hDlg, "Xbox 360 Assert!" ); + SetDlgItemText( hDlg, IDC_FILENAME_CONTROL, g_AssertInfo ); + + // Center the dialog. + RECT rcDlg, rcDesktop; + GetWindowRect( hDlg, &rcDlg ); + GetWindowRect( GetDesktopWindow(), &rcDesktop ); + SetWindowPos( + hDlg, + HWND_TOP, + ((rcDesktop.right-rcDesktop.left) - (rcDlg.right-rcDlg.left)) / 2, + ((rcDesktop.bottom-rcDesktop.top) - (rcDlg.bottom-rcDlg.top)) / 2, + 0, + 0, + SWP_NOSIZE ); + } + return true; + + case WM_COMMAND: + { + switch( LOWORD( wParam ) ) + { + // Ignore Asserts in this file from now on. + case IDC_IGNORE_FILE: + { + g_AssertAction = ASSERT_ACTION_IGNORE_FILE; + EndDialog( hDlg, 0 ); + return true; + } + + // Ignore this Assert once. + case IDC_IGNORE_THIS: + { + g_AssertAction = ASSERT_ACTION_IGNORE_THIS; + EndDialog( hDlg, 0 ); + return true; + } + + // Always ignore this Assert. + case IDC_IGNORE_ALWAYS: + { + g_AssertAction = ASSERT_ACTION_IGNORE_ALWAYS; + EndDialog( hDlg, 0 ); + return true; + } + + // Ignore all Asserts from now on. + case IDC_IGNORE_ALL: + { + g_AssertAction = ASSERT_ACTION_IGNORE_ALL; + EndDialog( hDlg, 0 ); + return true; + } + + case IDC_BREAK: + { + g_AssertAction = ASSERT_ACTION_BREAK; + EndDialog( hDlg, 0 ); + return true; + } + } + + case WM_KEYDOWN: + { + // Escape? + if ( wParam == 2 ) + { + // Ignore this Assert. + g_AssertAction = ASSERT_ACTION_IGNORE_THIS; + EndDialog( hDlg, 0 ); + return true; + } + } + } + return true; + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// rc_Assert +// +// Sent from application on hitting an Assert +//----------------------------------------------------------------------------- +int rc_Assert( char* commandPtr ) +{ + char* cmdToken; + int retAddr; + int errCode = -1; + + // Flash the taskbar icon (otherwise users may not realise the app has stalled on an Assert, esp. during loading) + FLASHWINFO flashWInfo = { sizeof(FLASHWINFO), g_hDlgMain, FLASHW_ALL|FLASHW_TIMERNOFG, 0, 1000 }; + FlashWindowEx( &flashWInfo ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + if (1 != sscanf( cmdToken, "%x", &retAddr )) + goto cleanUp; + + // skip whitespace + while ( commandPtr[0] == ' ' ) + { + commandPtr++; + } + + // Display file/line/expression info from the message in the Assert dialog + // (convert '\t' to '\n'; way simpler than tokenizing a general assert expression) + g_AssertInfo = commandPtr; + char *tab = commandPtr; + while( ( tab = strchr( tab, '\t' ) ) != NULL ) + { + tab[0] = '\n'; + } + + // Open the Assert dialog, to determine the desired action + g_AssertAction = ASSERT_ACTION_BREAK; + g_AssertDialogActive = true; + DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_ASSERT_DIALOG ), g_hDlgMain, ( DLGPROC )AssertDialogProc ); + g_AssertDialogActive = false; + + // Write the (endian-converted) result directly back into the application's memory: + int xboxRetVal = BigDWord( g_AssertAction ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + // success + errCode = 0; + +cleanUp: + return errCode; +} diff --git a/utils/xbox/vxconsole/assert_dialog.rc b/utils/xbox/vxconsole/assert_dialog.rc new file mode 100644 index 0000000..0d19bd2 --- /dev/null +++ b/utils/xbox/vxconsole/assert_dialog.rc @@ -0,0 +1,107 @@ +// Microsoft Visual C++ generated resource script. +// +#include "assert_resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "assert_resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ASSERT_DIALOG DIALOGEX 0, 0, 268, 158 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Assert" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + LTEXT "c:/hl2/src/blah.cpp",IDC_FILENAME_CONTROL,7,7,246,34 + DEFPUSHBUTTON "&Break in Debugger",IDC_BREAK,7,49,98,14 + PUSHBUTTON "&Ignore This Assert",IDC_IGNORE_THIS,7,66,98,14 + EDITTEXT IDC_IGNORE_NUMTIMES,110,66,24,14,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED + LTEXT "time(s).",IDC_NOID,138,69,23,8 + PUSHBUTTON "Always Ignore &This Assert",IDC_IGNORE_ALWAYS,7,83,98,14 + PUSHBUTTON "Ignore &Nearby Asserts",IDC_IGNORE_NEARBY,7,100,98,14,WS_DISABLED + LTEXT "within",IDC_NOID,109,103,19,8 + EDITTEXT IDC_IGNORE_NUMLINES,131,100,40,14,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED + LTEXT "lines.",IDC_NOID,175,103,17,8 + PUSHBUTTON "Ignore Asserts in This &File",IDC_IGNORE_FILE,7,117,98,14 + PUSHBUTTON "Ignore &All Asserts",IDC_IGNORE_ALL,7,134,98,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ASSERT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 261 + TOPMARGIN, 7 + BOTTOMMARGIN, 151 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/utils/xbox/vxconsole/assert_resource.h b/utils/xbox/vxconsole/assert_resource.h new file mode 100644 index 0000000..b23c645 --- /dev/null +++ b/utils/xbox/vxconsole/assert_resource.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by assert_dialog.rc +// +#define IDD_ASSERT_DIALOG 101 +#define IDC_FILENAME_CONTROL 1000 +#define IDC_LINE_CONTROL 1001 +#define IDC_IGNORE_FILE 1002 +#define IDC_IGNORE_NEARBY 1003 +#define IDC_IGNORE_NUMLINES 1004 +#define IDC_IGNORE_THIS 1005 +#define IDC_BREAK 1006 +#define IDC_IGNORE_ALL 1008 +#define IDC_IGNORE_ALWAYS 1009 +#define IDC_IGNORE_NUMTIMES 1010 +#define IDC_ASSERT_MSG_CTRL 1011 +#define IDC_NOID -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1005 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/utils/xbox/vxconsole/bindings.cpp b/utils/xbox/vxconsole/bindings.cpp new file mode 100644 index 0000000..67bce48 --- /dev/null +++ b/utils/xbox/vxconsole/bindings.cpp @@ -0,0 +1,591 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// BINDINGS.CPP +// +// Keyboard Shortcuts +//=====================================================================================// +#include "vxconsole.h" + +#define ID_BINDINGS_LISTVIEW 100 + +// column id +#define ID_BIND_KEYCODE 0 +#define ID_BIND_MENUNAME 1 +#define ID_BIND_COMMAND 2 + +typedef struct +{ const CHAR* name; + int width; + int subItemIndex; +} label_t; + +typedef struct +{ + int keyCode; + const char *pKeyString; + char *pMenuName; + char *pCommandString; +} bind_t; + +// {VK_F1, "F1", "WireFrame", "incrementvar mat_wireframe 0 2 1"}, +// {VK_F2, "F2", "FullBright", "incrementvar mat_fullbright 0 2 1"}, +// {VK_F3, "F3", "Impulse 101", "impulse 101"}, +// {VK_F4, "F4", "Screenshot", "*screenshot"}, + + +bind_t g_bindings[MAX_BINDINGS] = +{ + {VK_F1, "F1", NULL, NULL}, + {VK_F2, "F2", NULL, NULL}, + {VK_F3, "F3", NULL, NULL}, + {VK_F4, "F4", NULL, NULL}, + {VK_F5, "F5", NULL, NULL}, + {VK_F6, "F6", NULL, NULL}, + {VK_F7, "F7", NULL, NULL}, + {VK_F8, "F8", NULL, NULL}, + {VK_F9, "F9", NULL, NULL}, + {VK_F10, "F10", NULL, NULL}, + {VK_F11, "F11", NULL, NULL}, + {VK_F12, "F12", NULL, NULL}, +}; + +label_t g_bindings_labels[] = +{ + {"Key", 80, ID_BIND_KEYCODE}, + {"Menu Name", 150, ID_BIND_MENUNAME}, + {"Command", 400, ID_BIND_COMMAND}, +}; + +HWND g_bindings_hWnd; +HWND g_bindings_hWndListView; +RECT g_bindings_windowRect; +char g_bindingsModify_menuName[256]; +char g_bindingsModify_command[256]; +char g_bindingsModify_keyCode[256]; + +//----------------------------------------------------------------------------- +// Bindings_ModifyEntry +// +//----------------------------------------------------------------------------- +void Bindings_ModifyEntry( int i, const char *pMenuName, const char *pCommandString ) +{ + if ( g_bindings[i].pMenuName && g_bindings[i].pMenuName[0] ) + Sys_Free( g_bindings[i].pMenuName ); + g_bindings[i].pMenuName = Sys_CopyString( pMenuName ); + + if ( g_bindings[i].pCommandString && g_bindings[i].pCommandString[0] ) + Sys_Free( g_bindings[i].pCommandString ); + g_bindings[i].pCommandString = Sys_CopyString( pCommandString ); +} + +//----------------------------------------------------------------------------- +// Bindings_GetSelectedItem +// +//----------------------------------------------------------------------------- +int Bindings_GetSelectedItem() +{ + int i; + int selection = -1; + int state; + + for ( i=0; i<MAX_BINDINGS; i++ ) + { + state = ListView_GetItemState( g_bindings_hWndListView, i, LVIS_SELECTED ); + if ( state == LVIS_SELECTED ) + { + selection = i; + break; + } + } + + return selection; +} + +//----------------------------------------------------------------------------- +// Bindings_TranslateKey +// +//----------------------------------------------------------------------------- +bool Bindings_TranslateKey( int vkKeyCode ) +{ + int i; + + for ( i=0; i<MAX_BINDINGS; i++ ) + { + if ( !g_bindings[i].pCommandString || !g_bindings[i].pCommandString[0] ) + continue; + + if ( vkKeyCode == g_bindings[i].keyCode ) + { + ProcessCommand( g_bindings[i].pCommandString ); + return true; + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Bindings_MenuSelection +// +//----------------------------------------------------------------------------- +bool Bindings_MenuSelection( int wID ) +{ + int index; + + index = wID - IDM_BINDINGS_BIND1; + if ( index < 0 || index > MAX_BINDINGS-1 ) + return false; + + // as if the key were pressed... + return ( Bindings_TranslateKey( g_bindings[index].keyCode ) ); +} + +//----------------------------------------------------------------------------- +// Bindings_UpdateMenu +// +// Builds the dynamic menu +//----------------------------------------------------------------------------- +void Bindings_UpdateMenu() +{ + HMENU hMenu; + HMENU hNewMenu; + MENUITEMINFO menuItemInfo; + int i; + int numAdded; + char menuBuff[64]; + + hMenu = GetMenu( g_hDlgMain ); + if ( !hMenu ) + return; + + memset( &menuItemInfo, 0, sizeof( menuItemInfo ) ); + menuItemInfo.cbSize = sizeof( MENUITEMINFO ); + + numAdded = 0; + hNewMenu = CreatePopupMenu(); + menuItemInfo.fMask = MIIM_ID|MIIM_FTYPE|MIIM_STRING; + menuItemInfo.fType = MFT_STRING; + for ( i=MAX_BINDINGS-1; i>=0; i-- ) + { + if ( !g_bindings[i].pCommandString || !g_bindings[i].pCommandString[0] ) + continue; + + menuItemInfo.wID = IDM_BINDINGS_BIND1+i; + sprintf( menuBuff, "%s\tF%d", g_bindings[i].pMenuName, g_bindings[i].keyCode-VK_F1+1 ); + menuItemInfo.dwTypeData = ( LPSTR )menuBuff; + InsertMenuItem( hNewMenu, 0, true, &menuItemInfo ); + + numAdded++; + } + + if ( numAdded ) + { + // add seperator + menuItemInfo.fMask = MIIM_FTYPE; + menuItemInfo.fType = MFT_SEPARATOR; + InsertMenuItem( hNewMenu, 0, true, &menuItemInfo ); + } + + menuItemInfo.fMask = MIIM_ID|MIIM_FTYPE|MIIM_STRING; + menuItemInfo.fType = MFT_STRING; + menuItemInfo.wID = IDM_BINDINGS_EDIT; + menuItemInfo.dwTypeData = "Edit..."; + InsertMenuItem( hNewMenu, 0, true, &menuItemInfo ); + + // delete the previous menu + menuItemInfo.fMask = MIIM_SUBMENU; + GetMenuItemInfo( hMenu, IDM_BINDINGS, false, &menuItemInfo ); + if ( menuItemInfo.hSubMenu ) + DestroyMenu( menuItemInfo.hSubMenu ); + else + { + // add a new menu at the tail of the app menu + AppendMenu( hMenu, MF_STRING, ( UINT_PTR )IDM_BINDINGS, "Bindings" ); + } + + // add the new menu to bar + menuItemInfo.fMask = MIIM_SUBMENU; + menuItemInfo.hSubMenu = hNewMenu; + SetMenuItemInfo( hMenu, IDM_BINDINGS, false, &menuItemInfo ); + + DrawMenuBar( g_hDlgMain ); +} + +//----------------------------------------------------------------------------- +// BindingsModifyDlg_Proc +// +//----------------------------------------------------------------------------- +BOOL CALLBACK BindingsModifyDlg_Proc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch ( message ) + { + case WM_INITDIALOG: + SetDlgItemText( hWnd, IDC_MODIFYBIND_KEYCODE, g_bindingsModify_keyCode ); + SetDlgItemText( hWnd, IDC_MODIFYBIND_MENUNAME, g_bindingsModify_menuName ); + SetDlgItemText( hWnd, IDC_MODIFYBIND_COMMAND, g_bindingsModify_command ); + return ( TRUE ); + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDC_OK: + GetDlgItemText( hWnd, IDC_MODIFYBIND_MENUNAME, g_bindingsModify_menuName, sizeof( g_bindingsModify_menuName ) ); + GetDlgItemText( hWnd, IDC_MODIFYBIND_COMMAND, g_bindingsModify_command, sizeof( g_bindingsModify_command ) ); + case IDCANCEL: + case IDC_CANCEL: + EndDialog( hWnd, wParam ); + return ( TRUE ); + } + break; + } + return ( FALSE ); +} + +//----------------------------------------------------------------------------- +// BindingsModifyDlg_Open +// +//----------------------------------------------------------------------------- +void BindingsModifyDlg_Open( int selection ) +{ + int result; + + sprintf( g_bindingsModify_keyCode, "F%d", selection+1 ); + strcpy( g_bindingsModify_menuName, g_bindings[selection].pMenuName ); + strcpy( g_bindingsModify_command, g_bindings[selection].pCommandString ); + + result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_MODIFYBIND ), g_hDlgMain, ( DLGPROC )BindingsModifyDlg_Proc ); + if ( LOWORD( result ) != IDC_OK ) + return; + + // accept changes and update + Bindings_ModifyEntry( selection, g_bindingsModify_menuName, g_bindingsModify_command ); + ListView_RedrawItems( g_bindings_hWndListView, 0, MAX_BINDINGS-1 ); + UpdateWindow( g_bindings_hWndListView ); + Bindings_UpdateMenu(); +} + +//----------------------------------------------------------------------------- +// Bindings_LoadConfig +// +//----------------------------------------------------------------------------- +void Bindings_LoadConfig() +{ + char valueBuff[256]; + char keyBuff[32]; + char menuName[256]; + char commandString[256]; + char *ptr; + char *token; + int keyCode; + int i; + int numArgs; + char buff[256]; + + for ( i=0; i<MAX_BINDINGS; i++ ) + { + menuName[0] = '\0'; + commandString[0] = '\0'; + + sprintf( keyBuff, "bind%d", i ); + Sys_GetRegistryString( keyBuff, valueBuff, "", sizeof( valueBuff ) ); + + // parse and populate valid values + ptr = valueBuff; + token = Sys_GetToken( &ptr, false, NULL ); + if ( token[0] ) + keyCode = atoi( token ); + + token = Sys_GetToken( &ptr, false, NULL ); + if ( token[0] ) + strcpy( menuName, token ); + + token = Sys_GetToken( &ptr, false, NULL ); + if ( token[0] ) + strcpy( commandString, token ); + + Bindings_ModifyEntry( i, menuName, commandString ); + } + + Sys_GetRegistryString( "bindingsWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_bindings_windowRect.left, &g_bindings_windowRect.top, &g_bindings_windowRect.right, &g_bindings_windowRect.bottom ); + if ( numArgs != 4 ) + memset( &g_bindings_windowRect, 0, sizeof( g_bindings_windowRect ) ); +} + +//----------------------------------------------------------------------------- +// Bindings_SaveConfig +// +//----------------------------------------------------------------------------- +void Bindings_SaveConfig() +{ + char valueBuff[256]; + char buff[256]; + char keyBuff[32]; + char *pMenuName; + char *pCommandString; + int len; + int i; + WINDOWPLACEMENT wp; + + if ( g_bindings_hWnd ) + { + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_bindings_hWnd, &wp ); + g_bindings_windowRect = wp.rcNormalPosition; + sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom ); + Sys_SetRegistryString( "bindingsWindowRect", buff ); + } + + for ( i=0; i<MAX_BINDINGS; i++ ) + { + sprintf( keyBuff, "bind%d", i ); + + pMenuName = g_bindings[i].pMenuName; + if ( !pMenuName ) + pMenuName = ""; + + pCommandString = g_bindings[i].pCommandString; + if ( !pCommandString ) + pCommandString = ""; + + len = _snprintf( valueBuff, sizeof( valueBuff ), "%d \"%s\" \"%s\"", g_bindings[i].keyCode, pMenuName, pCommandString ); + if ( len == -1 ) + { + // kill it + valueBuff[0] = '\0'; + } + + Sys_SetRegistryString( keyBuff, valueBuff ); + } +} + +//----------------------------------------------------------------------------- +// Bindings_SizeWindow +// +//----------------------------------------------------------------------------- +void Bindings_SizeWindow( HWND hwnd, int cx, int cy ) +{ + if ( cx==0 || cy==0 ) + { + RECT rcClient; + GetClientRect( hwnd, &rcClient ); + cx = rcClient.right; + cy = rcClient.bottom; + } + + // position the ListView + SetWindowPos( g_bindings_hWndListView, NULL, 0, 0, cx, cy, SWP_NOZORDER ); +} + +//----------------------------------------------------------------------------- +// Bindings_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK Bindings_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + bind_t* pBind; + int selection; + + switch ( message ) + { + case WM_CREATE: + return 0L; + + case WM_DESTROY: + Bindings_SaveConfig(); + Bindings_UpdateMenu(); + + g_bindings_hWnd = NULL; + return 0L; + + case WM_SIZE: + Bindings_SizeWindow( hwnd, LOWORD( lParam ), HIWORD( lParam ) ); + return 0L; + + case WM_NOTIFY: + switch ( ( ( LPNMHDR )lParam )->code ) + { + case LVN_GETDISPINFO: + NMLVDISPINFO* plvdi; + plvdi = ( NMLVDISPINFO* )lParam; + pBind = ( bind_t* )plvdi->item.lParam; + switch ( plvdi->item.iSubItem ) + { + case ID_BIND_KEYCODE: + plvdi->item.pszText = ( LPSTR )pBind->pKeyString; + return 0L; + + case ID_BIND_MENUNAME: + plvdi->item.pszText = pBind->pMenuName; + return 0L; + + case ID_BIND_COMMAND: + plvdi->item.pszText = pBind->pCommandString; + return 0L; + + default: + break; + } + break; + + case NM_DBLCLK: + NMITEMACTIVATE *pnmitem; + pnmitem = ( LPNMITEMACTIVATE )lParam; + BindingsModifyDlg_Open( pnmitem->iItem ); + break; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_BINDOPTIONS_MODIFY: + selection = Bindings_GetSelectedItem(); + if ( selection >= 0 ) + BindingsModifyDlg_Open( selection ); + return 0L; + + case IDM_BINDOPTIONS_DELETE: + selection = Bindings_GetSelectedItem(); + if ( selection >= 0 ) + { + Bindings_ModifyEntry( selection, "", "" ); + ListView_RedrawItems( g_bindings_hWndListView, 0, MAX_BINDINGS-1 ); + UpdateWindow( g_bindings_hWndListView ); + Bindings_UpdateMenu(); + } + return 0L; + } + break; + } + + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// Bindings_Open +// +//----------------------------------------------------------------------------- +void Bindings_Open() +{ + RECT clientRect; + HWND hWnd; + int i; + LVITEM lvi; + + if ( g_bindings_hWnd ) + { + // only one instance + if ( IsIconic( g_bindings_hWnd ) ) + ShowWindow( g_bindings_hWnd, SW_RESTORE ); + SetForegroundWindow( g_bindings_hWnd ); + return; + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "BINDINGSCLASS", + "Edit Bindings", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 600, + 300, + g_hDlgMain, + NULL, + g_hInstance, + NULL ); + g_bindings_hWnd = hWnd; + + GetClientRect( g_bindings_hWnd, &clientRect ); + hWnd = CreateWindow( + WC_LISTVIEW, + "", + WS_VISIBLE|WS_CHILD|LVS_REPORT|LVS_SHOWSELALWAYS|LVS_SINGLESEL|LVS_NOSORTHEADER, + 0, + 0, + clientRect.right-clientRect.left, + clientRect.bottom-clientRect.top, + g_bindings_hWnd, + ( HMENU )ID_BINDINGS_LISTVIEW, + g_hInstance, + NULL ); + g_bindings_hWndListView = hWnd; + + // init list view columns + for ( i=0; i<sizeof( g_bindings_labels )/sizeof( g_bindings_labels[0] ); i++ ) + { + LVCOLUMN lvc; + memset( &lvc, 0, sizeof( lvc ) ); + + lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; + lvc.iSubItem = 0; + lvc.cx = g_bindings_labels[i].width; + lvc.fmt = LVCFMT_LEFT; + lvc.pszText = ( LPSTR )g_bindings_labels[i].name; + + ListView_InsertColumn( g_bindings_hWndListView, i, &lvc ); + } + + ListView_SetBkColor( g_bindings_hWndListView, g_backgroundColor ); + ListView_SetTextBkColor( g_bindings_hWndListView, g_backgroundColor ); + + DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP; + ListView_SetExtendedListViewStyleEx( g_bindings_hWndListView, style, style ); + + // populate list view + for ( i=0; i<MAX_BINDINGS; i++ ) + { + int itemCount = ListView_GetItemCount( g_bindings_hWndListView ); + + // setup and insert at end of list + memset( &lvi, 0, sizeof( lvi ) ); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = itemCount; + lvi.iSubItem = 0; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; + lvi.lParam = ( LPARAM )&g_bindings[i]; + + ListView_InsertItem( g_bindings_hWndListView, &lvi ); + } + + // set the first item selected + ListView_SetItemState( g_bindings_hWndListView, 0, LVIS_SELECTED, LVIS_SELECTED ); + SetFocus( g_bindings_hWndListView ); + + if ( g_bindings_windowRect.right && g_bindings_windowRect.bottom ) + MoveWindow( g_bindings_hWnd, g_bindings_windowRect.left, g_bindings_windowRect.top, g_bindings_windowRect.right-g_bindings_windowRect.left, g_bindings_windowRect.bottom-g_bindings_windowRect.top, FALSE ); + ShowWindow( g_bindings_hWnd, SHOW_OPENWINDOW ); +} + +//----------------------------------------------------------------------------- +// Bindings_Init +// +//----------------------------------------------------------------------------- +bool Bindings_Init() +{ + // set up our window class + WNDCLASS wndclass; + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = Bindings_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_BINDOPTIONS ); + wndclass.lpszClassName = "BINDINGSCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + Bindings_LoadConfig(); + Bindings_UpdateMenu(); + + return true; +}
\ No newline at end of file diff --git a/utils/xbox/vxconsole/bug.cpp b/utils/xbox/vxconsole/bug.cpp new file mode 100644 index 0000000..1d288eb --- /dev/null +++ b/utils/xbox/vxconsole/bug.cpp @@ -0,0 +1,1576 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// BUG.CPP +// +// Tracker bridge +//=====================================================================================// +#include "vxconsole.h" + +// two bug systems, certain games are tied to a specific system +#define BUG_REPORTER_DLLNAME_1 "bugreporter.dll" +#define BUG_REPORTER_DLLNAME_2 "bugreporter_filequeue.dll" + +#define BUG_REPOSITORY_URL "\\\\fileserver\\bugs" +#define REPOSITORY_VALIDATION_FILE "info.txt" +#define BUG_ERRORTITLE "Bug Error" +#define BUG_COLOR ( RGB( 0,255,255 ) ) + +HWND g_bug_hWnd; +HMODULE g_bug_hBugReporter1; +HMODULE g_bug_hBugReporter2; +IBugReporter *g_bug_pReporter1; +IBugReporter *g_bug_pReporter2; +IBugReporter *g_bug_pReporter; +char g_bug_szTitle[512]; +char g_bug_szDescription[1024]; +char g_bug_szOwner[128]; +char g_bug_szSeverity[128]; +char g_bug_szReportType[128]; +char g_bug_szPriority[128]; +char g_bug_szArea[128]; +char g_bug_szMapNumber[128]; +int g_bug_GameType; +bool g_bug_bActive; +char g_bug_szScreenshot[MAX_PATH]; +char g_bug_szSavegame[MAX_PATH]; +char g_bug_szBSPName[MAX_PATH]; +xrMapInfo_t g_bug_mapInfo; +bool g_bug_bCompressScreenshot; +bool g_bug_bFirstCommand; + +struct GameSystem_t +{ + const char *pFriendlyName; + const char *pGameName; + bool bUsesSystem1; +}; + +GameSystem_t g_Games[] = +{ + { "Half Life 2", "hl2", true }, + { "Episode 1", "episodic", true }, + { "Episode 2", "ep2", true }, + { "Portal", "portal", false }, + { "Team Fortress 2", "tf", false }, +}; + +static const char *GetRepositoryURL( void ) +{ + const char *pURL = g_bug_pReporter->GetRepositoryURL(); + if ( pURL ) + { + return pURL; + } + + return BUG_REPOSITORY_URL; +} + +const char *GetSubmissionURL( int bugid ) +{ + const char *pURL = g_bug_pReporter->GetSubmissionURL(); + if ( pURL ) + { + return pURL; + } + + static char url[MAX_PATH]; + Q_snprintf( url, sizeof(url), "%s/%i", GetRepositoryURL(), bugid ); + + return url; +} + +//----------------------------------------------------------------------------- +// BugReporter_SelectReporter +// +//----------------------------------------------------------------------------- +bool BugReporter_SelectReporter( const char *pGameName ) +{ + int system = -1; + for ( int i = 0; i < ARRAYSIZE( g_Games ); i++ ) + { + if ( pGameName && !V_stricmp( g_Games[i].pGameName, pGameName ) ) + { + system = i; + break; + } + } + + if ( system == -1 ) + { + // not found, slam to first + system = 0; + } + + // games uses different systems + int oldGameType = g_bug_GameType; + g_bug_GameType = system; + if ( g_Games[system].bUsesSystem1 ) + { + g_bug_pReporter = g_bug_pReporter1; + } + else + { + g_bug_pReporter = g_bug_pReporter2; + } + + // force the game area + if ( g_Games[g_bug_GameType].bUsesSystem1 ) + { + strcpy( g_bug_szArea, "XBOX 360" ); + } + else + { + strcpy( g_bug_szArea, g_Games[g_bug_GameType].pFriendlyName ); + } + + bool bChanged = ( oldGameType != g_bug_GameType ); + return bChanged; +} + +//----------------------------------------------------------------------------- +// BugReporter_LoadDLL +// +//----------------------------------------------------------------------------- +IBugReporter *BugReporter_LoadDLL( const char *pDLLName, HMODULE *phModule ) +{ + HMODULE hModule; + IBugReporter *pBugReporter; + + *phModule = NULL; + + hModule = LoadLibrary( pDLLName ); + if ( !hModule ) + { + Sys_MessageBox( BUG_ERRORTITLE, "Could not open '%s'\n", pDLLName ); + return NULL; + } + + FARPROC pCreateInterface = GetProcAddress( hModule, CREATEINTERFACE_PROCNAME ); + if ( !pCreateInterface ) + { + Sys_MessageBox( BUG_ERRORTITLE, "Missing '%s' interface for '%s'\n", CREATEINTERFACE_PROCNAME, pDLLName ); + return NULL; + } + + pBugReporter = (IBugReporter *)((CreateInterfaceFn)pCreateInterface)( INTERFACEVERSION_BUGREPORTER, NULL ); + if ( !pBugReporter ) + { + Sys_MessageBox( BUG_ERRORTITLE, "Missing interface '%s' for '%s'\n", INTERFACEVERSION_BUGREPORTER, pDLLName ); + return NULL; + } + + bool bSuccess = pBugReporter->Init( NULL ); + if ( !bSuccess ) + { + return NULL; + } + + *phModule = hModule; + return pBugReporter; +} + +//----------------------------------------------------------------------------- +// BugReporter_GetInterfaces +// +//----------------------------------------------------------------------------- +bool BugReporter_GetInterfaces() +{ + if ( !g_bug_pReporter1 ) + { + g_bug_pReporter1 = BugReporter_LoadDLL( BUG_REPORTER_DLLNAME_1, &g_bug_hBugReporter1 ); + if ( !g_bug_pReporter1 ) + { + Sys_MessageBox( BUG_ERRORTITLE, "PVCS intialization failed!\n" ); + } + } + + if ( !g_bug_pReporter2 ) + { + g_bug_pReporter2 = BugReporter_LoadDLL( BUG_REPORTER_DLLNAME_2, &g_bug_hBugReporter2 ); + if ( !g_bug_pReporter2 ) + { + Sys_MessageBox( BUG_ERRORTITLE, "BugBait intialization failed!\n" ); + } + } + + if ( g_bug_pReporter1 ) + { + // determine submitter name + ConsoleWindowPrintf( BUG_COLOR, "Bug Reporter: PVCS Username: '%s' Display As: '%s'\n", g_bug_pReporter1->GetUserName(), g_bug_pReporter1->GetUserName_Display() ); + } + if ( g_bug_pReporter2 ) + { + // determine submitter name + ConsoleWindowPrintf( BUG_COLOR, "Bug Reporter: BugBait Username: '%s' Display As: '%s'\n", g_bug_pReporter2->GetUserName(), g_bug_pReporter2->GetUserName_Display() ); + } + + BugReporter_SelectReporter( NULL ); + + // See if we can see the bug repository right now + char fn[MAX_PATH]; + V_snprintf( fn, sizeof( fn ), "%s/%s", GetRepositoryURL(), REPOSITORY_VALIDATION_FILE ); + Sys_NormalizePath( fn, false ); + + FILE *fp = fopen( fn, "rb" ); + if ( fp ) + { + ConsoleWindowPrintf( BUG_COLOR, "PVCS Repository '%s'\n", GetRepositoryURL() ); + fclose( fp ); + } + else + { + Sys_MessageBox( BUG_ERRORTITLE, "Unable to see '%s', check permissions and network connectivity.\n", fn ); + return false; + } + + // success + return true; +} + +//----------------------------------------------------------------------------- +// BugReporter_FreeInterfaces +// +//----------------------------------------------------------------------------- +void BugReporter_FreeInterfaces() +{ + if ( g_bug_pReporter1 ) + { + g_bug_pReporter1->Shutdown(); + g_bug_pReporter1 = NULL; + FreeLibrary( g_bug_hBugReporter1 ); + g_bug_hBugReporter1 = NULL; + } + + if ( g_bug_pReporter2 ) + { + g_bug_pReporter2->Shutdown(); + g_bug_pReporter2 = NULL; + FreeLibrary( g_bug_hBugReporter2 ); + g_bug_hBugReporter2 = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Expanded data destination object for CUtlBuffer output +//----------------------------------------------------------------------------- +struct JPEGDestinationManager_t +{ + struct jpeg_destination_mgr pub; // public fields + + CUtlBuffer *pBuffer; // target/final buffer + byte *buffer; // start of temp buffer +}; + +// choose an efficiently bufferaable size +#define OUTPUT_BUF_SIZE 4096 + +//----------------------------------------------------------------------------- +// Purpose: Initialize destination --- called by jpeg_start_compress +// before any data is actually written. +//----------------------------------------------------------------------------- +void init_destination( j_compress_ptr cinfo ) +{ + JPEGDestinationManager_t *dest = ( JPEGDestinationManager_t *) cinfo->dest; + + // Allocate the output buffer --- it will be released when done with image + dest->buffer = (byte *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * sizeof(byte)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +//----------------------------------------------------------------------------- +// Purpose: Empty the output buffer --- called whenever buffer fills up. +// Input : boolean - +//----------------------------------------------------------------------------- +boolean empty_output_buffer( j_compress_ptr cinfo ) +{ + JPEGDestinationManager_t *dest = ( JPEGDestinationManager_t * ) cinfo->dest; + + CUtlBuffer *buf = dest->pBuffer; + + // Add some data + buf->Put( dest->buffer, OUTPUT_BUF_SIZE ); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + + return TRUE; +} + +//----------------------------------------------------------------------------- +// Purpose: Terminate destination --- called by jpeg_finish_compress +// after all data has been written. Usually needs to flush buffer. +// +// NB: *not* called by jpeg_abort or jpeg_destroy; surrounding +// application must deal with any cleanup that should happen even +// for error exit. +//----------------------------------------------------------------------------- +void term_destination( j_compress_ptr cinfo ) +{ + JPEGDestinationManager_t *dest = (JPEGDestinationManager_t *) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + + CUtlBuffer *buf = dest->pBuffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) + { + buf->Put( dest->buffer, datacount ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Set up functions for writing data to a CUtlBuffer instead of FILE * +//----------------------------------------------------------------------------- +void jpeg_UtlBuffer_dest( j_compress_ptr cinfo, CUtlBuffer *pBuffer ) +{ + JPEGDestinationManager_t *dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_stdio_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(JPEGDestinationManager_t)); + } + + dest = ( JPEGDestinationManager_t * ) cinfo->dest; + + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->pBuffer = pBuffer; +} + +//----------------------------------------------------------------------------- +// BugDlg_CompressScreenshot +// +// Compress .BMP to .JPG, Delete .BMP +//----------------------------------------------------------------------------- +bool BugDlg_CompressScreenshot() +{ + if ( !g_bug_szScreenshot[0] ) + { + return false; + } + + bool bSuccess = false; + HBITMAP hBitmap = NULL; + HDC hDC = NULL; + char *pBMPBits = NULL; + + CUtlBuffer buf( 0, 0 ); + + hBitmap = (HBITMAP)LoadImage( NULL, g_bug_szScreenshot, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE ); + if ( !hBitmap ) + goto cleanUp; + + hDC = CreateCompatibleDC( NULL ); + if ( !hDC ) + goto cleanUp; + + BITMAPINFO bitmapInfo; + ZeroMemory( &bitmapInfo, sizeof( BITMAPINFO ) ); + bitmapInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); + + // populate the bmp info + if ( !GetDIBits( hDC, hBitmap, 0, 0, NULL, &bitmapInfo, DIB_RGB_COLORS ) ) + goto cleanUp; + + pBMPBits = (char *)Sys_Alloc( bitmapInfo.bmiHeader.biSizeImage ); + if ( !pBMPBits ) + goto cleanUp; + + // could be bottom-up or top-down + int nHeight = abs( bitmapInfo.bmiHeader.biHeight ); + + if ( bitmapInfo.bmiHeader.biBitCount != 32 ) + { + // unexpected format + goto cleanUp; + } + + if ( bitmapInfo.bmiHeader.biCompression != BI_RGB && bitmapInfo.bmiHeader.biCompression != BI_BITFIELDS ) + { + // unexpected format + goto cleanUp; + } + + // don't want color masks + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + // get the raw bits + if ( !GetDIBits( hDC, hBitmap, 0, nHeight, pBMPBits, &bitmapInfo, DIB_RGB_COLORS ) ) + goto cleanUp; + + JSAMPROW row_pointer[1]; + + // compression data structure + struct jpeg_compress_struct cinfo; + ZeroMemory( &cinfo, sizeof( jpeg_compress_struct ) ); + + // point at stderr + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error( &jerr ); + + // create compressor + jpeg_create_compress( &cinfo ); + + // Hook CUtlBuffer to compression + jpeg_UtlBuffer_dest( &cinfo, &buf ); + + // image width and height, in pixels + cinfo.image_width = bitmapInfo.bmiHeader.biWidth; + cinfo.image_height = nHeight; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + // Apply settings + jpeg_set_defaults( &cinfo ); + jpeg_set_quality( &cinfo, 50, TRUE ); + + // Start compressor + jpeg_start_compress( &cinfo, TRUE); + + char *pRowBuffer = (char*)_alloca( bitmapInfo.bmiHeader.biWidth * 3 ); + row_pointer[0] = (JSAMPROW)pRowBuffer; + + // Write scanlines + while ( cinfo.next_scanline < cinfo.image_height ) + { + char *pSrc; + if ( bitmapInfo.bmiHeader.biHeight < 0 ) + { + // top down + pSrc = &pBMPBits[cinfo.next_scanline * bitmapInfo.bmiHeader.biWidth * 4]; + } + else + { + // bottom up + pSrc = &pBMPBits[(nHeight-1 - cinfo.next_scanline) * bitmapInfo.bmiHeader.biWidth * 4]; + } + + // convert to BGR to RGB + char *pDst = pRowBuffer; + for ( int i=0; i<bitmapInfo.bmiHeader.biWidth; i++ ) + { + pDst[0] = pSrc[2]; + pDst[1] = pSrc[1]; + pDst[2] = pSrc[0]; + pSrc += 4; + pDst += 3; + } + jpeg_write_scanlines( &cinfo, row_pointer, 1 ); + } + + // Finalize image + jpeg_finish_compress( &cinfo ); + + char jpgFilename[MAX_PATH]; + Sys_StripExtension( g_bug_szScreenshot, jpgFilename, sizeof( jpgFilename ) ); + Sys_AddExtension( ".jpg", jpgFilename, sizeof( jpgFilename ) ); + if ( !Sys_SaveFile( jpgFilename, buf.Base(), buf.TellMaxPut() ) ) + goto cleanUp; + + // remove the uncompressed version + unlink( g_bug_szScreenshot ); + strcpy( g_bug_szScreenshot, jpgFilename ); + + bSuccess = true; + +cleanUp: + if ( hBitmap ) + DeleteObject( hBitmap ); + if ( hDC ) + DeleteDC( hDC ); + if ( pBMPBits ) + Sys_Free( pBMPBits ); + + return bSuccess; +} + + +//----------------------------------------------------------------------------- +// BugDlg_GetAppData +// +//----------------------------------------------------------------------------- +void BugDlg_GetAppData( HWND hWnd ) +{ + // clear stale data from previous query + memset( &g_bug_mapInfo, 0, sizeof( g_bug_mapInfo ) ); + + SetDlgItemText( hWnd, IDC_BUG_POSITION_LABEL, "" ); + SetDlgItemText( hWnd, IDC_BUG_ORIENTATION_LABEL, "" ); + SetDlgItemText( hWnd, IDC_BUG_MAP_LABEL, "" ); + SetDlgItemText( hWnd, IDC_BUG_BUILD_LABEL, "" ); + + EnableWindow( GetDlgItem( hWnd, IDC_BUG_SAVEGAME ), false ); + EnableWindow( GetDlgItem( hWnd, IDC_BUG_INCLUDEBSP ), false ); + + if ( g_connectedToApp ) + { + // send to app, responds with position info + if ( !g_bug_bFirstCommand ) + { + // first command must send pause and status to be processed correctly + g_bug_bFirstCommand = true; + ProcessCommand( "pause ; status" ); + } + else + { + ProcessCommand( "status" ); + } + } +} + +//----------------------------------------------------------------------------- +// BugDlg_GetDataFileBase +// +//----------------------------------------------------------------------------- +void BugDlg_GetDataFileBase( char const *suffix, bool bLocalPath, char *buf, int bufsize ) +{ + char filepath[MAX_PATH]; + char filename[MAX_PATH]; + + struct tm t; + + time_t ltime; + time( <ime ); + tm *pTime = localtime( <ime ); + memcpy( &t, pTime, sizeof( t ) ); + + char who[128]; + strncpy( who, suffix, sizeof( who ) ); + _strlwr( who ); + + if ( bLocalPath ) + { + // add a qualified local path + // used as a gathering store before uploading to server + strcpy( filepath, g_localPath ); + Sys_AddFileSeperator( filepath, sizeof( filepath ) ); + strcat( filepath, "bug/" ); + Sys_NormalizePath( filepath, false ); + Sys_CreatePath( filepath ); + } + else + { + filepath[0] = '\0'; + } + + sprintf( filename, "%i_%02i_%02i_%s", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, who ); + V_snprintf( buf, bufsize, "%s%s", filepath, filename ); +} + +//----------------------------------------------------------------------------- +// BugDlg_CheckSubmit +// +//----------------------------------------------------------------------------- +bool BugDlg_CheckSubmit( HWND hWnd ) +{ + bool bEnableSubmit = false; + + if ( g_Games[g_bug_GameType].bUsesSystem1 ) + { + if ( g_bug_szTitle[0] && + g_bug_szDescription[0] && + g_bug_szSeverity[0] && + g_bug_szOwner[0] && + g_bug_szReportType[0] && + g_bug_szPriority[0] && + g_bug_szArea[0] ) + { + bEnableSubmit = true; + } + } + else + { + if ( g_bug_szTitle[0] && + g_bug_szDescription[0] && + g_bug_szSeverity[0] && + g_bug_szOwner[0] && + g_bug_szArea[0] && + g_bug_szMapNumber[0] ) + { + bEnableSubmit = true; + } + } + + EnableWindow( GetDlgItem( hWnd, IDC_BUG_SUBMIT ), bEnableSubmit ); + + return bEnableSubmit; +} + +//----------------------------------------------------------------------------- +// BugDlg_GetChanges +// +//----------------------------------------------------------------------------- +bool BugDlg_GetChanges( HWND hWnd ) +{ + int curSel; + + // title + GetDlgItemText( hWnd, IDC_BUG_TITLE, g_bug_szTitle, sizeof( g_bug_szTitle ) ); + + // description + GetDlgItemText( hWnd, IDC_BUG_DESCRIPTION, g_bug_szDescription, sizeof( g_bug_szDescription ) ); + + // owner + curSel = SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_GETCURSEL, 0, 0 ); + if ( curSel == CB_ERR ) + { + g_bug_szOwner[0] = '\0'; + } + else + { + strncpy( g_bug_szOwner, g_bug_pReporter->GetDisplayName( curSel ), sizeof( g_bug_szOwner ) ); + g_bug_szOwner[sizeof( g_bug_szOwner )-1] = '\0'; + + if ( V_stristr( g_bug_szOwner, "unassigned" ) ) + { + g_bug_szOwner[0] = '\0'; + } + } + + // severity + curSel = SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_GETCURSEL, 0, 0 ); + if ( curSel == CB_ERR ) + { + g_bug_szSeverity[0] = '\0'; + } + else + { + V_strncpy( g_bug_szSeverity, g_bug_pReporter->GetSeverity( curSel ), sizeof( g_bug_szSeverity ) ); + } + + // report type + curSel = SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_GETCURSEL, 0, 0 ); + if ( curSel == CB_ERR ) + { + g_bug_szReportType[0] = '\0'; + } + else + { + V_strncpy( g_bug_szReportType, g_bug_pReporter->GetReportType( curSel ), sizeof( g_bug_szReportType ) ); + } + + // priority + curSel = SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_GETCURSEL, 0, 0 ); + if ( curSel == CB_ERR ) + { + g_bug_szPriority[0] = '\0'; + } + else + { + V_strncpy( g_bug_szPriority, g_bug_pReporter->GetPriority( curSel ), sizeof( g_bug_szPriority ) ); + } + + // area + curSel = SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_GETCURSEL, 0, 0 ); + int areaIndex = 0; + if ( curSel == CB_ERR ) + { + g_bug_szArea[0] = '\0'; + } + else + { + V_strncpy( g_bug_szArea, g_bug_pReporter->GetArea( curSel ), sizeof( g_bug_szArea ) ); + areaIndex = curSel; + } + + if ( !g_Games[g_bug_GameType].bUsesSystem1 ) + { + // map number + curSel = SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_GETCURSEL, 0, 0 ); + if ( curSel == CB_ERR ) + { + g_bug_szMapNumber[0] = '\0'; + } + else + { + V_strncpy( g_bug_szMapNumber, g_bug_pReporter->GetLevel( areaIndex, curSel ), sizeof( g_bug_szMapNumber ) ); + } + } + + g_bug_bCompressScreenshot = ( IsDlgButtonChecked( hWnd, IDC_BUG_COMPRESS_SCREENSHOT ) != 0 ); + + BugDlg_CheckSubmit( hWnd ); + + // success + return true; +} + +//----------------------------------------------------------------------------- +// BugDlg_UpdateReporter +// +//----------------------------------------------------------------------------- +bool BugDlg_UpdateReporter( HWND hWnd ) +{ + // game + int newGameType; + int curSel = SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_GETCURSEL, 0, 0 ); + if ( curSel == CB_ERR ) + { + newGameType = 0; + } + else + { + newGameType = curSel; + } + + return BugReporter_SelectReporter( g_Games[newGameType].pGameName ); +} + +//----------------------------------------------------------------------------- +// BugDlg_Populate +// +//----------------------------------------------------------------------------- +void BugDlg_Populate( HWND hWnd ) +{ + int i; + int count; + int curSel; + + g_bug_bActive = false; + + // title + SendDlgItemMessage( hWnd, IDC_BUG_TITLE, EM_LIMITTEXT, sizeof( g_bug_szTitle )-1, 0 ); + SetDlgItemText( hWnd, IDC_BUG_TITLE, g_bug_szTitle ); + + // description + SendDlgItemMessage( hWnd, IDC_BUG_DESCRIPTION, EM_LIMITTEXT, sizeof( g_bug_szDescription )-1, 0 ); + SetDlgItemText( hWnd, IDC_BUG_DESCRIPTION, g_bug_szDescription ); + + // submitter + SetDlgItemText( hWnd, IDC_BUG_SUBMITTER_LABEL, g_bug_pReporter->GetUserName_Display() ); + + // owner + SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_RESETCONTENT, 0, 0 ); + count = g_bug_pReporter->GetDisplayNameCount(); + for ( i = 0; i < count; i++ ) + { + SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetDisplayName( i ) ); + } + if ( count ) + { + curSel = SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szOwner ); + if ( curSel != CB_ERR ) + { + SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_SETCURSEL, curSel, 0 ); + } + } + + // severity + SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_RESETCONTENT, 0, 0 ); + count = g_bug_pReporter->GetSeverityCount(); + for ( i = 0; i < count; i++ ) + { + SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetSeverity( i ) ); + } + if ( count ) + { + curSel = SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szSeverity ); + if ( curSel != CB_ERR ) + { + SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_SETCURSEL, curSel, 0 ); + } + } + + // report type + SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_RESETCONTENT, 0, 0 ); + EnableWindow( GetDlgItem( hWnd, IDC_BUG_REPORTTYPE ), g_Games[g_bug_GameType].bUsesSystem1 ); + if ( g_Games[g_bug_GameType].bUsesSystem1 ) + { + count = g_bug_pReporter->GetReportTypeCount(); + for ( i = 0; i < count; i++ ) + { + SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetReportType( i ) ); + } + if ( count ) + { + curSel = SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szReportType ); + if ( curSel != CB_ERR ) + { + SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_SETCURSEL, curSel, 0 ); + } + } + } + + // priority + SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_RESETCONTENT, 0, 0 ); + EnableWindow( GetDlgItem( hWnd, IDC_BUG_PRIORITY ), g_Games[g_bug_GameType].bUsesSystem1 ); + if ( g_Games[g_bug_GameType].bUsesSystem1 ) + { + count = g_bug_pReporter->GetPriorityCount(); + for ( i = 0; i < count; i++ ) + { + SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetPriority( i ) ); + } + if ( count ) + { + curSel = SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szPriority ); + if ( curSel != CB_ERR ) + { + SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_SETCURSEL, curSel, 0 ); + } + } + } + + // area + SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_RESETCONTENT, 0, 0 ); + count = g_bug_pReporter->GetAreaCount(); + int areaIndex = 0; + for ( i = 0; i < count; i++ ) + { + SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetArea( i ) ); + } + if ( count ) + { + curSel = SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szArea ); + if ( curSel != CB_ERR ) + { + SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_SETCURSEL, curSel, 0 ); + areaIndex = curSel; + } + } + + // map name or number + SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_RESETCONTENT, 0, 0 ); + EnableWindow( GetDlgItem( hWnd, IDC_BUG_MAPNUMBER ), g_Games[g_bug_GameType].bUsesSystem1 == false ); + if ( !g_Games[g_bug_GameType].bUsesSystem1 ) + { + // new system has map names + count = g_bug_pReporter->GetLevelCount( areaIndex ); + for ( i = 0; i < count; i++ ) + { + SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetLevel( areaIndex, i ) ); + } + } + if ( count ) + { + curSel = SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szMapNumber ); + if ( curSel != CB_ERR ) + { + SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_SETCURSEL, curSel, 0 ); + } + } + + // game + SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_RESETCONTENT, 0, 0 ); + count = ARRAYSIZE( g_Games ); + for ( i = 0; i < count; i++ ) + { + SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_Games[i].pFriendlyName ); + } + if ( count ) + { + curSel = SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_Games[g_bug_GameType].pFriendlyName ); + if ( curSel != CB_ERR ) + { + SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_SETCURSEL, curSel, 0 ); + } + } + + CheckDlgButton( hWnd, IDC_BUG_COMPRESS_SCREENSHOT, g_bug_bCompressScreenshot ? BST_CHECKED : BST_UNCHECKED ); + + SetDlgItemText( hWnd, IDC_BUG_TAKESHOT_LABEL, g_bug_szScreenshot ); + SetDlgItemText( hWnd, IDC_BUG_SAVEGAME_LABEL, g_bug_szSavegame ); + SetDlgItemText( hWnd, IDC_BUG_INCLUDEBSP_LABEL, g_bug_szBSPName ); + SetDlgItemText( hWnd, IDC_BUG_INCLUDEVMF_LABEL, "" ); + + EnableWindow( GetDlgItem( hWnd, IDC_BUG_TAKESHOT ), g_connectedToApp ); + EnableWindow( GetDlgItem( hWnd, IDC_BUG_INCLUDEVMF ), false ); + EnableWindow( GetDlgItem( hWnd, IDC_BUG_UPDATE ), g_connectedToApp ); + + BugDlg_GetAppData( hWnd ); + + BugDlg_CheckSubmit( hWnd ); + + g_bug_bActive = true; +} + +//----------------------------------------------------------------------------- +// BugDlg_TakeScreenshot +// +//----------------------------------------------------------------------------- +void BugDlg_TakeScreenshot( HWND hWnd ) +{ + char buff[1024]; + + SetDlgItemText( hWnd, IDC_BUG_TAKESHOT_LABEL, "Working..." ); + + BugDlg_GetDataFileBase( g_bug_pReporter->GetUserName(), true, g_bug_szScreenshot, sizeof( g_bug_szScreenshot ) ); + strcat( g_bug_szScreenshot, ".bmp" ); + + // remove local version + unlink( g_bug_szScreenshot ); + + sprintf( buff, "*screenshot \"%s\"", g_bug_szScreenshot ); + if ( !ProcessCommand( buff ) ) + { + g_bug_szScreenshot[0] = '\0'; + } + + SetDlgItemText( hWnd, IDC_BUG_TAKESHOT_LABEL, g_bug_szScreenshot ); +} + +//----------------------------------------------------------------------------- +// BugDlg_SaveGame +// +//----------------------------------------------------------------------------- +void BugDlg_SaveGame( HWND hWnd ) +{ + char buff[1024]; + char savename[MAX_PATH]; + char remoteFile[MAX_PATH]; + + if ( !g_bug_mapInfo.savePath[0] ) + { + return; + } + + SetDlgItemText( hWnd, IDC_BUG_SAVEGAME_LABEL, "Working..." ); + + BugDlg_GetDataFileBase( g_bug_pReporter->GetUserName(), true, g_bug_szSavegame, sizeof( g_bug_szSavegame ) ); + Sys_StripPath( g_bug_szSavegame, savename, sizeof( savename ) ); + strcat( g_bug_szSavegame, ".360.sav" ); + + sprintf( remoteFile, "%s\\%s.360.sav", g_bug_mapInfo.savePath, savename ); + + // delete file locally + unlink( g_bug_szSavegame ); + + // delete file remotely + DmDeleteFile( remoteFile, false ); + + // save, and wait to ensure async completes + sprintf( buff, "save \"%s\" notmostrecent wait", savename ); + if ( !ProcessCommand( buff ) ) + { + // failed + g_bug_szSavegame[0] = '\0'; + } + else + { + DM_FILE_ATTRIBUTES fileAttributes; + for (int i=0; i<5; i++) + { + // wait for the save file to appear + HRESULT hr = DmGetFileAttributes( remoteFile, &fileAttributes ); + if ( hr == XBDM_NOERR ) + break; + + // wait for it + Sleep( 1000 ); + } + + HRESULT hr = DmReceiveFile( g_bug_szSavegame, remoteFile ); + if ( hr != XBDM_NOERR ) + { + // failed + g_bug_szSavegame[0] = '\0'; + } + } + + SetDlgItemText( hWnd, IDC_BUG_SAVEGAME_LABEL, g_bug_szSavegame ); +} + +//----------------------------------------------------------------------------- +// BugDlg_IncludeBSP +// +//----------------------------------------------------------------------------- +void BugDlg_IncludeBSP( HWND hWnd ) +{ + if ( !g_bug_mapInfo.mapPath[0] ) + { + return; + } + + SetDlgItemText( hWnd, IDC_BUG_INCLUDEBSP_LABEL, "Working..." ); + + BugDlg_GetDataFileBase( g_bug_pReporter->GetUserName(), true, g_bug_szBSPName, sizeof( g_bug_szBSPName ) ); + strcat( g_bug_szBSPName, ".360.bsp" ); + + // remove local version + unlink( g_bug_szBSPName ); + + // get the file locally + HRESULT hr = DmReceiveFile( g_bug_szBSPName, g_bug_mapInfo.mapPath ); + if ( hr != XBDM_NOERR ) + { + // failed + g_bug_szBSPName[0] = '\0'; + } + + SetDlgItemText( hWnd, IDC_BUG_INCLUDEBSP_LABEL, g_bug_szBSPName ); +} + +//----------------------------------------------------------------------------- +// BugDlg_ResetAndPopulate +// +//----------------------------------------------------------------------------- +void BugDlg_ResetAndPopulate( HWND hWnd, bool bFullReset = true ) +{ + // reset all fields + if ( bFullReset ) + { + g_bug_szTitle[0] = '\0'; + g_bug_szDescription[0] = '\0'; + } + g_bug_szOwner[0] = '\0'; + g_bug_szSeverity[0] = '\0'; + g_bug_szReportType[0] = '\0'; + g_bug_szPriority[0] = '\0'; + g_bug_szMapNumber[0] = '\0'; + + if ( bFullReset ) + { + g_bug_szScreenshot[0] = '\0'; + g_bug_szSavegame[0] = '\0'; + g_bug_szBSPName[0] = '\0'; + } + + g_bug_bCompressScreenshot = true; + + memset( &g_bug_mapInfo, 0, sizeof( g_bug_mapInfo ) ); + + // populate with reset fields + BugDlg_Populate( hWnd ); +} + +//----------------------------------------------------------------------------- +// BugDlg_Setup +// +//----------------------------------------------------------------------------- +void BugDlg_Setup( HWND hWnd ) +{ + g_bug_hWnd = hWnd; + + // clear stale data from app + g_bug_bFirstCommand = false; + memset( &g_bug_mapInfo, 0, sizeof( g_bug_mapInfo ) ); + + // always reset these fields + g_bug_szTitle[0] = '\0'; + g_bug_szDescription[0] = '\0'; + g_bug_szScreenshot[0] = '\0'; + g_bug_szSavegame[0] = '\0'; + g_bug_szBSPName[0] = '\0'; + + g_bug_bCompressScreenshot = true; + + memset( &g_bug_mapInfo, 0, sizeof( g_bug_mapInfo ) ); + + BugDlg_Populate( hWnd ); +} + +//----------------------------------------------------------------------------- +// BugDlg_UploadFile +// +//----------------------------------------------------------------------------- +bool BugDlg_UploadFile( char const *pLocalName, char const *pRemoteName, bool bDeleteLocal ) +{ + FILE *fp; + int len; + void *pLocalData; + + ConsoleWindowPrintf( BUG_COLOR, "Uploading %s to %s\n", pLocalName, pRemoteName ); + + len = Sys_LoadFile( pLocalName, &pLocalData ); + if ( !pLocalData || !len ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "UploadFile: Unable to open local path '%s'\n", pLocalName ); + return false; + } + + Sys_CreatePath( pRemoteName ); + + fp = fopen( pRemoteName, "wb" ); + if ( !fp ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "UploadFile: Unable to open remote path '%s'\n", pRemoteName ); + Sys_Free( pLocalData ); + return false; + } + + fwrite( pLocalData, len, 1, fp ); + + fclose( fp ); + Sys_Free( pLocalData ); + + if ( bDeleteLocal ) + { + unlink( pLocalName ); + } + + return true; +} + +//----------------------------------------------------------------------------- +// BugDlg_UploadBugSubmission +// +// Expects fully qualified source paths +//----------------------------------------------------------------------------- +bool BugDlg_UploadBugSubmission( int bugID, char const *pSavefile, char const *pScreenshot, char const *pBspFile, char const *pVmfFile ) +{ + char szFilename[MAX_PATH]; + char szLocalfile[MAX_PATH]; + char szRemotefile[MAX_PATH]; + bool bSuccess = true; + + if ( pSavefile && pSavefile[0] ) + { + V_snprintf( szLocalfile, sizeof( szLocalfile ), "%s", pSavefile ); + Sys_StripPath( pSavefile, szFilename, sizeof( szFilename ) ); + V_snprintf( szRemotefile, sizeof( szRemotefile ), "%s/%s", GetSubmissionURL( bugID ), szFilename ); + Sys_NormalizePath( szLocalfile, false ); + Sys_NormalizePath( szRemotefile, false ); + + if ( !BugDlg_UploadFile( szLocalfile, szRemotefile, false ) ) + { + bSuccess = false; + } + } + + if ( pScreenshot && pScreenshot[0] ) + { + V_snprintf( szLocalfile, sizeof( szLocalfile ), "%s", pScreenshot ); + Sys_StripPath( pScreenshot, szFilename, sizeof( szFilename ) ); + V_snprintf( szRemotefile, sizeof( szRemotefile ), "%s/%s", GetSubmissionURL( bugID ), szFilename ); + Sys_NormalizePath( szLocalfile, false ); + Sys_NormalizePath( szRemotefile, false ); + + if ( !BugDlg_UploadFile( szLocalfile, szRemotefile, true ) ) + { + bSuccess = false; + } + } + + if ( pBspFile && pBspFile[0] ) + { + V_snprintf( szLocalfile, sizeof( szLocalfile ), "%s", pBspFile ); + Sys_StripPath( pBspFile, szFilename, sizeof( szFilename ) ); + V_snprintf( szRemotefile, sizeof( szRemotefile ), "%s/%s", GetSubmissionURL( bugID ), szFilename ); + Sys_NormalizePath( szLocalfile, false ); + Sys_NormalizePath( szRemotefile, false ); + + if ( !BugDlg_UploadFile( szLocalfile, szRemotefile, true ) ) + { + bSuccess = false; + } + } + + return bSuccess; +} + +//----------------------------------------------------------------------------- +// BugDlg_Submit +// +//----------------------------------------------------------------------------- +bool BugDlg_Submit( HWND hWnd ) +{ + char title[1024]; + char miscInfo[1024]; + char basename[MAX_PATH]; + char filename[MAX_PATH]; + char positionName[MAX_PATH]; + char orientationName[MAX_PATH]; + char buildName[MAX_PATH]; + char mapName[MAX_PATH]; + bool bSuccess = false; + + sprintf( positionName, "%f %f %f", g_bug_mapInfo.position[0], g_bug_mapInfo.position[1], g_bug_mapInfo.position[2] ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_POSITION_LABEL, positionName ); + + sprintf( orientationName, "%f %f %f", g_bug_mapInfo.angle[0], g_bug_mapInfo.angle[1], g_bug_mapInfo.angle[2] ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_ORIENTATION_LABEL, orientationName ); + + sprintf( buildName, "%d", g_bug_mapInfo.build ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_BUILD_LABEL, buildName ); + + V_FileBase( g_bug_mapInfo.mapPath, mapName, sizeof( mapName ) ); + char *pExtension = V_stristr( mapName, ".bsp" ); + if ( pExtension ) + { + *pExtension = '\0'; + } + pExtension = V_stristr( mapName, ".360" ); + if ( pExtension ) + { + *pExtension = '\0'; + } + + V_snprintf( miscInfo, sizeof( miscInfo ), "skill %d", g_bug_mapInfo.skill ); + + // Stuff bug data files up to server + g_bug_pReporter->StartNewBugReport(); + + g_bug_pReporter->SetOwner( g_bug_pReporter->GetUserNameForDisplayName( g_bug_szOwner ) ); + g_bug_pReporter->SetSubmitter( NULL ); + + if ( mapName[0] ) + V_snprintf( title, sizeof( title ), "%s: %s", mapName, g_bug_szTitle ); + else + V_snprintf( title, sizeof( title ), "%s", g_bug_szTitle ); + g_bug_pReporter->SetTitle( title ); + + g_bug_pReporter->SetDescription( g_bug_szDescription ); + g_bug_pReporter->SetLevel( mapName ); + g_bug_pReporter->SetPosition( positionName ); + g_bug_pReporter->SetOrientation( orientationName ); + g_bug_pReporter->SetBuildNumber( buildName ); + + g_bug_pReporter->SetSeverity( g_bug_szSeverity ); + g_bug_pReporter->SetPriority( g_bug_szPriority ); + g_bug_pReporter->SetArea( g_bug_szArea ); + g_bug_pReporter->SetMapNumber( g_bug_szMapNumber ); + g_bug_pReporter->SetReportType( g_bug_szReportType ); + g_bug_pReporter->SetMiscInfo( miscInfo ); + + g_bug_pReporter->SetDriverInfo( "" ); + g_bug_pReporter->SetExeName( "" ); + g_bug_pReporter->SetGameDirectory( "" ); + g_bug_pReporter->SetRAM( 0 ); + g_bug_pReporter->SetCPU( 0 ); + g_bug_pReporter->SetProcessor( "" ); + g_bug_pReporter->SetDXVersion( 0, 0, 0, 0 ); + g_bug_pReporter->SetOSVersion( "" ); + g_bug_pReporter->ResetIncludedFiles(); + g_bug_pReporter->SetZipAttachmentName( "" ); + + if ( g_bug_szScreenshot[0] ) + { + if ( g_bug_bCompressScreenshot ) + { + BugDlg_CompressScreenshot(); + } + + // strip the fully qualified path into filename only + Sys_StripPath( g_bug_szScreenshot, basename, sizeof( basename ) ); + V_snprintf( filename, sizeof( filename ), "%s/BugId/%s", GetRepositoryURL(), basename ); + Sys_NormalizePath( filename, false ); + g_bug_pReporter->SetScreenShot( filename ); + } + + if ( g_bug_szSavegame[0] ) + { + // strip the fully qualified path into filename only + Sys_StripPath( g_bug_szSavegame, basename, sizeof( basename ) ); + V_snprintf( filename, sizeof( filename ), "%s/BugId/%s", GetRepositoryURL(), basename ); + Sys_NormalizePath( filename, false ); + g_bug_pReporter->SetSaveGame( filename ); + } + + if ( g_bug_szBSPName[0] ) + { + // strip the fully qualified path into filename only + Sys_StripPath( g_bug_szBSPName, basename, sizeof( basename ) ); + V_snprintf( filename, sizeof( filename ), "%s/BugId/%s", GetRepositoryURL(), basename ); + Sys_NormalizePath( filename, false ); + g_bug_pReporter->SetBSPName( filename ); + } + + int bugID = -1; + + bSuccess = g_bug_pReporter->CommitBugReport( bugID ); + if ( bSuccess ) + { + if ( !BugDlg_UploadBugSubmission( bugID, g_bug_szSavegame, g_bug_szScreenshot, g_bug_szBSPName, NULL ) ) + { + Sys_MessageBox( BUG_ERRORTITLE, "Unable to upload files to bug repository!\n" ); + bSuccess = false; + } + } + else + { + Sys_MessageBox( BUG_ERRORTITLE, "Unable to post bug report to database!\n" ); + } + + if ( bSuccess ) + { + if ( g_Games[g_bug_GameType].bUsesSystem1 ) + { + ConsoleWindowPrintf( BUG_COLOR, "Bug Reporter: PVCS submission succeeded for bug! (%d)\n", bugID ); + } + else + { + ConsoleWindowPrintf( BUG_COLOR, "Bug Reporter: BugBait submission succeeded for bug!\n" ); + } + } + else + { + ConsoleWindowPrintf( XBX_CLR_RED, "Bug Reporter: Submission failed\n" ); + } + + return bSuccess; +} + +//----------------------------------------------------------------------------- +// BugDlg_Proc +// +//----------------------------------------------------------------------------- +BOOL CALLBACK BugDlg_Proc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch ( message ) + { + case WM_INITDIALOG: + BugDlg_Setup( hwnd ); + return ( TRUE ); + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDC_BUG_TAKESHOT: + BugDlg_TakeScreenshot( hwnd ); + break; + + case IDC_BUG_SAVEGAME: + BugDlg_SaveGame( hwnd ); + break; + + case IDC_BUG_INCLUDEBSP: + BugDlg_IncludeBSP( hwnd ); + break; + + case IDC_BUG_INCLUDEVMF: + // not implemented, no reason to + break; + + case IDC_BUG_CLEARFORM: + BugDlg_ResetAndPopulate( hwnd ); + return TRUE; + + case IDC_BUG_UPDATE: + BugDlg_GetAppData( hwnd ); + return TRUE; + + case IDC_BUG_OWNER: + case IDC_BUG_SEVERITY: + case IDC_BUG_REPORTTYPE: + case IDC_BUG_PRIORITY: + case IDC_BUG_AREA: + case IDC_BUG_MAPNUMBER: + if ( g_bug_bActive && HIWORD( wParam ) == CBN_CLOSEUP ) + { + BugDlg_GetChanges( hwnd ); + return TRUE; + } + break; + + case IDC_BUG_GAME: + if ( HIWORD( wParam ) == CBN_CLOSEUP ) + { + if ( BugDlg_UpdateReporter( hwnd ) ) + { + // reporter changed, clear critical parts of form + BugDlg_ResetAndPopulate( hwnd, false ); + } + return TRUE; + } + break; + + case IDC_BUG_TITLE: + case IDC_BUG_DESCRIPTION: + if ( g_bug_bActive && HIWORD( wParam ) == EN_CHANGE ) + { + BugDlg_GetChanges( hwnd ); + return TRUE; + } + break; + + case IDC_BUG_COMPRESS_SCREENSHOT: + BugDlg_GetChanges( hwnd ); + return TRUE; + + case IDC_BUG_SUBMIT: + if ( !BugDlg_Submit( hwnd ) ) + break; + // fall through + case IDCANCEL: + case IDC_CANCEL: + if ( g_connectedToApp && g_bug_bFirstCommand ) + { + ProcessCommand( "unpause" ); + } + EndDialog( hwnd, wParam ); + return ( TRUE ); + } + break; + } + return ( FALSE ); +} + +//----------------------------------------------------------------------------- +// BugDlg_SaveConfig +// +//----------------------------------------------------------------------------- +void BugDlg_SaveConfig() +{ + Sys_SetRegistryString( "bug_owner", g_bug_szOwner ); + Sys_SetRegistryString( "bug_severity", g_bug_szSeverity ); + Sys_SetRegistryString( "bug_reporttype", g_bug_szReportType ); + Sys_SetRegistryString( "bug_priority", g_bug_szPriority ); + Sys_SetRegistryInteger( "bug_gametype", g_bug_GameType ); +} + +//----------------------------------------------------------------------------- +// BugDlg_LoadConfig +// +//----------------------------------------------------------------------------- +void BugDlg_LoadConfig() +{ + // get our config + Sys_GetRegistryString( "bug_owner", g_bug_szOwner, "", sizeof( g_bug_szOwner ) ); + Sys_GetRegistryString( "bug_severity", g_bug_szSeverity, "", sizeof( g_bug_szSeverity ) ); + Sys_GetRegistryString( "bug_reporttype", g_bug_szReportType, "", sizeof( g_bug_szReportType ) ); + Sys_GetRegistryString( "bug_priority", g_bug_szPriority, "", sizeof( g_bug_szPriority ) ); + Sys_GetRegistryInteger( "bug_gametype", 0, g_bug_GameType ); + + // start with expected reporter + BugReporter_SelectReporter( g_Games[g_bug_GameType].pGameName ); +} + +//----------------------------------------------------------------------------- +// BugDlg_Open +// +//----------------------------------------------------------------------------- +void BugDlg_Open( void ) +{ + int result; + + // need access to bug databases via DLLs + if ( !BugReporter_GetInterfaces() ) + { + return; + } + + BugDlg_LoadConfig(); + + result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_BUG ), g_hDlgMain, ( DLGPROC )BugDlg_Proc ); + if ( LOWORD( result ) == IDC_BUG_SUBMIT ) + { + BugDlg_SaveConfig(); + } + + g_bug_hWnd = NULL; +} + +//----------------------------------------------------------------------------- +// BugDlg_Init +// +//----------------------------------------------------------------------------- +bool BugDlg_Init() +{ + return true; +} + +//----------------------------------------------------------------------------- +// rc_MapInfo +// +// Sent from application with bug dialog info +//----------------------------------------------------------------------------- +int rc_MapInfo( char* commandPtr ) +{ + char* cmdToken; + int errCode; + int infoAddr; + int retVal; + int retAddr; + char buff[128]; + + // success + errCode = 0; + + // get address of data + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &infoAddr ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &retAddr ); + + // get the caller's info data + DmGetMemory( ( void* )infoAddr, sizeof( xrMapInfo_t ), &g_bug_mapInfo, NULL ); + + // swap the structure + BigFloat( &g_bug_mapInfo.position[0], &g_bug_mapInfo.position[0] ); + BigFloat( &g_bug_mapInfo.position[1], &g_bug_mapInfo.position[1] ); + BigFloat( &g_bug_mapInfo.position[2], &g_bug_mapInfo.position[2] ); + BigFloat( &g_bug_mapInfo.angle[0], &g_bug_mapInfo.angle[0] ); + BigFloat( &g_bug_mapInfo.angle[1], &g_bug_mapInfo.angle[1] ); + BigFloat( &g_bug_mapInfo.angle[2], &g_bug_mapInfo.angle[2] ); + g_bug_mapInfo.build = BigDWord( g_bug_mapInfo.build ); + g_bug_mapInfo.skill = BigDWord( g_bug_mapInfo.skill ); + + Sys_NormalizePath( g_bug_mapInfo.savePath, false ); + Sys_NormalizePath( g_bug_mapInfo.mapPath, false ); + + if ( g_bug_hWnd ) + { + if ( g_bug_mapInfo.mapPath[0] ) + { + Sys_StripPath( g_bug_mapInfo.mapPath, buff, sizeof( buff ) ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_MAP_LABEL, buff ); + + if ( !g_Games[g_bug_GameType].bUsesSystem1 ) + { + char *pExtension = V_stristr( buff, ".bsp" ); + if ( pExtension ) + { + *pExtension = '\0'; + } + pExtension = V_stristr( buff, ".360" ); + if ( pExtension ) + { + *pExtension = '\0'; + } + V_strncpy( g_bug_szMapNumber, buff, sizeof( g_bug_szMapNumber ) ); + + int curSel = SendDlgItemMessage( g_bug_hWnd, IDC_BUG_MAPNUMBER, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szMapNumber ); + if ( curSel == CB_ERR ) + curSel = 0; + SendDlgItemMessage( g_bug_hWnd, IDC_BUG_MAPNUMBER, CB_SETCURSEL, curSel, 0 ); + } + + sprintf( buff, "%.2f %.2f %.2f", g_bug_mapInfo.position[0], g_bug_mapInfo.position[1], g_bug_mapInfo.position[2] ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_POSITION_LABEL, buff ); + + sprintf( buff, "%.2f %.2f %.2f", g_bug_mapInfo.angle[0], g_bug_mapInfo.angle[1], g_bug_mapInfo.angle[2] ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_ORIENTATION_LABEL, buff ); + } + else + { + SetDlgItemText( g_bug_hWnd, IDC_BUG_MAP_LABEL, "" ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_POSITION_LABEL, "" ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_ORIENTATION_LABEL, "" ); + } + + sprintf( buff, "%d", g_bug_mapInfo.build ); + SetDlgItemText( g_bug_hWnd, IDC_BUG_BUILD_LABEL, buff ); + + EnableWindow( GetDlgItem( g_bug_hWnd, IDC_BUG_SAVEGAME ), g_bug_mapInfo.savePath[0] != '\0' && g_bug_mapInfo.mapPath[0] != '\0' ); + EnableWindow( GetDlgItem( g_bug_hWnd, IDC_BUG_INCLUDEBSP ), g_bug_mapInfo.mapPath[0] != '\0' ); + } + + // return the result + retVal = 0; + int xboxRetVal = BigDWord( retVal ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + DebugCommand( "0x%8.8x = MapInfo( 0x%8.8x )\n", retVal, infoAddr ); + +cleanUp: + return errCode; +} + diff --git a/utils/xbox/vxconsole/common.cpp b/utils/xbox/vxconsole/common.cpp new file mode 100644 index 0000000..1b8418c --- /dev/null +++ b/utils/xbox/vxconsole/common.cpp @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// COMMON.CPP +// +// Common/Misc specialized support routines not uniquely owned. +//=====================================================================================// +#include "vxconsole.h" + +vprofState_e g_vprof_state = VPROF_OFF; + +//----------------------------------------------------------------------------- +// NotImplementedYet +// +//----------------------------------------------------------------------------- +void NotImplementedYet() +{ + Sys_MessageBox( "Attention!", "Sorry, Not Implemented Yet." ); +} + +//----------------------------------------------------------------------------- +// VProf_GetState +// +//----------------------------------------------------------------------------- +vprofState_e VProf_GetState() +{ + return g_vprof_state; +} + +//----------------------------------------------------------------------------- +// VProf_Enable +// +// Coordinates multiple vprof commands for proper exclusion +//----------------------------------------------------------------------------- +void VProf_Enable( vprofState_e state ) +{ + char commandString[256]; + + switch ( state ) + { + case VPROF_CPU: + strcpy( commandString, "vprof_off ; vprof_on ; vprof_update cpu" ); + break; + + case VPROF_TEXTURE: + strcpy( commandString, "vprof_off ; vprof_on ; vprof_update texture" ); + break; + + case VPROF_TEXTUREFRAME: + strcpy( commandString, "vprof_off ; vprof_on ; vprof_update texture_frame" ); + break; + + default: + state = VPROF_OFF; + strcpy( commandString, "vprof_off" ); + break; + + } + + // track state + if ( g_vprof_state != state ) + { + g_vprof_state = state; + + // do command + ProcessCommand( commandString ); + + // update all the dependant titles + CpuProfile_SetTitle(); + TexProfile_SetTitle(); + } +} + + diff --git a/utils/xbox/vxconsole/config.cpp b/utils/xbox/vxconsole/config.cpp new file mode 100644 index 0000000..85558d7 --- /dev/null +++ b/utils/xbox/vxconsole/config.cpp @@ -0,0 +1,217 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// CONFIG.CPP +// +// Configuration Dialog +//=====================================================================================// +#include "vxconsole.h" + +CHAR g_xboxTargetName[MAX_XBOXNAMELEN]; +char g_localPath[MAX_PATH]; +char g_targetPath[MAX_PATH]; +BOOL g_clsOnConnect; +BOOL g_loadSymbolsOnConnect; +char g_xexTargetPath[MAX_PATH]; +BOOL g_alwaysAutoConnect; +BOOL g_startMinimized; +char g_installPath[MAX_PATH]; +BOOL g_captureDebugSpew_StartupState; + +//----------------------------------------------------------------------------- +// ConfigDlg_LoadConfig +// +//----------------------------------------------------------------------------- +void ConfigDlg_LoadConfig() +{ + // get our config + Sys_GetRegistryString( "xboxName", g_xboxTargetName, "", sizeof( g_xboxTargetName ) ); + Sys_GetRegistryString( "localPath", g_localPath, "u:\\dev\\game", sizeof( g_localPath ) ); + Sys_GetRegistryString( "targetPath", g_targetPath, "e:\\valve", sizeof( g_targetPath ) ); + Sys_GetRegistryString( "installPath", g_installPath, "\\\\fileserver\\user\\xbox\\xbox_orange", sizeof( g_installPath ) ); + Sys_GetRegistryInteger( "clearOnConnect", true, g_clsOnConnect ); + Sys_GetRegistryInteger( "loadSymbolsOnConnect", false, g_loadSymbolsOnConnect ); + Sys_GetRegistryInteger( "alwaysAutoConnect", false, g_alwaysAutoConnect ); + Sys_GetRegistryInteger( "startMinimized", false, g_startMinimized ); + Sys_GetRegistryInteger( "captureDebugSpew", true, g_captureDebugSpew_StartupState ); +} + +//----------------------------------------------------------------------------- +// ConfigDlg_SaveConfig +// +//----------------------------------------------------------------------------- +void ConfigDlg_SaveConfig() +{ + // save config + Sys_SetRegistryString( "xboxName", g_xboxTargetName ); + Sys_SetRegistryString( "localPath", g_localPath ); + Sys_SetRegistryString( "targetPath", g_targetPath ); + Sys_SetRegistryString( "installPath", g_installPath ); + Sys_SetRegistryInteger( "clearOnConnect", g_clsOnConnect ); + Sys_SetRegistryInteger( "loadSymbolsOnConnect", g_loadSymbolsOnConnect ); + Sys_SetRegistryInteger( "alwaysAutoConnect", g_alwaysAutoConnect ); + Sys_SetRegistryInteger( "startMinimized", g_startMinimized ); + Sys_SetRegistryInteger( "captureDebugSpew", g_captureDebugSpew_StartupState ); + + // update + SetMainWindowTitle(); +} + +//----------------------------------------------------------------------------- +// ConfigDlg_Setup +// +//----------------------------------------------------------------------------- +void ConfigDlg_Setup( HWND hWnd ) +{ + SetDlgItemText( hWnd,IDC_CONFIG_XBOXNAME, g_xboxTargetName ); + SetDlgItemText( hWnd,IDC_CONFIG_LOCALPATH, g_localPath ); + SetDlgItemText( hWnd,IDC_CONFIG_TARGETPATH, g_targetPath ); + SetDlgItemText( hWnd,IDC_CONFIG_INSTALLPATH, g_installPath ); + + EnableWindow( GetDlgItem( hWnd, IDC_CONFIG_PING ), strlen( g_xboxTargetName ) > 0 ); + + CheckDlgButton( hWnd, IDC_CONFIG_CLEARONCONNECT, g_clsOnConnect ? BST_CHECKED : BST_UNCHECKED ); + CheckDlgButton( hWnd, IDC_CONFIG_ALWAYSAUTOCONNECT, g_alwaysAutoConnect ? BST_CHECKED : BST_UNCHECKED ); + CheckDlgButton( hWnd, IDC_CONFIG_STARTMINIMIZED, g_startMinimized ? BST_CHECKED : BST_UNCHECKED ); + CheckDlgButton( hWnd, IDC_CONFIG_CAPTUREDEBUGSPEW, g_captureDebugSpew_StartupState ? BST_CHECKED : BST_UNCHECKED ); +} + +//----------------------------------------------------------------------------- +// ConfigDlg_Ping +// +//----------------------------------------------------------------------------- +BOOL ConfigDlg_Ping( HWND hwnd ) +{ + char xboxName[MAX_XBOXNAMELEN]; + BOOL canConnect; + char* args[1]; + + xboxName[0] = '\0'; + GetDlgItemText( hwnd, IDC_CONFIG_XBOXNAME, xboxName, MAX_XBOXNAMELEN ); + + // ignore ping to current connection + if ( !stricmp( g_xboxName, xboxName ) ) + { + if ( g_connectedToXBox ) + { + Sys_MessageBox( "Ping", "Already Connected To: '%s'", xboxName ); + return true; + } + } + + // terminate any current connection + lc_disconnect( 0, NULL ); + + // trial connect + args[0] = xboxName; + canConnect = lc_connect( 1, args ); + + if ( !canConnect ) + Sys_MessageBox( "Ping FAILURE", "Could Not Connect To: %s", xboxName ); + else + Sys_MessageBox( "Ping SUCCESS", "Connection Valid To: %s", g_xboxName ); + + if ( canConnect ) + lc_disconnect( 0, NULL ); + + return canConnect; +} + +//----------------------------------------------------------------------------- +// ConfigDlg_GetChanges +// +//----------------------------------------------------------------------------- +bool ConfigDlg_GetChanges( HWND hwnd ) +{ + char remotePath[MAX_PATH]; + char localPath[MAX_PATH]; + char targetPath[MAX_PATH]; + char installPath[MAX_PATH]; + char xboxName[MAX_XBOXNAMELEN]; + char xexLocalPath[MAX_PATH]; + char xexTargetPath[MAX_PATH]; + + xboxName[0] = '\0'; + remotePath[0] = '\0'; + localPath[0] = '\0'; + targetPath[0] = '\0'; + xexLocalPath[0] = '\0'; + xexTargetPath[0] = '\0'; + + GetDlgItemText( hwnd, IDC_CONFIG_XBOXNAME, xboxName, MAX_XBOXNAMELEN ); + GetDlgItemText( hwnd, IDC_CONFIG_LOCALPATH, localPath, MAX_PATH ); + GetDlgItemText( hwnd, IDC_CONFIG_TARGETPATH, targetPath, MAX_PATH ); + GetDlgItemText( hwnd, IDC_CONFIG_INSTALLPATH, installPath, MAX_PATH ); + + strcpy( g_localPath, localPath ); + Sys_NormalizePath( g_localPath, true ); + + strcpy( g_targetPath, targetPath ); + Sys_NormalizePath( g_targetPath, true ); + + strcpy( g_installPath, installPath ); + Sys_NormalizePath( g_installPath, true ); + + strcpy( g_xboxTargetName, xboxName ); + + g_clsOnConnect = IsDlgButtonChecked( hwnd, IDC_CONFIG_CLEARONCONNECT ); + g_loadSymbolsOnConnect = IsDlgButtonChecked( hwnd, IDC_CONFIG_LOADSYMBOLS ); + g_alwaysAutoConnect = IsDlgButtonChecked( hwnd, IDC_CONFIG_ALWAYSAUTOCONNECT ); + g_startMinimized = IsDlgButtonChecked( hwnd, IDC_CONFIG_STARTMINIMIZED ); + g_captureDebugSpew_StartupState = IsDlgButtonChecked( hwnd, IDC_CONFIG_CAPTUREDEBUGSPEW ); + + // success + return ( true ); +} + +//----------------------------------------------------------------------------- +// ConfigDlg_Proc +// +//----------------------------------------------------------------------------- +BOOL CALLBACK ConfigDlg_Proc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch ( message ) + { + case WM_INITDIALOG: + ConfigDlg_Setup( hwnd ); + return ( TRUE ); + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDC_CONFIG_PING: + ConfigDlg_Ping( hwnd ); + break; + + case IDC_CONFIG_XBOXNAME: + CHAR buff[MAX_XBOXNAMELEN]; + GetDlgItemText( hwnd, IDC_CONFIG_XBOXNAME, buff, sizeof( buff ) ); + EnableWindow( GetDlgItem( hwnd, IDC_CONFIG_PING ), strlen( buff ) > 0 ); + break; + + case IDC_OK: + if ( !ConfigDlg_GetChanges( hwnd ) ) + break; + case IDCANCEL: + case IDC_CANCEL: + EndDialog( hwnd, wParam ); + return ( TRUE ); + } + break; + } + return ( FALSE ); +} + +//----------------------------------------------------------------------------- +// ConfigDlg_Open +// +//----------------------------------------------------------------------------- +void ConfigDlg_Open( void ) +{ + int result; + + result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_CONFIG ), g_hDlgMain, ( DLGPROC )ConfigDlg_Proc ); + if ( LOWORD( result ) != IDC_OK ) + return; + + ConfigDlg_SaveConfig(); +} diff --git a/utils/xbox/vxconsole/cpu_profile.cpp b/utils/xbox/vxconsole/cpu_profile.cpp new file mode 100644 index 0000000..57571e4 --- /dev/null +++ b/utils/xbox/vxconsole/cpu_profile.cpp @@ -0,0 +1,983 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// CPU_PROFILE.CPP +// +// Cpu Profiling Display +//=====================================================================================// +#include "vxconsole.h" + +#define PROFILE_MAXCOUNTERS 64 +#define PROFILE_MAXSAMPLES 512 + +#define PROFILE_HISTORY_TIMINGHEIGHT 100 +#define PROFILE_HISTORY_NUMMINORTICKS 3 +#define PROFILE_HISTORY_LABELWIDTH 50 +#define PROFILE_HISTORY_SCALESTEPS 5 +#define PROFILE_HISTORY_MINSCALE 0.3f +#define PROFILE_HISTORY_MAXSCALE 3.0f + +#define PROFILE_SAMPLES_ITEMHEIGHT 15 +#define PROFILE_SAMPLES_BARHEIGHT 10 +#define PROFILE_SAMPLES_TIMINGWIDTH 200 +#define PROFILE_SAMPLES_LABELWIDTH 150 +#define PROFILE_SAMPLES_LABELGAP 5 +#define PROFILE_SAMPLES_NUMMINORTICKS 3 +#define PROFILE_SAMPLES_PEAKHOLDTIME 3000 +#define PROFILE_SAMPLES_SCALESTEPS 10 +#define PROFILE_SAMPLES_MINSCALE 0.3f +#define PROFILE_SAMPLES_MAXSCALE 3.0f + +#define ID_CPUPROFILE_SAMPLES 1 +#define ID_CPUPROFILE_HISTORY 2 + +typedef struct +{ + unsigned int samples[PROFILE_MAXSAMPLES]; + unsigned int peakSample; + char label[64]; + COLORREF color; +} profileCounter_t; + +HWND g_cpuProfile_hWndSamples; +HWND g_cpuProfile_hWndHistory; +int g_cpuProfile_numCounters; +profileCounter_t g_cpuProfile_counters[PROFILE_MAXCOUNTERS]; +RECT g_cpuProfile_samplesWindowRect; +RECT g_cpuProfile_historyWindowRect; +DWORD g_cpuProfile_lastPeakTime; +bool g_cpuProfile_history_tickMarks = true; +bool g_cpuProfile_history_colors = true; +int g_cpuProfile_history_scale; +bool g_cpuProfile_samples_tickMarks = true; +bool g_cpuProfile_samples_colors = true; +int g_cpuProfile_samples_scale; +int g_cpuProfile_numSamples; +int g_cpuProfile_fpsLabels; + +//----------------------------------------------------------------------------- +// CpuProfile_SaveConfig +// +//----------------------------------------------------------------------------- +void CpuProfile_SaveConfig() +{ + char buff[256]; + WINDOWPLACEMENT wp; + + // profile samples + if ( g_cpuProfile_hWndSamples ) + { + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_cpuProfile_hWndSamples, &wp ); + g_cpuProfile_samplesWindowRect = wp.rcNormalPosition; + sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom ); + Sys_SetRegistryString( "profileSamplesWindowRect", buff ); + } + Sys_SetRegistryInteger( "profileSamplesScale", g_cpuProfile_samples_scale ); + + // profile history + if ( g_cpuProfile_hWndHistory ) + { + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_cpuProfile_hWndHistory, &wp ); + g_cpuProfile_historyWindowRect = wp.rcNormalPosition; + sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom ); + Sys_SetRegistryString( "profileHistoryWindowRect", buff ); + } + Sys_SetRegistryInteger( "profileHistoryScale", g_cpuProfile_history_scale ); + + Sys_SetRegistryInteger( "cpuProfileFpsLabels", g_cpuProfile_fpsLabels ); +} + +//----------------------------------------------------------------------------- +// CpuProfile_LoadConfig +// +//----------------------------------------------------------------------------- +void CpuProfile_LoadConfig() +{ + int numArgs; + char buff[256]; + + // profile samples + Sys_GetRegistryString( "profileSamplesWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_cpuProfile_samplesWindowRect.left, &g_cpuProfile_samplesWindowRect.top, &g_cpuProfile_samplesWindowRect.right, &g_cpuProfile_samplesWindowRect.bottom ); + if ( numArgs != 4 ) + memset( &g_cpuProfile_samplesWindowRect, 0, sizeof( g_cpuProfile_samplesWindowRect ) ); + Sys_GetRegistryInteger( "profileSamplesScale", 0, g_cpuProfile_samples_scale ); + if ( g_cpuProfile_samples_scale < -PROFILE_SAMPLES_SCALESTEPS || g_cpuProfile_samples_scale > PROFILE_SAMPLES_SCALESTEPS ) + g_cpuProfile_samples_scale = 0; + + // profile history + Sys_GetRegistryString( "profileHistoryWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_cpuProfile_historyWindowRect.left, &g_cpuProfile_historyWindowRect.top, &g_cpuProfile_historyWindowRect.right, &g_cpuProfile_historyWindowRect.bottom ); + if ( numArgs != 4 ) + memset( &g_cpuProfile_historyWindowRect, 0, sizeof( g_cpuProfile_historyWindowRect ) ); + Sys_GetRegistryInteger( "profileHistoryScale", 0, g_cpuProfile_history_scale ); + if ( g_cpuProfile_history_scale < -PROFILE_HISTORY_SCALESTEPS || g_cpuProfile_history_scale > PROFILE_HISTORY_SCALESTEPS ) + g_cpuProfile_history_scale = 0; + + Sys_GetRegistryInteger( "cpuProfileFpsLabels", 0, g_cpuProfile_fpsLabels ); +} + +//----------------------------------------------------------------------------- +// CpuProfile_SetTitle +// +//----------------------------------------------------------------------------- +void CpuProfile_SetTitle() +{ + char titleBuff[128]; + + if ( g_cpuProfile_hWndSamples ) + { + strcpy( titleBuff, "CPU Usage Snapshot" ); + if ( VProf_GetState() == VPROF_CPU ) + strcat( titleBuff, " [ON]" ); + + SetWindowText( g_cpuProfile_hWndSamples, titleBuff ); + } + + if ( g_cpuProfile_hWndHistory ) + { + strcpy( titleBuff, "CPU Usage History" ); + if ( VProf_GetState() == VPROF_CPU ) + strcat( titleBuff, " [ON]" ); + + SetWindowText( g_cpuProfile_hWndHistory, titleBuff ); + } +} + +//----------------------------------------------------------------------------- +// CpuProfile_UpdateWindow +// +//----------------------------------------------------------------------------- +void CpuProfile_UpdateWindow() +{ + if ( g_cpuProfile_hWndSamples && !IsIconic( g_cpuProfile_hWndSamples ) ) + { + // visible - force a client repaint + InvalidateRect( g_cpuProfile_hWndSamples, NULL, true ); + } + + if ( g_cpuProfile_hWndHistory && !IsIconic( g_cpuProfile_hWndHistory ) ) + { + // visible - force a client repaint + InvalidateRect( g_cpuProfile_hWndHistory, NULL, true ); + } +} + +//----------------------------------------------------------------------------- +// rc_SetCpuProfile +// +//----------------------------------------------------------------------------- +int rc_SetCpuProfile( char* commandPtr ) +{ + int i; + char* cmdToken; + int retAddr; + int errCode = -1; + xrProfile_t* localList; + int profileList; + int numProfiles; + int retVal; + + // get numProfiles + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken,"%x",&numProfiles ); + + // get profile attributes + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &profileList ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken,"%x",&retAddr ); + + localList = new xrProfile_t[numProfiles]; + memset( localList, 0, numProfiles*sizeof( xrProfile_t ) ); + + // get the caller's profile list + DmGetMemory( ( void* )profileList, numProfiles*sizeof( xrProfile_t ), localList, NULL ); + + g_cpuProfile_numCounters = numProfiles; + if ( g_cpuProfile_numCounters > PROFILE_MAXCOUNTERS-1 ) + g_cpuProfile_numCounters = PROFILE_MAXCOUNTERS-1; + + for ( i=0; i<g_cpuProfile_numCounters; i++ ) + { + // swap the structure + localList[i].color = BigDWord( localList[i].color ); + + // clear the old counter + memset( &g_cpuProfile_counters[i], 0, sizeof( profileCounter_t ) ); + + V_strncpy( g_cpuProfile_counters[i].label, localList[i].labelString, sizeof( g_cpuProfile_counters[i].label ) ); + g_cpuProfile_counters[i].color = localList[i].color; + } + + // build out the reserved last counter as total count + memset( &g_cpuProfile_counters[g_cpuProfile_numCounters], 0, sizeof( profileCounter_t ) ); + strcpy( g_cpuProfile_counters[g_cpuProfile_numCounters].label, "Total" ); + g_cpuProfile_counters[i].color = RGB( 255,255,255 ); + g_cpuProfile_numCounters++; + + // set the return code + retVal = g_cpuProfile_numCounters-1; + int xboxRetVal = BigDWord( retVal ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + DebugCommand( "0x%8.8x = SetCpuProfile( 0x%8.8x, 0x%8.8x )\n", retVal, numProfiles, profileList ); + + delete [] localList; + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} + +//----------------------------------------------------------------------------- +// rc_SetCpuProfileData +// +//----------------------------------------------------------------------------- +int rc_SetCpuProfileData( char* commandPtr ) +{ + int i; + int total; + char* cmdToken; + int errCode = -1; + int counters; + int currentSample; + bool newPeaks; + unsigned int localCounters[PROFILE_MAXCOUNTERS]; + DWORD newTime; + + // get profiles + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + { + goto cleanUp; + } + sscanf( cmdToken, "%x", &counters ); + + // get the caller's profile list + if ( g_cpuProfile_numCounters ) + { + DmGetMemory( ( void* )counters, ( g_cpuProfile_numCounters-1 )*sizeof( int ), localCounters, NULL ); + } + + // timeout peaks + newTime = Sys_GetSystemTime(); + if ( newTime - g_cpuProfile_lastPeakTime > PROFILE_SAMPLES_PEAKHOLDTIME ) + { + g_cpuProfile_lastPeakTime = newTime; + newPeaks = true; + } + else + { + newPeaks = false; + } + + // next sample + currentSample = g_cpuProfile_numSamples % PROFILE_MAXSAMPLES; + g_cpuProfile_numSamples++; + + total = 0; + for ( i=0; i<g_cpuProfile_numCounters; i++ ) + { + // swap + localCounters[i] = BigDWord( localCounters[i] ); + + if ( i != g_cpuProfile_numCounters-1 ) + { + g_cpuProfile_counters[i].samples[currentSample] = localCounters[i]; + total += localCounters[i]; + } + else + { + // reserved total counter + g_cpuProfile_counters[i].samples[currentSample] = total; + } + + if ( newPeaks || g_cpuProfile_counters[i].peakSample < g_cpuProfile_counters[i].samples[currentSample] ) + { + g_cpuProfile_counters[i].peakSample = g_cpuProfile_counters[i].samples[currentSample]; + } + } + + DebugCommand( "SetCpuProfileData( 0x%8.8x )\n", counters ); + + CpuProfile_UpdateWindow(); + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} + +//----------------------------------------------------------------------------- +// CpuProfile_ZoomIn +// +//----------------------------------------------------------------------------- +void CpuProfile_ZoomIn( int& scale, int numSteps ) +{ + scale++; + if ( scale > numSteps ) + { + scale = numSteps; + return; + } + CpuProfile_UpdateWindow(); +} + +//----------------------------------------------------------------------------- +// CpuProfile_ZoomOut +// +//----------------------------------------------------------------------------- +void CpuProfile_ZoomOut( int& scale, int numSteps ) +{ + scale--; + if ( scale < -numSteps ) + { + scale = -numSteps; + return; + } + CpuProfile_UpdateWindow(); +} + +//----------------------------------------------------------------------------- +// CpuProfile_CalcScale +// +//----------------------------------------------------------------------------- +float CpuProfile_CalcScale( int scale, int numSteps, float min, float max ) +{ + float t; + + // from integral scale [-numSteps..numSteps] to float scale [min..max] + t = ( float )( scale + numSteps )/( float )( 2*numSteps ); + t = min + t*( max-min ); + + return t; +} + +//----------------------------------------------------------------------------- +// ProfileSamples_Draw +// +//----------------------------------------------------------------------------- +void ProfileSamples_Draw( HDC hdc, RECT* clientRect ) +{ + int i; + int j; + int x; + int y; + int x0; + int y0; + int w; + float t; + float scale; + float sampleTime; + char labelBuff[128]; + HPEN hBlackPen; + HPEN hPenOld; + HPEN hGreyPen; + HBRUSH hColoredBrush; + HBRUSH hbrushOld; + HFONT hFontOld; + RECT rect; + int currentSample; + int numTicks; + int timingWidth; + int windowWidth; + int windowHeight; + + hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) ); + hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) ); + hPenOld = ( HPEN )SelectObject( hdc, hBlackPen ); + hFontOld = SelectFont( hdc, g_hProportionalFont ); + + SetBkColor( hdc, g_backgroundColor ); + + // zoom + scale = CpuProfile_CalcScale( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS, PROFILE_SAMPLES_MINSCALE, PROFILE_SAMPLES_MAXSCALE ); + timingWidth = ( int )( PROFILE_SAMPLES_TIMINGWIDTH*scale ); + windowWidth = clientRect->right-clientRect->left; + windowHeight = clientRect->bottom-clientRect->top; + + numTicks = ( windowWidth-PROFILE_SAMPLES_LABELWIDTH )/timingWidth + 1; + if ( numTicks < 0 ) + numTicks = 1; + + rect.left = 0; + rect.right = PROFILE_SAMPLES_LABELWIDTH; + rect.top = 0; + rect.bottom = PROFILE_SAMPLES_ITEMHEIGHT; + DrawText( hdc, "Name", -1, &rect, DT_LEFT ); + + // draw timing ticks + x = PROFILE_SAMPLES_LABELWIDTH; + y = 0; + for ( i=0; i<numTicks; i++ ) + { + // tick labels + rect.left = x-40; + rect.right = x+40; + rect.top = y; + rect.bottom = y+PROFILE_SAMPLES_ITEMHEIGHT; + if ( !g_cpuProfile_fpsLabels ) + sprintf( labelBuff, "%.2fms", i*( 1000.0f/60.0f ) ); + else + sprintf( labelBuff, "%.2ffps", i == 0 ? 0 : 60.0f/i ); + DrawText( hdc, labelBuff, -1, &rect, DT_CENTER ); + + // major ticks + x0 = x; + y0 = y + PROFILE_SAMPLES_ITEMHEIGHT; + SelectObject( hdc, hBlackPen ); + MoveToEx( hdc, x0, y0, NULL ); + LineTo( hdc, x0, y0+windowHeight ); + + if ( g_cpuProfile_samples_tickMarks && g_cpuProfile_samples_scale > -PROFILE_SAMPLES_SCALESTEPS ) + { + // minor ticks + x0 = x; + y0 = y + PROFILE_SAMPLES_ITEMHEIGHT; + SelectObject( hdc, hGreyPen ); + for ( j=0; j<PROFILE_SAMPLES_NUMMINORTICKS; j++ ) + { + x0 += timingWidth/( PROFILE_SAMPLES_NUMMINORTICKS+1 ); + + MoveToEx( hdc, x0, y0, NULL ); + LineTo( hdc, x0, y0+windowHeight ); + } + } + x += timingWidth; + } + + // seperator + SelectObject( hdc, hBlackPen ); + MoveToEx( hdc, 0, PROFILE_SAMPLES_ITEMHEIGHT, NULL ); + LineTo( hdc, windowWidth, PROFILE_SAMPLES_ITEMHEIGHT ); + + // draw labels + x = 0; + y = PROFILE_SAMPLES_ITEMHEIGHT; + for ( i=0; i<g_cpuProfile_numCounters; i++ ) + { + if ( !g_cpuProfile_counters[i].label ) + continue; + + rect.left = x; + rect.right = x+PROFILE_SAMPLES_LABELWIDTH-PROFILE_SAMPLES_LABELGAP; + rect.top = y; + rect.bottom = y+PROFILE_SAMPLES_ITEMHEIGHT; + DrawText( hdc, g_cpuProfile_counters[i].label, -1, &rect, DT_VCENTER|DT_RIGHT|DT_SINGLELINE|DT_END_ELLIPSIS|DT_MODIFYSTRING ); + + // draw the under line + MoveToEx( hdc, x, y+PROFILE_SAMPLES_ITEMHEIGHT, NULL ); + LineTo( hdc, x+PROFILE_SAMPLES_LABELWIDTH, y+PROFILE_SAMPLES_ITEMHEIGHT ); + + y += PROFILE_SAMPLES_ITEMHEIGHT; + } + + // draw bars + SelectObject( hdc, hBlackPen ); + x = PROFILE_SAMPLES_LABELWIDTH; + y = PROFILE_SAMPLES_ITEMHEIGHT; + currentSample = g_cpuProfile_numSamples-1; + if ( currentSample < 0 ) + currentSample = 0; + else + currentSample %= PROFILE_MAXSAMPLES; + for ( i=0; i<g_cpuProfile_numCounters; i++ ) + { + if ( !g_cpuProfile_counters[i].label ) + continue; + + hColoredBrush = CreateSolidBrush( g_cpuProfile_samples_colors ? g_cpuProfile_counters[i].color : g_backgroundColor ); + hbrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush ); + + // bar - count is in us i.e. 1 major tick = 16667us + t = ( float )g_cpuProfile_counters[i].samples[currentSample]/( 1000000.0f/60.0f ); + w = ( int )( t * ( float )timingWidth ); + if ( w > windowWidth ) + w = windowWidth; + x0 = x; + y0 = y + ( PROFILE_SAMPLES_ITEMHEIGHT-PROFILE_SAMPLES_BARHEIGHT )/2 + 1; + Rectangle( hdc, x0, y0, x0 + w, y0 + PROFILE_SAMPLES_BARHEIGHT ); + + // peak + t = ( float )g_cpuProfile_counters[i].peakSample/( 1000000.0f/60.0f ); + w = ( int )( t * ( float )timingWidth ); + if ( w > windowWidth ) + w = windowWidth; + x0 = x + w; + y0 = y + PROFILE_SAMPLES_ITEMHEIGHT/2 + 1; + + POINT points[4]; + points[0].x = x0; + points[0].y = y0-4; + points[1].x = x0+4; + points[1].y = y0; + points[2].x = x0; + points[2].y = y0+4; + points[3].x = x0-4; + points[3].y = y0; + Polygon( hdc, points, 4 ); + + SelectObject( hdc, hbrushOld ); + DeleteObject( hColoredBrush ); + + // draw peak times + sampleTime = ( float )g_cpuProfile_counters[i].peakSample/1000.0f; + if ( sampleTime >= 0.01F ) + { + sprintf( labelBuff, "%.2f", sampleTime ); + rect.left = x0 + 8; + rect.right = x0 + 8 + 100; + rect.top = y; + rect.bottom = y + PROFILE_SAMPLES_ITEMHEIGHT; + DrawText( hdc, labelBuff, -1, &rect, DT_VCENTER|DT_LEFT|DT_SINGLELINE ); + } + + y += PROFILE_SAMPLES_ITEMHEIGHT; + } + + SelectObject( hdc, hFontOld ); + SelectObject( hdc, hPenOld ); + DeleteObject( hBlackPen ); + DeleteObject( hGreyPen ); +} + +//----------------------------------------------------------------------------- +// ProfileHistory_Draw +// +//----------------------------------------------------------------------------- +void ProfileHistory_Draw( HDC hdc, RECT* clientRect ) +{ + char labelBuff[128]; + HPEN hBlackPen; + HPEN hPenOld; + HPEN hNullPen; + HPEN hGreyPen; + HBRUSH hColoredBrush; + HBRUSH hBrushOld; + HFONT hFontOld; + int currentSample; + int numTicks; + int timingHeight; + int windowWidth; + int windowHeight; + int x; + int y; + int y0; + int i; + int j; + int h; + int numbars; + RECT rect; + float t; + float scale; + + hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) ); + hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) ); + hNullPen = CreatePen( PS_NULL, 0, RGB( 0,0,0 ) ); + hPenOld = ( HPEN )SelectObject( hdc, hBlackPen ); + hFontOld = SelectFont( hdc, g_hProportionalFont ); + + // zoom + scale = CpuProfile_CalcScale( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS, PROFILE_HISTORY_MINSCALE, PROFILE_HISTORY_MAXSCALE ); + timingHeight = ( int )( PROFILE_HISTORY_TIMINGHEIGHT*scale ); + windowWidth = clientRect->right-clientRect->left; + windowHeight = clientRect->bottom-clientRect->top; + + numTicks = windowHeight/timingHeight + 2; + if ( numTicks < 0 ) + numTicks = 1; + + SetBkColor( hdc, g_backgroundColor ); + + x = 0; + y = windowHeight; + for ( i=0; i<numTicks; i++ ) + { + // major ticks + SelectObject( hdc, hBlackPen ); + MoveToEx( hdc, 0, y, NULL ); + LineTo( hdc, windowWidth, y ); + + if ( g_cpuProfile_history_tickMarks && g_cpuProfile_history_scale > -PROFILE_HISTORY_SCALESTEPS ) + { + // minor ticks + y0 = y; + SelectObject( hdc, hGreyPen ); + for ( j=0; j<PROFILE_HISTORY_NUMMINORTICKS; j++ ) + { + y0 += timingHeight/( PROFILE_SAMPLES_NUMMINORTICKS+1 ); + MoveToEx( hdc, 0, y0, NULL ); + LineTo( hdc, windowWidth, y0 ); + } + } + + // tick labels + if ( i ) + { + rect.left = windowWidth-50; + rect.right = windowWidth; + rect.top = y-20; + rect.bottom = y; + if ( !g_cpuProfile_fpsLabels ) + sprintf( labelBuff, "%.2fms", i*( 1000.0f/60.0f ) ); + else + sprintf( labelBuff, "%.2ffps", 60.0f/i ); + DrawText( hdc, labelBuff, -1, &rect, DT_RIGHT|DT_SINGLELINE|DT_BOTTOM ); + } + + y -= timingHeight; + } + + // vertical bars + if ( g_cpuProfile_numSamples ) + { + SelectObject( hdc, hNullPen ); + + numbars = windowWidth-PROFILE_HISTORY_LABELWIDTH; + currentSample = g_cpuProfile_numSamples-1; + for ( x=numbars-1; x>=0; x-=4 ) + { + // all the counters at this sample + y = windowHeight; + for ( j=0; j<g_cpuProfile_numCounters-1; j++ ) + { + if ( !g_cpuProfile_counters[j].label ) + continue; + + t = ( float )g_cpuProfile_counters[j].samples[currentSample % PROFILE_MAXSAMPLES]/( 1000000.0f/60.0f ); + h = ( int )( t * ( float )timingHeight ); + if ( h ) + { + if ( h > windowHeight ) + h = windowHeight; + + hColoredBrush = CreateSolidBrush( g_cpuProfile_history_colors ? g_cpuProfile_counters[j].color : RGB( 80,80,80 ) ); + hBrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush ); + + Rectangle( hdc, x-4, y-h, x, y+1 ); + y -= h; + + SelectObject( hdc, hBrushOld ); + DeleteObject( hColoredBrush ); + } + } + currentSample--; + if ( currentSample < 0 ) + { + // no data + break; + } + } + } + + SelectObject( hdc, hFontOld ); + SelectObject( hdc, hPenOld ); + DeleteObject( hBlackPen ); + DeleteObject( hGreyPen ); +} + +//----------------------------------------------------------------------------- +// CpuProfile_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK CpuProfile_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + HDC hdc; + PAINTSTRUCT ps; + RECT rect; + int id; + bool bIsSamples; + bool bIsHistory; + CREATESTRUCT *createStructPtr; + + // identify window + id = ( int )GetWindowLong( hwnd, GWL_USERDATA+0 ); + bIsSamples = ( id == ID_CPUPROFILE_SAMPLES ); + bIsHistory = ( id == ID_CPUPROFILE_HISTORY ); + + switch ( message ) + { + case WM_CREATE: + // set the window identifier + createStructPtr = ( CREATESTRUCT* )lParam; + SetWindowLong( hwnd, GWL_USERDATA+0, ( LONG )createStructPtr->lpCreateParams ); + + // reset peaks + g_cpuProfile_lastPeakTime = 0; + return 0L; + + case WM_DESTROY: + CpuProfile_SaveConfig(); + + if ( bIsSamples ) + g_cpuProfile_hWndSamples = NULL; + else if ( bIsHistory ) + g_cpuProfile_hWndHistory = NULL; + + if ( VProf_GetState() == VPROF_CPU ) + { + VProf_Enable( VPROF_OFF ); + } + return 0L; + + case WM_INITMENU: + if ( bIsSamples ) + { + CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_cpuProfile_samples_tickMarks ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_COLORS, MF_BYCOMMAND | ( g_cpuProfile_samples_colors ? MF_CHECKED : MF_UNCHECKED ) ); + } + else if ( bIsHistory ) + { + CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_cpuProfile_history_tickMarks ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_COLORS, MF_BYCOMMAND | ( g_cpuProfile_history_colors ? MF_CHECKED : MF_UNCHECKED ) ); + } + CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_FPSLABELS, MF_BYCOMMAND | ( g_cpuProfile_fpsLabels ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_CPUPROFILE_ENABLE, MF_BYCOMMAND | ( VProf_GetState() == VPROF_CPU ? MF_CHECKED : MF_UNCHECKED ) ); + return 0L; + + case WM_PAINT: + GetClientRect( hwnd, &rect ); + hdc = BeginPaint( hwnd, &ps ); + if ( bIsSamples ) + ProfileSamples_Draw( hdc, &rect ); + else if ( bIsHistory ) + ProfileHistory_Draw( hdc, &rect ); + EndPaint( hwnd, &ps ); + return 0L; + + case WM_SIZE: + // force a redraw + CpuProfile_UpdateWindow(); + return 0L; + + case WM_KEYDOWN: + switch ( wParam ) + { + case VK_INSERT: + if ( bIsSamples ) + CpuProfile_ZoomIn( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS ); + else if ( bIsHistory ) + CpuProfile_ZoomIn( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS ); + return 0L; + + case VK_DELETE: + if ( bIsSamples ) + CpuProfile_ZoomOut( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS ); + else if ( bIsHistory ) + CpuProfile_ZoomOut( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS ); + return 0L; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_CPUPROFILE_TICKMARKS: + if ( bIsSamples ) + g_cpuProfile_samples_tickMarks ^= 1; + else if ( bIsHistory ) + g_cpuProfile_history_tickMarks ^= 1; + CpuProfile_UpdateWindow(); + return 0L; + + case IDM_CPUPROFILE_COLORS: + if ( bIsSamples ) + g_cpuProfile_samples_colors ^= 1; + else if ( bIsHistory ) + g_cpuProfile_history_colors ^= 1; + CpuProfile_UpdateWindow(); + return 0L; + + case IDM_CPUPROFILE_FPSLABELS: + g_cpuProfile_fpsLabels ^= 1; + CpuProfile_UpdateWindow(); + return 0L; + + case IDM_CPUPROFILE_ZOOMIN: + if ( bIsSamples ) + CpuProfile_ZoomIn( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS ); + else if ( bIsHistory ) + CpuProfile_ZoomIn( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS ); + return 0L; + + case IDM_CPUPROFILE_ZOOMOUT: + if ( bIsSamples ) + CpuProfile_ZoomOut( g_cpuProfile_samples_scale, PROFILE_SAMPLES_SCALESTEPS ); + else if ( bIsHistory ) + CpuProfile_ZoomOut( g_cpuProfile_history_scale, PROFILE_HISTORY_SCALESTEPS ); + return 0L; + + case IDM_CPUPROFILE_ENABLE: + bool bEnable = ( VProf_GetState() == VPROF_CPU ); + bEnable ^= 1; + if ( !bEnable ) + VProf_Enable( VPROF_OFF ); + else + VProf_Enable( VPROF_CPU ); + CpuProfile_SetTitle(); + return 0L; + } + break; + } + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// CpuProfileHistory_Open +// +//----------------------------------------------------------------------------- +void CpuProfileHistory_Open() +{ + HWND hWnd; + + if ( g_cpuProfile_hWndHistory ) + { + // only one profile instance + if ( IsIconic( g_cpuProfile_hWndHistory ) ) + ShowWindow( g_cpuProfile_hWndHistory, SW_RESTORE ); + SetForegroundWindow( g_cpuProfile_hWndHistory ); + return; + } + + if ( VProf_GetState() == VPROF_OFF ) + { + VProf_Enable( VPROF_CPU ); + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "CPUPROFILEHISTORYCLASS", + "", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 600, + 500, + g_hDlgMain, + NULL, + g_hInstance, + ( void* )ID_CPUPROFILE_HISTORY ); + g_cpuProfile_hWndHistory = hWnd; + + CpuProfile_SetTitle(); + + if ( g_cpuProfile_historyWindowRect.right && g_cpuProfile_historyWindowRect.bottom ) + MoveWindow( g_cpuProfile_hWndHistory, g_cpuProfile_historyWindowRect.left, g_cpuProfile_historyWindowRect.top, g_cpuProfile_historyWindowRect.right-g_cpuProfile_historyWindowRect.left, g_cpuProfile_historyWindowRect.bottom-g_cpuProfile_historyWindowRect.top, FALSE ); + ShowWindow( g_cpuProfile_hWndHistory, SHOW_OPENWINDOW ); +} + +//----------------------------------------------------------------------------- +// CpuProfileSamples_Open +// +//----------------------------------------------------------------------------- +void CpuProfileSamples_Open() +{ + HWND hWnd; + + if ( g_cpuProfile_hWndSamples ) + { + // only one profile instance + if ( IsIconic( g_cpuProfile_hWndSamples ) ) + ShowWindow( g_cpuProfile_hWndSamples, SW_RESTORE ); + SetForegroundWindow( g_cpuProfile_hWndSamples ); + return; + } + + if ( VProf_GetState() == VPROF_OFF ) + { + VProf_Enable( VPROF_CPU ); + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "CPUPROFILESAMPLESCLASS", + "", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 600, + 500, + g_hDlgMain, + NULL, + g_hInstance, + ( void* )ID_CPUPROFILE_SAMPLES ); + g_cpuProfile_hWndSamples = hWnd; + + CpuProfile_SetTitle(); + + if ( g_cpuProfile_samplesWindowRect.right && g_cpuProfile_samplesWindowRect.bottom ) + MoveWindow( g_cpuProfile_hWndSamples, g_cpuProfile_samplesWindowRect.left, g_cpuProfile_samplesWindowRect.top, g_cpuProfile_samplesWindowRect.right-g_cpuProfile_samplesWindowRect.left, g_cpuProfile_samplesWindowRect.bottom-g_cpuProfile_samplesWindowRect.top, FALSE ); + ShowWindow( g_cpuProfile_hWndSamples, SHOW_OPENWINDOW ); +} + +//----------------------------------------------------------------------------- +// CpuProfile_Clear +// +//----------------------------------------------------------------------------- +void CpuProfile_Clear() +{ + // clear counters and history + g_cpuProfile_numCounters = 0; + g_cpuProfile_numSamples = 0; + + CpuProfile_UpdateWindow(); +} + +//----------------------------------------------------------------------------- +// CpuProfile_Init +// +//----------------------------------------------------------------------------- +bool CpuProfile_Init() +{ + WNDCLASS wndclass; + + // set up our window class + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = CpuProfile_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_CPUPROFILE ); + wndclass.lpszClassName = "CPUPROFILESAMPLESCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + // set up our window class + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = CpuProfile_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_CPUPROFILE ); + wndclass.lpszClassName = "CPUPROFILEHISTORYCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + CpuProfile_LoadConfig(); + + return true; +} diff --git a/utils/xbox/vxconsole/exclude_paths.cpp b/utils/xbox/vxconsole/exclude_paths.cpp new file mode 100644 index 0000000..668a835 --- /dev/null +++ b/utils/xbox/vxconsole/exclude_paths.cpp @@ -0,0 +1,1134 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// EXCLUDE_PATHS.CPP +// +// DVD Exclude paths. +//=====================================================================================// +#include "vxconsole.h" + +#define UM_CHECKSTATECHANGE (WM_USER + 100) +#define UM_FIRSTTIMEPOPULATE (WM_USER + 101) + +#define MAX_TREE_DEPTH 32 +#define ROOT_NAME "Xbox:\\" +#define EXCLUDEPATHS_FILE "xbox_exclude_paths.txt" + +// known shipping 360 gamedirs +struct GameName_t +{ + const char *pName; + bool bIsModPath; +}; + +struct GamePath_t +{ + CUtlString pathName; + bool bIsModPath; +}; + +GameName_t g_GameNames[] = +{ + { "bin", false }, + { "platform", false }, + { "tf", true }, + { "portal", true }, + { "hl2", true }, + { "episodic", true }, + { "ep2", true } +}; + +CUtlVector< CUtlString > g_ExcludePaths; +BOOL g_bLinkGameDirs; + +inline bool PathLessThan( GamePath_t const &lhs, GamePath_t const &rhs ) +{ + if ( lhs.bIsModPath != rhs.bIsModPath ) + { + // sort mod paths to the bottom + return ( lhs.bIsModPath == false ); + } + + return ( stricmp( lhs.pathName.String(), rhs.pathName.String() ) < 0 ); +} +CUtlRBTree< GamePath_t > g_PathTable( 0, 0, PathLessThan ); + +//----------------------------------------------------------------------------- +// Add string to TreeView at specified level. Assumes an inorder insert. +// A node (at specified depth) must be inserted before it's children. +//----------------------------------------------------------------------------- +static HTREEITEM AddItemToTree( HWND hWndTree, LPSTR lpszItem, int nLevel, bool bIsModPath ) +{ + TVITEM tvi = { 0 }; + TVINSERTSTRUCT tvins = { 0 }; + static HTREEITEM s_hPrevItems[MAX_TREE_DEPTH]; + + if ( nLevel < 0 || nLevel >= MAX_TREE_DEPTH ) + { + Assert( 0 ); + return NULL; + } + + HTREEITEM hParent; + HTREEITEM hPrev; + if ( !nLevel ) + { + // one root item only, reset + for ( int i = 0; i < ARRAYSIZE( s_hPrevItems ); i++ ) + { + s_hPrevItems[i] = NULL; + } + hParent = TVI_ROOT; + hPrev = (HTREEITEM)TVI_FIRST; + } + else + { + hParent = s_hPrevItems[nLevel-1]; + hPrev = s_hPrevItems[nLevel]; + if ( !hParent ) + { + // parent should have been setup + Assert( 0 ); + return NULL; + } + if ( !hPrev ) + { + hPrev = TVI_FIRST; + } + } + + tvi.mask = TVIF_TEXT | TVIF_PARAM; + tvi.pszText = lpszItem; + tvi.cchTextMax = sizeof(tvi.pszText)/sizeof(tvi.pszText[0]); + tvi.lParam = (LPARAM)MAKELONG( nLevel, bIsModPath ); + + tvins.item = tvi; + tvins.hParent = hParent; + tvins.hInsertAfter = hPrev; + + // Add the item to the tree-view control. + hPrev = TreeView_InsertItem( hWndTree, &tvins ); + s_hPrevItems[nLevel] = hPrev; + + if ( nLevel > 0 ) + { + // set a back link to its parent + tvi.mask = TVIF_HANDLE; + tvi.hItem = TreeView_GetParent( hWndTree, hPrev ); + TreeView_SetItem( hWndTree, &tvi ); + } + + return hPrev; +} + +//----------------------------------------------------------------------------- +// Purpose: Get list of files from current path that match pattern +//----------------------------------------------------------------------------- +static int GetFileList( const char* pDirPath, const char* pPattern, CUtlVector< CUtlString > &fileList ) +{ + char sourcePath[MAX_PATH]; + char fullPath[MAX_PATH]; + bool bFindDirs; + + fileList.Purge(); + + strcpy( sourcePath, pDirPath ); + int len = (int)strlen( sourcePath ); + if ( !len ) + { + strcpy( sourcePath, ".\\" ); + } + else if ( sourcePath[len-1] != '\\' ) + { + sourcePath[len] = '\\'; + sourcePath[len+1] = '\0'; + } + + strcpy( fullPath, sourcePath ); + if ( pPattern[0] == '\\' && pPattern[1] == '\0' ) + { + // find directories only + bFindDirs = true; + strcat( fullPath, "*" ); + } + else + { + // find files, use provided pattern + bFindDirs = false; + strcat( fullPath, pPattern ); + } + + struct _finddata_t findData; + intptr_t h = _findfirst( fullPath, &findData ); + if ( h == -1 ) + { + return 0; + } + + do + { + // dos attribute complexities i.e. _A_NORMAL is 0 + if ( bFindDirs ) + { + // skip non dirs + if ( !( findData.attrib & _A_SUBDIR ) ) + continue; + } + else + { + // skip dirs + if ( findData.attrib & _A_SUBDIR ) + continue; + } + + if ( !stricmp( findData.name, "." ) ) + continue; + + if ( !stricmp( findData.name, ".." ) ) + continue; + + char fileName[MAX_PATH]; + strcpy( fileName, sourcePath ); + strcat( fileName, findData.name ); + + int j = fileList.AddToTail(); + fileList[j].Set( fileName ); + } + while ( !_findnext( h, &findData ) ); + + _findclose( h ); + + return fileList.Count(); +} + +//----------------------------------------------------------------------------- +// Purpose: Recursively determine directory tree +//----------------------------------------------------------------------------- +static void RecurseFileTree_r( const char *pBasePath, const char *pDirPath, int depth, CUtlVector< CUtlString > &dirList, bool bIsModPath ) +{ + if ( depth >= 2 ) + { + // too much unecessary detail + return; + } + + // ignore path roots, only interested in subdirs + const char *pSubName = pDirPath + strlen( pBasePath ); + if ( pSubName[0] ) + { + GamePath_t gamePath; + gamePath.pathName = pSubName; + gamePath.bIsModPath = bIsModPath; + + int iIndex = g_PathTable.Find( gamePath ); + if ( iIndex == g_PathTable.InvalidIndex() ) + { + g_PathTable.Insert( gamePath ); + } + } + + // recurse from source directory, get directories only + CUtlVector< CUtlString > fileList; + int dirCount = GetFileList( pDirPath, "\\", fileList ); + if ( !dirCount ) + { + // add directory name to search tree + int j = dirList.AddToTail(); + dirList[j].Set( pDirPath ); + return; + } + + for ( int i=0; i<dirCount; i++ ) + { + // form new path name, recurse into + RecurseFileTree_r( pBasePath, fileList[i].String(), depth+1, dirList, bIsModPath ); + } + + int j = dirList.AddToTail(); + dirList[j].Set( pDirPath ); +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_SetCheckState_r +// +// Propogate the check state to all children +//----------------------------------------------------------------------------- +void ExcludePathsDlg_SetCheckState_r( HWND hWndTree, HTREEITEM hTree, int depth, int checkState ) +{ + if ( !hTree ) + { + return; + } + + TreeView_SetCheckState( hWndTree, hTree, ( checkState == 1 ) ); + + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN; + tvi.hItem = hTree; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_SetCheckState_r( hWndTree, hChild, depth+1, checkState ); + } + } + } + else + { + return; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + return; + } + + TreeView_SetCheckState( hWndTree, hSibling, ( checkState == 1 ) ); + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_SetCheckState_r( hWndTree, hChild, depth+1, checkState ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_SetCheckStateLinked_r +// +// Propogate the check state to all "mod path" children that match the specified name. +// A NULL name matches all. +//----------------------------------------------------------------------------- +void ExcludePathsDlg_SetCheckStateLinked_r( HWND hWndTree, HTREEITEM hTree, int depth, int checkState, const char *pName ) +{ + if ( !hTree ) + { + return; + } + + char szNodeName[MAX_PATH]; + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN | TVIF_TEXT | TVIF_PARAM; + tvi.hItem = hTree; + tvi.pszText = szNodeName; + tvi.cchTextMax = sizeof( szNodeName ); + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + bool bIsModPath = HIWORD( tvi.lParam ) != 0; + if ( bIsModPath && ( !pName || !V_stricmp( szNodeName, pName ) ) ) + { + TreeView_SetCheckState( hWndTree, hTree, ( checkState == 1 ) ); + } + + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_SetCheckStateLinked_r( hWndTree, hChild, depth+1, checkState, pName ); + } + } + } + else + { + return; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + return; + } + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + bool bIsModPath = HIWORD( tvi.lParam ) != 0; + if ( bIsModPath && ( !pName || !V_stricmp( szNodeName, pName ) ) ) + { + TreeView_SetCheckState( hWndTree, hSibling, ( checkState == 1 ) ); + } + + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_SetCheckStateLinked_r( hWndTree, hChild, depth+1, checkState, pName ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_GetCheckState_r +// +// Caller invokes at node. Returns with state set. +// State 0: unchecked, 1: checked, -1:unknown. +// Returns true if All children match, false otherwise. +//----------------------------------------------------------------------------- +bool ExcludePathsDlg_GetCheckState_r( HWND hWndTree, HTREEITEM hTree, int depth, int *pCheckState ) +{ + int checkState; + + checkState = TreeView_GetCheckState( hWndTree, hTree ); + if ( *pCheckState == -1 ) + { + *pCheckState = checkState; + } + else if ( *pCheckState != checkState ) + { + // disparate state, no need to recurse + return false; + } + + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN; + tvi.hItem = hTree; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + if ( !ExcludePathsDlg_GetCheckState_r( hWndTree, hChild, depth+1, pCheckState ) ) + { + return false; + } + } + } + } + else + { + return false; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return true; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + break; + } + + checkState = TreeView_GetCheckState( hWndTree, hSibling ); + if ( *pCheckState != checkState ) + { + // disparate state, no need to recurse + return false; + } + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + if ( !ExcludePathsDlg_GetCheckState_r( hWndTree, hChild, depth+1, pCheckState ) ) + { + return false; + } + } + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Expand_r +// +// MaxDepth >= 0, Expand/Collapse up to specified depth. +//----------------------------------------------------------------------------- +void ExcludePathsDlg_Expand_r( HWND hWndTree, HTREEITEM hTree, int depth, int maxDepth, bool bExpand ) +{ + if ( !hTree ) + { + return; + } + + if ( maxDepth >= 0 && depth >= maxDepth ) + { + return; + } + + int flags; + if ( bExpand ) + flags = TVE_EXPAND; + else + flags = TVE_COLLAPSE; + + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN; + tvi.hItem = hTree; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + TreeView_Expand( hWndTree, hTree, flags ); + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_Expand_r( hWndTree, hChild, depth+1, maxDepth, bExpand ); + } + } + } + else + { + return; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + return; + } + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + if ( tvi.cChildren ) + { + TreeView_Expand( hWndTree, hSibling, flags ); + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_Expand_r( hWndTree, hChild, depth+1, maxDepth, bExpand ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_ExpandToShowState_r +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_ExpandToShowState_r( HWND hWndTree, HTREEITEM hTree, int depth ) +{ + if ( !hTree ) + { + return; + } + + TVITEM tvi = { 0 }; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN; + tvi.hItem = hTree; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + int checkState = -1; + bool bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hTree, 0, &checkState ); + + if ( tvi.cChildren && !bStateIsSame ) + { + TreeView_Expand( hWndTree, hTree, TVE_EXPAND ); + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_ExpandToShowState_r( hWndTree, hChild, depth+1 ); + } + } + } + else + { + return; + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + return; + } + + tvi.hItem = hSibling; + if ( TreeView_GetItem( hWndTree, &tvi ) ) + { + int checkState = -1; + bool bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hSibling, 0, &checkState ); + + if ( tvi.cChildren && !bStateIsSame ) + { + TreeView_Expand( hWndTree, hSibling, TVE_EXPAND ); + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_ExpandToShowState_r( hWndTree, hChild, depth+1 ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Find_r +// +//----------------------------------------------------------------------------- +HTREEITEM ExcludePathsDlg_Find_r( HWND hWndTree, HTREEITEM hTree, int depth, const char *pBasePath, const char *pFindPath ) +{ + TVITEM tvi = { 0 }; + char szName[MAX_PATH]; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN | TVIF_TEXT; + tvi.hItem = hTree; + tvi.pszText = szName; + tvi.cchTextMax = sizeof( szName ); + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + return NULL; + } + + char szPath[MAX_PATH]; + V_ComposeFileName( pBasePath, szName, szPath, sizeof( szPath ) ); + if ( !stricmp( szPath, pFindPath ) ) + { + return hTree; + } + + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + HTREEITEM hFindTree = ExcludePathsDlg_Find_r( hWndTree, hChild, depth+1, szPath, pFindPath ); + if ( hFindTree ) + { + return hFindTree; + } + } + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return NULL; + } + + // iterate siblings + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + break; + } + + tvi.hItem = hSibling; + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + break; + } + + V_ComposeFileName( pBasePath, szName, szPath, sizeof( szPath ) ); + if ( !stricmp( szPath, pFindPath ) ) + { + return hSibling; + } + + if ( tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + HTREEITEM hFindTree = ExcludePathsDlg_Find_r( hWndTree, hChild, depth+1, szPath, pFindPath ); + if ( hFindTree ) + { + return hFindTree; + } + } + } + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_BuildExcludeList_r +// +// An exclude path represents the path head, and thus does not need to iterate its children +// if they are deemed to the same exclusion state. +//----------------------------------------------------------------------------- +void ExcludePathsDlg_BuildExcludeList_r( HWND hWndTree, HTREEITEM hTree, int depth, const char *pPath ) +{ + int checkState = -1; + bool bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hTree, 0, &checkState ); + if ( checkState == -1 ) + { + return; + } + + TVITEM tvi = { 0 }; + char szName[MAX_PATH]; + tvi.mask = TVIF_HANDLE | TVIF_CHILDREN | TVIF_TEXT; + tvi.hItem = hTree; + tvi.pszText = szName; + tvi.cchTextMax = sizeof( szName ); + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + return; + } + + char szPath[MAX_PATH]; + V_ComposeFileName( pPath, szName, szPath, sizeof( szPath ) ); + + if ( checkState == 1 && ( bStateIsSame || !tvi.cChildren ) ) + { + // add to exclude list + g_ExcludePaths.AddToTail( szPath ); + } + + if ( !bStateIsSame && tvi.cChildren ) + { + // mixed states, must recurse to resolve + HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); + if ( hChild ) + { + ExcludePathsDlg_BuildExcludeList_r( hWndTree, hChild, depth+1, szPath ); + } + } + + if ( !depth ) + { + // only iterate siblings of the parent's child + return; + } + + // iterate siblings + HTREEITEM hSibling = hTree; + while ( 1 ) + { + hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); + if ( !hSibling ) + { + break; + } + + checkState = -1; + bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hSibling, 0, &checkState ); + if ( checkState == -1 ) + { + break; + } + + tvi.hItem = hSibling; + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + break; + } + + V_ComposeFileName( pPath, szName, szPath, sizeof( szPath ) ); + + if ( checkState == 1 && ( bStateIsSame || !tvi.cChildren ) ) + { + // add to exclude list + g_ExcludePaths.AddToTail( szPath ); + } + + if ( !bStateIsSame && tvi.cChildren ) + { + HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); + if ( hChild ) + { + ExcludePathsDlg_BuildExcludeList_r( hWndTree, hChild, depth+1, szPath ); + } + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_SaveChanges +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_SaveChanges( HWND hWnd ) +{ + g_ExcludePaths.Purge(); + HWND hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + ExcludePathsDlg_BuildExcludeList_r( hWndTree, TreeView_GetRoot( hWndTree ), 0, "" ); + + char szPath[MAX_PATH]; + V_ComposeFileName( g_localPath, EXCLUDEPATHS_FILE, szPath, sizeof( szPath ) ); + + if ( !g_ExcludePaths.Count() ) + { + // no exclude paths + unlink( szPath ); + } + else + { + FILE *fp = fopen( szPath, "wt" ); + if ( !fp ) + { + Sys_MessageBox( "Error", "Could not open '%s' for writing\n", szPath ); + return; + } + + fprintf( fp, "// Auto-Generated by VXConsole - DO NOT MODIFY!\n" ); + for ( int i = 0; i < g_ExcludePaths.Count(); i++ ) + { + // strip expected root path + const char *pPath = g_ExcludePaths[i].String(); + pPath += strlen( ROOT_NAME ); + if ( !pPath[0] ) + { + // special code for root + fprintf( fp, "*\n" ); + break; + } + fprintf( fp, "\"\\%s\"\n", pPath ); + } + fclose( fp ); + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Populate +// +// Generate a path table. +//----------------------------------------------------------------------------- +void ExcludePathsDlg_Populate( HWND hWnd, bool bRefresh ) +{ + struct GamePath_t + { + CUtlString pathName; + bool bIsModPath; + }; + + CUtlVector< GamePath_t > gamePaths; + + // can skip the time consuming directory scan, unless forced + if ( bRefresh || !g_PathTable.Count() ) + { + g_PathTable.Purge(); + + for ( int i = 0; i < ARRAYSIZE( g_GameNames ); i++ ) + { + char szTargetPath[MAX_PATH]; + V_strncpy( szTargetPath, g_localPath, sizeof( szTargetPath ) ); + V_AppendSlash( szTargetPath, sizeof( szTargetPath ) ); + V_strncat( szTargetPath, g_GameNames[i].pName, sizeof( szTargetPath ) ); + + GamePath_t gamePath; + gamePath.pathName = szTargetPath; + gamePath.bIsModPath = g_GameNames[i].bIsModPath; + gamePaths.AddToTail( gamePath ); + } + + // iterate all game paths + for ( int i = 0; i < gamePaths.Count(); i++ ) + { + CUtlVector< CUtlString > dirList; + RecurseFileTree_r( g_localPath, gamePaths[i].pathName.String(), 0, dirList, gamePaths[i].bIsModPath ); + } + } + + // reset the tree + HWND hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + TreeView_DeleteAllItems( hWndTree ); + + // reset and add root + // only the root is at depth 0 + AddItemToTree( hWndTree, ROOT_NAME, 0, false ); + + // build the tree view + for ( int iIndex = g_PathTable.FirstInorder(); iIndex != g_PathTable.InvalidIndex(); iIndex = g_PathTable.NextInorder( iIndex ) ) + { + // due to sorting, number of slashes is depth + const char *pString = g_PathTable[iIndex].pathName.String(); + int depth = 0; + for ( int j = 0; j < (int)strlen( pString ); j++ ) + { + if ( pString[j] == '\\' ) + { + depth++; + } + } + if ( !depth ) + { + depth = 1; + } + + char szPath[MAX_PATH]; + V_FileBase( pString, szPath, sizeof( szPath ) ); + AddItemToTree( hWndTree, szPath, depth, g_PathTable[iIndex].bIsModPath ); + } + + HTREEITEM hTreeRoot = TreeView_GetRoot( hWndTree ); + for ( int i = 0; i < g_ExcludePaths.Count(); i++ ) + { + HTREEITEM hTree = ExcludePathsDlg_Find_r( hWndTree, hTreeRoot, 0, "", g_ExcludePaths[i].String() ); + if ( hTree ) + { + ExcludePathsDlg_SetCheckState_r( hWndTree, hTree, 0, true ); + } + } + + // expand the root node to show state + ExcludePathsDlg_ExpandToShowState_r( hWndTree, hTreeRoot, 0 ); +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Setup +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_Setup( HWND hWnd ) +{ + TreeView_SetBkColor( GetDlgItem( hWnd, IDC_PATHS_TREE ), g_backgroundColor ); + + CheckDlgButton( hWnd, IDC_PATHS_LINKGAMEDIRS, g_bLinkGameDirs ? BST_CHECKED : BST_UNCHECKED ); + + // read the exisiting exclude paths + g_ExcludePaths.Purge(); + char szFilename[MAX_PATH]; + V_ComposeFileName( g_localPath, EXCLUDEPATHS_FILE, szFilename, sizeof( szFilename ) ); + if ( Sys_Exists( szFilename ) ) + { + Sys_LoadScriptFile( szFilename ); + while ( 1 ) + { + char *pToken = Sys_GetToken( true ); + if ( !pToken || !pToken[0] ) + { + break; + } + Sys_StripQuotesFromToken( pToken ); + if ( !stricmp( pToken, "*" ) ) + { + pToken = ""; + } + else if ( pToken[0] == '\\' ) + { + pToken++; + } + + char szPath[MAX_PATH]; + V_ComposeFileName( ROOT_NAME, pToken, szPath, sizeof( szPath ) ); + V_FixSlashes( szPath ); + + g_ExcludePaths.AddToTail( szPath ); + } + } +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Proc +// +//----------------------------------------------------------------------------- +BOOL CALLBACK ExcludePathsDlg_Proc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + HWND hWndTree; + LPNMHDR lpnmh; + HTREEITEM hTree; + HTREEITEM hTreeRoot; + int checkState; + static bool s_bAllowPopulate = 0; + + switch ( message ) + { + case WM_INITDIALOG: + ExcludePathsDlg_Setup( hWnd ); + s_bAllowPopulate = true; + return TRUE; + + case WM_NOTIFY: + lpnmh = (LPNMHDR)lParam; + if ( ( lpnmh->code == NM_CLICK ) && ( lpnmh->idFrom == IDC_PATHS_TREE ) ) + { + TVHITTESTINFO ht = {0}; + DWORD dwpos = GetMessagePos(); + ht.pt.x = GET_X_LPARAM( dwpos ); + ht.pt.y = GET_Y_LPARAM( dwpos ); + MapWindowPoints( HWND_DESKTOP, lpnmh->hwndFrom, &ht.pt, 1 ); + TreeView_HitTest( lpnmh->hwndFrom, &ht ); + if ( ht.flags & TVHT_ONITEMSTATEICON ) + { + PostMessage( hWnd, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.hItem ); + } + } + break; + + case UM_CHECKSTATECHANGE: + hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + hTreeRoot = TreeView_GetRoot( hWndTree ); + hTree = (HTREEITEM)lParam; + checkState = TreeView_GetCheckState( hWndTree, hTree ); + if ( checkState != -1 ) + { + TVITEM tvi = { 0 }; + char szName[MAX_PATH]; + tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT; + tvi.hItem = hTree; + tvi.pszText = szName; + tvi.cchTextMax = sizeof( szName ); + if ( !TreeView_GetItem( hWndTree, &tvi ) ) + { + break; + } + int nDepth = LOWORD( tvi.lParam ); + bool bIsModPath = HIWORD( tvi.lParam ) != 0; + + if ( g_bLinkGameDirs && bIsModPath ) + { + // a mod path root is at depth 1 + // a child of a mod path (depth > 1), will match all other children in mod paths + // a mod path (depth = 1) will match all other modpaths + ExcludePathsDlg_SetCheckStateLinked_r( hWndTree, hTreeRoot, 0, checkState, nDepth == 1 ? NULL : szName ); + } + else + { + ExcludePathsDlg_SetCheckState_r( hWndTree, hTree, 0, checkState ); + } + } + break; + + case WM_PAINT: + if ( s_bAllowPopulate ) + { + // unfortunate, but tree view needs to paint first before its state can be set + // related to checkbox style which doesn't manifest until after WM_INITDIALOG + // stall the initial population until after the first paint + s_bAllowPopulate = false; + PostMessage( hWnd, UM_FIRSTTIMEPOPULATE, 0, 0 ); + } + break; + + case UM_FIRSTTIMEPOPULATE: + ExcludePathsDlg_Populate( hWnd, false ); + break; + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDC_OK: + ExcludePathsDlg_SaveChanges( hWnd ); + EndDialog( hWnd, wParam ); + return TRUE; + + case IDC_PATHS_RESCAN: + ExcludePathsDlg_Populate( hWnd, true ); + return TRUE; + + case IDC_PATHS_EXPAND: + // expand from root + hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + ExcludePathsDlg_Expand_r( hWndTree, TreeView_GetRoot( hWndTree ), 0, -1, true ); + return TRUE; + + case IDC_PATHS_COLLAPSE: + // collapse from root + hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); + ExcludePathsDlg_Expand_r( hWndTree, TreeView_GetRoot( hWndTree ), 0, -1, false ); + return TRUE; + + case IDC_PATHS_LINKGAMEDIRS: + g_bLinkGameDirs = IsDlgButtonChecked( hWnd, IDC_PATHS_LINKGAMEDIRS ); + return TRUE; + + case IDCANCEL: + case IDC_CANCEL: + EndDialog( hWnd, wParam ); + return TRUE; + } + break; + } + return FALSE; +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_LoadConfig +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_LoadConfig() +{ + // get our config + Sys_GetRegistryInteger( "ExcludePaths_LinkGameDirs", true, g_bLinkGameDirs ); +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_SaveConfig +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_SaveConfig() +{ + Sys_SetRegistryInteger( "ExcludePaths_LinkGameDirs", g_bLinkGameDirs ); +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Init +// +//----------------------------------------------------------------------------- +bool ExcludePathsDlg_Init() +{ + return true; +} + +//----------------------------------------------------------------------------- +// ExcludePathsDlg_Open +// +//----------------------------------------------------------------------------- +void ExcludePathsDlg_Open() +{ + ExcludePathsDlg_LoadConfig(); + + int result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_EXCLUDEPATHS ), g_hDlgMain, ( DLGPROC )ExcludePathsDlg_Proc ); + if ( LOWORD( result ) != IDC_OK ) + return; + + ExcludePathsDlg_SaveConfig(); +} diff --git a/utils/xbox/vxconsole/fileio.cpp b/utils/xbox/vxconsole/fileio.cpp new file mode 100644 index 0000000..9b9ca25 --- /dev/null +++ b/utils/xbox/vxconsole/fileio.cpp @@ -0,0 +1,416 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// FILEIO.CPP +// +// File I/O Service Routines +//=====================================================================================// +#include "vxconsole.h" + +//----------------------------------------------------------------------------- +// SystemTimeToString +// +// mm/dd/yyyy hh:mm:ss am +//----------------------------------------------------------------------------- +char *SystemTimeToString( SYSTEMTIME *systemTime, char *buffer, int bufferSize ) +{ + char timeString[256]; + char dateString[256]; + int length; + + GetDateFormat( LOCALE_SYSTEM_DEFAULT, 0, systemTime, "MM'/'dd'/'yyyy", dateString, sizeof( dateString ) ); + GetTimeFormat( LOCALE_SYSTEM_DEFAULT, 0, systemTime, "hh':'mm':'ss tt", timeString, sizeof( timeString ) ); + length = _snprintf( buffer, bufferSize, "%s %s", dateString, timeString ); + if ( length == -1 ) + buffer[bufferSize-1] = '\0'; + + return buffer; +} + +//----------------------------------------------------------------------------- +// CompareFileTimes_NTFStoFATX +// +//----------------------------------------------------------------------------- +int CompareFileTimes_NTFStoFATX( FILETIME* ntfsFileTime, char *ntfsTimeString, int ntfsStringSize, FILETIME* fatxFileTime, char *fatxTimeString, int fatxStringSize ) +{ + SYSTEMTIME ntfsSystemTime; + SYSTEMTIME fatxSystemTime; + int diff; + int ntfsSeconds; + int fatxSeconds; + + TIME_ZONE_INFORMATION tzInfo; + GetTimeZoneInformation( &tzInfo ); + + // cannot compare UTC file times directly + // disjoint filesystems - xbox has a +/- 2s error + // daylight savings time handling on each file system may cause problems + FileTimeToSystemTime( ntfsFileTime, &ntfsSystemTime ); + FileTimeToSystemTime( fatxFileTime, &fatxSystemTime ); + + // operate on local times, assumes xbox and pc are both set for same time zone and daylight saving + SYSTEMTIME ntfsLocalTime; + SYSTEMTIME fatxLocalTime; + SystemTimeToTzSpecificLocalTime( &tzInfo, &ntfsSystemTime, &ntfsLocalTime ); + SystemTimeToTzSpecificLocalTime( &tzInfo, &fatxSystemTime, &fatxLocalTime ); + + if ( ntfsTimeString ) + { + SystemTimeToString( &ntfsLocalTime, ntfsTimeString, ntfsStringSize ); + } + + if ( fatxTimeString ) + { + SystemTimeToString( &fatxLocalTime, fatxTimeString, fatxStringSize ); + } + + diff = ntfsLocalTime.wYear-fatxLocalTime.wYear; + if ( diff ) + return diff; + + diff = ntfsLocalTime.wMonth-fatxLocalTime.wMonth; + if ( diff ) + return diff; + + diff = ntfsLocalTime.wDay-fatxLocalTime.wDay; + if ( diff ) + return diff; + + diff = ntfsLocalTime.wHour-fatxLocalTime.wHour; + if ( diff ) + return diff; + + // allow for +/- 3s error + ntfsSeconds = ntfsLocalTime.wHour*60*60 + ntfsLocalTime.wMinute*60 + ntfsLocalTime.wSecond; + fatxSeconds = fatxLocalTime.wHour*60*60 + fatxLocalTime.wMinute*60 + fatxLocalTime.wSecond; + + diff = ntfsSeconds-fatxSeconds; + if ( diff > 3 || diff < -3 ) + return diff; + + // times are considered equal + return 0; +} + +//----------------------------------------------------------------------------- +// FreeTargetFileList +// +//----------------------------------------------------------------------------- +void FreeTargetFileList( fileNode_t* pFileList ) +{ + fileNode_t *nodePtr; + fileNode_t *nextPtr; + + if ( !pFileList ) + return; + + nodePtr = pFileList; + while ( nodePtr ) + { + nextPtr = nodePtr->nextPtr; + + Sys_Free( nodePtr->filename ); + Sys_Free( nodePtr ); + + nodePtr = nextPtr; + } +} + +//----------------------------------------------------------------------------- +// GetTargetFileList_r +// +//----------------------------------------------------------------------------- +bool GetTargetFileList_r( char* targetPath, bool recurse, int attributes, int level, fileNode_t** pFileList ) +{ + HRESULT hr; + PDM_WALK_DIR pWalkDir = NULL; + DM_FILE_ATTRIBUTES fileAttr; + bool valid; + char filename[MAX_PATH]; + fileNode_t* nodePtr; + bool bGetNormal; + int fixedAttributes; + + if ( !level ) + *pFileList = NULL; + + fixedAttributes = attributes; + if ( fixedAttributes & FILE_ATTRIBUTE_NORMAL ) + { + fixedAttributes &= ~FILE_ATTRIBUTE_NORMAL; + bGetNormal = true; + } + else + bGetNormal = false; + + while ( 1 ) + { + hr = DmWalkDir( &pWalkDir, targetPath, &fileAttr ); + if ( hr != XBDM_NOERR ) + break; + + strcpy( filename, targetPath ); + Sys_AddFileSeperator( filename, sizeof( filename ) ); + strcat( filename, fileAttr.Name ); + + // restrict to desired attributes + if ( ( bGetNormal && !fileAttr.Attributes ) || ( fileAttr.Attributes & fixedAttributes ) ) + { + Sys_NormalizePath( filename, false ); + + // create a new file node + nodePtr = ( fileNode_t* )Sys_Alloc( sizeof( fileNode_t ) ); + + // link it in + nodePtr->filename = Sys_CopyString( filename ); + nodePtr->changeTime = fileAttr.ChangeTime; + nodePtr->creationTime = fileAttr.CreationTime; + nodePtr->sizeHigh = fileAttr.SizeHigh; + nodePtr->sizeLow = fileAttr.SizeLow; + nodePtr->attributes = fileAttr.Attributes; + nodePtr->level = level; + nodePtr->nextPtr = *pFileList; + *pFileList = nodePtr; + } + + if ( fileAttr.Attributes & FILE_ATTRIBUTE_DIRECTORY ) + { + if ( recurse ) + { + // descend into directory + valid = GetTargetFileList_r( filename, recurse, attributes, level+1, pFileList ); + if ( !valid ) + return false; + } + } + } + DmCloseDir( pWalkDir ); + + if ( hr != XBDM_ENDOFLIST ) + { + // failure + return false; + } + + // ok + return true; +} + +//----------------------------------------------------------------------------- +// FileSyncEx +// +// -1: failure, 0: nothing, 1: synced +//----------------------------------------------------------------------------- +int FileSyncEx( const char* localFilename, const char* targetFilename, int fileSyncMode, bool bVerbose, bool bNoWrite ) +{ + bool copy; + bool pathExist; + WIN32_FILE_ATTRIBUTE_DATA localAttributes; + DM_FILE_ATTRIBUTES targetAttributes; + HRESULT hr; + int errCode; + int deltaTime; + char localTimeString[256]; + char targetTimeString[256]; + + if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_OFF ) + { + return 0; + } + + if ( !GetFileAttributesEx( localFilename, GetFileExInfoStandard, &localAttributes ) ) + { + // failed to get the local file's attributes + if ( bVerbose ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failure: Local file %s not available\n", localFilename ); + } + return -1; + } + + if ( localAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + // ignore directory + return 0; + } + + if ( fileSyncMode & FSYNC_ANDEXISTSONTARGET ) + { + hr = DmGetFileAttributes( targetFilename, &targetAttributes ); + if ( hr != XBDM_NOERR ) + { + // target doesn't exist, no sync operation should commence + if ( bVerbose ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, Target file %s not available\n", targetFilename ); + } + return 0; + } + } + + // default success, no operation + errCode = 0; + + // default, create path and copy + copy = true; + pathExist = false; + + if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_IFNEWER ) + { + hr = DmGetFileAttributes( targetFilename, &targetAttributes ); + if ( hr == XBDM_NOERR ) + { + // target path to file exists + pathExist = true; + + // compare times + deltaTime = CompareFileTimes_NTFStoFATX( &localAttributes.ftLastWriteTime, localTimeString, sizeof( localTimeString), &targetAttributes.ChangeTime, targetTimeString, sizeof( targetTimeString ) ); + if ( deltaTime < 0 ) + { + // ntfs is older, fatx is newer, no update + if ( bVerbose ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, %s [%s] is newer than %s [%s]\n", targetFilename, targetTimeString, localFilename, localTimeString ); + } + copy = false; + } + else if ( !deltaTime ) + { + // equal times, compare sizes + if ( localAttributes.nFileSizeLow == targetAttributes.SizeLow && + localAttributes.nFileSizeHigh == targetAttributes.SizeHigh ) + { + // file appears synced + copy = false; + } + if ( bVerbose ) + { + if ( copy ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Update, %s [%s] [%d] has different size than %s [%s] [%d]\n", targetFilename, targetTimeString, targetAttributes.SizeLow, localFilename, localTimeString, localAttributes.nFileSizeLow ); + } + else + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "No Update, %s [%s] [%d] has same time and file size as %s [%s] [%d]\n", targetFilename, targetTimeString, targetAttributes.SizeLow, localFilename, localTimeString, localAttributes.nFileSizeLow ); + } + } + } + else + { + // ntfs is newer, fatx is older, update + if ( bVerbose ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Update, %s [%s] is older than %s [%s]\n", targetFilename, targetTimeString, localFilename, localTimeString ); + } + } + } + } + else if ( ( fileSyncMode & FSYNC_TYPEMASK ) == FSYNC_ALWAYS ) + { + if ( bVerbose ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Force Update, %s\n", targetFilename ); + } + } + + if ( copy && !bNoWrite ) + { + if ( !pathExist ) + { + CreateTargetPath( targetFilename ); + } + + hr = DmSendFile( localFilename, targetFilename ); + if ( hr == XBDM_NOERR ) + { + // force the target to match the local attributes + // to ensure sync + memset( &targetAttributes, 0, sizeof( targetAttributes ) ); + targetAttributes.SizeHigh = localAttributes.nFileSizeHigh; + targetAttributes.SizeLow = localAttributes.nFileSizeLow; + targetAttributes.CreationTime = localAttributes.ftCreationTime; + targetAttributes.ChangeTime = localAttributes.ftLastWriteTime; + DmSetFileAttributes( targetFilename, &targetAttributes ); + + // success, file copied + errCode = 1; + } + else + { + // failure + if ( bVerbose ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failed!\n" ); + } + errCode = -1; + } + + DebugCommand( "0x%8.8x = FileSyncEx( %s, %s )\n", hr, localFilename, targetFilename ); + } + + return errCode; +} + +//----------------------------------------------------------------------------- +// LoadTargetFile +// +//----------------------------------------------------------------------------- +bool LoadTargetFile( const char *pTargetPath, int *pFileSize, void **pData ) +{ + DM_FILE_ATTRIBUTES fileAttributes; + HRESULT hr; + DWORD bytesRead; + char *pBuffer; + + *pFileSize = 0; + *pData = (void *)NULL; + + hr = DmGetFileAttributes( pTargetPath, &fileAttributes ); + if ( hr != XBDM_NOERR || !fileAttributes.SizeLow ) + return false; + + // allocate for size and terminating null + pBuffer = (char *)Sys_Alloc( fileAttributes.SizeLow+1 ); + + hr = DmReadFilePartial( pTargetPath, 0, (LPBYTE)pBuffer, fileAttributes.SizeLow, &bytesRead ); + if ( hr != XBDM_NOERR || ( bytesRead != fileAttributes.SizeLow ) ) + { + Sys_Free( pBuffer ); + return false; + } + + // add a terminating null + pBuffer[fileAttributes.SizeLow] = '\0'; + + *pFileSize = fileAttributes.SizeLow; + *pData = pBuffer; + + // success + return true; +} + +//----------------------------------------------------------------------------- +// CreateTargetPath +// +//----------------------------------------------------------------------------- +bool CreateTargetPath( const char *pTargetFilename ) +{ + // create path chain + char *pPath; + char dirPath[MAX_PATH]; + + // prime and skip to first seperator + strcpy( dirPath, pTargetFilename ); + pPath = strchr( dirPath, '\\' ); + while ( pPath ) + { + pPath = strchr( pPath+1, '\\' ); + if ( pPath ) + { + *pPath = '\0'; + DmMkdir( dirPath ); + *pPath = '\\'; + } + } + + return true; +} diff --git a/utils/xbox/vxconsole/icon_connect1.ico b/utils/xbox/vxconsole/icon_connect1.ico Binary files differnew file mode 100644 index 0000000..dd373b0 --- /dev/null +++ b/utils/xbox/vxconsole/icon_connect1.ico diff --git a/utils/xbox/vxconsole/icon_connect2.ico b/utils/xbox/vxconsole/icon_connect2.ico Binary files differnew file mode 100644 index 0000000..638dd28 --- /dev/null +++ b/utils/xbox/vxconsole/icon_connect2.ico diff --git a/utils/xbox/vxconsole/icon_connect2a.ico b/utils/xbox/vxconsole/icon_connect2a.ico Binary files differnew file mode 100644 index 0000000..61473ea --- /dev/null +++ b/utils/xbox/vxconsole/icon_connect2a.ico diff --git a/utils/xbox/vxconsole/icon_disconnect.ico b/utils/xbox/vxconsole/icon_disconnect.ico Binary files differnew file mode 100644 index 0000000..2146fe3 --- /dev/null +++ b/utils/xbox/vxconsole/icon_disconnect.ico diff --git a/utils/xbox/vxconsole/local_cmds.cpp b/utils/xbox/vxconsole/local_cmds.cpp new file mode 100644 index 0000000..05e5cdb --- /dev/null +++ b/utils/xbox/vxconsole/local_cmds.cpp @@ -0,0 +1,1307 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// LOCAL_CMDS.CPP +// +// Local commands ( *xxxx ) executed by this application. +//=====================================================================================// +#include "vxconsole.h" + +localCommand_t g_localCommands[] = +{ + // Command name, Flags Handler Help string + // console commands + { "*cls", FN_CONSOLE, lc_cls, ": Clear the screen" }, + { "*connect", FN_CONSOLE, lc_autoConnect, ": Connect and listen until successful" }, + { "*disconnect", FN_CONSOLE, lc_disconnect, ": Terminate Debug Console session" }, + { "*help", FN_CONSOLE, lc_help, "[command] : List commands/usage" }, + { "*quit", FN_CONSOLE, lc_quit, ": Terminate console" }, + { "*run", FN_XBOX, lc_run, "[app.xex] : Run application or Reboot" }, + { "*reset", FN_XBOX, lc_reset, "Reboot" }, + { "*screenshot", FN_XBOX, lc_screenshot, "<file.bmp> : Copy the screen to file.bmp" }, + { "*memory", FN_APP, lc_memory, ": Dump Memory Stats" }, + { "*dir", FN_XBOX, lc_dir, "<filepath> [/s]: Directory listing" }, + { "*del", FN_XBOX, lc_del, "<filepath> [/s] [/q]: Delete file" }, + { "*modules", FN_XBOX, lc_modules, ": Lists currently loaded modules" }, + { "*sections", FN_XBOX, lc_sections, "<module> : Lists the sections in the module" }, + { "*bug", FN_CONSOLE, lc_bug, ": Open bug submission form" }, + { "*clearconfigs", FN_XBOX, lc_ClearConfigs, ": Erase all game configs" }, + + // xcommands + { "*break", FN_XBOX, NULL, " addr=<address> | 'Write'/'Read'/'Execute'=<address> size=<DataSize> ['clear']: Sets/Clears a breakpoint" }, +// { "*bye", FN_XBOX, NULL, ": Closes connection" }, + { "*continue", FN_XBOX, NULL, " thread=<threadid>: Resumes execution of a thread which has been stopped" }, +// { "*delete", FN_XBOX, NULL, " name=<remotefile>: Deletes a file on the Xbox" }, +// { "*dirlist", FN_XBOX, NULL, " name=<remotedir>: Lists the items in the directory" }, + { "*getcontext", FN_XBOX, NULL, " thread=<threadid> 'Control' | 'Int' | 'FP' | 'Full': Gets the context of the thread" }, + { "*getfileattributes", FN_XBOX, NULL, " name=<remotefile>: Gets attributes of a file" }, + { "*getmem", FN_XBOX, NULL, " addr=<address> length=<len>: Reads memory from the Xbox" }, + { "*go", FN_XBOX, NULL, ": Resumes suspended title threads" }, + { "*halt", FN_XBOX, NULL, " thread=<threadid> Breaks a thread" }, + { "*isstopped", FN_XBOX, NULL, " thread=<threadid>: Determines if a thread is stopped and why" }, + { "*mkdir", FN_XBOX, NULL, " name=<remotedir>: Creates a new directory on the Xbox" }, + { "*modlong", FN_XBOX, NULL, " name=<module>: Lists the long name of the module" }, +// { "*reboot", FN_XBOX, NULL, " [warm] [wait]: Reboots the xbox" }, + { "*rename", FN_XBOX, NULL, " name=<remotefile> newname=<newname>: Renames a file on the Xbox" }, + { "*resume", FN_XBOX, NULL, " thread=<threadid>: Resumes thread execution" }, + { "*setcontext", FN_XBOX, NULL, " thread=<threadid>: Sets the context of the thread." }, + { "*setfileattributes", FN_XBOX, NULL, " <remotefile> <attrs>: Sets attributes of a file" }, + { "*setmem", FN_XBOX, NULL, " addr=<address> data=<rawdata>: Sets memory on the Xbox" }, + { "*stop", FN_XBOX, NULL, ": Stops the process" }, + { "*suspend", FN_XBOX, NULL, " thread=<threadid>: Suspends the thread" }, + { "*systime", FN_XBOX, NULL, ": Gets the system time of the xbox" }, + { "*threadinfo", FN_XBOX, NULL, " thread=<threadid>: Gets thread info" }, + { "*threads", FN_XBOX, lc_threads, ": Gets the thread list" }, +// { "*title", FN_XBOX, NULL, " dir=<remotedir> name=<remotexex> [cmdline=<cmdline>]: Sets title to run" }, + { "*xexinfo", FN_XBOX, NULL, " name=<remotexex | 'running'>: Gets info on an xex" }, + { "*crash", FN_XBOX, lc_crashdump, " crash the console, emitting a dump" }, +}; +const int g_numLocalCommands = sizeof( g_localCommands )/sizeof( g_localCommands[0] ); + +static BOOL g_bAutoConnectQuiet; +static int g_bAutoConnectWait; + +//----------------------------------------------------------------------------- +// MatchCommands +// +//----------------------------------------------------------------------------- +int MatchLocalCommands( char* cmdStr, const char* cmdList[], int maxCmds ) +{ + int numCommands = 0; + + // look in local + int matchLen = strlen( cmdStr ); + for ( int i=0; i<g_numLocalCommands; i++ ) + { + if ( !strnicmp( cmdStr, g_localCommands[i].strCommand, matchLen ) ) + { + cmdList[numCommands++] = g_localCommands[i].strCommand; + if ( numCommands >= maxCmds ) + break; + } + } + + return ( numCommands ); +} + +//----------------------------------------------------------------------------- +// DecodeRebootArgs +// +//----------------------------------------------------------------------------- +void DecodeRebootArgs( int argc, char** argv, char* xexPath, char* xexName, char* xexArgs ) +{ + char drive[MAX_PATH]; + char dir[MAX_PATH]; + char filename[MAX_PATH]; + char extension[MAX_PATH]; + + xexPath[0] = '\0'; + xexName[0] = '\0'; + xexArgs[0] = '\0'; + + if ( !argc ) + return; + + _splitpath( argv[0], drive, dir, filename, extension ); + + sprintf( xexPath, "%s%s", drive, dir ); + sprintf( xexName, "%s%s", filename, extension ); + + for ( int i=1; i<argc; i++ ) + { + strcat( xexArgs, argv[i] ); + if ( i < argc-1 ) + strcat( xexArgs, " " ); + } +} + +//----------------------------------------------------------------------------- +// Helper function. Causes a disconnect, has optional re-connect time. +// A non-zero wait will delay before attempting re-connect. +//----------------------------------------------------------------------------- +void DoDisconnect( BOOL bKeepConnection, int waitTime ) +{ + // save state, user gates auto-connect ability + int autoConnect = g_autoConnect; + + // full disconnect, disables autoconnect + lc_disconnect( 0, NULL ); + + if ( autoConnect && bKeepConnection && waitTime > 0 ) + { + // restore autoconnect status + lc_autoConnect( 0, NULL ); + + // lets the system settle a little between contexts + g_bAutoConnectWait = waitTime; + g_bAutoConnectQuiet = FALSE; + } +} + +//----------------------------------------------------------------------------- +// lc_bug +// +//----------------------------------------------------------------------------- +BOOL lc_bug( int argc, char* argv[] ) +{ + if ( argc != 1 ) + { + char* args[2] = {"*help", argv[0]}; + lc_help( 1, args ); + goto cleanUp; + } + + BugDlg_Open(); + + return TRUE; + +cleanUp: + return FALSE; +} + +//----------------------------------------------------------------------------- +// lc_dir +// +//----------------------------------------------------------------------------- +BOOL lc_dir( int argc, char* argv[] ) +{ + fileNode_t *nodePtr; + fileNode_t *pFileList; + int numFiles; + int numDirs; + __int64 totalBytes; + bool recurse; + char dateTimeString[256]; + char sizeString[64]; + char filePath[MAX_PATH]; + char fileName[MAX_PATH]; + char targetName[MAX_PATH]; + char newPath[MAX_PATH]; + SYSTEMTIME systemTime; + SYSTEMTIME localTime; + const char *dirString; + BOOL errCode; + int nPass; + TIME_ZONE_INFORMATION tzInfo; + + pFileList = NULL; + errCode = FALSE; + + if ( argc < 2 ) + { + char* args[2] = {"*dir", argv[0]}; + lc_help( 2, args ); + goto cleanUp; + } + + strcpy( newPath, argv[1] ); + + // seperate components + Sys_StripFilename( newPath, filePath, sizeof( filePath ) ); + Sys_StripPath( newPath, fileName, sizeof( fileName ) ); + + if ( fileName[0] ) + { + if ( !strstr( fileName,"*" ) && !strstr( fileName,"?" ) ) + { + // assume filename was a directory name + strcat( newPath, "\\" ); + Sys_StripFilename( newPath, filePath, sizeof( filePath ) ); + Sys_StripPath( newPath, fileName, sizeof( fileName ) ); + } + } + + recurse = false; + if ( argc >= 3 ) + { + if ( !stricmp( argv[2], "/s" ) ) + recurse = true; + } + + if ( !GetTargetFileList_r( filePath, recurse, FA_NORMAL|FA_DIRECTORY|FA_READONLY, 0, &pFileList ) ) + { + ConsoleWindowPrintf( RGB( 255,0,0 ), "Bad Target Path '%s'\n", filePath ); + goto cleanUp; + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\nDirectory of %s\n\n", argv[1] ); + + GetTimeZoneInformation( &tzInfo ); + + numFiles = 0; + numDirs = 0; + totalBytes = 0; + for ( nPass=0; nPass<2; nPass++ ) + { + for ( nodePtr=pFileList; nodePtr; nodePtr=nodePtr->nextPtr ) + { + if ( !nPass && !( nodePtr->attributes & FA_DIRECTORY ) ) + { + // first pass, dirs only + continue; + } + else if ( nPass && ( nodePtr->attributes & FA_DIRECTORY ) ) + { + // second pass, files only + continue; + } + + Sys_StripPath( nodePtr->filename, targetName, sizeof( targetName ) ); + + if ( fileName[0] && !Sys_IsWildcardMatch( fileName, targetName, false ) ) + continue; + + FileTimeToSystemTime( &nodePtr->changeTime, &systemTime ); + SystemTimeToTzSpecificLocalTime( &tzInfo, &systemTime, &localTime ); + SystemTimeToString( &localTime, dateTimeString, sizeof( dateTimeString ) ); + + __int64 fullSize = MAKEINT64( nodePtr->sizeHigh, nodePtr->sizeLow ); + + if ( nodePtr->attributes & FA_DIRECTORY ) + { + numDirs++; + dirString = "<DIR>"; + sprintf( sizeString, "%s", " " ); + } + else + { + numFiles++; + dirString = " "; + Sys_NumberToCommaString( fullSize, sizeString, sizeof( sizeString ) ); + totalBytes += fullSize; + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s %12s %s\n", dateTimeString, dirString, sizeString, targetName ); + } + } + + Sys_NumberToCommaString( totalBytes, sizeString, sizeof( sizeString ) ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%9s %d File(s) %s bytes\n", " ", numFiles, sizeString ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%9s %d Dir(s)\n", " ", numDirs ); + + // success + errCode = TRUE; + +cleanUp: + if ( pFileList ) + FreeTargetFileList( pFileList ); + + return errCode; +} + +//----------------------------------------------------------------------------- +// lc_del +// +//----------------------------------------------------------------------------- +BOOL lc_del( int argc, char* argv[] ) +{ + HRESULT hr; + fileNode_t *nodePtr; + fileNode_t *pFileList; + int numDeleted; + int numErrors; + bool recurse; + char filePath[MAX_PATH]; + char fileName[MAX_PATH]; + char targetName[MAX_PATH]; + BOOL errCode; + + pFileList = NULL; + errCode = FALSE; + + if ( argc < 2 ) + { + char* args[2] = {"*del", argv[0]}; + lc_help( 2, args ); + goto cleanUp; + } + + // seperate components + Sys_StripFilename( argv[1], filePath, sizeof( filePath ) ); + Sys_StripPath( argv[1], fileName, sizeof( fileName ) ); + + bool bQuiet = false; + recurse = false; + if ( argc >= 3 ) + { + for ( int i = 2; i < argc; i++ ) + { + if ( !V_stricmp( argv[i], "/s" ) ) + { + recurse = true; + } + else if ( !V_stricmp( argv[i], "/q" ) ) + { + // silence errors + bQuiet = true; + } + } + } + + if ( !GetTargetFileList_r( filePath, recurse, FA_NORMAL|FA_READONLY|FA_DIRECTORY, 0, &pFileList ) ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Bad Target Path '%s'\n", filePath ); + goto cleanUp; + } + + numErrors = 0; + numDeleted = 0; + for ( nodePtr=pFileList; nodePtr; nodePtr=nodePtr->nextPtr ) + { + Sys_StripPath( nodePtr->filename, targetName, sizeof( targetName ) ); + + if ( fileName[0] && !Sys_IsWildcardMatch( fileName, targetName, false ) ) + continue; + + hr = DmDeleteFile( nodePtr->filename, ( nodePtr->attributes & FA_DIRECTORY ) != 0 ); + if ( hr != XBDM_NOERR ) + { + if ( !bQuiet ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Error Deleting '%s'\n", nodePtr->filename ); + } + numErrors++; + } + else + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Deleted '%s'\n", nodePtr->filename ); + numDeleted++; + } + } + + if ( !numDeleted && !numErrors ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "No Files found for '%s'\n", argv[1] ); + } + else + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%d files deleted.\n", numDeleted ); + } + + // success + errCode = TRUE; + +cleanUp: + if ( pFileList ) + FreeTargetFileList( pFileList ); + + return errCode; +} + +//----------------------------------------------------------------------------- +// lc_memory +// +//----------------------------------------------------------------------------- +BOOL lc_memory( int argc, char* argv[] ) +{ + HRESULT hr; + + hr = DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__memory__", true ); + if ( FAILED( hr ) ) + return FALSE; + + // success + return TRUE; +} + +//----------------------------------------------------------------------------- +// lc_screenshot +// +//----------------------------------------------------------------------------- +BOOL lc_screenshot( int argc, char* argv[] ) +{ + char filename[MAX_PATH]; + char filepath[MAX_PATH]; + static int shot = 0; + struct _stat dummyStat; + + if ( argc <= 1 ) + { + strcpy( filepath, g_localPath ); + Sys_AddFileSeperator( filepath, sizeof( filepath ) ); + + // spin up to available file + while ( 1 ) + { + sprintf( filename, "%sscreenshot_%4.4d.bmp", filepath, shot ); + if ( _stat( filename, &dummyStat ) == -1 ) + { + // filename not in use + break; + } + shot++; + } + } + else if ( argc == 2 ) + { + strcpy( filename, argv[1] ); + Sys_AddExtension( ".bmp", filename, sizeof( filename ) ); + } + else if ( argc > 2 ) + { + char* args[2] = {"*help", argv[0]}; + lc_help( 2, args ); + goto cleanUp; + } + + HRESULT hr = DmScreenShot( filename ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_screenshot(): DmScreenShot() failure", hr ); + goto cleanUp; + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Screenshot saved to %s\n", filename ); + + // advance the shot + shot++; + + // success + return TRUE; + +cleanUp: + return FALSE; +} + +//----------------------------------------------------------------------------- +// lc_modules +// +//----------------------------------------------------------------------------- +BOOL lc_modules( int argc, char* argv[] ) +{ + HRESULT hr; + PDM_WALK_MODULES pWalkMod = NULL; + CUtlVector< DMN_MODLOAD > list; + + // add a fake module at 0xFFFFFFFF to make sorting simple + DMN_MODLOAD modLoad = { 0 }; + modLoad.BaseAddress = (VOID*)0xFFFFFFFF; + list.AddToTail( modLoad ); + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Modules:\n" ); + while ( 1 ) + { + hr = DmWalkLoadedModules( &pWalkMod, &modLoad ); + if ( hr == XBDM_ENDOFLIST ) + { + hr = XBDM_NOERR; + break; + } + else if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_modules(): DmWalkLoadedModules() failure", hr ); + break; + } + + // add in ascending address order + for ( int i = 0; i < list.Count(); i++ ) + { + if ( modLoad.BaseAddress <= list[i].BaseAddress ) + { + list.InsertBefore( i, modLoad ); + break; + } + } + } + + unsigned int total = 0; + for ( int i = 0; i < list.Count()-1; i++ ) + { + DMN_MODLOAD *pModule = &list[i]; + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Base: 0x%8.8x, Size: %5.2f MB, [%s]\n", pModule->BaseAddress, pModule->Size/( 1024.0f*1024.0f ), pModule->Name ); + + total += pModule->Size; + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Total: %.2f MB\n\n", total/( 1024.0f*1024.0f ) ); + + if ( pWalkMod ) + { + DmCloseLoadedModules( pWalkMod ); + } + + if ( !FAILED( hr ) ) + { + // success + return TRUE; + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// lc_sections +// +//----------------------------------------------------------------------------- +BOOL lc_sections( int argc, char* argv[] ) +{ + char moduleName[MAX_PATH]; + HRESULT hr; + PDM_WALK_MODSECT pWalkModSect = NULL; + DMN_SECTIONLOAD sectLoad; + + if ( argc != 2 ) + { + char* args[2] = {"*help", argv[0]}; + lc_help( 2, args ); + goto cleanUp; + } + + strcpy( moduleName, argv[1] ); + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Sections:\n" ); + while ( 1 ) + { + hr = DmWalkModuleSections( &pWalkModSect, moduleName, §Load ); + if ( hr == XBDM_ENDOFLIST ) + { + hr = XBDM_NOERR; + break; + } + else if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_sections(): DmWalkModuleSections() failure", hr ); + break; + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "[%s]:\n", sectLoad.Name ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Base: 0x%8.8x\n", sectLoad.BaseAddress ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Size: %.2f MB ( %d bytes )\n", sectLoad.Size/( 1024.0f*1024.0f ), sectLoad.Size ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Index: %d\n", sectLoad.Index ); + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "End.\n\n" ); + + if ( pWalkModSect ) + DmCloseModuleSections( pWalkModSect ); + + if ( !FAILED( hr ) ) + { + // success + return TRUE; + } + +cleanUp: + return FALSE; +} + +//----------------------------------------------------------------------------- +// lc_threads +// +//----------------------------------------------------------------------------- +BOOL lc_threads( int argc, char* argv[] ) +{ + char nameBuff[256]; + char suspendBuff[32]; + + DWORD threadList[256]; + DWORD numThreads = 256; + memset( &threadList, 0, sizeof( threadList ) ); + HRESULT hr = DmGetThreadList( threadList, &numThreads ); + if ( FAILED( hr ) ) + return FALSE; + + // enumerate threads and display sorted by processor + DM_THREADINFOEX threadInfoEx; + for ( int core = 0; core < 3; core++ ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n--- CORE %d ---\n", core ); + + for ( int unit = 0; unit < 2; unit++ ) + { + for ( int i = 0; i < (int)numThreads; i++ ) + { + threadInfoEx.Size = sizeof( DM_THREADINFOEX ); + hr = DmGetThreadInfoEx( threadList[i], &threadInfoEx ); + if ( FAILED( hr ) ) + return FALSE; + + if ( threadInfoEx.CurrentProcessor != core*2 + unit ) + { + continue; + } + + nameBuff[0] = '\0'; + DmGetMemory( threadInfoEx.ThreadNameAddress, threadInfoEx.ThreadNameLength, nameBuff, NULL ); + if ( !nameBuff[0] ) + { + strcpy( nameBuff, "???" ); + } + + suspendBuff[0] = '\0'; + if ( threadInfoEx.SuspendCount ) + { + sprintf( suspendBuff, "(Suspend: %d)", threadInfoEx.SuspendCount ); + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Id: 0x%8.8x Pri: %2d Proc: %1d Stack: %7.2f KB [%s] %s\n", + threadList[i], + threadInfoEx.Priority, + threadInfoEx.CurrentProcessor, + (float)( (unsigned int)threadInfoEx.StackBase - (unsigned int)threadInfoEx.StackLimit )/1024.0f, + nameBuff, + suspendBuff ); + } + } + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// lc_run +// +//----------------------------------------------------------------------------- +BOOL lc_run( int argc, char* argv[] ) +{ + HRESULT hr; + char xexDrive[MAX_PATH]; + char xexPath[MAX_PATH]; + char xexName[MAX_PATH]; + char xexArgs[MAX_PATH]; + + if ( !argc ) + { + char* args[2] = {"*help", argv[0]}; + lc_help( 2, args ); + goto cleanUp; + } + + // copy args + g_rebootArgc = argc-1; + for ( int i=1; i<argc; i++ ) + { + if ( i==1 ) + { + strcpy( xexPath, argv[i] ); + Sys_AddExtension( ".xex", xexPath, sizeof( xexPath ) ); + _splitpath( xexPath, xexDrive, NULL, NULL, NULL ); + if ( !xexDrive[0] ) + { + char szTempPath[MAX_PATH]; + V_strncpy( szTempPath, "e:\\", sizeof( szTempPath ) ); + V_strncat( szTempPath, xexPath, sizeof( szTempPath ) ); + V_strncpy( xexPath, szTempPath, sizeof( xexPath ) ); + } + + g_rebootArgv[i-1] = Sys_CopyString( xexPath ); + } + else + { + g_rebootArgv[i-1] = Sys_CopyString( argv[i] ); + } + } + + if ( !g_rebootArgc ) + { + // reboot + hr = DmReboot( DMBOOT_COLD ); + } + else + { + DecodeRebootArgs( g_rebootArgc, g_rebootArgv, xexPath, xexName, xexArgs ); + + // trial set title - ensure title is present + hr = DmSetTitle( xexPath, xexName, xexArgs ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_Run(): DmSetTitle() failure", hr ); + goto cleanUp; + } + + // reboot - wait for 15s to connect and run title + hr = DmReboot( DMBOOT_WAIT ); + } + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_Run(): DmReboot() failure", hr ); + goto cleanUp; + } + + // set reboot state + g_reboot = true; + + return TRUE; + +cleanUp: + // free args + for ( int i=0; i<g_rebootArgc; i++ ) + Sys_Free( g_rebootArgv[i] ); + g_rebootArgc = 0; + + return FALSE; +} + +//----------------------------------------------------------------------------- +// lc_reset +// +//----------------------------------------------------------------------------- +BOOL lc_reset( int argc, char* argv[] ) +{ + if ( !argc ) + { + char* args[2] = {"*help", argv[0]}; + lc_help( 2, args ); + return FALSE; + } + + HRESULT hr = DmReboot( DMBOOT_COLD ); + + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_Run(): DmReboot() failure", hr ); + return FALSE; + } + + // set reboot state + g_reboot = true; + + return TRUE; +} + +//----------------------------------------------------------------------------- +// lc_help +// +// Handles the "help" command. If no args, prints a list of built-in +// and remote commands ( remote only if connected ). If a command +// is specified, prints detailed help for that command +//----------------------------------------------------------------------------- +BOOL lc_help( int argc, char* argv[] ) +{ + if ( argc <= 1 ) + { + // no arguments - print out our list of commands + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Console Commands:\n" ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "---------------\n" ); + for ( int i = 0; i < g_numLocalCommands; i++ ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", g_localCommands[i].strCommand ); + } + + if ( g_connectedToApp ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Remote Commands: ( %d )\n", g_numRemoteCommands ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "----------------\n" ); + if ( !g_numRemoteCommands ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "( None )\n" ); + } + else + { + for ( int i=0; i<g_numRemoteCommands; i++ ) + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", g_remoteCommands[i]->strCommand ); + } + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" ); + } + } + else + { + // match as many as possible + int cch = lstrlenA( argv[1] ); + + // print help description for all local matches + for ( int i=0; i<g_numLocalCommands; i++ ) + { + if ( !_strnicmp( g_localCommands[i].strCommand, argv[1], cch ) && g_localCommands[i].strHelp ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s\n", g_localCommands[i].strCommand, g_localCommands[i].strHelp ); + } + } + + // print help description for all remote matches + if ( g_connectedToApp ) + { + for ( int i=0; i<g_numRemoteCommands; i++ ) + { + if ( !_strnicmp( g_remoteCommands[i]->strCommand, argv[1], cch ) && g_remoteCommands[i]->strHelp ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s\n", g_remoteCommands[i]->strCommand, g_remoteCommands[i]->strHelp ); + } + } + } + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" ); + } + + return TRUE; + } + +//----------------------------------------------------------------------------- +// lc_cls +//----------------------------------------------------------------------------- +BOOL lc_cls( int argc, char* argv[] ) +{ + SetWindowText( g_hwndOutputWindow, "" ); + + // non't let the compiler complain about unused parameters + ( VOID )argc; + ( VOID )argv; + + return TRUE; +} + +//----------------------------------------------------------------------------- +// lc_connect +// +// Connect to XBox +//----------------------------------------------------------------------------- +BOOL lc_connect( int argc, char* argv[] ) +{ + HRESULT hr; + BOOL connected = FALSE; + + if ( g_connectedToXBox ) + { + if ( !lc_disconnect( 0, NULL ) ) + return FALSE; + } + + if ( argc >= 1 && argv[0][0] ) + { + hr = DmSetXboxName( argv[0] ); + if ( FAILED( hr ) ) + { + char message[255]; + sprintf( message, "ConnectToXBox(): DmSetXboxName( %s ) failure", argv[0] ); + DmAPI_DisplayError( message, hr ); + goto cleanUp; + } + } + + // open connection + hr = DmOpenConnection( &g_pdmConnection ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "ConnectToXBox(): DmOpenConnection() failure", hr ); + goto cleanUp; + } + connected = TRUE; + + DWORD namelen = MAX_XBOXNAMELEN; + hr = DmGetXboxName( g_xboxName, &namelen ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "ConnectToXBox(): DmGetXboxName() failure", hr ); + goto cleanUp; + } + hr = DmResolveXboxName( &g_xboxAddress ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "ConnectToXBox(): DmResolveXboxName() failure", hr ); + goto cleanUp; + } + + // success + g_connectedToXBox = TRUE; + g_connectFailure = 0; + + if ( !g_connectCount ) + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Connected To: '%s'(%d.%d.%d.%d)\n", g_xboxName, ( ( byte* )&g_xboxAddress )[3], ( ( byte* )&g_xboxAddress )[2], ( ( byte* )&g_xboxAddress )[1], ( ( byte* )&g_xboxAddress )[0] ); + g_connectCount++; + + SetConnectionIcon( ICON_CONNECTED_XBOX ); + + if ( g_connectCount == 1 ) + { + // inital connect + } + + return TRUE; + +cleanUp: + if ( connected ) + DmCloseConnection( g_pdmConnection ); + + return FALSE; +} + +//----------------------------------------------------------------------------- +// lc_listen +// +// Open listen session with App +//----------------------------------------------------------------------------- +BOOL lc_listen( int argc, char* argv[] ) +{ + HRESULT hr; + BOOL success; + BOOL sessionStarted; + BOOL sessionValid; + char *args[1]; + char cmdStr[256]; + + if ( g_connectedToXBox || g_connectedToApp ) + { + if ( !lc_disconnect( 0, NULL ) ) + return ( FALSE ); + } + + if ( !g_connectedToXBox ) + { + // connect to xbox + args[0] = g_xboxTargetName; + if ( !lc_connect( 1, args ) ) + return FALSE; + } + + // until otherwise + success = FALSE; + sessionStarted = FALSE; + sessionValid = FALSE; + + // init session + hr = DmOpenNotificationSession( 0, &g_pdmnSession ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_session(): DmOpenNotificationSession() failure", hr ); + goto cleanUp; + } + sessionStarted = TRUE; + + // get notifications of app debugging output + hr = DmNotify( g_pdmnSession, DM_DEBUGSTR, Remote_NotifyDebugString ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_session(): DmNotify() failure", hr ); + goto cleanUp; + } + + // get command notifications + hr = DmRegisterNotificationProcessor( g_pdmnSession, VXCONSOLE_COMMAND_PREFIX, Remote_NotifyCommandFunc ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_session(): DmRegisterNotificationProcessor() failure", hr ); + goto cleanUp; + } + + // get print notifications + hr = DmRegisterNotificationProcessor( g_pdmnSession, VXCONSOLE_PRINT_PREFIX, Remote_NotifyPrintFunc ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "lc_session(): DmRegisterNotificationProcessor() failure", hr ); + goto cleanUp; + } + sessionValid = TRUE; + + // Send initial connect command to the External Command Processor so it knows we're here + sprintf( cmdStr, "%s %d", VXCONSOLE_COMMAND_PREFIX "!" "__connect__", VXCONSOLE_PROTOCOL_VERSION ); + hr = DmAPI_SendCommand( cmdStr, true ); + if ( FAILED( hr ) ) + { + if ( !g_autoConnect ) + ConsoleWindowPrintf( RGB( 255,0,0 ), "Couldn't Find Application\n" ); + goto cleanUp; + } + else + { + // connected + success = TRUE; + g_connectedToApp = TRUE; + g_connectedTime = Sys_GetSystemTime(); + SetConnectionIcon( ICON_CONNECTED_APP1 ); + + if ( g_clsOnConnect ) + { + if ( g_bPlayTestMode ) + { + // demarcate the log + ConsoleWindowPrintf( CLR_DEFAULT, "\n******** CONNECTION ********\n" ); + } + + lc_cls( 0, NULL ); + CpuProfile_Clear(); + TimeStampLog_Clear(); + } + + goto cleanUp; + } + +cleanUp: + if ( !success ) + { + if ( sessionValid ) + DmNotify( g_pdmnSession, DM_NONE, NULL ); + + if ( sessionStarted ) + DmCloseNotificationSession( g_pdmnSession ); + } + + return ( success ); +} + +//----------------------------------------------------------------------------- +// AutoConnectTimerProc +// +//----------------------------------------------------------------------------- +void AutoConnectTimerProc( HWND hwnd, UINT_PTR idEvent ) +{ + static BOOL busy; + int icon; + char* cmdStr; + BOOL bKeepConnection = TRUE; + + // blink the connection icon + if ( g_connectedToApp && (! g_bSuppressBlink ) ) + { + if ( g_currentIcon == ICON_CONNECTED_APP0 ) + icon = ICON_CONNECTED_APP1; + else + icon = ICON_CONNECTED_APP0; + SetConnectionIcon( icon ); + } + + if ( busy ) + { + // not ready for new tick + return; + } + + if ( g_bAutoConnectWait > 0 ) + { + if ( g_bAutoConnectWait && !g_bAutoConnectQuiet ) + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Waiting... %d seconds remaining\n", g_bAutoConnectWait ); + g_bAutoConnectWait--; + return; + } + + // no more ticks until ready + busy = TRUE; + + if ( !g_connectedToApp ) + { + // looking for application - must force re-connect every time + if ( g_connectedToXBox ) + { + // temporary "partial" disconnect + DmCloseConnection( g_pdmConnection ); + g_connectedToXBox = FALSE; + } + + // attempt to start or re-establish connection and session + lc_listen( 0, NULL ); + + if ( !g_connectedToXBox ) + { + SetConnectionIcon( ICON_DISCONNECTED ); + g_connectFailure++; + } + + if ( g_reboot && g_connectedToXBox ) + { + char xexPath[MAX_PATH]; + char xexName[MAX_PATH]; + char xexArgs[MAX_PATH]; + + DecodeRebootArgs( g_rebootArgc, g_rebootArgv, xexPath, xexName, xexArgs ); + + if ( g_rebootArgc ) + { + // free args + for ( int i=0; i<g_rebootArgc; i++ ) + Sys_Free( g_rebootArgv[i] ); + g_rebootArgc = 0; + + HRESULT hr = DmSetTitle( xexPath, xexName, xexArgs ); + if ( FAILED( hr ) ) + DmAPI_DisplayError( "Reboot: DmSetTitle() failure", hr ); + else + { + hr = DmGo(); + if ( FAILED( hr ) ) + DmAPI_DisplayError( "Reboot: DmGo() failure", hr ); + } + } + + g_reboot = false; + } + + if ( !g_connectFailure ) + { + // quietly attempt re-connection or ping every 3 seconds + g_bAutoConnectWait = 3; + g_bAutoConnectQuiet = TRUE; + busy = FALSE; + } + else + { + if ( g_connectFailure == 1 ) + { + // console may be rebooting, allow sufficient dvd boot up delay, then attempt re-connection + // 5 seconds barely covers the xbox splash + g_bAutoConnectWait = 15; + g_bAutoConnectQuiet = FALSE; + busy = FALSE; + } + else + { + // a sustained connection failure means the xbox is just not there + // re-trying is too cpu intensive and causes pc to appear locked + // warn and stop auto connecting, user must fix + bKeepConnection = FALSE; + goto disconnect; + } + } + return; + } + else + { + // try to send ping across open connection at an idle interval + cmdStr = VXCONSOLE_COMMAND_PREFIX "!"; + HRESULT hr = DmAPI_SendCommand( cmdStr, false ); + if ( FAILED( hr ) && hr != XBDM_UNDEFINED ) + goto disconnect; + + // quietly ping + g_bAutoConnectWait = 3; + g_bAutoConnectQuiet = TRUE; + busy = FALSE; + return; + } + +disconnect: + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Connection To Xbox Lost.\n" ); + + DoDisconnect( bKeepConnection, 3 ); + + busy = FALSE; +} + +//----------------------------------------------------------------------------- +// lc_autoConnect +//----------------------------------------------------------------------------- +BOOL lc_autoConnect( int argc, char* argv[] ) +{ + if ( !g_autoConnect ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Enabling Auto Connect.\n" ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Looking for Connection...\n" ); + g_autoConnect = TRUE; + } + else + { + // already enabled + return ( TRUE ); + } + + if ( !g_autoConnectTimer ) + { + UINT_PTR timer = TIMERID_AUTOCONNECT; + g_autoConnectTimer = SetTimer( g_hDlgMain, timer, 1000, NULL ); + } + + return ( TRUE ); +} + +//----------------------------------------------------------------------------- +// lc_disconnect +//----------------------------------------------------------------------------- +BOOL lc_disconnect( int argc, char* argv[] ) +{ + if ( g_autoConnect ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Disabling Auto Connect.\n" ); + if ( g_autoConnectTimer ) + { + UINT_PTR timer = TIMERID_AUTOCONNECT; + KillTimer( g_hDlgMain, timer ); + } + g_autoConnectTimer = 0; + g_autoConnect = FALSE; + } + + if ( g_connectedToApp ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Closing Session.\n" ); + + DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__disconnect__", false ); + + // close session + DmNotify( g_pdmnSession, DM_NONE, NULL ); + DmCloseNotificationSession( g_pdmnSession ); + + g_connectedToApp = FALSE; + } + + if ( g_connectedToXBox ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Closing Connection.\n" ); + + // close connection + DmCloseConnection( g_pdmConnection ); + + // set the command ready mutex + SetEvent( g_hCommandReadyEvent ); + + g_connectedToXBox = FALSE; + g_xboxName[0] = '\0'; + g_xboxAddress = 0; + } + + SetConnectionIcon( ICON_DISCONNECTED ); + + g_connectCount = 0; + + // free remote commands + Remote_DeleteCommands(); + + // Don't let the compiler complain about unused parameters + ( VOID )argc; + ( VOID )argv; + + return TRUE; +} + +//----------------------------------------------------------------------------- +// lc_crashdump +//----------------------------------------------------------------------------- +BOOL lc_crashdump( int argc, char* argv[] ) +{ + DmCrashDump(); + + // Don't let the compiler complain about unused parameters + ( VOID )argc; + ( VOID )argv; + + return TRUE; +} + +//----------------------------------------------------------------------------- +// lc_quit +//----------------------------------------------------------------------------- +BOOL lc_quit( int argc, char* argv[] ) +{ + PostMessage( g_hDlgMain, WM_CLOSE, 0, 0 ); + + // don't let the compiler complain about unused parameters + ( VOID )argc; + ( VOID )argv; + + return TRUE; +} + +//----------------------------------------------------------------------------- +// lc_ClearConfigs +// +//----------------------------------------------------------------------------- +BOOL lc_ClearConfigs( int argc, char* argv[] ) +{ + if ( argc != 1 ) + { + char* args[2] = {"*help", argv[0]}; + lc_help( 1, args ); + goto cleanUp; + } + + // delete any configurations (ignore errors) + char szTempFilename[MAX_PATH]; + V_ComposeFileName( "HDD:\\Content", "*.*", szTempFilename, sizeof( szTempFilename ) ); + char *pArgs[4]; + pArgs[0] = "*del"; + pArgs[1] = szTempFilename; + pArgs[2] = "/s"; + pArgs[3] = "/q"; + lc_del( 4, pArgs ); + + return TRUE; + +cleanUp: + return FALSE; +} diff --git a/utils/xbox/vxconsole/mem_profile.cpp b/utils/xbox/vxconsole/mem_profile.cpp new file mode 100644 index 0000000..d15aee3 --- /dev/null +++ b/utils/xbox/vxconsole/mem_profile.cpp @@ -0,0 +1,561 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// MEM_PROFILE.CPP +// +// Memory Profiling Display +//=====================================================================================// +#include "vxconsole.h" + +#define PROFILE_MAXSAMPLES 512 +#define PROFILE_MEMORYHEIGHT 100 +#define PROFILE_NUMMINORTICKS 3 +#define PROFILE_LABELWIDTH 50 +#define PROFILE_SCALESTEPS 8 +#define PROFILE_MINSCALE 0.2f +#define PROFILE_MAXSCALE 3.0f +#define PROFILE_NUMMINORTICKS 3 +#define PROFILE_MAJORTICKMB 16 +#define PROFILE_WARNINGMB 10 +#define PROFILE_SEVEREMB 5 + +#define ID_MEMPROFILE 1 + +HWND g_memProfile_hWnd; +RECT g_memProfile_WindowRect; +int g_memProfile_tickMarks; +int g_memProfile_colors; +int g_memProfile_scale; +UINT_PTR g_memProfile_Timer; +int g_memProfile_numSamples; +int g_memProfile_samples[PROFILE_MAXSAMPLES]; + +//----------------------------------------------------------------------------- +// MemProfile_SaveConfig +// +//----------------------------------------------------------------------------- +void MemProfile_SaveConfig() +{ + char buff[256]; + WINDOWPLACEMENT wp; + + // profile history + if ( g_memProfile_hWnd ) + { + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_memProfile_hWnd, &wp ); + g_memProfile_WindowRect = wp.rcNormalPosition; + sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom ); + Sys_SetRegistryString( "MemProfileWindowRect", buff ); + } + + Sys_SetRegistryInteger( "MemProfileScale", g_memProfile_scale ); + Sys_SetRegistryInteger( "MemProfileTickMarks", g_memProfile_tickMarks ); + Sys_SetRegistryInteger( "MemProfileColors", g_memProfile_colors ); +} + +//----------------------------------------------------------------------------- +// MemProfile_LoadConfig +// +//----------------------------------------------------------------------------- +void MemProfile_LoadConfig() +{ + int numArgs; + char buff[256]; + + // profile history + Sys_GetRegistryString( "MemProfileWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_memProfile_WindowRect.left, &g_memProfile_WindowRect.top, &g_memProfile_WindowRect.right, &g_memProfile_WindowRect.bottom ); + if ( numArgs != 4 ) + { + memset( &g_memProfile_WindowRect, 0, sizeof( g_memProfile_WindowRect ) ); + } + + Sys_GetRegistryInteger( "MemProfileScale", 0, g_memProfile_scale ); + if ( g_memProfile_scale < -PROFILE_SCALESTEPS || g_memProfile_scale > PROFILE_SCALESTEPS ) + { + g_memProfile_scale = 0; + } + + Sys_GetRegistryInteger( "MemProfileTickMarks", 1, g_memProfile_tickMarks ); + Sys_GetRegistryInteger( "MemProfileColors", 1, g_memProfile_colors ); +} + +//----------------------------------------------------------------------------- +// MemProfile_SetTitle +// +//----------------------------------------------------------------------------- +void MemProfile_SetTitle() +{ + char titleBuff[128]; + + if ( g_memProfile_hWnd ) + { + strcpy( titleBuff, "Free Memory Available" ); + if ( g_memProfile_Timer ) + { + strcat( titleBuff, " [ON]" ); + } + + SetWindowText( g_memProfile_hWnd, titleBuff ); + } +} + +//----------------------------------------------------------------------------- +// MemProfile_EnableProfiling +// +//----------------------------------------------------------------------------- +void MemProfile_EnableProfiling( bool bEnable ) +{ + if ( !g_memProfile_hWnd ) + { + return; + } + + UINT_PTR timer = TIMERID_MEMPROFILE; + if ( bEnable && !g_memProfile_Timer ) + { + // run at 10Hz + g_memProfile_Timer = SetTimer( g_memProfile_hWnd, timer, 100, NULL ); + } + else if ( !bEnable && g_memProfile_Timer ) + { + KillTimer( g_memProfile_hWnd, timer ); + g_memProfile_Timer = NULL; + } +} + +//----------------------------------------------------------------------------- +// MemProfile_UpdateWindow +// +//----------------------------------------------------------------------------- +void MemProfile_UpdateWindow() +{ + if ( g_memProfile_hWnd && !IsIconic( g_memProfile_hWnd ) ) + { + // visible - force a client repaint + InvalidateRect( g_memProfile_hWnd, NULL, true ); + } +} + +//----------------------------------------------------------------------------- +// rc_FreeMemory +// +//----------------------------------------------------------------------------- +int rc_FreeMemory( char* commandPtr ) +{ + int errCode = -1; + int freeMemory; + + char *cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + { + goto cleanUp; + } + sscanf( cmdToken, "%x", &freeMemory ); + + g_memProfile_samples[g_memProfile_numSamples % PROFILE_MAXSAMPLES] = freeMemory; + g_memProfile_numSamples++; + + DebugCommand( "FreeMemory( 0x%8.8x )\n", freeMemory ); + + MemProfile_UpdateWindow(); + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} + +//----------------------------------------------------------------------------- +// MemProfile_ZoomIn +// +//----------------------------------------------------------------------------- +void MemProfile_ZoomIn( int& scale, int numSteps ) +{ + scale++; + if ( scale > numSteps ) + { + scale = numSteps; + return; + } + MemProfile_UpdateWindow(); +} + +//----------------------------------------------------------------------------- +// MemProfile_ZoomOut +// +//----------------------------------------------------------------------------- +void MemProfile_ZoomOut( int& scale, int numSteps ) +{ + scale--; + if ( scale < -numSteps ) + { + scale = -numSteps; + return; + } + MemProfile_UpdateWindow(); +} + +//----------------------------------------------------------------------------- +// MemProfile_CalcScale +// +//----------------------------------------------------------------------------- +float MemProfile_CalcScale( int scale, int numSteps, float min, float max ) +{ + float t; + + // from integral scale [-numSteps..numSteps] to float scale [min..max] + t = ( float )( scale + numSteps )/( float )( 2*numSteps ); + t = min + t*( max-min ); + + return t; +} + +//----------------------------------------------------------------------------- +// MemProfile_Draw +// +//----------------------------------------------------------------------------- +void MemProfile_Draw( HDC hdc, RECT* clientRect ) +{ + char labelBuff[128]; + HPEN hBlackPen; + HPEN hPenOld; + HPEN hNullPen; + HPEN hGreyPen; + HBRUSH hColoredBrush; + HBRUSH hBrushOld; + HFONT hFontOld; + int currentSample; + int numTicks; + int memoryHeight; + int windowWidth; + int windowHeight; + int x; + int y; + int y0; + int i; + int j; + int h; + int numbars; + RECT rect; + float t; + float scale; + + hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) ); + hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) ); + hNullPen = CreatePen( PS_NULL, 0, RGB( 0,0,0 ) ); + hPenOld = ( HPEN )SelectObject( hdc, hBlackPen ); + hFontOld = SelectFont( hdc, g_hProportionalFont ); + + // zoom + scale = MemProfile_CalcScale( g_memProfile_scale, PROFILE_SCALESTEPS, PROFILE_MINSCALE, PROFILE_MAXSCALE ); + memoryHeight = ( int )( PROFILE_MEMORYHEIGHT*scale ); + windowWidth = clientRect->right-clientRect->left; + windowHeight = clientRect->bottom-clientRect->top; + + numTicks = windowHeight/memoryHeight + 2; + if ( numTicks < 0 ) + { + numTicks = 1; + } + else if ( numTicks > 512/PROFILE_MAJORTICKMB + 1 ) + { + numTicks = 512/PROFILE_MAJORTICKMB + 1; + } + + SetBkColor( hdc, g_backgroundColor ); + + x = 0; + y = windowHeight; + for ( i=0; i<numTicks; i++ ) + { + // major ticks + SelectObject( hdc, hBlackPen ); + MoveToEx( hdc, 0, y, NULL ); + LineTo( hdc, windowWidth, y ); + + if ( g_memProfile_tickMarks ) + { + // could be very zoomed out, gap must be enough for label, otherwise don't draw + int gapY = memoryHeight/( PROFILE_NUMMINORTICKS+1 ); + if ( gapY >= 10 ) + { + // minor ticks + y0 = y; + SelectObject( hdc, hGreyPen ); + for ( j=0; j<PROFILE_NUMMINORTICKS; j++ ) + { + y0 += gapY; + MoveToEx( hdc, 0, y0, NULL ); + LineTo( hdc, windowWidth, y0 ); + } + } + } + + // tick labels + if ( i ) + { + rect.left = windowWidth - 50; + rect.right = windowWidth; + rect.top = y - 20; + rect.bottom = y; + sprintf( labelBuff, "%d MB", i*PROFILE_MAJORTICKMB ); + DrawText( hdc, labelBuff, -1, &rect, DT_RIGHT|DT_SINGLELINE|DT_BOTTOM ); + } + + y -= memoryHeight; + } + + // vertical bars + if ( g_memProfile_numSamples ) + { + SelectObject( hdc, hNullPen ); + + numbars = windowWidth-PROFILE_LABELWIDTH; + currentSample = g_memProfile_numSamples-1; + for ( x=numbars-1; x>=0; x-=4 ) + { + float sample = g_memProfile_samples[currentSample % PROFILE_MAXSAMPLES]/( 1024.0f * 1024.0f ); + + y = windowHeight; + t = sample/(float)PROFILE_MAJORTICKMB; + h = ( int )( t * ( float )memoryHeight ); + if ( h ) + { + if ( h > windowHeight ) + h = windowHeight; + + COLORREF barColor; + if ( sample >= PROFILE_WARNINGMB ) + { + barColor = RGB( 100, 255, 100 ); + } + else if ( sample >= PROFILE_SEVEREMB ) + { + barColor = RGB( 255, 255, 100 ); + } + else + { + barColor = RGB( 255, 0, 0 ); + } + + hColoredBrush = CreateSolidBrush( g_memProfile_colors ? barColor : RGB( 80, 80, 80 ) ); + hBrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush ); + + Rectangle( hdc, x-4, y-h, x, y+1 ); + y -= h; + + SelectObject( hdc, hBrushOld ); + DeleteObject( hColoredBrush ); + } + + currentSample--; + if ( currentSample < 0 ) + { + // no data + break; + } + } + } + + SelectObject( hdc, hFontOld ); + SelectObject( hdc, hPenOld ); + DeleteObject( hBlackPen ); + DeleteObject( hGreyPen ); +} + +//----------------------------------------------------------------------------- +// MemProfile_TimerProc +// +//----------------------------------------------------------------------------- +void MemProfile_TimerProc( HWND hwnd, UINT_PTR idEvent ) +{ + static bool busy = false; + + if ( busy ) + { + return; + } + + busy = true; + + if ( g_connectedToApp ) + { + // send as async + DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__memory__ quiet", false ); + } + + busy = false; +} + +//----------------------------------------------------------------------------- +// MemProfile_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK MemProfile_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + HDC hdc; + PAINTSTRUCT ps; + RECT rect; + CREATESTRUCT *createStructPtr; + + switch ( message ) + { + case WM_CREATE: + // set the window identifier + createStructPtr = ( CREATESTRUCT* )lParam; + SetWindowLong( hwnd, GWL_USERDATA+0, ( LONG )createStructPtr->lpCreateParams ); + + // clear samples + g_memProfile_numSamples = 0; + memset( g_memProfile_samples, 0, sizeof( g_memProfile_samples ) ); + return 0L; + + case WM_DESTROY: + MemProfile_SaveConfig(); + MemProfile_EnableProfiling( false ); + g_memProfile_hWnd = NULL; + return 0L; + + case WM_INITMENU: + CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_memProfile_tickMarks ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_COLORS, MF_BYCOMMAND | ( g_memProfile_colors ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_MEMPROFILE_ENABLE, MF_BYCOMMAND | ( g_memProfile_Timer != NULL ? MF_CHECKED : MF_UNCHECKED ) ); + return 0L; + + case WM_PAINT: + GetClientRect( hwnd, &rect ); + hdc = BeginPaint( hwnd, &ps ); + MemProfile_Draw( hdc, &rect ); + EndPaint( hwnd, &ps ); + return 0L; + + case WM_SIZE: + // force a redraw + MemProfile_UpdateWindow(); + return 0L; + + case WM_TIMER: + if ( wID == TIMERID_MEMPROFILE ) + { + MemProfile_TimerProc( hwnd, TIMERID_MEMPROFILE ); + return 0L; + } + break; + + case WM_KEYDOWN: + switch ( wParam ) + { + case VK_INSERT: + MemProfile_ZoomIn( g_memProfile_scale, PROFILE_SCALESTEPS ); + return 0L; + + case VK_DELETE: + MemProfile_ZoomOut( g_memProfile_scale, PROFILE_SCALESTEPS ); + return 0L; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_MEMPROFILE_TICKMARKS: + g_memProfile_tickMarks ^= 1; + MemProfile_UpdateWindow(); + return 0L; + + case IDM_MEMPROFILE_COLORS: + g_memProfile_colors ^= 1; + MemProfile_UpdateWindow(); + return 0L; + + case IDM_MEMPROFILE_ZOOMIN: + MemProfile_ZoomIn( g_memProfile_scale, PROFILE_SCALESTEPS ); + return 0L; + + case IDM_MEMPROFILE_ZOOMOUT: + MemProfile_ZoomOut( g_memProfile_scale, PROFILE_SCALESTEPS ); + return 0L; + + case IDM_MEMPROFILE_ENABLE: + bool bEnable = ( g_memProfile_Timer != NULL ); + bEnable ^= 1; + MemProfile_EnableProfiling( bEnable ); + MemProfile_SetTitle(); + return 0L; + } + break; + } + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// MemProfile_Open +// +//----------------------------------------------------------------------------- +void MemProfile_Open() +{ + HWND hWnd; + + if ( g_memProfile_hWnd ) + { + // only one profile instance + if ( IsIconic( g_memProfile_hWnd ) ) + ShowWindow( g_memProfile_hWnd, SW_RESTORE ); + SetForegroundWindow( g_memProfile_hWnd ); + return; + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "MEMPROFILECLASS", + "", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 600, + 500, + g_hDlgMain, + NULL, + g_hInstance, + ( void* )ID_MEMPROFILE ); + g_memProfile_hWnd = hWnd; + + MemProfile_EnableProfiling( true ); + MemProfile_SetTitle(); + + if ( g_memProfile_WindowRect.right && g_memProfile_WindowRect.bottom ) + MoveWindow( g_memProfile_hWnd, g_memProfile_WindowRect.left, g_memProfile_WindowRect.top, g_memProfile_WindowRect.right-g_memProfile_WindowRect.left, g_memProfile_WindowRect.bottom-g_memProfile_WindowRect.top, FALSE ); + ShowWindow( g_memProfile_hWnd, SHOW_OPENWINDOW ); +} + +//----------------------------------------------------------------------------- +// MemProfile_Init +// +//----------------------------------------------------------------------------- +bool MemProfile_Init() +{ + WNDCLASS wndclass; + + // set up our window class + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = MemProfile_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_MEMPROFILE ); + wndclass.lpszClassName = "MEMPROFILECLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + MemProfile_LoadConfig(); + + return true; +} diff --git a/utils/xbox/vxconsole/progress.cpp b/utils/xbox/vxconsole/progress.cpp new file mode 100644 index 0000000..50d90f4 --- /dev/null +++ b/utils/xbox/vxconsole/progress.cpp @@ -0,0 +1,359 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// PROGRESS.CPP +// +// Progress Metering Utility. +//=====================================================================================// +#include "vxconsole.h" + +#define PROGRESS_WIDTH 425 +#define PROGRESS_HEIGHT 170 + +#define ID_PROGRESS_STATUS1 100 +#define ID_PROGRESS_STATUS2 101 +#define ID_PROGRESS_STATUS3 102 +#define ID_PROGRESS_PERCENT 103 +#define ID_PROGRESS_METER 104 +#define ID_PROGRESS_CANCEL 105 + +//----------------------------------------------------------------------------- +// CProgress_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK Progress_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + CProgress *pProgress; + CREATESTRUCT *createStructPtr; + + switch ( message ) + { + case WM_CREATE: + createStructPtr = ( CREATESTRUCT* )lParam; + SetWindowLong( hwnd, GWL_USERDATA+0, ( LONG )createStructPtr->lpCreateParams ); + return 0L; + + case WM_DESTROY: + pProgress = ( CProgress* )GetWindowLong( hwnd, GWL_USERDATA+0 ); + if ( pProgress ) + pProgress->m_hWnd = NULL; + return 0L; + + case WM_CTLCOLORSTATIC: + SetBkColor( ( HDC )wParam, g_backgroundColor ); + return ( BOOL )g_hBackgroundBrush; + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case ID_PROGRESS_CANCEL: + pProgress = ( CProgress* )GetWindowLong( hwnd, GWL_USERDATA+0 ); + if ( pProgress ) + pProgress->m_bCancelPressed = true; + return ( TRUE ); + } + break; + } + + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// CProgress::Update +// +// Pump the message loop +//----------------------------------------------------------------------------- +void CProgress::Update() +{ + MSG msg; + + while ( PeekMessage( &msg, NULL, 0, 0, PM_NOYIELD|PM_REMOVE ) ) + { + if ( !TranslateAccelerator( g_hDlgMain, g_hAccel, &msg ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } +} + +//----------------------------------------------------------------------------- +// CProgress::IsCancel +// +//----------------------------------------------------------------------------- +bool CProgress::IsCancel() +{ + return m_bCancelPressed; +} + +//----------------------------------------------------------------------------- +// CProgress::SetMeter +// +//----------------------------------------------------------------------------- +void CProgress::SetMeter( int currentPos, int range ) +{ + char buff[16]; + int percent; + + if ( !m_hWnd || !m_hWndPercent || !m_hWndMeter ) + return; + + if ( range >= 0 ) + { + SendMessage( m_hWndMeter, PBM_SETRANGE, 0, MAKELPARAM( 0, range ) ); + m_range = range; + } + SendMessage( m_hWndMeter, PBM_SETPOS, currentPos, 0 ); + + if ( m_range > 0 ) + { + percent = ( int )( 100.0f*currentPos/m_range ); + if ( percent > 100 ) + percent = 100; + } + else + percent = 0; + sprintf( buff, "%d%%", percent ); + SetWindowText( m_hWndPercent, buff ); + + Update(); +} + +//----------------------------------------------------------------------------- +// CProgress::SetStatus +// +//----------------------------------------------------------------------------- +void CProgress::SetStatus( const char *line1, const char *line2, const char *line3 ) +{ + if ( !m_hWnd ) + return; + + if ( line1 ) + SetWindowText( m_hWndStatus1, line1 ); + if ( line2 ) + SetWindowText( m_hWndStatus2, line2 ); + if ( line3 ) + SetWindowText( m_hWndStatus3, line3 ); + + Update(); +} + +//----------------------------------------------------------------------------- +// CProgress::Open +// +//----------------------------------------------------------------------------- +void CProgress::Open( const char* title, bool canCancel, bool bHasMeter ) +{ + HWND hWnd; + RECT clientRect; + RECT parentRect; + int cx; + int cy; + int cw; + int ch; + int y; + int dialogHeight; + + dialogHeight = PROGRESS_HEIGHT; + if ( !canCancel ) + dialogHeight -= 25; + if ( !bHasMeter ) + dialogHeight -= GetSystemMetrics( SM_CYVSCROLL ); + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "PROGRESSCLASS", + title, + WS_POPUP|WS_CAPTION, + 0, + 0, + PROGRESS_WIDTH, + dialogHeight, + g_hDlgMain, + NULL, + g_hInstance, + ( void* )this ); + m_hWnd = hWnd; + if ( !m_hWnd ) + return; + + // status text line #1 + GetClientRect( m_hWnd, &clientRect ); + y = 10; + hWnd = CreateWindowEx( + 0, + WC_STATIC, + "", + WS_VISIBLE|WS_CHILD|SS_WORDELLIPSIS, + 8, + 10, + clientRect.right-clientRect.left-2*8 - 50, + 20, + m_hWnd, + ( HMENU )ID_PROGRESS_STATUS1, + g_hInstance, + NULL ); + m_hWndStatus1 = hWnd; + y += 20; + + // status text line #2 + hWnd = CreateWindowEx( + 0, + WC_STATIC, + "", + WS_VISIBLE|WS_CHILD|SS_PATHELLIPSIS, + 8, + y, + clientRect.right-clientRect.left-2*8 -50, + 20, + m_hWnd, + ( HMENU )ID_PROGRESS_STATUS2, + g_hInstance, + NULL ); + m_hWndStatus2 = hWnd; + y += 20; + + // status text line #3 + hWnd = CreateWindowEx( + 0, + WC_STATIC, + "", + WS_VISIBLE|WS_CHILD|SS_PATHELLIPSIS, + 8, + y, + clientRect.right-clientRect.left-2*8 -50, + 20, + m_hWnd, + ( HMENU )ID_PROGRESS_STATUS3, + g_hInstance, + NULL ); + m_hWndStatus3 = hWnd; + y += 20; + + // set font + SendMessage( m_hWndStatus1, WM_SETFONT, ( WPARAM )g_hProportionalFont, TRUE ); + SendMessage( m_hWndStatus2, WM_SETFONT, ( WPARAM )g_hProportionalFont, TRUE ); + SendMessage( m_hWndStatus3, WM_SETFONT, ( WPARAM )g_hProportionalFont, TRUE ); + + if ( bHasMeter ) + { + // percent + hWnd = CreateWindowEx( + 0, + WC_STATIC, + "0%", + WS_VISIBLE|WS_CHILD|SS_RIGHT, + ( clientRect.right-clientRect.left ) - 2*8 - 50, + y - 20, + 50, + 20, + m_hWnd, + ( HMENU )ID_PROGRESS_PERCENT, + g_hInstance, + NULL ); + m_hWndPercent = hWnd; + SendMessage( m_hWndPercent, WM_SETFONT, ( WPARAM )g_hProportionalFont, TRUE ); + + // progress meter + ch = GetSystemMetrics( SM_CYVSCROLL ); + cw = ( clientRect.right-clientRect.left ) - 2*8; + cx = ( clientRect.left + clientRect.right )/2 - cw/2; + cy = y; + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + PROGRESS_CLASS, + NULL, + WS_VISIBLE|WS_CHILD, + cx, + cy, + cw, + ch, + m_hWnd, + ( HMENU )ID_PROGRESS_METER, + g_hInstance, + NULL ); + m_hWndMeter = hWnd; + y = cy+ch; + + // ensure bar is reset + SendMessage( m_hWndMeter, PBM_SETRANGE, 0, 0 ); + SendMessage( m_hWndMeter, PBM_SETPOS, 0, 0 ); + } + else + { + m_hWndPercent = NULL; + m_hWndMeter = NULL; + } + + m_bCancelPressed = false; + if ( canCancel ) + { + ch = 25; + cw = 80; + cx = ( clientRect.left + clientRect.right )/2 - cw/2; + cy = clientRect.bottom - 8 - ch; + + // cancel button + hWnd = CreateWindowEx( + 0, + WC_BUTTON, + "Cancel", + WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, + cx, + cy, + cw, + ch, + m_hWnd, + ( HMENU )ID_PROGRESS_CANCEL, + g_hInstance, + NULL ); + m_hWndCancel = hWnd; + + SendMessage( m_hWndCancel, WM_SETFONT, ( WPARAM )g_hProportionalFont, TRUE ); + } + + // get parent rectangle + GetWindowRect( g_hDlgMain, &parentRect ); + cx = ( parentRect.left + parentRect.right )/2 - PROGRESS_WIDTH/2; + cy = ( parentRect.top + parentRect.bottom )/2 - dialogHeight/2; + + MoveWindow( m_hWnd, cx, cy, PROGRESS_WIDTH, dialogHeight, FALSE ); + ShowWindow( m_hWnd, SHOW_OPENWINDOW ); +} + +//----------------------------------------------------------------------------- +// CProgress::~CProgress +// +//----------------------------------------------------------------------------- +CProgress::~CProgress() +{ + if ( !m_hWnd ) + return; + + DestroyWindow( m_hWnd ); + m_hWnd = NULL; +} + +//----------------------------------------------------------------------------- +// CProgress::CProgress +// +//----------------------------------------------------------------------------- +CProgress::CProgress() +{ + // set up our window class + WNDCLASS wndclass; + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = Progress_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = sizeof( CProgress* ); + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = "PROGRESSCLASS"; + RegisterClass( &wndclass ); + + m_hWnd = 0; + m_bCancelPressed = false; +} diff --git a/utils/xbox/vxconsole/remote_cmds.cpp b/utils/xbox/vxconsole/remote_cmds.cpp new file mode 100644 index 0000000..f74bda0 --- /dev/null +++ b/utils/xbox/vxconsole/remote_cmds.cpp @@ -0,0 +1,484 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// REMOTE_CMDS.CPP +// +// Remote commands received by an external application and dispatched. +//=====================================================================================// +#include "vxconsole.h" + +remoteCommand_t *g_remoteCommands[MAX_RCMDS]; +int g_numRemoteCommands; + +//----------------------------------------------------------------------------- +// MatchRemoteCommands +// +//----------------------------------------------------------------------------- +int MatchRemoteCommands( char *pCmdStr, const char *cmdList[], int maxCmds ) +{ + int numCommands = 0; + + // look in local + int matchLen = strlen( pCmdStr ); + for ( int i=0; i<g_numRemoteCommands; i++ ) + { + if ( !strnicmp( pCmdStr, g_remoteCommands[i]->strCommand, matchLen ) ) + { + cmdList[numCommands++] = g_remoteCommands[i]->strCommand; + if ( numCommands >= maxCmds ) + break; + } + } + + return ( numCommands ); +} + +//----------------------------------------------------------------------------- +// GetToken +// +//----------------------------------------------------------------------------- +char *GetToken( char **ppTokenStream ) +{ + static char token[MAX_TOKENCHARS]; + int len; + char c; + char *pData; + + len = 0; + token[0] = 0; + + if ( !ppTokenStream ) + return NULL; + + pData = *ppTokenStream; + + // skip whitespace +skipwhite: + while ( ( c = *pData ) <= ' ' ) + { + if ( !c ) + goto cleanup; + pData++; + } + + // skip // comments + if ( c=='/' && pData[1] == '/' ) + { + while ( *pData && *pData != '\n' ) + pData++; + goto skipwhite; + } + + // handle quoted strings specially + if ( c == '\"' ) + { + pData++; + while ( 1 ) + { + c = *pData++; + if ( c=='\"' || !c ) + goto cleanup; + + token[len] = c; + len++; + if ( len > MAX_TOKENCHARS-1 ) + goto cleanup; + } + } + + // parse a regular word + do + { + token[len] = c; + pData++; + len++; + if ( len > MAX_TOKENCHARS-1 ) + break; + c = *pData; + } + while ( c > ' ' && c <= '~' ); + +cleanup: + token[len] = 0; + *ppTokenStream = pData; + return ( token ); +} + +//----------------------------------------------------------------------------- +// CommandCompleted +// +//----------------------------------------------------------------------------- +void CommandCompleted( int errCode ) +{ + char cmdString[MAX_PATH]; + + // send command complete + sprintf( cmdString, "%s!__complete__%d", VXCONSOLE_COMMAND_PREFIX, errCode ); + DmAPI_SendCommand( cmdString, true ); +} + +//----------------------------------------------------------------------------- +// DebugCommand +//----------------------------------------------------------------------------- +void DebugCommand( const char *pStrFormat, ... ) +{ + char buffer[MAX_QUEUEDSTRINGLEN]; + va_list arglist; + + if ( !g_debugCommands ) + return; + + va_start( arglist, pStrFormat ); + _vsnprintf( buffer, MAX_QUEUEDSTRINGLEN, pStrFormat, arglist ); + va_end( arglist ); + + PrintToQueue( RGB( 0,128,0 ), "[CMD]: %s", buffer ); +} + +//----------------------------------------------------------------------------- +// Remote_NotifyPrintFunc +// +//----------------------------------------------------------------------------- +DWORD __stdcall Remote_NotifyPrintFunc( const CHAR *pStrNotification ) +{ + int color; + + if ( !strnicmp( pStrNotification, VXCONSOLE_PRINT_PREFIX, strlen( VXCONSOLE_PRINT_PREFIX ) ) ) + { + // skip past prefix! + pStrNotification += strlen( VXCONSOLE_PRINT_PREFIX )+1; + } + + color = XBX_CLR_DEFAULT; + + if ( !strnicmp( pStrNotification, VXCONSOLE_COLOR_PREFIX, strlen( VXCONSOLE_COLOR_PREFIX ) ) ) + { + // skip past prefix[12345678] + char buff[16]; + pStrNotification += strlen( VXCONSOLE_COLOR_PREFIX ); + memcpy( buff, pStrNotification, 10 ); + if ( buff[0] == '[' && buff[9] == ']' ) + { + buff[0] = ' '; + buff[9] = ' '; + buff[10] = '\0'; + + sscanf( buff, "%x", &color ); + pStrNotification += 10; + } + } + + PrintToQueue( color, "%s\n", pStrNotification ); + return S_OK; +} + +//----------------------------------------------------------------------------- +// Remote_NotifyDebugString +// +// Print as [DBG]:xxxx +//----------------------------------------------------------------------------- +DWORD __stdcall Remote_NotifyDebugString( ULONG dwNotification, DWORD dwParam ) +{ + if ( g_captureDebugSpew ) + { + PDMN_DEBUGSTR p = ( PDMN_DEBUGSTR )dwParam; + int len; + + // strip all terminating cr + len = p->Length-1; + while ( len > 0 ) + { + if ( p->String[len] != '\n' ) + { + len++; + break; + } + len--; + } + + // for safety, terminate + CHAR* strTemp = new CHAR[len+1]; + memcpy( strTemp, p->String, len*sizeof( CHAR ) ); + strTemp[len] = '\0'; + + PrintToQueue( RGB( 0,0,255 ), "[DBG]: %s\n", strTemp ); + + delete[] strTemp; + } + + // Don't let the compiler complain about unused parameters + ( VOID )dwNotification; + + return 0; +} + +//----------------------------------------------------------------------------- +// Remote_CompareCommands +// +//----------------------------------------------------------------------------- +int Remote_CompareCommands( const void *pElem1, const void *pElem2 ) +{ + remoteCommand_t *pCmd1; + remoteCommand_t *pCmd2; + + pCmd1 = *( remoteCommand_t** )( pElem1 ); + pCmd2 = *( remoteCommand_t** )( pElem2 ); + + return ( strcmp( pCmd1->strCommand, pCmd2->strCommand ) ); +} + +//----------------------------------------------------------------------------- +// Remote_DeleteCommands +// +//----------------------------------------------------------------------------- +void Remote_DeleteCommands() +{ + if ( !g_numRemoteCommands ) + return; + + for ( int i=0; i<g_numRemoteCommands; i++ ) + { + delete [] g_remoteCommands[i]->strCommand; + delete [] g_remoteCommands[i]->strHelp; + delete g_remoteCommands[i]; + + g_remoteCommands[i] = NULL; + } + + g_numRemoteCommands = 0; +} + +//----------------------------------------------------------------------------- +// Remote_AddCommand +// +//----------------------------------------------------------------------------- +bool Remote_AddCommand( char *command, char *helptext ) +{ + if ( g_numRemoteCommands == MAX_RCMDS ) + { + // full + return false; + } + + // look for duplicate + int i; + for ( i = 0; i < g_numRemoteCommands; i++ ) + { + if ( !stricmp( command, g_remoteCommands[i]->strCommand ) ) + break; + } + if ( i < g_numRemoteCommands ) + { + // already in list, skip - not an error + return true; + } + + // add new command to list + g_remoteCommands[g_numRemoteCommands] = new remoteCommand_t; + g_remoteCommands[g_numRemoteCommands]->strCommand = new char[strlen( command )+1]; + strcpy( g_remoteCommands[g_numRemoteCommands]->strCommand, command ); + + g_remoteCommands[g_numRemoteCommands]->strHelp = new char[strlen( helptext )+1]; + strcpy( g_remoteCommands[g_numRemoteCommands]->strHelp, helptext ); + + g_numRemoteCommands++; + + // success + return true; +} + +//----------------------------------------------------------------------------- +// rc_AddCommands +// +// Exposes an app's list of remote commands +//----------------------------------------------------------------------------- +int rc_AddCommands( char *commandPtr ) +{ + char* cmdToken; + int numCommands; + int cmdList; + int retAddr; + int retVal; + int errCode; + xrCommand_t* locallist; + + errCode = -1; + + // pacifier for lengthy operation + ConsoleWindowPrintf( RGB( 0, 0, 0 ), "Receiving Console Commands From Game..." ); + + // get number of commands + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &numCommands ); + + // get command list + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &cmdList ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &retAddr ); + + locallist = new xrCommand_t[numCommands]; + memset( locallist, 0, numCommands*sizeof( xrCommand_t ) ); + + // get the caller's command list + DmGetMemory( ( void* )cmdList, numCommands*sizeof( xrCommand_t ), locallist, NULL ); + + int numAdded = 0; + for ( int i=0; i<numCommands; i++ ) + { + if ( Remote_AddCommand( locallist[i].nameString, locallist[i].helpString ) ) + numAdded++; + } + + // sort the list + qsort( g_remoteCommands, g_numRemoteCommands, sizeof( remoteCommand_t* ), Remote_CompareCommands ); + + ConsoleWindowPrintf( RGB( 0, 0, 0 ), "Completed.\n" ); + + // return the result + retVal = numAdded; + int xboxRetVal = BigDWord( retVal ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + DebugCommand( "0x%8.8x = AddCommands( 0x%8.8x, 0x%8.8x )\n", retVal, numCommands, cmdList ); + + delete [] locallist; + + // success + errCode = 0; + + if ( g_bPlayTestMode ) + { + if ( g_connectedToApp ) + { + // send the developer command + ProcessCommand( "developer 1" ); + } + } + +cleanUp: + return ( errCode ); +} + +//----------------------------------------------------------------------------- +// Remote_NotifyCommandFunc +// +//----------------------------------------------------------------------------- +DWORD __stdcall Remote_NotifyCommandFunc( const CHAR *strNotification ) +{ + CHAR* commandPtr; + CHAR* cmdToken; + int errCode; + bool async; + + // skip over the command prefix and the exclamation mark + strNotification += strlen( VXCONSOLE_COMMAND_PREFIX ) + 1; + commandPtr = ( CHAR* )strNotification; + + // failure until otherwise + errCode = -1; + + // default synchronous + async = false; + + cmdToken = GetToken( &commandPtr ); + + if ( cmdToken && !stricmp( cmdToken, "AddCommands()" ) ) + { + errCode = rc_AddCommands( commandPtr ); + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "SetProfile()" ) ) + { + // first arg dictates routing + cmdToken = GetToken( &commandPtr ); + if ( cmdToken && !stricmp( cmdToken, "cpu" ) ) + errCode = rc_SetCpuProfile( commandPtr ); + else if ( cmdToken && !stricmp( cmdToken, "texture" ) ) + errCode = rc_SetTexProfile( commandPtr ); + + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "SetProfileData()" ) ) + { + // first arg dictates routing + cmdToken = GetToken( &commandPtr ); + if ( cmdToken && !stricmp( cmdToken, "cpu" ) ) + errCode = rc_SetCpuProfileData( commandPtr ); + else if ( cmdToken && !stricmp( cmdToken, "texture" ) ) + errCode = rc_SetTexProfileData( commandPtr ); + + async = true; + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "TextureList()" ) ) + { + errCode = rc_TextureList( commandPtr ); + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "MaterialList()" ) ) + { + errCode = rc_MaterialList( commandPtr ); + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "SoundList()" ) ) + { + errCode = rc_SoundList( commandPtr ); + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "TimeStampLog()" ) ) + { + errCode = rc_TimeStampLog( commandPtr ); + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "MemDump()" ) ) + { + errCode = rc_MemDump( commandPtr ); + async = true; + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "MapInfo()" ) ) + { + errCode = rc_MapInfo( commandPtr ); + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "Assert()" ) ) + { + errCode = rc_Assert( commandPtr ); + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "FreeMemory()" ) ) + { + errCode = rc_FreeMemory( commandPtr ); + async = true; + goto cleanUp; + } + else if ( cmdToken && !stricmp( cmdToken, "Disconnect()" ) ) + { + // disconnect requires specialized processing + // send command status first while connection valid, then do actual disconnect + // disconnect is always assumed to be valid, can't be denied + CommandCompleted( 0 ); + DoDisconnect( TRUE ); + return S_OK; + } + else + { + // unknown command + PrintToQueue( RGB( 255,0,0 ), "Unknown Command: %s\n", strNotification ); + goto cleanUp; + } + +cleanUp: + if ( !async ) + CommandCompleted( errCode ); + + return ( S_OK ); +} diff --git a/utils/xbox/vxconsole/resource.h b/utils/xbox/vxconsole/resource.h new file mode 100644 index 0000000..ed5c602 --- /dev/null +++ b/utils/xbox/vxconsole/resource.h @@ -0,0 +1,241 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by vxconsole.rc +// +#define MENU_PROFILE 4 +#define MENU_CPUPROFILE 4 +#define MENU_VXCONSOLE 100 +#define IDD_VXCONSOLE 104 +#define IDD_CONFIG 111 +#define IDC_LABEL 113 +#define IDD_SYNCFILES 116 +#define MENU_SHOWTEXTURES 118 +#define MENU_TEXPROFILE 120 +#define MENU_BINDOPTIONS 122 +#define IDD_MODIFYBIND 123 +#define MENU_SHOWMATERIALS 124 +#define MENU_SHOWSOUNDS 125 +#define MENU_SHOWMEMORYDUMP 127 +#define IDD_BUG 128 +#define MENU_TIMESTAMPLOG 129 +#define IDD_EXCLUDEPATHS 131 +#define IDD_INSTALL 132 +#define MENU_MEMPROFILE 133 +#define IDI_VXCONSOLE 200 +#define IDI_DISCONNECTED 201 +#define IDI_CONNECT1_ON 202 +#define IDI_CONNECT2_ON 203 +#define IDI_CONNECT2_OFF 204 +#define IDC_COMMAND 1000 +#define IDC_OUTPUT 1010 +#define IDC_CONFIG_XBOXNAME 1015 +#define IDC_CONFIG_REMOTEPATH 1016 +#define IDC_CONFIG_LOCALPATH 1017 +#define IDC_CONFIG_PING 1018 +#define IDC_OK 1019 +#define IDC_CANCEL 1020 +#define IDC_CONFIG_CLEARONCONNECT 1021 +#define IDC_CONFIG_TARGETPATH 1022 +#define IDC_CONFIG_XBELOCALPATH 1023 +#define IDC_CONFIG_XEXLOCALPATH 1023 +#define IDC_CONFIG_XBETARGETPATH 1024 +#define IDC_CONFIG_XEXTARGETPATH 1024 +#define IDC_CONFIG_INSTALLPATH 1025 +#define IDC_CONFIG_LOADSYMBOLS 1028 +#define IDC_SYNCFILES_LOCALPATH 1029 +#define IDC_SYNCFILES_TARGETPATH 1030 +#define IDC_SYNCFILES_FORCESYNC 1035 +#define IDC_SYNCFILES_NOWRITE 1036 +#define IDC_SYNCFILES_DELETEORPHANS 1037 +#define IDC_CONFIG_SAMPLEFILE 1038 +#define IDC_SYNCFILES_VERBOSE 1038 +#define IDC_CONFIG_SAMPLELOCAL 1039 +#define IDC_SYNCFILES_ANDEXISTSONXBOX 1039 +#define IDC_CONFIG_SAMPLETARGET 1040 +#define IDC_CONFIG_XBEFORCESYNC 1045 +#define IDC_CONFIG_XEXFORCESYNC 1045 +#define IDC_CONFIG_XBESYNCONCONNECT 1046 +#define IDC_CONFIG_XEXSYNCONCONNECT 1046 +#define IDC_MODIFYBIND_MENUNAME 1050 +#define IDC_MODIFYBIND_COMMAND 1051 +#define IDC_MODIFYBIND_KEYCODE 1052 +#define IDC_CONFIG_ALWAYSAUTOCONNECT 1053 +#define IDC_CONFIG_STARTMINIMIZED 1054 +#define IDC_CONFIG_CAPTUREDEBUGSPEW 1055 +#define IDC_BUG_CLEARFORM 1056 +#define IDC_BUG_TITLE 1057 +#define IDC_BUG_DESCRIPTION 1058 +#define IDC_BUG_CLEARFORM2 1059 +#define IDC_BUG_UPDATE 1059 +#define IDC_BUG_INCLUDEBSP 1060 +#define IDC_BUG_SAVEGAME 1061 +#define IDC_BUG_INCLUDEVMF 1062 +#define IDC_BUG_TAKESHOT 1063 +#define IDC_BUG_SEVERITY 1065 +#define IDC_BUG_REPORTTYPE 1066 +#define IDC_BUG_PRIORITY 1067 +#define IDC_BUG_AREA 1068 +#define IDC_BUG_TAKESHOT_LABEL 1069 +#define IDC_BUG_SAVEGAME_LABEL 1070 +#define IDC_BUG_INCLUDEBSP_LABEL 1071 +#define IDC_BUG_INCLUDEVMF_LABEL 1072 +#define IDC_BUG_POSITION_LABEL 1073 +#define IDC_BUG_ORIENTATION_LABEL 1074 +#define IDC_BUG_MAP_LABEL 1075 +#define IDC_BUG_BUILD_LABEL 1076 +#define IDC_BUG_SUBMITTER_LABEL 1077 +#define IDC_BUG_MAPNUMBER 1078 +#define IDC_BUG_SUBMIT 1079 +#define IDC_BUG_SEVERITY2 1080 +#define IDC_BUG_OWNER 1080 +#define IDC_BUG_GAME 1082 +#define IDC_CHECK1 1083 +#define IDC_BUG_COMPRESS_SCREENSHOT 1083 +#define IDC_PATHS_LINKGAMEDIRS 1083 +#define IDC_INSTALL_FORCESYNC 1083 +#define IDC_PATHS_TREE 1085 +#define IDC_PATHS_RESCAN 1086 +#define IDC_PATHS_EXPAND 1087 +#define IDC_PATHS_COLLAPSE 1088 +#define IDC_INSTALL_LIST 1088 +#define IDC_INSTALL_REFRESH 1089 +#define IDC_CHECK2 1091 +#define IDC_INSTALL_CLEANTARGET 1091 +#define IDR_MAIN_ACCEL 3000 +#define IDM_CONNECT 40002 +#define IDM_DEBUGMONITOR 40004 +#define IDM_DEBUGCOMMANDS 40008 +#define IDM_AUTOCONNECT 40009 +#define IDM_DISCONNECT 40013 +#define IDM_EXIT 40017 +#define IDM_CONFIG 40018 +#define IDM_DEBUGMEMORY 40019 +#define IDM_FILELOG 40021 +#define IDM_CLEARLOG 40026 +#define IDM_ENABLELOG 40027 +#define IDM_REFRESHLOG 40031 +#define ID_LOG_SUMMARY 40032 +#define IDM_SUMMARYLOG 40035 +#define ID_Menu 40048 +#define IDM_PROFILESAMPLES 40064 +#define IDM_PROFILEHISTORY 40066 +#define IDM_SYNCTARGET 40073 +#define IDM_SYNCIFNEWER 40074 +#define IDM_ENABLEFILESERVING 40075 +#define ID_CONNECTION_FILESERVING 40076 +#define IDM_FILESERVING_LOCALONLY 40080 +#define IDM_FILESERVING_REMOTEONLY 40081 +#define IDM_FILESERVING_LOCALFIRST 40083 +#define IDM_FILESYNC_OFF 40088 +#define IDM_FILESYNC_ALWAYS 40089 +#define IDM_FILESYNC_IFNEWER 40090 +#define IDM_EXPORTLOG 40092 +#define ID_Menu40094 40094 +#define IDM_SYMBOLS_ADDRESS 40106 +#define IDM_SYMBOLS_FUNCTIONNAME 40110 +#define IDM_SYMBOLS_MODULEANDLINE 40112 +#define IDM_SYMBOLS_FILEPATHANDLINE 40114 +#define IDM_SYMBOLS_LOAD 40116 +#define IDM_SYNCFILES 40117 +#define IDM_SYMBOLS_DETAILS 40119 +#define IDM_OPTIONS_TREEVIEW 40121 +#define ID_Menu40123 40123 +#define IDM_SHOWMATERIALS 40124 +#define IDM_REFRESH 40127 +#define IDM_SHOWRESOURCES_TEXTURES 40130 +#define IDM_OPTIONS_CURRENTFRAME 40132 +#define IDM_OPTIONS_SUMMARY 40135 +#define IDM_OPTIONS_REFRESH 40136 +#define IDM_OPTIONS_EXPORT 40137 +#define IDM_OPTIONS_FULLPATH 40139 +#define ID_CONNECTION_PROFILING 40140 +#define ID_PROFILING_CPU 40141 +#define ID_PROFILING_TEXTURE 40142 +#define ID_CONNECTION_TEXTUREPROFILING 40147 +#define IDM_CPU_SAMPLES 40148 +#define IDM_CPU_HISTORY 40149 +#define IDM_SHOWRESOURCES_MATERIALS 40154 +#define IDM_SHOWRESOURCES_MODELS 40155 +#define ID_CONNECTION_EE 40157 +#define IDM_CPUPROFILE_TICKMARKS 40160 +#define IDM_CPUPROFILE_COLORS 40161 +#define IDM_CPUPROFILE_ZOOMIN 40162 +#define IDM_CPUPROFILE_ZOOMOUT 40163 +#define IDM_CPUPROFILE_ENABLE 40164 +#define IDM_TEXPROFILE_TICKMARKS 40166 +#define IDM_TEXPROFILE_COLORS 40168 +#define IDM_TEXPROFILE_ZOOMIN 40172 +#define IDM_TEXPROFILE_ZOOMOUT 40173 +#define IDM_TEXPROFILE_ENABLE 40174 +#define IDM_TEXPROFILE_CURRENTFRAME 40176 +#define ID_Menu40177 40177 +#define ID_VPROFILING_SHOWTEXTURE 40178 +#define ID_Menu40189 40189 +#define IDM_BINDOPTIONS_MODIFY 40192 +#define IDM_BINDOPTIONS_DELETE 40193 +#define IDM_TIMESTAMPLOG 50502 +#define IDM_CPUPROFILE_FPSLABELS 50505 +#define IDM_SHOWRESOURCES_SOUNDS 50509 +#define IDM_OPTIONS_PLAYSOUND 50513 +#define IDM_D3D_SAMPLES 50516 +#define IDM_D3D_HISTORY 50517 +#define IDM_MEMORYDUMP 50520 +#define IDM_OPTIONS_BYTES 50527 +#define IDM_OPTIONS_KILOBYTES 50530 +#define IDM_OPTIONS_MEGABYTES 50531 +#define IDM_OPTIONS_COLLAPSEOUTPUT 50533 +#define IDM_SYNCINSTALL 50535 +#define ID_Menu50536 50536 +#define IDM_FILESYNC_ANDEXISTSONTARGET 50539 +#define ID_CONNECTION_SEARCHPATHS 50540 +#define ID_SEARCHPATHS_NOZIPS 50541 +#define ID_SEARCHPATHS_PAKFILESFIRST 50542 +#define ID_SEARCHPATHS_PAKFILES 50543 +#define ID_Menu50546 50546 +#define IDM_SYNCINSTALL_TODVD 50547 +#define IDM_SYNCINSTALL_TOHDD 50548 +#define IDM_SHOWRESOURCES_BUG 50550 +#define IDM_BUG 50552 +#define IDM_SYNCXEX 50553 +#define IDM_DEBUGSPEW 50557 +#define IDM_CAPTUREGAMESPEW 50560 +#define IDM_CAPTUREDEBUGSPEW 50561 +#define ID_CONNECTION_DVDEXCLUDEPATHS 50562 +#define IDM_DVDEXCLUDEPATHS 50563 +#define IDM_EXCLUDEPATHS 50564 +#define ID_OPTIONS_SHOWTEXTURE 50565 +#define IDM_OPTIONS_SHOWTEXTURE 50566 +#define IDM_OPTIONS_DRAWTEXTURE 50567 +#define ID_OPTIONS_HIDETEXTURE 50568 +#define IDM_OPTIONS_HIDETEXTURE 50569 +#define ID_PROFILING_SHOWMEMORYUSAGE 50570 +#define IDM_SHOWMEMORYUSAGE 50571 +#define IDM_SHOWFREEMEMORY 50572 +#define ID_OPTIONS_TICKMARKS 50573 +#define ID_OPTIONS_ZOOMIN 50574 +#define ID_OPTIONS_ZOOMOUT 50575 +#define ID_OPTIONS_ENABLE 50576 +#define IDM_MEMPROFILE_TICKMARKS 50577 +#define IDM_MEMPROFILE_ZOOMIN 50578 +#define IDM_MEMPROFILE_ZOOMOUT 50579 +#define IDM_MEMPROFILE_ENABLE 50580 +#define ID_OPTIONS_COLORS 50581 +#define IDM_MEMPROFILE_COLORS 50582 +#define ID_OPTIONS_CLEAR 50583 +#define IDM_OPTIONS_CLEAR 50584 +#define ID_PROFILING_TESTINGMODE 50585 +#define IDM_PLAYTESTMODE 50586 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 134 +#define _APS_NEXT_COMMAND_VALUE 50587 +#define _APS_NEXT_CONTROL_VALUE 1092 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/utils/xbox/vxconsole/show_materials.cpp b/utils/xbox/vxconsole/show_materials.cpp new file mode 100644 index 0000000..f57f5f9 --- /dev/null +++ b/utils/xbox/vxconsole/show_materials.cpp @@ -0,0 +1,575 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SHOW_MATERIALS.CPP +// +// Show Materials Display. +//=====================================================================================// +#include "vxconsole.h" + +#define ID_SHOWMATERIALS_LISTVIEW 100 + +// column id +#define ID_SM_NAME 0 +#define ID_SM_SHADER 1 +#define ID_SM_REFCOUNT 2 + +typedef struct +{ + int listIndex; + char *pName; + char *pShaderName; + int refCount; + char refCountBuff[16]; +} material_t; + +typedef struct +{ const CHAR* name; + int width; + int subItemIndex; + CHAR nameBuff[32]; +} label_t; + +HWND g_showMaterials_hWnd; +HWND g_showMaterials_hWndListView; +RECT g_showMaterials_windowRect; +int g_showMaterials_sortColumn; +int g_showMaterials_sortDescending; +material_t *g_showMaterials_pMaterials; +int g_showMaterials_numMaterials; +int g_showMaterials_currentFrame; + +label_t g_showMaterials_Labels[] = +{ + {"Name", 300, ID_SM_NAME}, + {"Shader", 150, ID_SM_SHADER}, + {"RefCount", 80, ID_SM_REFCOUNT}, +}; + +//----------------------------------------------------------------------------- +// ShowMaterials_SaveConfig +// +//----------------------------------------------------------------------------- +void ShowMaterials_SaveConfig() +{ + char buff[256]; + + Sys_SetRegistryInteger( "showMaterialsCurrentFrame", g_showMaterials_currentFrame ); + Sys_SetRegistryInteger( "showMaterialsSortColumn", g_showMaterials_sortColumn ); + Sys_SetRegistryInteger( "showMaterialsSortDescending", g_showMaterials_sortDescending ); + + WINDOWPLACEMENT wp; + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_showMaterials_hWnd, &wp ); + g_showMaterials_windowRect = wp.rcNormalPosition; + + sprintf( buff, "%d %d %d %d", g_showMaterials_windowRect.left, g_showMaterials_windowRect.top, g_showMaterials_windowRect.right, g_showMaterials_windowRect.bottom ); + Sys_SetRegistryString( "showMaterialsWindowRect", buff ); +} + +//----------------------------------------------------------------------------- +// ShowMaterials_LoadConfig +// +//----------------------------------------------------------------------------- +void ShowMaterials_LoadConfig() +{ + int numArgs; + char buff[256]; + + Sys_GetRegistryInteger( "showMaterialsCurrentFrame", false, g_showMaterials_currentFrame ); + Sys_GetRegistryInteger( "showMaterialsSortColumn", ID_SM_NAME, g_showMaterials_sortColumn ); + Sys_GetRegistryInteger( "showMaterialsSortDescending", false, g_showMaterials_sortDescending ); + + Sys_GetRegistryString( "showMaterialsWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_showMaterials_windowRect.left, &g_showMaterials_windowRect.top, &g_showMaterials_windowRect.right, &g_showMaterials_windowRect.bottom ); + if ( numArgs != 4 || g_showMaterials_windowRect.left < 0 || g_showMaterials_windowRect.top < 0 || g_showMaterials_windowRect.right < 0 || g_showMaterials_windowRect.bottom < 0 ) + memset( &g_showMaterials_windowRect, 0, sizeof( g_showMaterials_windowRect ) ); +} + +//----------------------------------------------------------------------------- +// ShowMaterials_Clear +// +//----------------------------------------------------------------------------- +void ShowMaterials_Clear() +{ + // delete all the list view entries + if ( g_showMaterials_hWnd ) + ListView_DeleteAllItems( g_showMaterials_hWndListView ); + + if ( !g_showMaterials_pMaterials ) + return; + + for ( int i=0; i<g_showMaterials_numMaterials; i++ ) + { + free( g_showMaterials_pMaterials[i].pName ); + free( g_showMaterials_pMaterials[i].pShaderName ); + } + + g_showMaterials_pMaterials = NULL; + g_showMaterials_numMaterials = 0; +} + +//----------------------------------------------------------------------------- +// ShowMaterials_Export +// +//----------------------------------------------------------------------------- +void ShowMaterials_Export() +{ +} + +//----------------------------------------------------------------------------- +// ShowMaterials_SetTitle +// +//----------------------------------------------------------------------------- +void ShowMaterials_SetTitle() +{ + char titleBuff[128]; + + if ( g_showMaterials_hWnd ) + { + strcpy( titleBuff, "Materials " ); + if ( g_showMaterials_currentFrame ) + strcat( titleBuff, " [FRAME]" ); + + SetWindowText( g_showMaterials_hWnd, titleBuff ); + } +} + +//----------------------------------------------------------------------------- +// ShowMaterials_CompareFunc +// +//----------------------------------------------------------------------------- +int CALLBACK ShowMaterials_CompareFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) +{ + material_t* pMaterialA = ( material_t* )lParam1; + material_t* pMaterialB = ( material_t* )lParam2; + + int sort = 0; + switch ( g_showMaterials_sortColumn ) + { + case ID_SM_NAME: + sort = stricmp( pMaterialA->pName, pMaterialB->pName ); + break; + + case ID_SM_SHADER: + sort = stricmp( pMaterialA->pShaderName, pMaterialB->pShaderName ); + break; + + case ID_SM_REFCOUNT: + sort = pMaterialA->refCount - pMaterialB->refCount; + break; + } + + // flip the sort order + if ( g_showMaterials_sortDescending ) + sort *= -1; + + return ( sort ); +} + +//----------------------------------------------------------------------------- +// ShowMaterials_SortItems +// +//----------------------------------------------------------------------------- +void ShowMaterials_SortItems() +{ + LVITEM lvitem; + material_t *pMaterial; + int i; + + if ( !g_showMaterials_hWnd ) + { + // only sort if window is visible + return; + } + + ListView_SortItems( g_showMaterials_hWndListView, ShowMaterials_CompareFunc, 0 ); + + memset( &lvitem, 0, sizeof( lvitem ) ); + lvitem.mask = LVIF_PARAM; + + // get each item and reset its list index + int itemCount = ListView_GetItemCount( g_showMaterials_hWndListView ); + for ( i=0; i<itemCount; i++ ) + { + lvitem.iItem = i; + ListView_GetItem( g_showMaterials_hWndListView, &lvitem ); + + pMaterial = ( material_t* )lvitem.lParam; + pMaterial->listIndex = i; + } + + // update list view columns with sort key + for ( i=0; i<sizeof( g_showMaterials_Labels )/sizeof( g_showMaterials_Labels[0] ); i++ ) + { + char symbol; + LVCOLUMN lvc; + + if ( i == g_showMaterials_sortColumn ) + symbol = g_showMaterials_sortDescending ? '<' : '>'; + else + symbol = ' '; + sprintf( g_showMaterials_Labels[i].nameBuff, "%s %c", g_showMaterials_Labels[i].name, symbol ); + + memset( &lvc, 0, sizeof( lvc ) ); + lvc.mask = LVCF_TEXT; + lvc.pszText = ( LPSTR )g_showMaterials_Labels[i].nameBuff; + + ListView_SetColumn( g_showMaterials_hWndListView, i, &lvc ); + } +} + +//----------------------------------------------------------------------------- +// ShowMaterials_AddViewItem +// +//----------------------------------------------------------------------------- +void ShowMaterials_AddViewItem( material_t* pMaterial ) +{ + LVITEM lvi; + + if ( !g_showMaterials_hWnd ) + { + // only valid if log window is visible + return; + } + + // update the text callback buffers + sprintf( pMaterial->refCountBuff, "%d", pMaterial->refCount ); + + int itemCount = ListView_GetItemCount( g_showMaterials_hWndListView ); + + // setup and insert at end of list + memset( &lvi, 0, sizeof( lvi ) ); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = itemCount; + lvi.iSubItem = 0; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; + lvi.lParam = ( LPARAM )pMaterial; + + // insert and set the real index + pMaterial->listIndex = ListView_InsertItem( g_showMaterials_hWndListView, &lvi ); +} + +//----------------------------------------------------------------------------- +// ShowMaterials_Refresh +// +//----------------------------------------------------------------------------- +void ShowMaterials_Refresh() +{ + char command[256]; + + strcpy( command, "mat_material_list" ); + +// if ( !g_showMaterials_currentFrame ) +// strcat( command, " all" ); + + // send the command to application which replies with list data + if ( g_connectedToApp ) + ProcessCommand( command ); +} + +//----------------------------------------------------------------------------- +// ShowMaterials_SizeWindow +// +//----------------------------------------------------------------------------- +void ShowMaterials_SizeWindow( HWND hwnd, int cx, int cy ) +{ + if ( cx==0 || cy==0 ) + { + RECT rcClient; + GetClientRect( hwnd, &rcClient ); + cx = rcClient.right; + cy = rcClient.bottom; + } + + // position the ListView + SetWindowPos( g_showMaterials_hWndListView, NULL, 0, 0, cx, cy, SWP_NOZORDER ); +} + +//----------------------------------------------------------------------------- +// ShowMaterials_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK ShowMaterials_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + material_t* pMaterial; + + switch ( message ) + { + case WM_CREATE: + return 0L; + + case WM_DESTROY: + ShowMaterials_SaveConfig(); + g_showMaterials_hWnd = NULL; + return 0L; + + case WM_INITMENU: + CheckMenuItem( ( HMENU )wParam, IDM_OPTIONS_CURRENTFRAME, MF_BYCOMMAND | ( g_showMaterials_currentFrame ? MF_CHECKED : MF_UNCHECKED ) ); + return 0L; + + case WM_SIZE: + ShowMaterials_SizeWindow( hwnd, LOWORD( lParam ), HIWORD( lParam ) ); + return 0L; + + case WM_NOTIFY: + switch ( ( ( LPNMHDR )lParam )->code ) + { + case LVN_COLUMNCLICK: + NMLISTVIEW* pnmlv; + pnmlv = ( NMLISTVIEW* )lParam; + if ( g_showMaterials_sortColumn == pnmlv->iSubItem ) + { + // user has clicked on same column - flip the sort + g_showMaterials_sortDescending ^= 1; + } + else + { + // sort by new column + g_showMaterials_sortColumn = pnmlv->iSubItem; + } + ShowMaterials_SortItems(); + return 0L; + + case LVN_GETDISPINFO: + NMLVDISPINFO* plvdi; + plvdi = ( NMLVDISPINFO* )lParam; + pMaterial = ( material_t* )plvdi->item.lParam; + switch ( plvdi->item.iSubItem ) + { + case ID_SM_NAME: + plvdi->item.pszText = pMaterial->pName; + return 0L; + + case ID_SM_SHADER: + plvdi->item.pszText = pMaterial->pShaderName; + return 0L; + + case ID_SM_REFCOUNT: + plvdi->item.pszText = pMaterial->refCountBuff; + return 0L; + + default: + break; + } + break; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_OPTIONS_REFRESH: + ShowMaterials_Refresh(); + return 0L; + + case IDM_OPTIONS_EXPORT: + ShowMaterials_Export(); + return 0L; + + case IDM_OPTIONS_CURRENTFRAME: + g_showMaterials_currentFrame ^= 1; + ShowMaterials_SetTitle(); + ShowMaterials_Refresh(); + return 0L; + } + break; + } + + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// ShowMaterials_Init +// +//----------------------------------------------------------------------------- +bool ShowMaterials_Init() +{ + // set up our window class + WNDCLASS wndclass; + + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = ShowMaterials_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_SHOWMATERIALS ); + wndclass.lpszClassName = "SHOWMATERIALSCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + ShowMaterials_LoadConfig(); + + return true; +} + +//----------------------------------------------------------------------------- +// ShowMaterials_Open +// +//----------------------------------------------------------------------------- +void ShowMaterials_Open() +{ + RECT clientRect; + HWND hWnd; + int i; + + if ( g_showMaterials_hWnd ) + { + // only one instance + if ( IsIconic( g_showMaterials_hWnd ) ) + ShowWindow( g_showMaterials_hWnd, SW_RESTORE ); + SetForegroundWindow( g_showMaterials_hWnd ); + return; + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "SHOWMATERIALSCLASS", + "", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 700, + 400, + g_hDlgMain, + NULL, + g_hInstance, + NULL ); + g_showMaterials_hWnd = hWnd; + + GetClientRect( g_showMaterials_hWnd, &clientRect ); + hWnd = CreateWindow( + WC_LISTVIEW, + "", + WS_VISIBLE|WS_CHILD|LVS_REPORT, + 0, + 0, + clientRect.right-clientRect.left, + clientRect.bottom-clientRect.top, + g_showMaterials_hWnd, + ( HMENU )ID_SHOWMATERIALS_LISTVIEW, + g_hInstance, + NULL ); + g_showMaterials_hWndListView = hWnd; + + // init list view columns + for ( i=0; i<sizeof( g_showMaterials_Labels )/sizeof( g_showMaterials_Labels[0] ); i++ ) + { + LVCOLUMN lvc; + memset( &lvc, 0, sizeof( lvc ) ); + + lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; + lvc.iSubItem = 0; + lvc.cx = g_showMaterials_Labels[i].width; + lvc.fmt = LVCFMT_LEFT; + lvc.pszText = ( LPSTR )g_showMaterials_Labels[i].name; + + ListView_InsertColumn( g_showMaterials_hWndListView, i, &lvc ); + } + + ListView_SetBkColor( g_showMaterials_hWndListView, g_backgroundColor ); + ListView_SetTextBkColor( g_showMaterials_hWndListView, g_backgroundColor ); + + DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP; + ListView_SetExtendedListViewStyleEx( g_showMaterials_hWndListView, style, style ); + + // populate list view + for ( i=0; i<g_showMaterials_numMaterials; i++ ) + ShowMaterials_AddViewItem( &g_showMaterials_pMaterials[i] ); + ShowMaterials_SortItems(); + + ShowMaterials_SetTitle(); + + if ( g_showMaterials_windowRect.right && g_showMaterials_windowRect.bottom ) + MoveWindow( g_showMaterials_hWnd, g_showMaterials_windowRect.left, g_showMaterials_windowRect.top, g_showMaterials_windowRect.right-g_showMaterials_windowRect.left, g_showMaterials_windowRect.bottom-g_showMaterials_windowRect.top, FALSE ); + ShowWindow( g_showMaterials_hWnd, SHOW_OPENWINDOW ); + + // get data from application + ShowMaterials_Refresh(); +} + +//----------------------------------------------------------------------------- +// rc_MaterialList +// +// Sent from application with material list +//----------------------------------------------------------------------------- +int rc_MaterialList( char* commandPtr ) +{ + char* cmdToken; + int numMaterials; + int materialList; + int retAddr; + int retVal; + int errCode = -1; + xrMaterial_t* pLocalList; + + // remove old entries + ShowMaterials_Clear(); + + // get number of materials + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &numMaterials ); + + // get material list + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &materialList ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &retAddr ); + + pLocalList = new xrMaterial_t[numMaterials]; + memset( pLocalList, 0, numMaterials*sizeof( xrMaterial_t ) ); + + g_showMaterials_numMaterials = numMaterials; + g_showMaterials_pMaterials = new material_t[numMaterials]; + memset( g_showMaterials_pMaterials, 0, numMaterials*sizeof( material_t ) ); + + // get the caller's command list + DmGetMemory( ( void* )materialList, numMaterials*sizeof( xrMaterial_t ), pLocalList, NULL ); + + // build out the resident list + for ( int i=0; i<numMaterials; i++ ) + { + // swap the structure + pLocalList[i].refCount = BigDWord( pLocalList[i].refCount ); + + g_showMaterials_pMaterials[i].pName = strdup( pLocalList[i].nameString ); + g_showMaterials_pMaterials[i].pShaderName = strdup( pLocalList[i].shaderString ); + g_showMaterials_pMaterials[i].refCount = pLocalList[i].refCount; + + // add to list view + ShowMaterials_AddViewItem( &g_showMaterials_pMaterials[i] ); + } + + // return the result + retVal = numMaterials; + int xboxRetVal = BigDWord( retVal ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + DebugCommand( "0x%8.8x = MaterialList( 0x%8.8x, 0x%8.8x )\n", retVal, numMaterials, materialList ); + + delete [] pLocalList; + + // update + ShowMaterials_SortItems(); + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} diff --git a/utils/xbox/vxconsole/show_memdump.cpp b/utils/xbox/vxconsole/show_memdump.cpp new file mode 100644 index 0000000..fc86833 --- /dev/null +++ b/utils/xbox/vxconsole/show_memdump.cpp @@ -0,0 +1,1440 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SHOW_MEMDUMP.CPP +// +// Show Mem Dump Display. +//=====================================================================================// +#include "vxconsole.h" + +#define ID_SHOWMEMDUMP_LISTVIEW 100 + +// column id, pool mode +#define ID_DUMPPOOL_POOL 0 +#define ID_DUMPPOOL_SIZE 1 +#define ID_DUMPPOOL_ALLOCATED 2 +#define ID_DUMPPOOL_FREE 3 +#define ID_DUMPPOOL_COMMITTED 4 +#define ID_DUMPPOOL_COMMITTEDSIZE 5 + +// column id, detailed mode +#define ID_DUMPDETAIL_ALLOCATION 0 +#define ID_DUMPDETAIL_CURRENTSIZE 1 +#define ID_DUMPDETAIL_PEAKSIZE 2 +#define ID_DUMPDETAIL_TOTALSIZE 3 +#define ID_DUMPDETAIL_OVERHEAD 4 +#define ID_DUMPDETAIL_PEAKOVERHEAD 5 +#define ID_DUMPDETAIL_TIME 6 +#define ID_DUMPDETAIL_CURRENTCOUNT 7 +#define ID_DUMPDETAIL_PEAKCOUNT 8 +#define ID_DUMPDETAIL_TOTALCOUNT 9 +#define ID_DUMPDETAIL_LTE16 10 +#define ID_DUMPDETAIL_LTE32 11 +#define ID_DUMPDETAIL_LTE128 12 +#define ID_DUMPDETAIL_LTE1024 13 +#define ID_DUMPDETAIL_GT1024 14 + +#define SHOW_BYTES 0 +#define SHOW_KILOBYTES 1 +#define SHOW_MEGABYTES 2 + +#define FORMAT_POOLS 0 +#define FORMAT_DETAILS 1 + +struct MemoryPool_t +{ + int pool; + char poolBuff[32]; + int size; + char sizeBuff[32]; + int allocated; + char allocatedBuff[32]; + int free; + char freeBuff[32]; + int committed; + char committedBuff[32]; + int committedSize; + char committedSizeBuff[32]; +}; + +struct MemoryDetail_t +{ + char *pAllocationName; + int currentSize; + char currentSizeBuff[32]; + int peakSize; + char peakSizeBuff[32]; + int totalSize; + char totalSizeBuff[32]; + int overheadSize; + char overheadSizeBuff[32]; + int peakOverheadSize; + char peakOverheadSizeBuff[32]; + int time; + char timeBuff[32]; + int currentCount; + char currentCountBuff[32]; + int peakCount; + char peakCountBuff[32]; + int totalCount; + char totalCountBuff[32]; + int lte16; + char lte16Buff[32]; + int lte32; + char lte32Buff[32]; + int lte128; + char lte128Buff[32]; + int lte1024; + char lte1024Buff[32]; + int gt1024; + char gt1024Buff[32]; +}; + +struct memory_t +{ + int listIndex; + MemoryPool_t pool; + MemoryDetail_t detail; +}; + +struct label_t +{ + const CHAR* name; + int width; + int subItemIndex; + CHAR nameBuff[64]; +}; + +HWND g_showMemDump_hWnd; +HWND g_showMemDump_hWndListView; +RECT g_showMemDump_windowRect; +int g_showMemDump_sortColumn; +int g_showMemDump_sortDescending; +memory_t *g_showMemDump_pMemory; +int g_showMemDump_numMemory; +int g_showMemDump_showBytes; +bool g_showMemDump_bCollapseOutput; +char g_showMemDump_currentFilename[MAX_PATH]; +int g_showMemDump_format; + +void ShowMemDump_Parse( const char *pBuffer, int fileSize ); + +label_t g_showMemDump_PoolLabels[] = +{ + {"Pool", 120, ID_DUMPPOOL_POOL}, + {"Size", 120, ID_DUMPPOOL_SIZE}, + {"Allocated Count", 120, ID_DUMPPOOL_ALLOCATED}, + {"Free Count", 120, ID_DUMPPOOL_FREE}, + {"Committed Count", 120, ID_DUMPPOOL_COMMITTED}, + {"Committed Size", 120, ID_DUMPPOOL_COMMITTEDSIZE}, +}; + +label_t g_showMemDump_DetailLabels[] = +{ + {"Allocation", 200, ID_DUMPDETAIL_ALLOCATION}, + {"Current Size", 120, ID_DUMPDETAIL_CURRENTSIZE}, + {"Peak Size", 120, ID_DUMPDETAIL_PEAKSIZE}, + {"Total Allocations", 120, ID_DUMPDETAIL_TOTALSIZE}, + {"Overhead Size", 120, ID_DUMPDETAIL_OVERHEAD}, + {"Peak Overhead Size", 120, ID_DUMPDETAIL_PEAKOVERHEAD}, + {"Time (ms)", 120, ID_DUMPDETAIL_TIME}, + {"Current Count", 120, ID_DUMPDETAIL_CURRENTCOUNT}, + {"Peak Count", 120, ID_DUMPDETAIL_PEAKCOUNT}, + {"Total Count", 120, ID_DUMPDETAIL_TOTALCOUNT}, + {"<=16 bytes", 100, ID_DUMPDETAIL_LTE16}, + {"17-32 bytes", 100, ID_DUMPDETAIL_LTE32}, + {"33-128 bytes", 100, ID_DUMPDETAIL_LTE128}, + {"129-1024 bytes", 100, ID_DUMPDETAIL_LTE1024}, + {"> 1024 bytes", 100, ID_DUMPDETAIL_GT1024}, +}; + +//----------------------------------------------------------------------------- +// ShowMemDump_FormatSize +// +//----------------------------------------------------------------------------- +char *ShowMemDump_FormatSize( int size, char *pBuff, bool bUnits ) +{ + switch ( g_showMemDump_showBytes ) + { + case SHOW_BYTES: + sprintf( pBuff, "%d", size ); + break; + + case SHOW_KILOBYTES: + sprintf( pBuff, "%.2f", (float)size/1024.0f ); + if ( bUnits ) + strcat( pBuff, " K"); + break; + + case SHOW_MEGABYTES: + sprintf( pBuff, "%.2f", (float)size/(1024.0f*1024.0f) ); + if ( bUnits ) + strcat( pBuff, " MB"); + break; + } + + return pBuff; +} + + +//----------------------------------------------------------------------------- +// ShowMemDump_SaveConfig +// +//----------------------------------------------------------------------------- +void ShowMemDump_SaveConfig() +{ + char buff[256]; + + Sys_SetRegistryInteger( "showMemDumpSortColumn", g_showMemDump_sortColumn ); + Sys_SetRegistryInteger( "showMemDumpSortDescending", g_showMemDump_sortDescending ); + Sys_SetRegistryInteger( "showMemDumpShowBytes", g_showMemDump_showBytes ); + + WINDOWPLACEMENT wp; + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_showMemDump_hWnd, &wp ); + g_showMemDump_windowRect = wp.rcNormalPosition; + + sprintf( buff, "%d %d %d %d", g_showMemDump_windowRect.left, g_showMemDump_windowRect.top, g_showMemDump_windowRect.right, g_showMemDump_windowRect.bottom ); + Sys_SetRegistryString( "showMemDumpWindowRect", buff ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_LoadConfig +// +//----------------------------------------------------------------------------- +void ShowMemDump_LoadConfig() +{ + int numArgs; + char buff[256]; + + Sys_GetRegistryInteger( "showMemDumpSortColumn", 0, g_showMemDump_sortColumn ); + Sys_GetRegistryInteger( "showMemDumpSortDescending", false, g_showMemDump_sortDescending ); + Sys_GetRegistryInteger( "showMemDumpShowBytes", SHOW_KILOBYTES, g_showMemDump_showBytes ); + + Sys_GetRegistryString( "showMemDumpWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_showMemDump_windowRect.left, &g_showMemDump_windowRect.top, &g_showMemDump_windowRect.right, &g_showMemDump_windowRect.bottom ); + if ( numArgs != 4 || g_showMemDump_windowRect.left < 0 || g_showMemDump_windowRect.top < 0 || g_showMemDump_windowRect.right < 0 || g_showMemDump_windowRect.bottom < 0 ) + memset( &g_showMemDump_windowRect, 0, sizeof( g_showMemDump_windowRect ) ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_Clear +// +//----------------------------------------------------------------------------- +void ShowMemDump_Clear() +{ + // delete all the list view entries + if ( g_showMemDump_hWnd ) + { + ListView_DeleteAllItems( g_showMemDump_hWndListView ); + } + + if ( !g_showMemDump_pMemory ) + return; + + for ( int i=0; i<g_showMemDump_numMemory; i++ ) + { + delete [] g_showMemDump_pMemory[i].detail.pAllocationName; + } + + Sys_Free( g_showMemDump_pMemory ); + + g_showMemDump_pMemory = NULL; + g_showMemDump_numMemory = 0; +} + +//----------------------------------------------------------------------------- +// ShowMemDump_Export +// +//----------------------------------------------------------------------------- +void ShowMemDump_Export() +{ + OPENFILENAME ofn; + char logFilename[MAX_PATH]; + int retval; + FILE* fp; + int i; + char buff[64]; + + if ( g_showMemDump_format != FORMAT_DETAILS ) + { + return; + } + + memset( &ofn, 0, sizeof( ofn ) ); + ofn.lStructSize = sizeof( ofn ); + ofn.hwndOwner = g_showMemDump_hWnd; + ofn.lpstrFile = logFilename; + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof( logFilename ); + ofn.lpstrFilter = "Excel CSV\0*.CSV\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = "c:\\"; + ofn.Flags = OFN_PATHMUSTEXIST; + + // display the Open dialog box. + retval = GetOpenFileName( &ofn ); + if ( !retval ) + return; + + Sys_AddExtension( ".csv", logFilename, sizeof( logFilename ) ); + + fp = fopen( logFilename, "wt+" ); + if ( !fp ) + return; + + // labels + fprintf( fp, "Allocation Type" ); + fprintf( fp, ",Current Size" ); + fprintf( fp, ",Peak Size" ); + fprintf( fp, ",Total Allocations" ); + fprintf( fp, ",Overhead Size" ); + fprintf( fp, ",Peak Overhead Size" ); + fprintf( fp, ",Time(ms)" ); + fprintf( fp, ",Current Count" ); + fprintf( fp, ",Peak Count" ); + fprintf( fp, ",Total Count" ); + fprintf( fp, ",<=16 Byte Allocations" ); + fprintf( fp, ",17-32 Byte Allocations" ); + fprintf( fp, ",33-128 Byte Allocations" ); + fprintf( fp, ",129-1024 Byte Allocations" ); + fprintf( fp, ",>1024 Byte Allocations" ); + fprintf( fp, "\n" ); + + // dump to the log + for ( i=0; i<g_showMemDump_numMemory; i++ ) + { + fprintf( fp, "\"%s\"", g_showMemDump_pMemory[i].detail.pAllocationName ); + fprintf( fp, ",%s", ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.currentSize, buff, false ) ); + fprintf( fp, ",%s", ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.peakSize, buff, false ) ); + fprintf( fp, ",%s", ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.totalSize, buff, false ) ); + fprintf( fp, ",%s", ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.overheadSize, buff, false ) ); + fprintf( fp, ",%s", ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.peakOverheadSize, buff, false ) ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.time ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.currentCount ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.peakCount ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.totalCount ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.lte16 ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.lte32 ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.lte128 ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.lte1024 ); + fprintf( fp, ",%d", g_showMemDump_pMemory[i].detail.gt1024 ); + fprintf( fp, "\n" ); + } + + fclose( fp ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_Summary +// +//----------------------------------------------------------------------------- +void ShowMemDump_Summary() +{ + char buff[1024]; + int i; + + if ( g_showMemDump_format != FORMAT_DETAILS ) + { + return; + } + + int currentSize = 0; + int peakSize = 0; + int totalSize = 0; + int overheadSize = 0; + int peakOverheadSize = 0; + int time = 0; + int currentCount = 0; + int peakCount = 0; + int totalCount = 0; + int lte16 = 0; + int lte32 = 0; + int lte128 = 0; + int lte1024 = 0; + int gt1024 = 0; + + // tally the totals + for (i=0; i<g_showMemDump_numMemory; i++) + { + if ( !strnicmp( g_showMemDump_pMemory[i].detail.pAllocationName, "Totals,", 7 ) ) + continue; + + currentSize += g_showMemDump_pMemory[i].detail.currentSize; + peakSize += g_showMemDump_pMemory[i].detail.peakSize; + totalSize += g_showMemDump_pMemory[i].detail.totalSize; + overheadSize += g_showMemDump_pMemory[i].detail.overheadSize; + peakOverheadSize += g_showMemDump_pMemory[i].detail.peakOverheadSize; + time += g_showMemDump_pMemory[i].detail.time; + currentCount += g_showMemDump_pMemory[i].detail.currentCount; + peakCount += g_showMemDump_pMemory[i].detail.peakCount; + totalCount += g_showMemDump_pMemory[i].detail.totalCount; + lte16 += g_showMemDump_pMemory[i].detail.lte16; + lte32 += g_showMemDump_pMemory[i].detail.lte32; + lte128 += g_showMemDump_pMemory[i].detail.lte128; + lte1024 += g_showMemDump_pMemory[i].detail.lte1024; + gt1024 += g_showMemDump_pMemory[i].detail.gt1024; + } + + sprintf( + buff, + "Entries:\t\t\t%d\n" + "Current Size:\t\t%.2f MB\n" + "Peak Size:\t\t%.2f MB\n" + "Total Size:\t\t%.2f MB\n" + "Overhead Size:\t\t%d\n" + "Peak Overhead Size:\t%d\n" + "Time:\t\t\t%d\n" + "Current Count:\t\t%d\n" + "Peak Count:\t\t%d\n" + "Total Count:\t\t%d\n" + "<= 16:\t\t\t%d\n" + "17-32:\t\t\t%d\n" + "33-128:\t\t\t%d\n" + "129-1024:\t\t%d\n" + "> 1024:\t\t\t%d\n", + g_showMemDump_numMemory, + (float)currentSize/( 1024.0F*1024.0F ), + (float)peakSize/( 1024.0F*1024.0F ), + (float)totalSize/( 1024.0F*1024.0F ), + overheadSize, + peakOverheadSize, + time, + currentCount, + peakCount, + totalCount, + lte16, + lte32, + lte128, + lte1024, + gt1024 ); + + MessageBox( g_showMemDump_hWnd, buff, "Memory Dump Summary", MB_OK|MB_APPLMODAL ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_SetTitle +// +//----------------------------------------------------------------------------- +void ShowMemDump_SetTitle() +{ + if ( g_showMemDump_hWnd ) + { + SetWindowText( g_showMemDump_hWnd, "Memory Dump" ); + } +} + +//----------------------------------------------------------------------------- +// ShowMemDump_CompareFunc +// +//----------------------------------------------------------------------------- +int CALLBACK ShowMemDump_CompareFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) +{ + memory_t* pMemoryA = (memory_t*)lParam1; + memory_t* pMemoryB = (memory_t*)lParam2; + + int sort = 0; + + if ( g_showMemDump_format == FORMAT_POOLS ) + { + switch ( g_showMemDump_sortColumn ) + { + case ID_DUMPPOOL_POOL: + sort = pMemoryA->pool.pool - pMemoryB->pool.pool; + break; + + case ID_DUMPPOOL_SIZE: + sort = pMemoryA->pool.size - pMemoryB->pool.size; + break; + + case ID_DUMPPOOL_ALLOCATED: + sort = pMemoryA->pool.allocated - pMemoryB->pool.allocated; + break; + + case ID_DUMPPOOL_FREE: + sort = pMemoryA->pool.free - pMemoryB->pool.free; + break; + + case ID_DUMPPOOL_COMMITTED: + sort = pMemoryA->pool.committed - pMemoryB->pool.committed; + break; + + case ID_DUMPPOOL_COMMITTEDSIZE: + sort = pMemoryA->pool.committedSize - pMemoryB->pool.committedSize; + break; + } + } + else + { + switch ( g_showMemDump_sortColumn ) + { + case ID_DUMPDETAIL_ALLOCATION: + sort = stricmp( pMemoryA->detail.pAllocationName, pMemoryB->detail.pAllocationName ); + break; + + case ID_DUMPDETAIL_CURRENTSIZE: + sort = pMemoryA->detail.currentSize - pMemoryB->detail.currentSize; + break; + + case ID_DUMPDETAIL_PEAKSIZE: + sort = pMemoryA->detail.peakSize - pMemoryB->detail.peakSize; + break; + + case ID_DUMPDETAIL_TOTALSIZE: + sort = pMemoryA->detail.totalSize - pMemoryB->detail.totalSize; + break; + + case ID_DUMPDETAIL_OVERHEAD: + sort = pMemoryA->detail.overheadSize - pMemoryB->detail.overheadSize; + break; + + case ID_DUMPDETAIL_PEAKOVERHEAD: + sort = pMemoryA->detail.peakOverheadSize - pMemoryB->detail.peakOverheadSize; + break; + + case ID_DUMPDETAIL_TIME: + sort = pMemoryA->detail.time - pMemoryB->detail.time; + break; + + case ID_DUMPDETAIL_CURRENTCOUNT: + sort = pMemoryA->detail.currentCount - pMemoryB->detail.currentCount; + break; + + case ID_DUMPDETAIL_PEAKCOUNT: + sort = pMemoryA->detail.peakCount - pMemoryB->detail.peakCount; + break; + + case ID_DUMPDETAIL_TOTALCOUNT: + sort = pMemoryA->detail.totalCount - pMemoryB->detail.totalCount; + break; + + case ID_DUMPDETAIL_LTE16: + sort = pMemoryA->detail.lte16 - pMemoryB->detail.lte16; + break; + + case ID_DUMPDETAIL_LTE32: + sort = pMemoryA->detail.lte32 - pMemoryB->detail.lte32; + break; + + case ID_DUMPDETAIL_LTE128: + sort = pMemoryA->detail.lte128 - pMemoryB->detail.lte128; + break; + + case ID_DUMPDETAIL_LTE1024: + sort = pMemoryA->detail.lte1024 - pMemoryB->detail.lte1024; + break; + + case ID_DUMPDETAIL_GT1024: + sort = pMemoryA->detail.gt1024 - pMemoryB->detail.gt1024; + break; + } + } + + // flip the sort order + if ( g_showMemDump_sortDescending ) + { + sort *= -1; + } + + return ( sort ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_SortItems +// +//----------------------------------------------------------------------------- +void ShowMemDump_SortItems() +{ + LVITEM lvitem; + memory_t *pMemory; + int i; + + if ( !g_showMemDump_hWnd ) + { + // only sort if window is visible + return; + } + + ListView_SortItems( g_showMemDump_hWndListView, ShowMemDump_CompareFunc, 0 ); + + memset( &lvitem, 0, sizeof( lvitem ) ); + lvitem.mask = LVIF_PARAM; + + // get each item and reset its list index + int itemCount = ListView_GetItemCount( g_showMemDump_hWndListView ); + for ( i=0; i<itemCount; i++ ) + { + lvitem.iItem = i; + ListView_GetItem( g_showMemDump_hWndListView, &lvitem ); + + pMemory = (memory_t*)lvitem.lParam; + pMemory->listIndex = i; + } + + int count; + label_t* pLabels; + if ( g_showMemDump_format == FORMAT_POOLS ) + { + count = sizeof( g_showMemDump_PoolLabels )/sizeof( g_showMemDump_PoolLabels[0] ); + pLabels = g_showMemDump_PoolLabels; + } + else + { + count = sizeof( g_showMemDump_DetailLabels )/sizeof( g_showMemDump_DetailLabels[0] ); + pLabels = g_showMemDump_DetailLabels; + } + + // update list view columns with sort key + for ( i = 0; i < count; i++ ) + { + char symbol; + LVCOLUMN lvc; + + if ( i == g_showMemDump_sortColumn ) + symbol = g_showMemDump_sortDescending ? '<' : '>'; + else + symbol = ' '; + sprintf( pLabels[i].nameBuff, "%s %c", pLabels[i].name, symbol ); + + memset( &lvc, 0, sizeof( lvc ) ); + lvc.mask = LVCF_TEXT; + lvc.pszText = (LPSTR)pLabels[i].nameBuff; + + ListView_SetColumn( g_showMemDump_hWndListView, i, &lvc ); + } +} + +//----------------------------------------------------------------------------- +// ShowMemDump_FormatItems +// +//----------------------------------------------------------------------------- +void ShowMemDump_FormatItems() +{ + if ( g_showMemDump_format == FORMAT_POOLS ) + { + for ( int i = 0; i < g_showMemDump_numMemory; i++ ) + { + sprintf( g_showMemDump_pMemory[i].pool.sizeBuff, "%d", g_showMemDump_pMemory[i].pool.size ); + ShowMemDump_FormatSize( g_showMemDump_pMemory[i].pool.committedSize, g_showMemDump_pMemory[i].pool.committedSizeBuff, true ); + } + } + else + { + for ( int i = 0; i < g_showMemDump_numMemory; i++ ) + { + ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.currentSize, g_showMemDump_pMemory[i].detail.currentSizeBuff, true ); + ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.peakSize, g_showMemDump_pMemory[i].detail.peakSizeBuff, true ); + ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.totalSize, g_showMemDump_pMemory[i].detail.totalSizeBuff, true ); + ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.overheadSize, g_showMemDump_pMemory[i].detail.overheadSizeBuff, true ); + ShowMemDump_FormatSize( g_showMemDump_pMemory[i].detail.peakOverheadSize, g_showMemDump_pMemory[i].detail.peakOverheadSizeBuff, true ); + } + } + + ShowMemDump_SortItems(); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_AddViewItem +// +//----------------------------------------------------------------------------- +void ShowMemDump_AddViewItem( memory_t* pMemory ) +{ + LVITEM lvi; + + if ( !g_showMemDump_hWnd ) + { + // only valid if log window is visible + return; + } + + // update the text callback buffers + if ( g_showMemDump_format == FORMAT_POOLS ) + { + sprintf( pMemory->pool.sizeBuff, "%d", pMemory->pool.size ); + sprintf( pMemory->pool.poolBuff, "%d", pMemory->pool.pool ); + sprintf( pMemory->pool.allocatedBuff, "%d", pMemory->pool.allocated ); + sprintf( pMemory->pool.freeBuff, "%d", pMemory->pool.free ); + sprintf( pMemory->pool.committedBuff, "%d", pMemory->pool.committed ); + ShowMemDump_FormatSize( pMemory->pool.committedSize, pMemory->pool.committedSizeBuff, true ); + } + else + { + ShowMemDump_FormatSize( pMemory->detail.currentSize, pMemory->detail.currentSizeBuff, true ); + ShowMemDump_FormatSize( pMemory->detail.peakSize, pMemory->detail.peakSizeBuff, true ); + ShowMemDump_FormatSize( pMemory->detail.totalSize, pMemory->detail.totalSizeBuff, true ); + ShowMemDump_FormatSize( pMemory->detail.overheadSize, pMemory->detail.overheadSizeBuff, true ); + ShowMemDump_FormatSize( pMemory->detail.peakOverheadSize, pMemory->detail.peakOverheadSizeBuff, true ); + sprintf( pMemory->detail.timeBuff, "%d", pMemory->detail.time ); + sprintf( pMemory->detail.currentCountBuff, "%d", pMemory->detail.currentCount ); + sprintf( pMemory->detail.peakCountBuff, "%d", pMemory->detail.peakCount ); + sprintf( pMemory->detail.totalCountBuff, "%d", pMemory->detail.totalCount ); + sprintf( pMemory->detail.lte16Buff, "%d", pMemory->detail.lte16 ); + sprintf( pMemory->detail.lte32Buff, "%d", pMemory->detail.lte32 ); + sprintf( pMemory->detail.lte128Buff, "%d", pMemory->detail.lte128 ); + sprintf( pMemory->detail.lte1024Buff, "%d", pMemory->detail.lte1024 ); + sprintf( pMemory->detail.gt1024Buff, "%d", pMemory->detail.gt1024 ); + } + + int itemCount = ListView_GetItemCount( g_showMemDump_hWndListView ); + + // setup and insert at end of list + memset( &lvi, 0, sizeof( lvi ) ); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = itemCount; + lvi.iSubItem = 0; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; + lvi.lParam = (LPARAM)pMemory; + + // insert and set the real index + pMemory->listIndex = ListView_InsertItem( g_showMemDump_hWndListView, &lvi ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_Refresh +// +//----------------------------------------------------------------------------- +void ShowMemDump_Refresh() +{ + // send the command to application which replies with list data + if ( g_connectedToApp ) + { + ProcessCommand( "mem_dump" ); + } +} + +//----------------------------------------------------------------------------- +// ShowMemDump_RefreshView +// +//----------------------------------------------------------------------------- +void ShowMemDump_RefreshView() +{ + if ( strlen( g_showMemDump_currentFilename ) == 0 ) + { + // first time + ShowMemDump_Refresh(); + return; + } + + // get current file + int fileSize; + char *pBuffer; + bool bSuccess = LoadTargetFile( g_showMemDump_currentFilename, &fileSize, (void **)&pBuffer ); + if ( !bSuccess ) + { + // stale, try again + ShowMemDump_Refresh(); + return; + } + + // parse and update view + ShowMemDump_Parse( pBuffer, fileSize ); + + Sys_Free( pBuffer ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_PopulateList +// +//----------------------------------------------------------------------------- +void ShowMemDump_PopulateList() +{ + // delete previous labels + while ( 1 ) + { + if ( !ListView_DeleteColumn( g_showMemDump_hWndListView, 0 ) ) + { + break; + } + } + + int count; + label_t* pLabels; + if ( g_showMemDump_format == FORMAT_POOLS ) + { + count = sizeof( g_showMemDump_PoolLabels )/sizeof( g_showMemDump_PoolLabels[0] ); + pLabels = g_showMemDump_PoolLabels; + } + else + { + count = sizeof( g_showMemDump_DetailLabels )/sizeof( g_showMemDump_DetailLabels[0] ); + pLabels = g_showMemDump_DetailLabels; + } + + // init list view columns + for ( int i = 0; i < count; i++ ) + { + LVCOLUMN lvc; + memset( &lvc, 0, sizeof( lvc ) ); + + lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; + lvc.iSubItem = 0; + lvc.cx = pLabels[i].width; + lvc.fmt = LVCFMT_LEFT; + lvc.pszText = ( LPSTR )pLabels[i].name; + + ListView_InsertColumn( g_showMemDump_hWndListView, i, &lvc ); + } + + // populate list view + for ( int i = 0; i < g_showMemDump_numMemory; i++ ) + { + ShowMemDump_AddViewItem( &g_showMemDump_pMemory[i] ); + } + + ShowMemDump_SortItems(); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_SizeWindow +// +//----------------------------------------------------------------------------- +void ShowMemDump_SizeWindow( HWND hwnd, int cx, int cy ) +{ + if ( cx==0 || cy==0 ) + { + RECT rcClient; + GetClientRect( hwnd, &rcClient ); + cx = rcClient.right; + cy = rcClient.bottom; + } + + // position the ListView + SetWindowPos( g_showMemDump_hWndListView, NULL, 0, 0, cx, cy, SWP_NOZORDER ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK ShowMemDump_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + memory_t* pMemory; + + switch ( message ) + { + case WM_CREATE: + return 0L; + + case WM_DESTROY: + ShowMemDump_SaveConfig(); + + g_showMemDump_hWnd = NULL; + return 0L; + + case WM_INITMENU: + CheckMenuItem( (HMENU)wParam, IDM_OPTIONS_BYTES, MF_BYCOMMAND | ( g_showMemDump_showBytes == SHOW_BYTES ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( (HMENU)wParam, IDM_OPTIONS_KILOBYTES, MF_BYCOMMAND | ( g_showMemDump_showBytes == SHOW_KILOBYTES ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( (HMENU)wParam, IDM_OPTIONS_MEGABYTES, MF_BYCOMMAND | ( g_showMemDump_showBytes == SHOW_MEGABYTES ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( (HMENU)wParam, IDM_OPTIONS_COLLAPSEOUTPUT, MF_BYCOMMAND | ( g_showMemDump_bCollapseOutput ? MF_CHECKED : MF_UNCHECKED ) ); + return 0L; + + case WM_SIZE: + ShowMemDump_SizeWindow( hwnd, LOWORD( lParam ), HIWORD( lParam ) ); + return 0L; + + case WM_NOTIFY: + switch ( ( ( LPNMHDR )lParam )->code ) + { + case LVN_COLUMNCLICK: + NMLISTVIEW* pnmlv; + pnmlv = ( NMLISTVIEW* )lParam; + if ( g_showMemDump_sortColumn == pnmlv->iSubItem ) + { + // user has clicked on same column - flip the sort + g_showMemDump_sortDescending ^= 1; + } + else + { + // sort by new column + g_showMemDump_sortColumn = pnmlv->iSubItem; + } + ShowMemDump_SortItems(); + return 0L; + + case LVN_GETDISPINFO: + NMLVDISPINFO* plvdi; + plvdi = (NMLVDISPINFO*)lParam; + pMemory = (memory_t*)plvdi->item.lParam; + + if ( g_showMemDump_format == FORMAT_POOLS ) + { + switch ( plvdi->item.iSubItem ) + { + case ID_DUMPPOOL_POOL: + plvdi->item.pszText = pMemory->pool.poolBuff; + return 0L; + + case ID_DUMPPOOL_SIZE: + plvdi->item.pszText = pMemory->pool.sizeBuff; + return 0L; + + case ID_DUMPPOOL_ALLOCATED: + plvdi->item.pszText = pMemory->pool.allocatedBuff; + return 0L; + + case ID_DUMPPOOL_FREE: + plvdi->item.pszText = pMemory->pool.freeBuff; + return 0L; + + case ID_DUMPPOOL_COMMITTED: + plvdi->item.pszText = pMemory->pool.committedBuff; + return 0L; + + case ID_DUMPPOOL_COMMITTEDSIZE: + plvdi->item.pszText = pMemory->pool.committedSizeBuff; + return 0L; + } + } + else + { + switch ( plvdi->item.iSubItem ) + { + case ID_DUMPDETAIL_ALLOCATION: + plvdi->item.pszText = pMemory->detail.pAllocationName; + return 0L; + + case ID_DUMPDETAIL_CURRENTSIZE: + plvdi->item.pszText = pMemory->detail.currentSizeBuff; + return 0L; + + case ID_DUMPDETAIL_PEAKSIZE: + plvdi->item.pszText = pMemory->detail.peakSizeBuff; + return 0L; + + case ID_DUMPDETAIL_TOTALSIZE: + plvdi->item.pszText = pMemory->detail.totalSizeBuff; + return 0L; + + case ID_DUMPDETAIL_OVERHEAD: + plvdi->item.pszText = pMemory->detail.overheadSizeBuff; + return 0L; + + case ID_DUMPDETAIL_PEAKOVERHEAD: + plvdi->item.pszText = pMemory->detail.peakOverheadSizeBuff; + return 0L; + + case ID_DUMPDETAIL_TIME: + plvdi->item.pszText = pMemory->detail.timeBuff; + return 0L; + + case ID_DUMPDETAIL_CURRENTCOUNT: + plvdi->item.pszText = pMemory->detail.currentCountBuff; + return 0L; + + case ID_DUMPDETAIL_PEAKCOUNT: + plvdi->item.pszText = pMemory->detail.peakCountBuff; + return 0L; + + case ID_DUMPDETAIL_TOTALCOUNT: + plvdi->item.pszText = pMemory->detail.totalCountBuff; + return 0L; + + case ID_DUMPDETAIL_LTE16: + plvdi->item.pszText = pMemory->detail.lte16Buff; + return 0L; + + case ID_DUMPDETAIL_LTE32: + plvdi->item.pszText = pMemory->detail.lte32Buff; + return 0L; + + case ID_DUMPDETAIL_LTE128: + plvdi->item.pszText = pMemory->detail.lte128Buff; + return 0L; + + case ID_DUMPDETAIL_LTE1024: + plvdi->item.pszText = pMemory->detail.lte1024Buff; + return 0L; + + case ID_DUMPDETAIL_GT1024: + plvdi->item.pszText = pMemory->detail.gt1024Buff; + return 0L; + + default: + break; + } + } + break; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_OPTIONS_REFRESH: + ShowMemDump_Refresh(); + return 0L; + + case IDM_OPTIONS_EXPORT: + ShowMemDump_Export(); + return 0L; + + case IDM_OPTIONS_SUMMARY: + ShowMemDump_Summary(); + return 0L; + + case IDM_OPTIONS_BYTES: + g_showMemDump_showBytes = SHOW_BYTES; + ShowMemDump_FormatItems(); + return 0L; + + case IDM_OPTIONS_KILOBYTES: + g_showMemDump_showBytes = SHOW_KILOBYTES; + ShowMemDump_FormatItems(); + return 0L; + + case IDM_OPTIONS_MEGABYTES: + g_showMemDump_showBytes = SHOW_MEGABYTES; + ShowMemDump_FormatItems(); + return 0L; + + case IDM_OPTIONS_COLLAPSEOUTPUT: + g_showMemDump_bCollapseOutput = !g_showMemDump_bCollapseOutput; + ShowMemDump_RefreshView(); + return 0L; + } + break; + } + + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// ShowMemDump_Init +// +//----------------------------------------------------------------------------- +bool ShowMemDump_Init() +{ + // set up our window class + WNDCLASS wndclass; + + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = ShowMemDump_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_SHOWMEMORYDUMP ); + wndclass.lpszClassName = "SHOWMEMDUMPCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + ShowMemDump_LoadConfig(); + + return true; +} + +//----------------------------------------------------------------------------- +// ShowMemDump_Open +// +//----------------------------------------------------------------------------- +void ShowMemDump_Open() +{ + RECT clientRect; + HWND hWnd; + + if ( g_showMemDump_hWnd ) + { + // only one instance + if ( IsIconic( g_showMemDump_hWnd ) ) + ShowWindow( g_showMemDump_hWnd, SW_RESTORE ); + SetForegroundWindow( g_showMemDump_hWnd ); + return; + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "SHOWMEMDUMPCLASS", + "", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 700, + 400, + g_hDlgMain, + NULL, + g_hInstance, + NULL ); + g_showMemDump_hWnd = hWnd; + + GetClientRect( g_showMemDump_hWnd, &clientRect ); + hWnd = CreateWindow( + WC_LISTVIEW, + "", + WS_VISIBLE|WS_CHILD|LVS_REPORT, + 0, + 0, + clientRect.right-clientRect.left, + clientRect.bottom-clientRect.top, + g_showMemDump_hWnd, + ( HMENU )ID_SHOWMEMDUMP_LISTVIEW, + g_hInstance, + NULL ); + g_showMemDump_hWndListView = hWnd; + + ListView_SetBkColor( g_showMemDump_hWndListView, g_backgroundColor ); + ListView_SetTextBkColor( g_showMemDump_hWndListView, g_backgroundColor ); + + DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP; + ListView_SetExtendedListViewStyleEx( g_showMemDump_hWndListView, style, style ); + + ShowMemDump_PopulateList(); + + ShowMemDump_SetTitle(); + + if ( g_showMemDump_windowRect.right && g_showMemDump_windowRect.bottom ) + MoveWindow( g_showMemDump_hWnd, g_showMemDump_windowRect.left, g_showMemDump_windowRect.top, g_showMemDump_windowRect.right-g_showMemDump_windowRect.left, g_showMemDump_windowRect.bottom-g_showMemDump_windowRect.top, FALSE ); + ShowWindow( g_showMemDump_hWnd, SHOW_OPENWINDOW ); + + // get data from application + ShowMemDump_Refresh(); +} + +//----------------------------------------------------------------------------- +// MatchAllocationName +// +//----------------------------------------------------------------------------- +void MatchAllocationName( memory_t *&pMemory ) +{ + memory_t *curEntry = g_showMemDump_pMemory; + for ( int i=0; i<g_showMemDump_numMemory; ++i ) + { + if ( !strcmp( curEntry->detail.pAllocationName, pMemory->detail.pAllocationName ) ) + { + pMemory = curEntry; + return; + } + ++curEntry; + } +} + +//----------------------------------------------------------------------------- +// ShowMemDump_Parse +// +//----------------------------------------------------------------------------- +void ShowMemDump_Parse( const char *pBuffer, int fileSize ) +{ + char *ptr; + char *pToken; + char *pLineStart; + int numLines; + int size; + memory_t *pMemory; + + // remove old entries + ShowMemDump_Clear(); + + if ( !pBuffer || !fileSize ) + { + // no valid data + return; + } + + Sys_SetScriptData( pBuffer, fileSize ); + + // skip first line, column headers + Sys_SkipRestOfLine(); + + Sys_SaveParser(); + + // count lines + numLines = 0; + while ( 1 ) + { + pToken = Sys_GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + numLines++; + Sys_SkipRestOfLine(); + } + + // each line represents one complete entry + g_showMemDump_pMemory = (memory_t *)Sys_Alloc( numLines * sizeof( memory_t ) ); + + Sys_RestoreParser(); + + pMemory = g_showMemDump_pMemory; + + int format = 0; + if ( !V_strnicmp( g_sys_scriptptr, "pool ", 5 ) ) + { + // parse as pool stats + format = FORMAT_POOLS; + + while ( 1 ) + { + // find start of relevant data + bool bFound = false; + while ( 1 ) + { + pToken = Sys_GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + if ( !V_stricmp( pToken, "size:" ) ) + { + bFound = true; + break; + } + } + if ( !bFound ) + { + break; + } + + memset( pMemory, 0, sizeof( memory_t ) ); + + pMemory->pool.pool = g_showMemDump_numMemory; + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->pool.size = atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + if ( !V_stricmp( pToken, "allocated:" ) ) + { + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->pool.allocated = atoi( pToken ); + } + else + { + break; + } + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + if ( !V_stricmp( pToken, "free:" ) ) + { + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->pool.free = atoi( pToken ); + } + else + { + break; + } + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + if ( !V_stricmp( pToken, "committed:" ) ) + { + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->pool.committed = atoi( pToken ); + } + else + { + break; + } + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + if ( !V_stricmp( pToken, "committedsize:" ) ) + { + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->pool.committedSize = atoi( pToken ); + } + else + { + break; + } + + pMemory++; + g_showMemDump_numMemory++; + if ( g_showMemDump_numMemory >= numLines ) + break; + } + } + else + { + // parse as detail stats + format = FORMAT_DETAILS; + + while ( 1 ) + { + pLineStart = g_sys_scriptptr; + + // can't tokenize, find start of parsable data + ptr = V_stristr( g_sys_scriptptr, ", line " ); + if ( !ptr ) + break; + g_sys_scriptptr = ptr + strlen( ", line " ); + + // advance past the expected line number + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + + if ( !g_showMemDump_bCollapseOutput ) + { + size = g_sys_scriptptr-pLineStart; + } + else + { + size = ptr-pLineStart; + } + + memset( pMemory, 0, sizeof(memory_t) ); + memory_t *pCurRecordStart = pMemory; + + pMemory->detail.pAllocationName = new char[size+1]; + memcpy( pMemory->detail.pAllocationName, pLineStart, size ); + pMemory->detail.pAllocationName[size] = '\0'; + Sys_NormalizePath( pMemory->detail.pAllocationName, false ); + + if ( g_showMemDump_bCollapseOutput ) + { + MatchAllocationName( pMemory ); + } + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.currentSize += (int)(1024.0f*atof( pToken )); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.peakSize += (int)(1024.0f*atof( pToken )); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.totalSize += (int)(1024.0f*atof( pToken )); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.overheadSize += (int)(1024.0f*atof( pToken )); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.peakOverheadSize += (int)(1024.0f*atof( pToken )); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.time += atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.currentCount += atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.peakCount += atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.totalCount += atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.lte16 += atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.lte32 += atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.lte128 += atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.lte1024 += atoi( pToken ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + break; + pMemory->detail.gt1024 += atoi( pToken ); + + Sys_SkipRestOfLine(); + + if( pMemory == pCurRecordStart ) + { + pMemory++; + g_showMemDump_numMemory++; + } + else + { + pMemory = pCurRecordStart; + } + + if ( g_showMemDump_numMemory >= numLines ) + break; + } + } + + if ( g_showMemDump_format != format ) + { + // format change will cause list view change + g_showMemDump_format = format; + g_showMemDump_sortColumn = 0; + g_showMemDump_sortDescending = 0; + } + + ShowMemDump_PopulateList(); +} + +//----------------------------------------------------------------------------- +// rc_MemDump +// +// Sent from application with memory dump file +//----------------------------------------------------------------------------- +int rc_MemDump( char *pCommand ) +{ + char* pToken; + int retVal; + int errCode = -1; + int fileSize; + char *pBuffer; + + // get name of file + pToken = GetToken( &pCommand ); + if ( !pToken[0] ) + goto cleanUp; + + // get file + strcpy( g_showMemDump_currentFilename, pToken ); + retVal = LoadTargetFile( g_showMemDump_currentFilename, &fileSize, (void **)&pBuffer ); + + DebugCommand( "0x%8.8x = MemDump( %s )\n", retVal, g_showMemDump_currentFilename ); + + // parse and update view + ShowMemDump_Parse( pBuffer, fileSize ); + + Sys_Free( pBuffer ); + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} diff --git a/utils/xbox/vxconsole/show_sounds.cpp b/utils/xbox/vxconsole/show_sounds.cpp new file mode 100644 index 0000000..f54be8d --- /dev/null +++ b/utils/xbox/vxconsole/show_sounds.cpp @@ -0,0 +1,778 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SHOW_SOUNDS.CPP +// +// Show Sounds Display. +//=====================================================================================// +#include "vxconsole.h" + +#define ID_SHOWSOUNDS_LISTVIEW 100 + +// column id +#define ID_SS_NAME 0 +#define ID_SS_PREFIX 1 +#define ID_SS_FORMAT 2 +#define ID_SS_RATE 3 +#define ID_SS_BITS 4 +#define ID_SS_CHANNELS 5 +#define ID_SS_SIZE 6 +#define ID_SS_STREAMED 7 +#define ID_SS_LOOPED 8 +#define ID_SS_LENGTH 9 + +typedef struct +{ + int listIndex; + char *pName; + char *pPrefix; + char *pFormat; + int rate; + char rateBuff[16]; + int bits; + char bitsBuff[16]; + int channels; + char channelsBuff[16]; + int numSamples; + int dataSize; + char dataSizeBuff[16]; + int streamed; + char streamedBuff[16]; + int looped; + char loopedBuff[16]; + float length; + char lengthBuff[16]; +} sound_t; + +typedef struct +{ const CHAR* name; + int width; + int subItemIndex; + CHAR nameBuff[32]; +} label_t; + +HWND g_showSounds_hWnd; +HWND g_showSounds_hWndListView; +RECT g_showSounds_windowRect; +int g_showSounds_sortColumn; +int g_showSounds_sortDescending; +sound_t *g_showSounds_pSounds; +int g_showSounds_numSounds; +int g_showSounds_currentFrame; + +label_t g_showSounds_Labels[] = +{ + {"Name", 300, ID_SS_NAME}, + {"Prefix", 80, ID_SS_PREFIX}, + {"Format", 80, ID_SS_FORMAT}, + {"Rate", 80, ID_SS_RATE}, + {"Bits", 80, ID_SS_BITS}, + {"Channels", 80, ID_SS_CHANNELS}, + {"Size", 80, ID_SS_SIZE}, + {"Streamed", 80, ID_SS_STREAMED}, + {"Looped", 80, ID_SS_LOOPED}, + {"Length", 80, ID_SS_LENGTH}, +}; + +//----------------------------------------------------------------------------- +// ShowSounds_SaveConfig +// +//----------------------------------------------------------------------------- +void ShowSounds_SaveConfig() +{ + char buff[256]; + + Sys_SetRegistryInteger( "showSoundsSortColumn", g_showSounds_sortColumn ); + Sys_SetRegistryInteger( "showSoundsSortDescending", g_showSounds_sortDescending ); + + WINDOWPLACEMENT wp; + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_showSounds_hWnd, &wp ); + g_showSounds_windowRect = wp.rcNormalPosition; + + sprintf( buff, "%d %d %d %d", g_showSounds_windowRect.left, g_showSounds_windowRect.top, g_showSounds_windowRect.right, g_showSounds_windowRect.bottom ); + Sys_SetRegistryString( "showSoundsWindowRect", buff ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_LoadConfig +// +//----------------------------------------------------------------------------- +void ShowSounds_LoadConfig() +{ + int numArgs; + char buff[256]; + + Sys_GetRegistryInteger( "showSoundsSortColumn", ID_SS_NAME, g_showSounds_sortColumn ); + Sys_GetRegistryInteger( "showSoundsSortDescending", false, g_showSounds_sortDescending ); + + Sys_GetRegistryString( "showSoundsWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_showSounds_windowRect.left, &g_showSounds_windowRect.top, &g_showSounds_windowRect.right, &g_showSounds_windowRect.bottom ); + if ( numArgs != 4 || g_showSounds_windowRect.left < 0 || g_showSounds_windowRect.top < 0 || g_showSounds_windowRect.right < 0 || g_showSounds_windowRect.bottom < 0 ) + memset( &g_showSounds_windowRect, 0, sizeof( g_showSounds_windowRect ) ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_Clear +// +//----------------------------------------------------------------------------- +void ShowSounds_Clear() +{ + // delete all the list view entries + if ( g_showSounds_hWnd ) + ListView_DeleteAllItems( g_showSounds_hWndListView ); + + if ( !g_showSounds_pSounds ) + return; + + for ( int i=0; i<g_showSounds_numSounds; i++ ) + { + free( g_showSounds_pSounds[i].pName ); + free( g_showSounds_pSounds[i].pPrefix ); + free( g_showSounds_pSounds[i].pFormat ); + } + + g_showSounds_pSounds = NULL; + g_showSounds_numSounds = 0; +} + +//----------------------------------------------------------------------------- +// ShowSounds_Export +// +//----------------------------------------------------------------------------- +void ShowSounds_Export() +{ +} + +//----------------------------------------------------------------------------- +// ShowSounds_Summary +// +//----------------------------------------------------------------------------- +void ShowSounds_Summary() +{ + char buff[1024]; + + // tally the totals + int totalStreamed = 0; + int totalStatic = 0; + for ( int i=0; i<g_showSounds_numSounds; i++ ) + { + if ( g_showSounds_pSounds[i].streamed ) + { + totalStreamed += g_showSounds_pSounds[i].dataSize; + } + else + { + totalStatic += g_showSounds_pSounds[i].dataSize; + } + } + + sprintf( + buff, + "Entries:\t\t\t%d\n" + "Static Memory:\t\t%.2f MB\n" + "Streamed Memory:\t\t%.2f MB\n", + g_showSounds_numSounds, + ( float )totalStatic/( 1024.0F*1024.0F ), + ( float )totalStreamed/( 1024.0F*1024.0F ) ); + + MessageBox( g_showSounds_hWnd, buff, "Sound Summary", MB_OK|MB_APPLMODAL ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_Play +// +//----------------------------------------------------------------------------- +void ShowSounds_Play() +{ + char command[256]; + sound_t* pSound; + int selection; + LVITEM lvitem; + + if ( !g_connectedToApp ) + return; + + selection = ListView_GetSelectionMark( g_showSounds_hWndListView ); + if ( selection == -1 ) + return; + + memset( &lvitem, 0, sizeof( lvitem ) ); + lvitem.mask = LVIF_PARAM; + lvitem.iItem = selection; + ListView_GetItem( g_showSounds_hWndListView, &lvitem ); + + pSound = ( sound_t* )lvitem.lParam; + + sprintf( command, "play %s%s", pSound->pPrefix, pSound->pName ); + + // send the command to application + ProcessCommand( command ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_CompareFunc +// +//----------------------------------------------------------------------------- +int CALLBACK ShowSounds_CompareFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) +{ + sound_t* pSoundA = ( sound_t* )lParam1; + sound_t* pSoundB = ( sound_t* )lParam2; + + int sort = 0; + switch ( g_showSounds_sortColumn ) + { + case ID_SS_NAME: + sort = stricmp( pSoundA->pName, pSoundB->pName ); + break; + + case ID_SS_PREFIX: + sort = stricmp( pSoundA->pPrefix, pSoundB->pPrefix ); + break; + + case ID_SS_FORMAT: + sort = stricmp( pSoundA->pFormat, pSoundB->pFormat ); + break; + + case ID_SS_RATE: + sort = pSoundA->rate - pSoundB->rate; + break; + + case ID_SS_BITS: + sort = pSoundA->bits - pSoundB->bits; + break; + + case ID_SS_CHANNELS: + sort = stricmp( pSoundA->channelsBuff, pSoundB->channelsBuff ); + break; + + case ID_SS_SIZE: + sort = pSoundA->dataSize - pSoundB->dataSize; + break; + + case ID_SS_STREAMED: + sort = stricmp( pSoundA->streamedBuff, pSoundB->streamedBuff ); + break; + + case ID_SS_LOOPED: + sort = stricmp( pSoundA->loopedBuff, pSoundB->loopedBuff ); + break; + + case ID_SS_LENGTH: + if ( pSoundA->length < pSoundB->length ) + sort = -1; + else if ( pSoundA->length == pSoundB->length ) + sort = 0; + else + sort = 1; + break; + } + + // flip the sort order + if ( g_showSounds_sortDescending ) + sort *= -1; + + return ( sort ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_SortItems +// +//----------------------------------------------------------------------------- +void ShowSounds_SortItems() +{ + LVITEM lvitem; + sound_t *pSound; + int i; + + if ( !g_showSounds_hWnd ) + { + // only sort if window is visible + return; + } + + ListView_SortItems( g_showSounds_hWndListView, ShowSounds_CompareFunc, 0 ); + + memset( &lvitem, 0, sizeof( lvitem ) ); + lvitem.mask = LVIF_PARAM; + + // get each item and reset its list index + int itemCount = ListView_GetItemCount( g_showSounds_hWndListView ); + for ( i=0; i<itemCount; i++ ) + { + lvitem.iItem = i; + ListView_GetItem( g_showSounds_hWndListView, &lvitem ); + + pSound = ( sound_t* )lvitem.lParam; + pSound->listIndex = i; + } + + // update list view columns with sort key + for ( i=0; i<sizeof( g_showSounds_Labels )/sizeof( g_showSounds_Labels[0] ); i++ ) + { + char symbol; + LVCOLUMN lvc; + + if ( i == g_showSounds_sortColumn ) + symbol = g_showSounds_sortDescending ? '<' : '>'; + else + symbol = ' '; + sprintf( g_showSounds_Labels[i].nameBuff, "%s %c", g_showSounds_Labels[i].name, symbol ); + + memset( &lvc, 0, sizeof( lvc ) ); + lvc.mask = LVCF_TEXT; + lvc.pszText = ( LPSTR )g_showSounds_Labels[i].nameBuff; + + ListView_SetColumn( g_showSounds_hWndListView, i, &lvc ); + } +} + +//----------------------------------------------------------------------------- +// ShowSounds_AddViewItem +// +//----------------------------------------------------------------------------- +void ShowSounds_AddViewItem( sound_t* pSound ) +{ + LVITEM lvi; + + if ( !g_showSounds_hWnd ) + { + // only valid if log window is visible + return; + } + + // update the text callback buffers + if ( pSound->rate >= 0 ) + sprintf( pSound->rateBuff, "%5.2f KHz", ( float )pSound->rate/1000.0f ); + else + strcpy( pSound->rateBuff, "???" ); + + if ( pSound->bits >= 0 ) + sprintf( pSound->bitsBuff, "%d", pSound->bits ); + else + strcpy( pSound->bitsBuff, "???" ); + + if ( pSound->channels >= 1 ) + strcpy( pSound->channelsBuff, pSound->channels == 2 ? "Stereo" : "Mono" ); + else + strcpy( pSound->channelsBuff, "???" ); + + if ( pSound->dataSize >= 0 ) + sprintf( pSound->dataSizeBuff, "%d", pSound->dataSize ); + else + strcpy( pSound->dataSizeBuff, "???" ); + + if ( pSound->streamed >= 0 ) + strcpy( pSound->streamedBuff, pSound->streamed ? "Stream" : "Static" ); + else + strcpy( pSound->streamedBuff, "???" ); + + if ( pSound->looped >= 0 ) + strcpy( pSound->loopedBuff, pSound->looped ? "Looped" : "One-Shot" ); + else + strcpy( pSound->loopedBuff, "???" ); + + sprintf( pSound->lengthBuff, "%2.2d:%2.2d:%3.3d", ( int )pSound->length/60, ( int )pSound->length%60, ( int )( 1000*( pSound->length-( int )pSound->length ) )%1000 ); + + int itemCount = ListView_GetItemCount( g_showSounds_hWndListView ); + + // setup and insert at end of list + memset( &lvi, 0, sizeof( lvi ) ); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = itemCount; + lvi.iSubItem = 0; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; + lvi.lParam = ( LPARAM )pSound; + + // insert and set the real index + pSound->listIndex = ListView_InsertItem( g_showSounds_hWndListView, &lvi ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_Refresh +// +//----------------------------------------------------------------------------- +void ShowSounds_Refresh() +{ + char command[256]; + + strcpy( command, "vx_soundlist" ); + + // send the command to application which replies with list data + if ( g_connectedToApp ) + ProcessCommand( command ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_SizeWindow +// +//----------------------------------------------------------------------------- +void ShowSounds_SizeWindow( HWND hwnd, int cx, int cy ) +{ + if ( cx==0 || cy==0 ) + { + RECT rcClient; + GetClientRect( hwnd, &rcClient ); + cx = rcClient.right; + cy = rcClient.bottom; + } + + // position the ListView + SetWindowPos( g_showSounds_hWndListView, NULL, 0, 0, cx, cy, SWP_NOZORDER ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK ShowSounds_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + sound_t* pSound; + + switch ( message ) + { + case WM_CREATE: + return 0L; + + case WM_DESTROY: + ShowSounds_SaveConfig(); + g_showSounds_hWnd = NULL; + return 0L; + + case WM_INITMENU: + return 0L; + + case WM_SIZE: + ShowSounds_SizeWindow( hwnd, LOWORD( lParam ), HIWORD( lParam ) ); + return 0L; + + case WM_NOTIFY: + switch ( ( ( LPNMHDR )lParam )->code ) + { + case LVN_COLUMNCLICK: + NMLISTVIEW* pnmlv; + pnmlv = ( NMLISTVIEW* )lParam; + if ( g_showSounds_sortColumn == pnmlv->iSubItem ) + { + // user has clicked on same column - flip the sort + g_showSounds_sortDescending ^= 1; + } + else + { + // sort by new column + g_showSounds_sortColumn = pnmlv->iSubItem; + } + ShowSounds_SortItems(); + return 0L; + + case LVN_GETDISPINFO: + NMLVDISPINFO* plvdi; + plvdi = ( NMLVDISPINFO* )lParam; + pSound = ( sound_t* )plvdi->item.lParam; + switch ( plvdi->item.iSubItem ) + { + case ID_SS_NAME: + plvdi->item.pszText = pSound->pName; + return 0L; + + case ID_SS_PREFIX: + plvdi->item.pszText = pSound->pPrefix; + return 0L; + + case ID_SS_FORMAT: + plvdi->item.pszText = pSound->pFormat; + return 0L; + + case ID_SS_RATE: + plvdi->item.pszText = pSound->rateBuff; + return 0L; + + case ID_SS_BITS: + plvdi->item.pszText = pSound->bitsBuff; + return 0L; + + case ID_SS_CHANNELS: + plvdi->item.pszText = pSound->channelsBuff; + return 0L; + + case ID_SS_SIZE: + plvdi->item.pszText = pSound->dataSizeBuff; + return 0L; + + case ID_SS_STREAMED: + plvdi->item.pszText = pSound->streamedBuff; + return 0L; + + case ID_SS_LOOPED: + plvdi->item.pszText = pSound->loopedBuff; + return 0L; + + case ID_SS_LENGTH: + plvdi->item.pszText = pSound->lengthBuff; + return 0L; + + default: + break; + } + break; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_OPTIONS_SUMMARY: + ShowSounds_Summary(); + return 0L; + + case IDM_OPTIONS_REFRESH: + ShowSounds_Refresh(); + return 0L; + + case IDM_OPTIONS_EXPORT: + ShowSounds_Export(); + return 0L; + + case IDM_OPTIONS_PLAYSOUND: + ShowSounds_Play(); + return 0L; + } + break; + } + + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// ShowSounds_Init +// +//----------------------------------------------------------------------------- +bool ShowSounds_Init() +{ + // set up our window class + WNDCLASS wndclass; + + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = ShowSounds_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_SHOWSOUNDS ); + wndclass.lpszClassName = "SHOWSOUNDSCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + ShowSounds_LoadConfig(); + + return true; +} + +//----------------------------------------------------------------------------- +// ShowSounds_Open +// +//----------------------------------------------------------------------------- +void ShowSounds_Open() +{ + RECT clientRect; + HWND hWnd; + int i; + + if ( g_showSounds_hWnd ) + { + // only one instance + if ( IsIconic( g_showSounds_hWnd ) ) + ShowWindow( g_showSounds_hWnd, SW_RESTORE ); + SetForegroundWindow( g_showSounds_hWnd ); + return; + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "SHOWSOUNDSCLASS", + "Sounds", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 700, + 400, + g_hDlgMain, + NULL, + g_hInstance, + NULL ); + g_showSounds_hWnd = hWnd; + + GetClientRect( g_showSounds_hWnd, &clientRect ); + hWnd = CreateWindow( + WC_LISTVIEW, + "", + WS_VISIBLE|WS_CHILD|LVS_REPORT|LVS_SHOWSELALWAYS|LVS_SINGLESEL, + 0, + 0, + clientRect.right-clientRect.left, + clientRect.bottom-clientRect.top, + g_showSounds_hWnd, + ( HMENU )ID_SHOWSOUNDS_LISTVIEW, + g_hInstance, + NULL ); + g_showSounds_hWndListView = hWnd; + + // init list view columns + for ( i=0; i<sizeof( g_showSounds_Labels )/sizeof( g_showSounds_Labels[0] ); i++ ) + { + LVCOLUMN lvc; + memset( &lvc, 0, sizeof( lvc ) ); + + lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; + lvc.iSubItem = 0; + lvc.cx = g_showSounds_Labels[i].width; + lvc.fmt = LVCFMT_LEFT; + lvc.pszText = ( LPSTR )g_showSounds_Labels[i].name; + + ListView_InsertColumn( g_showSounds_hWndListView, i, &lvc ); + } + + ListView_SetBkColor( g_showSounds_hWndListView, g_backgroundColor ); + ListView_SetTextBkColor( g_showSounds_hWndListView, g_backgroundColor ); + + DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP; + ListView_SetExtendedListViewStyleEx( g_showSounds_hWndListView, style, style ); + + // populate list view + for ( i=0; i<g_showSounds_numSounds; i++ ) + ShowSounds_AddViewItem( &g_showSounds_pSounds[i] ); + ShowSounds_SortItems(); + + if ( g_showSounds_windowRect.right && g_showSounds_windowRect.bottom ) + MoveWindow( g_showSounds_hWnd, g_showSounds_windowRect.left, g_showSounds_windowRect.top, g_showSounds_windowRect.right-g_showSounds_windowRect.left, g_showSounds_windowRect.bottom-g_showSounds_windowRect.top, FALSE ); + ShowWindow( g_showSounds_hWnd, SHOW_OPENWINDOW ); + + // get data from application + ShowSounds_Refresh(); +} + +//----------------------------------------------------------------------------- +// rc_SoundList +// +// Sent from application with sound list +//----------------------------------------------------------------------------- +int rc_SoundList( char* commandPtr ) +{ + char* cmdToken; + int numSounds; + int soundList; + int retAddr; + int retVal; + int errCode = -1; + xrSound_t* pLocalList; + int prefixLen; + char *pStr; + + // remove old entries + ShowSounds_Clear(); + + // get number of sounds + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &numSounds ); + + // get sound list + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &soundList ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &retAddr ); + + pLocalList = new xrSound_t[numSounds]; + memset( pLocalList, 0, numSounds*sizeof( xrSound_t ) ); + + g_showSounds_numSounds = numSounds; + g_showSounds_pSounds = new sound_t[numSounds]; + memset( g_showSounds_pSounds, 0, numSounds*sizeof( sound_t ) ); + + // get the caller's command list + DmGetMemory( ( void* )soundList, numSounds*sizeof( xrSound_t ), pLocalList, NULL ); + + // build out the resident list + for ( int i=0; i<numSounds; i++ ) + { + // swap the structure + pLocalList[i].rate = BigDWord( pLocalList[i].rate ); + pLocalList[i].bits = BigDWord( pLocalList[i].bits ); + pLocalList[i].channels = BigDWord( pLocalList[i].channels ); + pLocalList[i].looped = BigDWord( pLocalList[i].looped ); + pLocalList[i].dataSize = BigDWord( pLocalList[i].dataSize ); + pLocalList[i].numSamples = BigDWord( pLocalList[i].numSamples ); + pLocalList[i].streamed = BigDWord( pLocalList[i].streamed ); + + // strip the prefix + pStr = pLocalList[i].nameString; + while ( *pStr ) + { + if ( __iscsym( *pStr ) ) + { + // first non-preifx character + break; + } + pStr++; + } + g_showSounds_pSounds[i].pName = strdup( pStr ); + + char prefixString[256]; + prefixLen = pStr - pLocalList[i].nameString; + memcpy( prefixString, pLocalList[i].nameString, prefixLen ); + prefixString[prefixLen] = '\0'; + g_showSounds_pSounds[i].pPrefix = strdup( prefixString ); + + // get the format name + g_showSounds_pSounds[i].pFormat = strdup( pLocalList[i].formatString ); + + g_showSounds_pSounds[i].rate = pLocalList[i].rate; + g_showSounds_pSounds[i].bits = pLocalList[i].bits; + g_showSounds_pSounds[i].channels = pLocalList[i].channels; + g_showSounds_pSounds[i].dataSize = pLocalList[i].dataSize; + g_showSounds_pSounds[i].numSamples = pLocalList[i].numSamples; + g_showSounds_pSounds[i].streamed = pLocalList[i].streamed; + g_showSounds_pSounds[i].looped = pLocalList[i].looped; + + // determine duration + // must use sample count due to compression + if ( g_showSounds_pSounds[i].rate > 0 ) + g_showSounds_pSounds[i].length = ( float )g_showSounds_pSounds[i].numSamples/( float )g_showSounds_pSounds[i].rate; + else + g_showSounds_pSounds[i].length = 0; + + // add to list view + ShowSounds_AddViewItem( &g_showSounds_pSounds[i] ); + } + + // return the result + retVal = numSounds; + int xboxRetVal = BigDWord( retVal ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + DebugCommand( "0x%8.8x = SoundList( 0x%8.8x, 0x%8.8x )\n", retVal, numSounds, soundList ); + + delete [] pLocalList; + + // update + ShowSounds_SortItems(); + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} diff --git a/utils/xbox/vxconsole/show_textures.cpp b/utils/xbox/vxconsole/show_textures.cpp new file mode 100644 index 0000000..e8e9cbb --- /dev/null +++ b/utils/xbox/vxconsole/show_textures.cpp @@ -0,0 +1,971 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SHOW_TEXTURES.CPP +// +// Show Textures Display. +//=====================================================================================// +#include "vxconsole.h" + +#define ID_SHOWTEXTURES_LISTVIEW 100 + +// column id +#define ID_ST_NAME 0 +#define ID_ST_SIZE 1 +#define ID_ST_GROUP 2 +#define ID_ST_FORMAT 3 +#define ID_ST_WIDTH 4 +#define ID_ST_HEIGHT 5 +#define ID_ST_DEPTH 6 +#define ID_ST_NUMLEVELS 7 +#define ID_ST_BINDS 8 +#define ID_ST_REFCOUNT 9 +#define ID_ST_LOAD 10 + +typedef enum +{ + LS_STATIC, // surface + LS_PROCEDURAL, // lacks disk based bits + LS_SYNCHRONOUS, // loaded synchronously + LS_FALLBACK, // fallback version, queued hires + LS_HIRES, // finalized at hires + LS_FAILED, // failed to load + LS_MAX +} loadState_e; + +typedef struct +{ + int listIndex; + char *pLongName; + char *pShortName; + char *pGroupName; + char *pFormatName; + int size; + char sizeBuff[16]; + int width; + char widthBuff[16]; + int height; + char heightBuff[16]; + int depth; + char depthBuff[16]; + int numLevels; + char numLevelsBuff[16]; + int binds; + char bindsBuff[16]; + int refCount; + char refCountBuff[16]; + int loadState; + int edram; +} texture_t; + +typedef struct +{ + const CHAR* name; + int width; + int subItemIndex; + CHAR nameBuff[32]; +} label_t; + +HWND g_showTextures_hWnd; +HWND g_showTextures_hWndListView; +RECT g_showTextures_windowRect; +int g_showTextures_sortColumn; +int g_showTextures_sortDescending; +texture_t *g_showTextures_pTextures; +int g_showTextures_numTextures; +int g_showTextures_currentFrame; +int g_showTextures_fullPath; +char g_showTextures_drawTextureName[MAX_PATH]; + +char *g_showTextures_loadStrings[LS_MAX] = +{ + "Static", + "Procedural", + "Synchronous", + "Fallback", + "", + "Failed", +}; + +label_t g_showTextures_Labels[] = +{ + {"Name", 150, ID_ST_NAME}, + {"D3D Size", 80, ID_ST_SIZE}, + {"Group", 150, ID_ST_GROUP}, + {"Format", 120, ID_ST_FORMAT}, + {"Width", 80, ID_ST_WIDTH}, + {"Height", 80, ID_ST_HEIGHT}, + {"Depth", 80, ID_ST_DEPTH}, + {"NumLevels", 80, ID_ST_NUMLEVELS}, + {"Binds", 80, ID_ST_BINDS}, + {"RefCount", 80, ID_ST_REFCOUNT}, + {"Load State", 120, ID_ST_LOAD}, +}; + +//----------------------------------------------------------------------------- +// ShowTextures_SaveConfig +// +//----------------------------------------------------------------------------- +void ShowTextures_SaveConfig() +{ + char buff[256]; + + Sys_SetRegistryInteger( "showTexturesFullPath", g_showTextures_fullPath ); + Sys_SetRegistryInteger( "showTexturesCurrentFrame", g_showTextures_currentFrame ); + Sys_SetRegistryInteger( "showTexturesSortColumn", g_showTextures_sortColumn ); + Sys_SetRegistryInteger( "showTexturesSortDescending", g_showTextures_sortDescending ); + + WINDOWPLACEMENT wp; + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_showTextures_hWnd, &wp ); + g_showTextures_windowRect = wp.rcNormalPosition; + + sprintf( buff, "%d %d %d %d", g_showTextures_windowRect.left, g_showTextures_windowRect.top, g_showTextures_windowRect.right, g_showTextures_windowRect.bottom ); + Sys_SetRegistryString( "showTexturesWindowRect", buff ); +} + +//----------------------------------------------------------------------------- +// ShowTextures_LoadConfig +// +//----------------------------------------------------------------------------- +void ShowTextures_LoadConfig() +{ + int numArgs; + char buff[256]; + + Sys_GetRegistryInteger( "showTexturesFullPath", true, g_showTextures_fullPath ); + Sys_GetRegistryInteger( "showTexturesCurrentFrame", false, g_showTextures_currentFrame ); + Sys_GetRegistryInteger( "showTexturesSortColumn", ID_ST_NAME, g_showTextures_sortColumn ); + Sys_GetRegistryInteger( "showTexturesSortDescending", false, g_showTextures_sortDescending ); + + Sys_GetRegistryString( "showTexturesWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_showTextures_windowRect.left, &g_showTextures_windowRect.top, &g_showTextures_windowRect.right, &g_showTextures_windowRect.bottom ); + if ( numArgs != 4 || g_showTextures_windowRect.left < 0 || g_showTextures_windowRect.top < 0 || g_showTextures_windowRect.right < 0 || g_showTextures_windowRect.bottom < 0 ) + { + memset( &g_showTextures_windowRect, 0, sizeof( g_showTextures_windowRect ) ); + } +} + +//----------------------------------------------------------------------------- +// ShowTextures_Clear +// +//----------------------------------------------------------------------------- +void ShowTextures_Clear() +{ + // delete all the list view entries + if ( g_showTextures_hWnd ) + { + ListView_DeleteAllItems( g_showTextures_hWndListView ); + } + + if ( !g_showTextures_pTextures ) + { + return; + } + + for ( int i=0; i<g_showTextures_numTextures; i++ ) + { + free( g_showTextures_pTextures[i].pLongName ); + free( g_showTextures_pTextures[i].pShortName ); + free( g_showTextures_pTextures[i].pGroupName ); + free( g_showTextures_pTextures[i].pFormatName ); + } + + g_showTextures_pTextures = NULL; + g_showTextures_numTextures = 0; +} + +//----------------------------------------------------------------------------- +// ShowTextures_Export +// +//----------------------------------------------------------------------------- +void ShowTextures_Export() +{ + OPENFILENAME ofn; + char logFilename[MAX_PATH]; + int retval; + FILE* fp; + int i; + int count; + + memset( &ofn, 0, sizeof( ofn ) ); + ofn.lStructSize = sizeof( ofn ); + ofn.hwndOwner = g_showTextures_hWnd; + ofn.lpstrFile = logFilename; + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof( logFilename ); + ofn.lpstrFilter = "Excel CSV\0*.CSV\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = "c:\\"; + ofn.Flags = OFN_PATHMUSTEXIST; + + // display the Open dialog box. + retval = GetOpenFileName( &ofn ); + if ( !retval ) + { + return; + } + + Sys_AddExtension( ".csv", logFilename, sizeof( logFilename ) ); + + fp = fopen( logFilename, "wt+" ); + if ( !fp ) + { + return; + } + + // labels + count = sizeof( g_showTextures_Labels )/sizeof( g_showTextures_Labels[0] ); + for ( i=0; i<count; i++ ) + { + fprintf( fp, "\"%s\"", g_showTextures_Labels[i].name ); + if ( i != count-1 ) + { + fprintf( fp, "," ); + } + } + fprintf( fp, "\n" ); + + // dump to the log + for ( i=0; i<g_showTextures_numTextures; i++ ) + { + if ( g_showTextures_fullPath ) + { + fprintf( fp, "\"%s\"", g_showTextures_pTextures[i].pLongName ); + } + else + { + fprintf( fp, "\"%s\"", g_showTextures_pTextures[i].pShortName ); + } + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].sizeBuff ); + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].pGroupName ); + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].pFormatName ); + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].widthBuff ); + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].heightBuff ); + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].depthBuff ); + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].numLevelsBuff ); + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].bindsBuff ); + fprintf( fp, ",\"%s\"", g_showTextures_pTextures[i].refCountBuff ); + fprintf( fp, ",\"%s\"", g_showTextures_loadStrings[g_showTextures_pTextures[i].loadState] ); + fprintf( fp, "\n" ); + } + + fclose( fp ); +} + +//----------------------------------------------------------------------------- +// ShowTextures_Summary +// +//----------------------------------------------------------------------------- +void ShowTextures_Summary() +{ + char buff[1024]; + + // tally the totals + int total = 0; + for ( int i=0; i<g_showTextures_numTextures; i++ ) + { + if ( g_showTextures_pTextures[i].edram ) + { + // edram is does not affect system memory total + continue; + } + total += g_showTextures_pTextures[i].size; + } + + sprintf( + buff, + "Entries:\t\t\t%d\n" + "System D3D Memory:\t%.2f MB\n", + g_showTextures_numTextures, + ( float )total/( 1024.0F*1024.0F ) ); + + MessageBox( g_showTextures_hWnd, buff, "Texture Summary", MB_OK|MB_APPLMODAL ); +} + +//----------------------------------------------------------------------------- +// ShowTextures_DrawTexture +// +//----------------------------------------------------------------------------- +void ShowTextures_DrawTexture() +{ + char command[256]; + texture_t* pTexture; + int selection; + LVITEM lvitem; + + if ( !g_connectedToApp ) + return; + + selection = ListView_GetSelectionMark( g_showTextures_hWndListView ); + if ( selection == -1 ) + return; + + memset( &lvitem, 0, sizeof( lvitem ) ); + lvitem.mask = LVIF_PARAM; + lvitem.iItem = selection; + ListView_GetItem( g_showTextures_hWndListView, &lvitem ); + + pTexture = ( texture_t* )lvitem.lParam; + + if ( !V_stricmp( g_showTextures_drawTextureName, pTexture->pLongName ) ) + { + // hide + sprintf( command, "mat_drawTexture \"\"" ); + g_showTextures_drawTextureName[0] = '\0'; + } + else + { + // show + sprintf( command, "mat_drawTexture %s", pTexture->pLongName ); + V_strncpy( g_showTextures_drawTextureName, pTexture->pLongName, sizeof( g_showTextures_drawTextureName ) ); + } + + // send the command to application + ProcessCommand( command ); +} + +//----------------------------------------------------------------------------- +// ShowTextures_SetTitle +// +//----------------------------------------------------------------------------- +void ShowTextures_SetTitle() +{ + char titleBuff[128]; + + if ( g_showTextures_hWnd ) + { + strcpy( titleBuff, "Textures " ); + if ( g_showTextures_currentFrame ) + { + strcat( titleBuff, " [FRAME]" ); + } + if ( g_showTextures_fullPath ) + { + strcat( titleBuff, " [FULL PATH]" ); + } + + SetWindowText( g_showTextures_hWnd, titleBuff ); + } +} + +//----------------------------------------------------------------------------- +// ShowTextures_CompareFunc +// +//----------------------------------------------------------------------------- +int CALLBACK ShowTextures_CompareFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) +{ + texture_t* pTextureA = ( texture_t* )lParam1; + texture_t* pTextureB = ( texture_t* )lParam2; + + int sort = 0; + switch ( g_showTextures_sortColumn ) + { + case ID_ST_NAME: + if ( g_showTextures_fullPath ) + { + sort = stricmp( pTextureA->pLongName, pTextureB->pLongName ); + } + else + { + sort = stricmp( pTextureA->pShortName, pTextureB->pShortName ); + } + break; + + case ID_ST_GROUP: + sort = stricmp( pTextureA->pGroupName, pTextureB->pGroupName ); + break; + + case ID_ST_FORMAT: + sort = stricmp( pTextureA->pFormatName, pTextureB->pFormatName ); + break; + + case ID_ST_SIZE: + sort = pTextureA->size - pTextureB->size; + break; + + case ID_ST_WIDTH: + sort = pTextureA->width - pTextureB->width; + break; + + case ID_ST_HEIGHT: + sort = pTextureA->height - pTextureB->height; + break; + + case ID_ST_DEPTH: + sort = pTextureA->depth - pTextureB->depth; + break; + + case ID_ST_NUMLEVELS: + sort = pTextureA->numLevels - pTextureB->numLevels; + break; + + case ID_ST_BINDS: + sort = pTextureA->binds - pTextureB->binds; + break; + + case ID_ST_REFCOUNT: + sort = pTextureA->refCount - pTextureB->refCount; + break; + + case ID_ST_LOAD: + sort = stricmp( g_showTextures_loadStrings[pTextureA->loadState], g_showTextures_loadStrings[pTextureB->loadState] ); + break; + } + + // flip the sort order + if ( g_showTextures_sortDescending ) + { + sort *= -1; + } + + return ( sort ); +} + +//----------------------------------------------------------------------------- +// ShowTextures_SortItems +// +//----------------------------------------------------------------------------- +void ShowTextures_SortItems() +{ + LVITEM lvitem; + texture_t *pTexture; + int i; + + if ( !g_showTextures_hWnd ) + { + // only sort if window is visible + return; + } + + ListView_SortItems( g_showTextures_hWndListView, ShowTextures_CompareFunc, 0 ); + + memset( &lvitem, 0, sizeof( lvitem ) ); + lvitem.mask = LVIF_PARAM; + + // get each item and reset its list index + int itemCount = ListView_GetItemCount( g_showTextures_hWndListView ); + for ( i=0; i<itemCount; i++ ) + { + lvitem.iItem = i; + ListView_GetItem( g_showTextures_hWndListView, &lvitem ); + + pTexture = ( texture_t* )lvitem.lParam; + pTexture->listIndex = i; + } + + // update list view columns with sort key + for ( i=0; i<sizeof( g_showTextures_Labels )/sizeof( g_showTextures_Labels[0] ); i++ ) + { + char symbol; + LVCOLUMN lvc; + + if ( i == g_showTextures_sortColumn ) + { + symbol = g_showTextures_sortDescending ? '<' : '>'; + } + else + { + symbol = ' '; + } + sprintf( g_showTextures_Labels[i].nameBuff, "%s %c", g_showTextures_Labels[i].name, symbol ); + + memset( &lvc, 0, sizeof( lvc ) ); + lvc.mask = LVCF_TEXT; + lvc.pszText = ( LPSTR )g_showTextures_Labels[i].nameBuff; + + ListView_SetColumn( g_showTextures_hWndListView, i, &lvc ); + } +} + +//----------------------------------------------------------------------------- +// ShowTextures_AddViewItem +// +//----------------------------------------------------------------------------- +void ShowTextures_AddViewItem( texture_t* pTexture ) +{ + LVITEM lvi; + + if ( !g_showTextures_hWnd ) + { + // only valid if log window is visible + return; + } + + // update the text callback buffers + sprintf( pTexture->sizeBuff, "%d", pTexture->size ); + sprintf( pTexture->widthBuff, "%d", pTexture->width ); + sprintf( pTexture->heightBuff, "%d", pTexture->height ); + sprintf( pTexture->depthBuff, "%d", pTexture->depth ); + sprintf( pTexture->numLevelsBuff, "%d", pTexture->numLevels ); + sprintf( pTexture->bindsBuff, "%d", pTexture->binds ); + sprintf( pTexture->refCountBuff, "%d", pTexture->refCount ); + + int itemCount = ListView_GetItemCount( g_showTextures_hWndListView ); + + // setup and insert at end of list + memset( &lvi, 0, sizeof( lvi ) ); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = itemCount; + lvi.iSubItem = 0; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; + lvi.lParam = ( LPARAM )pTexture; + + // insert and set the real index + pTexture->listIndex = ListView_InsertItem( g_showTextures_hWndListView, &lvi ); +} + +//----------------------------------------------------------------------------- +// ShowTextures_Refresh +// +//----------------------------------------------------------------------------- +void ShowTextures_Refresh() +{ + char command[256]; + + strcpy( command, "mat_get_textures" ); + + if ( !g_showTextures_currentFrame ) + { + strcat( command, " all" ); + } + + // send the command to application which replies with list data + if ( g_connectedToApp ) + { + ProcessCommand( command ); + } +} + +//----------------------------------------------------------------------------- +// ShowTextures_SizeWindow +// +//----------------------------------------------------------------------------- +void ShowTextures_SizeWindow( HWND hwnd, int cx, int cy ) +{ + if ( cx==0 || cy==0 ) + { + RECT rcClient; + GetClientRect( hwnd, &rcClient ); + cx = rcClient.right; + cy = rcClient.bottom; + } + + // position the ListView + SetWindowPos( g_showTextures_hWndListView, NULL, 0, 0, cx, cy, SWP_NOZORDER ); +} + +//----------------------------------------------------------------------------- +// ShowTextures_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK ShowTextures_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + texture_t* pTexture; + + switch ( message ) + { + case WM_CREATE: + return 0L; + + case WM_DESTROY: + ShowTextures_SaveConfig(); + g_showTextures_hWnd = NULL; + return 0L; + + case WM_INITMENU: + CheckMenuItem( ( HMENU )wParam, IDM_OPTIONS_CURRENTFRAME, MF_BYCOMMAND | ( g_showTextures_currentFrame ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_OPTIONS_FULLPATH, MF_BYCOMMAND | ( g_showTextures_fullPath ? MF_CHECKED : MF_UNCHECKED ) ); + return 0L; + + case WM_SIZE: + ShowTextures_SizeWindow( hwnd, LOWORD( lParam ), HIWORD( lParam ) ); + return 0L; + + case WM_NOTIFY: + switch ( ( ( LPNMHDR )lParam )->code ) + { + case LVN_COLUMNCLICK: + NMLISTVIEW* pnmlv; + pnmlv = ( NMLISTVIEW* )lParam; + if ( g_showTextures_sortColumn == pnmlv->iSubItem ) + { + // user has clicked on same column - flip the sort + g_showTextures_sortDescending ^= 1; + } + else + { + // sort by new column + g_showTextures_sortColumn = pnmlv->iSubItem; + } + ShowTextures_SortItems(); + return 0L; + + case LVN_GETDISPINFO: + NMLVDISPINFO* plvdi; + plvdi = ( NMLVDISPINFO* )lParam; + pTexture = ( texture_t* )plvdi->item.lParam; + switch ( plvdi->item.iSubItem ) + { + case ID_ST_NAME: + if ( g_showTextures_fullPath ) + plvdi->item.pszText = pTexture->pLongName; + else + plvdi->item.pszText = pTexture->pShortName; + return 0L; + + case ID_ST_GROUP: + plvdi->item.pszText = pTexture->pGroupName; + return 0L; + + case ID_ST_FORMAT: + plvdi->item.pszText = pTexture->pFormatName; + return 0L; + + case ID_ST_SIZE: + plvdi->item.pszText = pTexture->sizeBuff; + return 0L; + + case ID_ST_WIDTH: + plvdi->item.pszText = pTexture->widthBuff; + return 0L; + + case ID_ST_HEIGHT: + plvdi->item.pszText = pTexture->heightBuff; + return 0L; + + case ID_ST_DEPTH: + plvdi->item.pszText = pTexture->depthBuff; + return 0L; + + case ID_ST_NUMLEVELS: + plvdi->item.pszText = pTexture->numLevelsBuff; + return 0L; + + case ID_ST_BINDS: + plvdi->item.pszText = pTexture->bindsBuff; + return 0L; + + case ID_ST_LOAD: + plvdi->item.pszText = g_showTextures_loadStrings[pTexture->loadState]; + return 0L; + + case ID_ST_REFCOUNT: + plvdi->item.pszText = pTexture->refCountBuff; + return 0L; + + default: + break; + } + break; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_OPTIONS_SUMMARY: + ShowTextures_Summary(); + return 0L; + + case IDM_OPTIONS_REFRESH: + ShowTextures_Refresh(); + return 0L; + + case IDM_OPTIONS_EXPORT: + ShowTextures_Export(); + return 0L; + + case IDM_OPTIONS_CURRENTFRAME: + g_showTextures_currentFrame ^= 1; + ShowTextures_SetTitle(); + ShowTextures_Refresh(); + return 0L; + + case IDM_OPTIONS_FULLPATH: + g_showTextures_fullPath ^= 1; + ShowTextures_SetTitle(); + ShowTextures_SortItems(); + return 0L; + + case IDM_OPTIONS_DRAWTEXTURE: + ShowTextures_DrawTexture(); + return 0L; + } + break; + } + + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// ShowTextures_Init +// +//----------------------------------------------------------------------------- +bool ShowTextures_Init() +{ + // set up our window class + WNDCLASS wndclass; + + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = ShowTextures_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_SHOWTEXTURES ); + wndclass.lpszClassName = "SHOWTEXTURESCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + ShowTextures_LoadConfig(); + + return true; +} + +//----------------------------------------------------------------------------- +// ShowTextures_Open +// +//----------------------------------------------------------------------------- +void ShowTextures_Open() +{ + RECT clientRect; + HWND hWnd; + int i; + + if ( g_showTextures_hWnd ) + { + // only one instance + if ( IsIconic( g_showTextures_hWnd ) ) + { + ShowWindow( g_showTextures_hWnd, SW_RESTORE ); + } + SetForegroundWindow( g_showTextures_hWnd ); + return; + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "SHOWTEXTURESCLASS", + "", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 700, + 400, + g_hDlgMain, + NULL, + g_hInstance, + NULL ); + g_showTextures_hWnd = hWnd; + + GetClientRect( g_showTextures_hWnd, &clientRect ); + hWnd = CreateWindow( + WC_LISTVIEW, + "", + WS_VISIBLE|WS_CHILD|LVS_REPORT, + 0, + 0, + clientRect.right-clientRect.left, + clientRect.bottom-clientRect.top, + g_showTextures_hWnd, + ( HMENU )ID_SHOWTEXTURES_LISTVIEW, + g_hInstance, + NULL ); + g_showTextures_hWndListView = hWnd; + + // init list view columns + for ( i=0; i<sizeof( g_showTextures_Labels )/sizeof( g_showTextures_Labels[0] ); i++ ) + { + LVCOLUMN lvc; + memset( &lvc, 0, sizeof( lvc ) ); + + lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; + lvc.iSubItem = 0; + lvc.cx = g_showTextures_Labels[i].width; + lvc.fmt = LVCFMT_LEFT; + lvc.pszText = ( LPSTR )g_showTextures_Labels[i].name; + ListView_InsertColumn( g_showTextures_hWndListView, i, &lvc ); + } + + ListView_SetBkColor( g_showTextures_hWndListView, g_backgroundColor ); + ListView_SetTextBkColor( g_showTextures_hWndListView, g_backgroundColor ); + + DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP; + ListView_SetExtendedListViewStyleEx( g_showTextures_hWndListView, style, style ); + + // populate list view + for ( i=0; i<g_showTextures_numTextures; i++ ) + { + ShowTextures_AddViewItem( &g_showTextures_pTextures[i] ); + } + ShowTextures_SortItems(); + + ShowTextures_SetTitle(); + + if ( g_showTextures_windowRect.right && g_showTextures_windowRect.bottom ) + { + MoveWindow( g_showTextures_hWnd, g_showTextures_windowRect.left, g_showTextures_windowRect.top, g_showTextures_windowRect.right-g_showTextures_windowRect.left, g_showTextures_windowRect.bottom-g_showTextures_windowRect.top, FALSE ); + } + ShowWindow( g_showTextures_hWnd, SHOW_OPENWINDOW ); + + // get data from application + ShowTextures_Refresh(); +} + +//----------------------------------------------------------------------------- +// rc_TextureList +// +// Sent from application with texture list +//----------------------------------------------------------------------------- +int rc_TextureList( char* commandPtr ) +{ + int errCode = -1; + char* cmdToken; + int numTextures; + int textureList; + int retAddr; + int retVal; + xrTexture_t* pLocalList; + + // remove old entries + ShowTextures_Clear(); + + // get number of textures + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &numTextures ); + + // get texture list + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &textureList ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &retAddr ); + + pLocalList = new xrTexture_t[numTextures]; + memset( pLocalList, 0, numTextures*sizeof( xrTexture_t ) ); + + g_showTextures_numTextures = numTextures; + g_showTextures_pTextures = new texture_t[numTextures]; + memset( g_showTextures_pTextures, 0, numTextures*sizeof( texture_t ) ); + + // get the caller's command list + DmGetMemory( ( void* )textureList, numTextures*sizeof( xrTexture_t ), pLocalList, NULL ); + + // build out the resident list + for ( int i=0; i<numTextures; i++ ) + { + // swap the structure + pLocalList[i].size = BigDWord( pLocalList[i].size ); + pLocalList[i].width = BigDWord( pLocalList[i].width ); + pLocalList[i].height = BigDWord( pLocalList[i].height ); + pLocalList[i].depth = BigDWord( pLocalList[i].depth ); + pLocalList[i].numLevels = BigDWord( pLocalList[i].numLevels ); + pLocalList[i].binds = BigDWord( pLocalList[i].binds ); + pLocalList[i].refCount = BigDWord( pLocalList[i].refCount ); + pLocalList[i].sRGB = BigDWord( pLocalList[i].sRGB ); + pLocalList[i].edram = BigDWord( pLocalList[i].edram ); + pLocalList[i].procedural = BigDWord( pLocalList[i].procedural ); + pLocalList[i].fallback = BigDWord( pLocalList[i].fallback ); + pLocalList[i].final = BigDWord( pLocalList[i].final ); + pLocalList[i].failed = BigDWord( pLocalList[i].failed ); + + // get the name + g_showTextures_pTextures[i].pLongName = strdup( pLocalList[i].nameString ); + + CHAR shortName[MAX_PATH]; + Sys_StripPath( g_showTextures_pTextures[i].pLongName, shortName, sizeof( shortName ) ); + g_showTextures_pTextures[i].pShortName = strdup( shortName ); + + // get the group name + g_showTextures_pTextures[i].pGroupName = strdup( pLocalList[i].groupString ); + + // get the format name + const char *pFormatName = pLocalList[i].formatString; + if ( !strnicmp( pFormatName, "D3DFMT_", 7 ) ) + { + // strip D3DFMT_ + pFormatName += 7; + } + char tempName[MAX_PATH]; + if ( pLocalList[i].sRGB ) + { + strcpy( tempName, pFormatName ); + strcat( tempName, " (SRGB)" ); + pFormatName = tempName; + } + g_showTextures_pTextures[i].pFormatName = strdup( pFormatName ); + + g_showTextures_pTextures[i].size = pLocalList[i].size; + g_showTextures_pTextures[i].width = pLocalList[i].width; + g_showTextures_pTextures[i].height = pLocalList[i].height; + g_showTextures_pTextures[i].depth = pLocalList[i].depth; + g_showTextures_pTextures[i].numLevels = pLocalList[i].numLevels; + g_showTextures_pTextures[i].binds = pLocalList[i].binds; + g_showTextures_pTextures[i].refCount = pLocalList[i].refCount; + g_showTextures_pTextures[i].edram = pLocalList[i].edram; + + loadState_e loadState; + if ( pLocalList[i].edram || V_stristr( g_showTextures_pTextures[i].pGroupName, "RenderTarget" ) ) + { + loadState = LS_STATIC; + } + else if ( pLocalList[i].procedural ) + { + loadState = LS_PROCEDURAL; + } + else if ( pLocalList[i].final ) + { + loadState = LS_HIRES; + } + else if ( pLocalList[i].failed ) + { + loadState = LS_FAILED; + } + else if ( pLocalList[i].fallback ) + { + loadState = LS_FALLBACK; + } + else + { + loadState = LS_SYNCHRONOUS; + } + g_showTextures_pTextures[i].loadState = loadState; + + // add to list view + ShowTextures_AddViewItem( &g_showTextures_pTextures[i] ); + } + + // return the result + retVal = numTextures; + int xboxRetVal = BigDWord( retVal ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + DebugCommand( "0x%8.8x = TextureList( 0x%8.8x, 0x%8.8x )\n", retVal, numTextures, textureList ); + + delete [] pLocalList; + + // update + ShowTextures_SortItems(); + + // success + errCode = 0; + +cleanUp: + return errCode; +} diff --git a/utils/xbox/vxconsole/sync_files.cpp b/utils/xbox/vxconsole/sync_files.cpp new file mode 100644 index 0000000..facb395 --- /dev/null +++ b/utils/xbox/vxconsole/sync_files.cpp @@ -0,0 +1,942 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SYNC_FILES.CPP +// +// Sync Files Routines. +//=====================================================================================// +#include "vxconsole.h" + +char g_syncfiles_localPath[MAX_PATH]; +char g_syncfiles_targetPath[MAX_PATH]; +fileNode_t *g_syncfiles_targetFiles; +int g_syncfiles_numTargetFiles; +CProgress *g_syncFiles_progress; +BOOL g_syncFiles_noWrite; +BOOL g_syncFiles_force; +BOOL g_syncFiles_verbose; + +struct dvdimage_t +{ + char szString[MAX_PATH]; + CUtlString installPath; + CUtlString versionDetailString; +}; +CUtlVector< dvdimage_t> g_install_dvdImages; +int g_install_Selection; +bool g_install_bForceSync; +bool g_install_bCleanTarget; + +//----------------------------------------------------------------------------- +// SyncFilesDlg_Validate +// +//----------------------------------------------------------------------------- +bool SyncFilesDlg_Validate() +{ + if ( !g_connectedToXBox ) + { + Sys_MessageBox( "Sync Error", "Cannot sync until connected to XBox." ); + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// SyncFilesDlg_Setup +// +//----------------------------------------------------------------------------- +void SyncFilesDlg_Setup( HWND hWnd ) +{ + SetDlgItemText( hWnd, IDC_SYNCFILES_LOCALPATH, g_syncfiles_localPath ); + SetDlgItemText( hWnd, IDC_SYNCFILES_TARGETPATH, g_syncfiles_targetPath ); + + CheckDlgButton( hWnd, IDC_SYNCFILES_FORCESYNC, g_syncFiles_force ? BST_CHECKED : BST_UNCHECKED ); + CheckDlgButton( hWnd, IDC_SYNCFILES_NOWRITE, g_syncFiles_noWrite ? BST_CHECKED : BST_UNCHECKED ); + CheckDlgButton( hWnd, IDC_SYNCFILES_VERBOSE, g_syncFiles_verbose ? BST_CHECKED : BST_UNCHECKED ); +} + +//----------------------------------------------------------------------------- +// SyncFilesDlg_GetChanges +// +//----------------------------------------------------------------------------- +bool SyncFilesDlg_GetChanges( HWND hwnd ) +{ + char localPath[MAX_PATH]; + char targetPath[MAX_PATH]; + + localPath[0] = '\0'; + targetPath[0] = '\0'; + + GetDlgItemText( hwnd, IDC_SYNCFILES_LOCALPATH, localPath, MAX_PATH ); + GetDlgItemText( hwnd, IDC_SYNCFILES_TARGETPATH, targetPath, MAX_PATH ); + + strcpy( g_syncfiles_localPath, localPath ); + Sys_NormalizePath( g_syncfiles_localPath, true ); + + strcpy( g_syncfiles_targetPath, targetPath ); + Sys_NormalizePath( g_syncfiles_targetPath, true ); + + g_syncFiles_force = IsDlgButtonChecked( hwnd, IDC_SYNCFILES_FORCESYNC ) != 0; + g_syncFiles_noWrite = IsDlgButtonChecked( hwnd, IDC_SYNCFILES_NOWRITE ) != 0; + g_syncFiles_verbose = IsDlgButtonChecked( hwnd, IDC_SYNCFILES_VERBOSE ) != 0; + + // success + return ( true ); +} + +//----------------------------------------------------------------------------- +// SyncFilesDlg_Proc +// +//----------------------------------------------------------------------------- +BOOL CALLBACK SyncFilesDlg_Proc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch ( message ) + { + case WM_INITDIALOG: + SyncFilesDlg_Setup( hwnd ); + return ( TRUE ); + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDC_OK: + if ( !SyncFilesDlg_GetChanges( hwnd ) ) + break; + EndDialog( hwnd, wParam ); + return ( TRUE ); + + case IDCANCEL: + case IDC_CANCEL: + EndDialog( hwnd, wParam ); + return ( TRUE ); + } + break; + } + return ( FALSE ); +} + +//----------------------------------------------------------------------------- +// SyncFiles_FreeTargetList +// +//----------------------------------------------------------------------------- +void SyncFiles_FreeTargetList() +{ + g_syncfiles_numTargetFiles = 0; + + FreeTargetFileList( g_syncfiles_targetFiles ); + g_syncfiles_targetFiles = NULL; +} + +//----------------------------------------------------------------------------- +// SyncFiles_DoUpdates +// +//----------------------------------------------------------------------------- +bool SyncFiles_DoUpdates() +{ + WIN32_FILE_ATTRIBUTE_DATA localAttributes; + fileNode_t *nodePtr; + char sourceFilename[MAX_PATH]; + char statusBuff1[MAX_PATH]; + char statusBuff2[MAX_PATH]; + int targetPathLen; + char *ptr; + int progress; + int fileSyncMode; + int numSynced; + int retVal; + + g_syncFiles_progress->SetStatus( "Syncing Target Files...", "", "" ); + g_syncFiles_progress->SetMeter( 0, g_syncfiles_numTargetFiles ); + + fileSyncMode = FSYNC_ANDEXISTSONTARGET; + if ( g_syncFiles_force ) + fileSyncMode |= FSYNC_ALWAYS; + else + fileSyncMode |= FSYNC_IFNEWER; + + targetPathLen = strlen( g_syncfiles_targetPath ); + + numSynced = 0; + progress = 0; + nodePtr = g_syncfiles_targetFiles; + while ( nodePtr ) + { + ptr = nodePtr->filename+targetPathLen; + if ( *ptr == '\\' ) + ptr++; + + // replace with source path head + strcpy( sourceFilename, g_syncfiles_localPath ); + Sys_AddFileSeperator( sourceFilename, sizeof( sourceFilename ) ); + strcat( sourceFilename, ptr ); + + float sourceFileSize = 0; + if ( GetFileAttributesEx( sourceFilename, GetFileExInfoStandard, &localAttributes ) ) + { + sourceFileSize = (float)localAttributes.nFileSizeLow / (1024.0f * 1024.0f); + } + + _snprintf( statusBuff1, sizeof( statusBuff1 ), "Local File: %s (%.2f MB)", sourceFilename, sourceFileSize ); + statusBuff1[sizeof( statusBuff1 ) - 1] = '\0'; + _snprintf( statusBuff2, sizeof( statusBuff2 ), "Target File: %s", nodePtr->filename ); + statusBuff1[sizeof( statusBuff2 ) - 1] = '\0'; + g_syncFiles_progress->SetStatus( NULL, statusBuff1, statusBuff2 ); + + retVal = FileSyncEx( sourceFilename, nodePtr->filename, fileSyncMode, g_syncFiles_verbose != FALSE, g_syncFiles_noWrite != FALSE); + if ( retVal == 1 ) + { + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Sync: %s -> %s\n", sourceFilename, nodePtr->filename ); + numSynced++; + } + + progress++; + g_syncFiles_progress->SetMeter( progress, -1 ); + if ( g_syncFiles_progress->IsCancel() ) + { + return false; + } + + nodePtr = nodePtr->nextPtr; + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Synced %d/%d Files.\n", numSynced, g_syncfiles_numTargetFiles ); + + return true; +} + +//----------------------------------------------------------------------------- +// SyncFiles_GetTargetList +// +//----------------------------------------------------------------------------- +bool SyncFiles_GetTargetList( char* pTargetPath ) +{ + g_syncFiles_progress->SetStatus( "Getting Target Files...", "", "" ); + g_syncFiles_progress->SetMeter( 0, 100 ); + + if ( !GetTargetFileList_r( pTargetPath, true, FA_NORMAL|FA_READONLY, 0, &g_syncfiles_targetFiles ) ) + { + ConsoleWindowPrintf( RGB( 255,0,0 ), "Bad Target Path '%s'\n", pTargetPath ); + return false; + } + + fileNode_t* pFileNode; + for ( pFileNode = g_syncfiles_targetFiles; pFileNode; pFileNode = pFileNode->nextPtr ) + { + g_syncfiles_numTargetFiles++; + } + + // success + return true; +} + +//----------------------------------------------------------------------------- +// SyncFilesDlg_SaveConfig +// +//----------------------------------------------------------------------------- +void SyncFilesDlg_SaveConfig() +{ + Sys_SetRegistryString( "syncfiles_localPath", g_syncfiles_localPath ); + Sys_SetRegistryString( "syncfiles_targetPath", g_syncfiles_targetPath ); + Sys_SetRegistryInteger( "syncfiles_force", g_syncFiles_force ); + Sys_SetRegistryInteger( "syncfiles_noWrite", g_syncFiles_noWrite ); + Sys_SetRegistryInteger( "syncfiles_verbose", g_syncFiles_verbose ); +} + +//----------------------------------------------------------------------------- +// SyncFilesDlg_Open +// +//----------------------------------------------------------------------------- +void SyncFilesDlg_Open( void ) +{ + int result; + bool bError; + bool bValid; + + result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_SYNCFILES ), g_hDlgMain, ( DLGPROC )SyncFilesDlg_Proc ); + if ( LOWORD( result ) != IDC_OK ) + return; + + SyncFilesDlg_SaveConfig(); + + if ( !SyncFilesDlg_Validate() ) + return; + + g_syncFiles_progress = new CProgress; + g_syncFiles_progress->Open( "Sync Files...", true, true ); + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\nSyncing Files From '%s' to '%s'\n", g_syncfiles_localPath, g_syncfiles_targetPath ); + + bError = true; + + // get a file listing from target + bValid = SyncFiles_GetTargetList( g_syncfiles_targetPath ); + if ( !bValid ) + goto cleanUp; + + // mark all files needing update + bValid = SyncFiles_DoUpdates(); + if ( !bValid ) + goto cleanUp; + + bError = false; + +cleanUp: + delete g_syncFiles_progress; + g_syncFiles_progress = NULL; + + if ( bError ) + ConsoleWindowPrintf( XBX_CLR_RED, "Aborted.\n" ); + else + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Finished.\n" ); + + SyncFiles_FreeTargetList(); +} + +//----------------------------------------------------------------------------- +// SyncFilesDlg_LoadConfig +// +//----------------------------------------------------------------------------- +void SyncFilesDlg_LoadConfig() +{ + // get our config + Sys_GetRegistryString( "syncfiles_localPath", g_syncfiles_localPath, g_localPath, sizeof( g_syncfiles_localPath ) ); + Sys_GetRegistryString( "syncfiles_targetPath", g_syncfiles_targetPath, g_targetPath, sizeof( g_syncfiles_targetPath ) ); + Sys_GetRegistryInteger( "syncfiles_force", false, g_syncFiles_force ); + Sys_GetRegistryInteger( "syncfiles_noWrite", false, g_syncFiles_noWrite ); + Sys_GetRegistryInteger( "syncfiles_verbose", false, g_syncFiles_verbose ); +} + +//----------------------------------------------------------------------------- +// SyncFilesDlg_Init +// +//----------------------------------------------------------------------------- +bool SyncFilesDlg_Init() +{ + SyncFilesDlg_LoadConfig(); + return true; +} + +//----------------------------------------------------------------------------- +// InstallDlg_InstallImage +// +//----------------------------------------------------------------------------- +void InstallDlg_InstallImage( const char *pInstallPath, bool bForce, bool bCleanTarget ) +{ + int errCode; + char *pToken; + char arg1[MAXTOKEN]; + char arg2[MAXTOKEN]; + char sourceFilename[MAX_PATH]; + char sourcePath[MAX_PATH]; + char targetFilename[MAX_PATH]; + char filename[MAX_PATH]; + WIN32_FIND_DATA findData; + HANDLE h; + + if ( !pInstallPath[0] ) + { + return; + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\nSyncing From Install Depot: %s\n", pInstallPath ); + + // get the install script + char szScriptPath[MAX_PATH]; + V_ComposeFileName( pInstallPath, "../dvd_install.txt", szScriptPath, sizeof( szScriptPath ) ); + if ( !Sys_Exists( szScriptPath ) ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Failed to open: %s\n", szScriptPath ); + return; + } + + // sanity check + // DVD image auto-build failure prevents the presence of the default.xex + char szTempFilename[MAX_PATH]; + V_ComposeFileName( pInstallPath, "default.xex", szTempFilename, sizeof( szTempFilename ) ); + if ( !Sys_Exists( szTempFilename ) ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Cancelled Installation! DVD Image Auto-Build Process Failed - Missing default.xex!\n" ); + return; + } + + // get the version detail + char szVersionPath[MAX_PATH]; + char *pVersionDetailString = NULL; + V_ComposeFileName( pInstallPath, "version.txt", szVersionPath, sizeof( szVersionPath ) ); + if ( Sys_LoadFile( szVersionPath, (void**)&pVersionDetailString ) <= 0 ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Cancelled Installation! DVD Image Auto-Build Process Failed! - Missing version.txt\n" ); + return; + } + + Sys_LoadScriptFile( szScriptPath ); + + CProgress* pProgress = new CProgress; + pProgress->Open( "Installing DVD Image...", true, false ); + + int numFailed = 0; + int numSkipped = 0; + int numUpdated = 0; + int version = 0; + + bool bFailed = true; + bool bSyntaxError = false; + bool bCancelled = false; + while ( 1 ) + { + pToken = Sys_GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + + if ( pProgress->IsCancel() ) + { + bCancelled = true; + break; + } + + if ( !stricmp( pToken, "$version" ) ) + { + // version <num> <targetroot> + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + { + bSyntaxError = true; + break; + } + version = atoi( pToken ); + if ( version < 0 ) + { + version = 0; + } + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + { + bSyntaxError = true; + break; + } + Sys_StripQuotesFromToken( pToken ); + V_FixSlashes( pToken ); + if ( pToken[0] == CORRECT_PATH_SEPARATOR ) + { + // remove initial slash + memcpy( pToken, pToken+1, strlen( pToken ) ); + } + + char szRootPath[MAX_PATH]; + V_ComposeFileName( g_targetPath, pToken, szRootPath, sizeof( szRootPath ) ); + + if ( bCleanTarget ) + { + // delete any exisiting files at target + DM_FILE_ATTRIBUTES fileAttributes; + HRESULT hr = DmGetFileAttributes( szRootPath, &fileAttributes ); + if ( hr == XBDM_NOERR ) + { + // delete all files at valid target + V_ComposeFileName( szRootPath, "*.*", szTempFilename, sizeof( szTempFilename ) ); + char *pArgs[3]; + pArgs[0] = "*del"; + pArgs[1] = szTempFilename; + pArgs[2] = "/s"; + if ( !lc_del( 3, pArgs ) ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Failed To Delete Files At '%s'.\n", szRootPath ); + break; + } + } + } + + char szTargetVersionPath[MAX_PATH]; + V_ComposeFileName( szRootPath, "version.txt", szTargetVersionPath, sizeof( szTargetVersionPath ) ); + + if ( !bForce ) + { + int fileSize; + char *pTargetVersionDetailString; + if ( !LoadTargetFile( szTargetVersionPath, &fileSize, (void**)&pTargetVersionDetailString ) ) + { + // expected version does not exist + // force full install + bForce = true; + } + else if ( strcmp( pVersionDetailString, pTargetVersionDetailString ) != 0 ) + { + // different versions + bForce = true; + } + Sys_Free( pTargetVersionDetailString ); + } + + if ( bForce && !FileSyncEx( szVersionPath, szTargetVersionPath, FSYNC_ALWAYS, true, false ) ) + { + numFailed++; + break; + } + } + else if ( !stricmp( pToken, "$print" ) ) + { + // print <string> + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + { + bSyntaxError = true; + break; + } + Sys_StripQuotesFromToken( pToken ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", pToken ); + } + else if ( !stricmp( pToken, "$copy" ) ) + { + // copy <source> <target> + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + { + bSyntaxError = true; + break; + } + Sys_StripQuotesFromToken( pToken ); + V_FixSlashes( pToken ); + if ( !V_strnicmp( pToken, "DVD\\", 4 ) ) + { + // skip past DVD, used as a placeholder + pToken += 4; + } + V_ComposeFileName( pInstallPath, pToken, arg1, sizeof( arg1 ) ); + + pToken = Sys_GetToken( false ); + if ( !pToken || !pToken[0] ) + { + bSyntaxError = true; + break; + } + Sys_StripQuotesFromToken( pToken ); + V_FixSlashes( pToken ); + if ( pToken[0] == CORRECT_PATH_SEPARATOR ) + { + // remove initial slash + memcpy( pToken, pToken+1, strlen( pToken ) ); + } + V_ComposeFileName( g_targetPath, pToken, arg2, sizeof( arg2 ) ); + + Sys_StripFilename( arg1, sourcePath, sizeof( sourcePath ) ); + + h = FindFirstFile( arg1, &findData ); + if ( h != INVALID_HANDLE_VALUE ) + { + do + { + if ( pProgress->IsCancel() ) + { + bCancelled = true; + break; + } + + if ( !stricmp( findData.cFileName, "." ) || !stricmp( findData.cFileName, ".." ) ) + { + continue; + } + if ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + continue; + } + + strcpy( sourceFilename, sourcePath ); + Sys_AddFileSeperator( sourceFilename, sizeof( sourceFilename ) ); + strcat( sourceFilename, findData.cFileName ); + Sys_NormalizePath( sourceFilename, false ); + + Sys_StripPath( arg2, filename, sizeof( filename ) ); + if ( filename[0] ) + { + // target filename is specified + strcpy( targetFilename, arg2 ); + } + else + { + // target filename is path + strcpy( targetFilename, arg2 ); + Sys_AddFileSeperator( targetFilename, sizeof( targetFilename ) ); + strcat( targetFilename, findData.cFileName ); + Sys_NormalizePath( targetFilename, false ); + } + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\nCopying: %s -> %s\n", sourceFilename, targetFilename ); + + WIN32_FILE_ATTRIBUTE_DATA localAttributes; + float sourceFileSize = 0; + if ( GetFileAttributesEx( sourceFilename, GetFileExInfoStandard, &localAttributes ) ) + { + sourceFileSize = (float)localAttributes.nFileSizeLow / (1024.0f * 1024.0f); + } + + char statusBuff1[MAX_PATH]; + V_snprintf( statusBuff1, sizeof( statusBuff1 ), "Copying (%.2f MB) ... Please Wait", sourceFileSize ); + pProgress->SetStatus( statusBuff1, sourceFilename, targetFilename ); + + int fileSyncMode = bForce ? FSYNC_ALWAYS : FSYNC_IFNEWER; + errCode = FileSyncEx( sourceFilename, targetFilename, fileSyncMode, true, false ); + if ( errCode < 0 ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Sync Failure!\n" ); + numFailed++; + } + else if ( errCode == 0 ) + { + ConsoleWindowPrintf( XBX_CLR_BLUE, "Sync Skipped!\n" ); + numSkipped++; + } + else if ( errCode == 1 ) + { + ConsoleWindowPrintf( XBX_CLR_GREEN, "Sync Completed!\n" ); + numUpdated++; + } + } + while ( FindNextFile( h, &findData ) ); + + FindClose( h ); + } + } + else if ( !stricmp( pToken, "$end" ) ) + { + bFailed = false; + break; + } + else + { + ConsoleWindowPrintf( XBX_CLR_RED, "Unknown token: '%s' in '%s'\n", pToken, szScriptPath ); + bSyntaxError = true; + break; + } + } + + if ( bSyntaxError ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Syntax Error in '%s'.\n", szScriptPath ); + } + + if ( bCancelled ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Cancelled Installation!\n" ); + } + else if ( bFailed ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "Failed Installation!\n" ); + } + else + { + char *pCRLF = V_stristr( pVersionDetailString, "\r\n" ); + if ( pCRLF ) + { + *pCRLF = '\0'; + } + + // spew stats + ConsoleWindowPrintf( XBX_CLR_BLACK, "\n" ); + ConsoleWindowPrintf( XBX_CLR_BLACK, "Installation Completed.\n" ); + ConsoleWindowPrintf( XBX_CLR_BLACK, "-----------------------\n" ); + ConsoleWindowPrintf( XBX_CLR_BLACK, "Version: %s\n", pVersionDetailString ? pVersionDetailString : "???" ); + + if ( numFailed ) + { + ConsoleWindowPrintf( XBX_CLR_RED, "%d Failures.\n", numFailed ); + } + ConsoleWindowPrintf( XBX_CLR_BLACK, "%d Files In Sync.\n", numSkipped ); + ConsoleWindowPrintf( XBX_CLR_BLACK, "%d Files Updated.\n", numUpdated ); + } + + delete pProgress; + Sys_Free( pVersionDetailString ); + Sys_FreeScriptFile(); +} + +//----------------------------------------------------------------------------- +// InstallDlg_GetChanges +// +//----------------------------------------------------------------------------- +bool InstallDlg_GetChanges( HWND hWnd ) +{ + g_install_bForceSync = IsDlgButtonChecked( hWnd, IDC_INSTALL_FORCESYNC ) != 0; + g_install_bCleanTarget = IsDlgButtonChecked( hWnd, IDC_INSTALL_CLEANTARGET ) != 0; + + g_install_Selection = -1; + for ( int i = 0; i < g_install_dvdImages.Count(); i++ ) + { + int state = ListView_GetItemState( GetDlgItem( hWnd, IDC_INSTALL_LIST ), i, LVIS_FOCUSED|LVIS_SELECTED ); + if ( state == ( LVIS_FOCUSED|LVIS_SELECTED ) ) + { + g_install_Selection = i; + break; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// SortDVDImages +// +//----------------------------------------------------------------------------- +int SortDVDImages( const dvdimage_t *pA, const dvdimage_t *pB ) +{ + char szStringA[256]; + char szStringB[256]; + + V_strncpy( szStringA, pA->szString, sizeof( szStringA ) ); + V_strncpy( szStringB, pB->szString, sizeof( szStringB ) ); + + // sort staging first + char *pCommentA = V_stristr( szStringA, " (" ); + char *pCommentB = V_stristr( szStringB, " (" ); + if ( pCommentA ) + { + *pCommentA = '\0'; + } + if ( pCommentB ) + { + *pCommentB = '\0'; + } + + return stricmp( szStringB, szStringA ); +} + +//----------------------------------------------------------------------------- +// InstallDlg_Populate +// +//----------------------------------------------------------------------------- +void InstallDlg_Populate( HWND hWnd ) +{ + HWND hWndListView = GetDlgItem( hWnd, IDC_INSTALL_LIST ); + + ListView_DeleteAllItems( hWndListView ); + g_install_dvdImages.Purge(); + + // get list of DVD images + char szPath[MAX_PATH]; + V_ComposeFileName( g_installPath, "DVD_*", szPath, sizeof( szPath ) ); + WIN32_FIND_DATA findData; + HANDLE h = FindFirstFile( szPath, &findData ); + if ( h != INVALID_HANDLE_VALUE ) + { + do + { + if ( !stricmp( findData.cFileName, "." ) || !stricmp( findData.cFileName, ".." ) ) + { + continue; + } + if ( !( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) + { + // skip files + continue; + } + + char szInstallPath[MAX_PATH]; + V_strncpy( szInstallPath, g_installPath, sizeof( szInstallPath ) ); + V_AppendSlash( szInstallPath, sizeof( szInstallPath ) ); + V_strncat( szInstallPath, findData.cFileName, sizeof( szInstallPath ) ); + + // qualify dvd dirs that are images + char szBooterPath[MAX_PATH]; + V_ComposeFileName( szInstallPath, "default.xex", szBooterPath, sizeof( szBooterPath ) ); + if ( !Sys_Exists( szBooterPath ) ) + { + continue; + } + char szVersionPath[MAX_PATH]; + V_ComposeFileName( szInstallPath, "version.txt", szVersionPath, sizeof( szVersionPath ) ); + char *pVersionDetailString = NULL; + if ( Sys_LoadFile( szVersionPath, (void**)&pVersionDetailString ) == -1 ) + { + continue; + } + + char *pCRLF = V_stristr( pVersionDetailString, "\r\n" ); + if ( pCRLF ) + { + *pCRLF = '\0'; + } + + dvdimage_t image; + + int year = 0; + int month = 0; + int day = 0; + int hour = 0; + int minute = 0; + char timeOfDay[256]; + sscanf( findData.cFileName, "DVD_%d_%d_%d_%d_%d_%s", &year, &month, &day, &hour, &minute, timeOfDay ); + + const char *pInfoString = timeOfDay; + if ( !V_strnicmp( timeOfDay, "PM", 2 ) ) + { + if ( hour != 12 ) + { + // 24 hour time for correct sorting + hour += 12; + } + pInfoString += 2; + } + else if ( !V_strnicmp( timeOfDay, "AM", 2 ) ) + { + if ( hour == 12 ) + { + // 24 hour time for correct sorting + hour = 0; + } + pInfoString += 2; + } + + char szCommentBuff[128]; + if ( pInfoString[0] == '_' ) + { + // optional info after AM/PM + pInfoString++; + V_snprintf( szCommentBuff, sizeof( szCommentBuff ), " (%s)", pInfoString ); + } + else + { + szCommentBuff[0] = '\0'; + } + + V_snprintf( image.szString, sizeof( image.szString ), "%2.2d/%2.2d/%4.4d %2.2d:%2.2d%s", month, day, year, hour, minute, szCommentBuff ); + + image.installPath = szInstallPath; + image.versionDetailString = pVersionDetailString; + g_install_dvdImages.AddToTail( image ); + Sys_Free( pVersionDetailString ); + } + while ( FindNextFile( h, &findData ) ); + FindClose( h ); + } + + // current image will be at head + g_install_dvdImages.Sort( SortDVDImages ); + + for ( int i = 0; i < g_install_dvdImages.Count(); i++ ) + { + // setup and insert at end of list + LVITEM lvi; + memset( &lvi, 0, sizeof( lvi ) ); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = i; + lvi.iSubItem = 0; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; + lvi.lParam = (LPARAM)i; + + ListView_InsertItem( hWndListView, &lvi ); + } + + if ( g_install_dvdImages.Count() ) + { + ListView_SetItemState( hWndListView, 0, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED ); + } +} + +//----------------------------------------------------------------------------- +// InstallDlg_Setup +// +//----------------------------------------------------------------------------- +void InstallDlg_Setup( HWND hWnd ) +{ + g_install_Selection = -1; + g_install_bForceSync = false; + g_install_bCleanTarget = false; + + HWND hWndListView = GetDlgItem( hWnd, IDC_INSTALL_LIST ); + + // initialize columns + LVCOLUMN lvc; + memset( &lvc, 0, sizeof( lvc ) ); + lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; + lvc.iSubItem = 0; + lvc.fmt = LVCFMT_LEFT; + lvc.cx = 200; + lvc.pszText = ( LPSTR )"Date Built:"; + ListView_InsertColumn( hWndListView, 0, &lvc ); + lvc.iSubItem = 0; + lvc.fmt = LVCFMT_LEFT; + lvc.cx = 500; + lvc.pszText = ( LPSTR )"Perforce Changelist:"; + ListView_InsertColumn( hWndListView, 1, &lvc ); + + ListView_SetBkColor( hWndListView, g_backgroundColor ); + ListView_SetTextBkColor( hWndListView, g_backgroundColor ); + + DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES; + ListView_SetExtendedListViewStyleEx( hWndListView, style, style ); + + InstallDlg_Populate( hWnd ); +} + +//----------------------------------------------------------------------------- +// InstallDlg_Proc +// +//----------------------------------------------------------------------------- +BOOL CALLBACK InstallDlg_Proc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch ( message ) + { + case WM_INITDIALOG: + InstallDlg_Setup( hWnd ); + return ( TRUE ); + + case WM_NOTIFY: + switch ( ( ( LPNMHDR )lParam )->code ) + { + case LVN_GETDISPINFO: + NMLVDISPINFO* plvdi; + plvdi = (NMLVDISPINFO*)lParam; + int item = (int)plvdi->item.lParam; + switch ( plvdi->item.iSubItem ) + { + case 0: + plvdi->item.pszText = g_install_dvdImages[item].szString; + return TRUE; + case 1: + plvdi->item.pszText = (LPSTR)g_install_dvdImages[item].versionDetailString.String(); + return TRUE; + } + } + break; + + case WM_COMMAND: + switch ( LOWORD( wParam ) ) + { + case IDC_OK: + InstallDlg_GetChanges( hWnd ); + EndDialog( hWnd, wParam ); + return ( TRUE ); + + case IDC_INSTALL_REFRESH: + InstallDlg_Populate( hWnd ); + return TRUE; + + case IDCANCEL: + case IDC_CANCEL: + EndDialog( hWnd, wParam ); + return ( TRUE ); + } + break; + } + return ( FALSE ); +} + +//----------------------------------------------------------------------------- +// InstallDlg_Open +// +//----------------------------------------------------------------------------- +void InstallDlg_Open( void ) +{ + int result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_INSTALL ), g_hDlgMain, ( DLGPROC )InstallDlg_Proc ); + if ( LOWORD( result ) == IDC_OK && g_install_Selection != -1 ) + { + InstallDlg_InstallImage( + g_install_dvdImages[g_install_Selection].installPath.String(), + g_install_bForceSync, + g_install_bCleanTarget ); + } + + g_install_dvdImages.Purge(); +} diff --git a/utils/xbox/vxconsole/sys_scriptlib.cpp b/utils/xbox/vxconsole/sys_scriptlib.cpp new file mode 100644 index 0000000..e52729c --- /dev/null +++ b/utils/xbox/vxconsole/sys_scriptlib.cpp @@ -0,0 +1,292 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SYS_SCRIPTLIB.CPP +// +// +//=====================================================================================// +#include "vxconsole.h" + +char g_sys_token[MAXTOKEN]; +char* g_sys_scriptbuff; +char* g_sys_scriptptr; +char* g_sys_scriptendptr; +int g_sys_scriptsize; +int g_sys_scriptline; +bool g_sys_endofscript; +bool g_sys_tokenready; +int g_sys_oldscriptline; +char* g_sys_oldscriptptr; + +//----------------------------------------------------------------------------- +// Sys_FreeScriptFile +// +//----------------------------------------------------------------------------- +void Sys_FreeScriptFile(void) +{ + if (g_sys_scriptbuff) + { + Sys_Free(g_sys_scriptbuff); + g_sys_scriptbuff = NULL; + } +} + +//----------------------------------------------------------------------------- +// Sys_LoadScriptFile +// +//----------------------------------------------------------------------------- +void Sys_LoadScriptFile(const char* filename) +{ + g_sys_scriptsize = Sys_LoadFile(filename,(void **)&g_sys_scriptbuff); + + Sys_ResetParser(); +} + +//----------------------------------------------------------------------------- +// Sys_SetScriptData +// +//----------------------------------------------------------------------------- +void Sys_SetScriptData(const char* data, int length) +{ + g_sys_scriptbuff = (char *)data; + g_sys_scriptsize = length; + + Sys_ResetParser(); +} + +//----------------------------------------------------------------------------- +// Sys_UnGetToken +// +//----------------------------------------------------------------------------- +void Sys_UnGetToken(void) +{ + g_sys_tokenready = true; +} + +//----------------------------------------------------------------------------- +// Sys_GetToken +// +//----------------------------------------------------------------------------- +char* Sys_GetToken(bool crossline) +{ + char* tokenptr; + + if (g_sys_tokenready) + { + g_sys_tokenready = false; + return (g_sys_token); + } + + g_sys_token[0] = '\0'; + + if (g_sys_scriptptr >= g_sys_scriptendptr) + { + g_sys_endofscript = true; + return (NULL); + } + +skipspace: + while (*g_sys_scriptptr <= ' ') + { + if (g_sys_scriptptr >= g_sys_scriptendptr) + { + g_sys_endofscript = true; + return (NULL); + } + + if (*g_sys_scriptptr++ == '\n') + { + if (!crossline) + { + // unexpected newline at g_sys_scriptline + return (NULL); + } + + g_sys_scriptline++; + } + } + + if (g_sys_scriptptr >= g_sys_scriptendptr) + { + g_sys_endofscript = true; + return (NULL); + } + + // skip commented line + if ((g_sys_scriptptr[0] == ';') || (g_sys_scriptptr[0] == '/' && g_sys_scriptptr[1] == '/')) + { + if (!crossline) + { + // unexpected newline at g_sys_scriptline + return (NULL); + } + + while (*g_sys_scriptptr++ != '\n') + { + if (g_sys_scriptptr >= g_sys_scriptendptr) + { + g_sys_endofscript = true; + return (NULL); + } + } + + g_sys_scriptline++; + goto skipspace; + } + + tokenptr = g_sys_token; + if (g_sys_scriptptr[0] == '\"' && g_sys_scriptptr[1]) + { + // copy quoted token + do + { + *tokenptr++ = *g_sys_scriptptr++; + if (g_sys_scriptptr == g_sys_scriptendptr) + break; + + if (tokenptr == &g_sys_token[MAXTOKEN]) + { + // token too large + return NULL; + } + } + while (*g_sys_scriptptr >= ' ' && *g_sys_scriptptr != '\"'); + + if (g_sys_scriptptr[0] == '\"') + *tokenptr++ = *g_sys_scriptptr++; + } + else + { + // copy token + while (*g_sys_scriptptr > ' ' && *g_sys_scriptptr != ';' && *g_sys_scriptptr != '\"') + { + *tokenptr++ = *g_sys_scriptptr++; + if (g_sys_scriptptr == g_sys_scriptendptr) + break; + + if (tokenptr == &g_sys_token[MAXTOKEN]) + { + // token too large + return NULL; + } + } + } + + *tokenptr = '\0'; + + return (g_sys_token); +} + +//----------------------------------------------------------------------------- +// Sys_SkipRestOfLine +// +//----------------------------------------------------------------------------- +void Sys_SkipRestOfLine(void) +{ + while (*g_sys_scriptptr++ != '\n') + { + if (g_sys_scriptptr >= g_sys_scriptendptr) + { + break; + } + } + + g_sys_scriptline++; + + // flush any queued token + g_sys_tokenready = false; +} + +//----------------------------------------------------------------------------- +// Sys_TokenAvailable +// +// Returns (TRUE) if token available on line. +//----------------------------------------------------------------------------- +bool Sys_TokenAvailable (void) +{ + char* ptr; + + ptr = g_sys_scriptptr; + while (*ptr <= ' ') + { + if (ptr >= g_sys_scriptendptr) + { + g_sys_endofscript = true; + return (false); + } + + if (*ptr++ == '\n') + return (false); + } + + return (true); +} + + +//----------------------------------------------------------------------------- +// Sys_EndOfScript +// +// Returns (TRUE) at end of script +//----------------------------------------------------------------------------- +bool Sys_EndOfScript(void) +{ + if (g_sys_scriptptr >= g_sys_scriptendptr) + { + g_sys_endofscript = true; + return (true); + } + + return (false); +} + +//----------------------------------------------------------------------------- +// Sys_ResetParser +// +//----------------------------------------------------------------------------- +void Sys_ResetParser(void) +{ + g_sys_scriptptr = g_sys_scriptbuff; + g_sys_scriptendptr = g_sys_scriptptr + g_sys_scriptsize; + g_sys_scriptline = 1; + g_sys_endofscript = false; + g_sys_tokenready = false; +} + +//----------------------------------------------------------------------------- +// Sys_SaveParser +// +//----------------------------------------------------------------------------- +void Sys_SaveParser(void) +{ + g_sys_oldscriptline = g_sys_scriptline; + g_sys_oldscriptptr = g_sys_scriptptr; +} + +//----------------------------------------------------------------------------- +// Sys_RestoreParser +// +//----------------------------------------------------------------------------- +void Sys_RestoreParser(void) +{ + g_sys_scriptline = g_sys_oldscriptline; + g_sys_scriptptr = g_sys_oldscriptptr; + g_sys_tokenready = false; +} + +//----------------------------------------------------------------------------- +// Sys_StripQuotesFromToken +// +//----------------------------------------------------------------------------- +void Sys_StripQuotesFromToken( char *pToken ) +{ + int len; + + len = strlen( pToken ); + if ( len >= 2 && pToken[0] == '\"' ) + { + memcpy( pToken, pToken+1, len-1 ); + pToken[len-2] = '\0'; + } +} + + + diff --git a/utils/xbox/vxconsole/sys_scriptlib.h b/utils/xbox/vxconsole/sys_scriptlib.h new file mode 100644 index 0000000..a019f83 --- /dev/null +++ b/utils/xbox/vxconsole/sys_scriptlib.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SYS_SCRIPTLIB.H +// +// System Utilities. +//=====================================================================================// +#pragma once + +#include "vxconsole.h" + +#define MAXTOKEN 128 + +extern void Sys_LoadScriptFile(const char* filename); +extern void Sys_SetScriptData(const char* data, int length); +extern void Sys_FreeScriptFile(void); +extern char* Sys_GetToken(bool crossline); +extern char* Sys_GetQuotedToken(bool crossline); +extern void Sys_UnGetToken(void); +extern bool Sys_TokenAvailable(void); +extern void Sys_SaveParser(void); +extern void Sys_RestoreParser(void); +extern void Sys_ResetParser(void); +extern void Sys_SkipRestOfLine(void); +extern bool Sys_EndOfScript(void); +extern char* Sys_GetRawToken(void); +extern void Sys_StripQuotesFromToken( char *pToken ); + +extern char g_sys_token[MAXTOKEN]; +extern char* g_sys_scriptbuffer; +extern char* g_sys_scriptptr; +extern char* g_sys_scriptendptr; +extern int g_sys_scriptsize; +extern int g_sys_scriptline; +extern bool g_sys_endofscript; diff --git a/utils/xbox/vxconsole/sys_utils.cpp b/utils/xbox/vxconsole/sys_utils.cpp new file mode 100644 index 0000000..d8bf23c --- /dev/null +++ b/utils/xbox/vxconsole/sys_utils.cpp @@ -0,0 +1,1090 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SYS_UTILS.C +// +//=====================================================================================// +#include "vxconsole.h" + +CHAR g_szRegistryPrefix[256]; + +//----------------------------------------------------------------------------- +// Sys_SetRegistryPrefix +// +//----------------------------------------------------------------------------- +void Sys_SetRegistryPrefix( const CHAR *pPrefix ) +{ + _snprintf_s( g_szRegistryPrefix, sizeof( g_szRegistryPrefix ), _TRUNCATE, pPrefix ); +} + +//----------------------------------------------------------------------------- +// Sys_SplitRegistryKey +// +//----------------------------------------------------------------------------- +static BOOL Sys_SplitRegistryKey( const CHAR *key, CHAR *key0, int key0Len, CHAR *key1, int key1Len ) +{ + if ( !key ) + { + return false; + } + + int len = (int)strlen( key ); + if ( !len ) + { + return false; + } + + int Start = -1; + for ( int i=len-1; i>=0; i-- ) + { + if ( key[i] == '\\' ) + break; + else + Start=i; + } + + if ( Start == -1 ) + return false; + + _snprintf_s( key0, Start, _TRUNCATE, key ); + _snprintf_s( key1, ( len-Start )+1, _TRUNCATE, key+Start ); + + return true; +} + +//----------------------------------------------------------------------------- +// Sys_SetRegistryString +// +//----------------------------------------------------------------------------- +BOOL Sys_SetRegistryString( const CHAR *keyName, const CHAR *value ) +{ + HKEY hKey; + CHAR key0[256]; + CHAR key1[256]; + CHAR keyBuff[256]; + CHAR *key; + + strcpy_s( keyBuff, sizeof( keyBuff ), g_szRegistryPrefix ); + strcat_s( keyBuff, sizeof( keyBuff ), keyName ); + key = keyBuff; + + HKEY hSlot = HKEY_CURRENT_USER; + if ( !strncmp( key, "HKEY_LOCAL_MACHINE", 18 ) ) + { + hSlot = HKEY_LOCAL_MACHINE; + key += 19; + } + else if ( !strncmp( key, "HKEY_CURRENT_USER", 17 ) ) + { + hSlot = HKEY_CURRENT_USER; + key += 18; + } + + if ( !Sys_SplitRegistryKey( key, key0, sizeof( key0 ), key1, sizeof( key1 ) ) ) + return false; + + if ( RegCreateKeyEx( hSlot,key0,NULL,NULL,REG_OPTION_NON_VOLATILE, value ? KEY_WRITE : KEY_ALL_ACCESS,NULL,&hKey,NULL )!=ERROR_SUCCESS ) + return false; + + if ( RegSetValueEx( hKey, key1, NULL, REG_SZ, ( UCHAR* )value, (int)strlen( value ) + 1 ) != ERROR_SUCCESS ) + { + RegCloseKey( hKey ); + return false; + } + + // success + RegCloseKey( hKey ); + return true; +} + +//----------------------------------------------------------------------------- +// Sys_GetRegistryString +// +//----------------------------------------------------------------------------- +BOOL Sys_GetRegistryString( const CHAR *keyName, CHAR *value, const CHAR* defValue, int valueLen ) +{ + HKEY hKey; + CHAR key0[256]; + CHAR key1[256]; + CHAR keyBuff[256]; + CHAR *key; + + strcpy_s( keyBuff, sizeof( keyBuff ), g_szRegistryPrefix ); + strcat_s( keyBuff, sizeof( keyBuff ), keyName ); + key = keyBuff; + + if ( defValue ) + { + _snprintf_s( value, valueLen, _TRUNCATE, defValue ); + } + + HKEY hSlot = HKEY_CURRENT_USER; + if ( !strncmp( key, "HKEY_LOCAL_MACHINE", 18 ) ) + { + hSlot = HKEY_LOCAL_MACHINE; + key += 19; + } + else if ( !strncmp( key, "HKEY_CURRENT_USER", 17 ) ) + { + hSlot = HKEY_CURRENT_USER; + key += 18; + } + + if ( !Sys_SplitRegistryKey( key,key0,256,key1,256 ) ) + return false; + + if ( RegOpenKeyEx( hSlot,key0,NULL,KEY_READ,&hKey )!=ERROR_SUCCESS ) + return false; + + unsigned long len=valueLen; + if ( RegQueryValueEx( hKey,key1,NULL,NULL,( UCHAR* )value,&len )!=ERROR_SUCCESS ) + { + RegCloseKey( hKey ); + return false; + } + + // success + RegCloseKey( hKey ); + return true; +} + +//----------------------------------------------------------------------------- +// Sys_SetRegistryInteger +// +//----------------------------------------------------------------------------- +BOOL Sys_SetRegistryInteger( const CHAR *keyName, int value ) +{ + HKEY hKey; + CHAR key0[256]; + CHAR key1[256]; + CHAR keyBuff[256]; + CHAR *key; + + strcpy_s( keyBuff, sizeof( keyBuff ), g_szRegistryPrefix ); + strcat_s( keyBuff, sizeof( keyBuff ), keyName ); + key = keyBuff; + + HKEY hSlot = HKEY_CURRENT_USER; + if ( !strncmp( key, "HKEY_LOCAL_MACHINE", 18 ) ) + { + hSlot = HKEY_LOCAL_MACHINE; + key += 19; + } + else if ( !strncmp( key, "HKEY_CURRENT_USER", 17 ) ) + { + hSlot = HKEY_CURRENT_USER; + key += 18; + } + + if ( !Sys_SplitRegistryKey( key,key0,256,key1,256 ) ) + return false; + + if ( RegCreateKeyEx( hSlot, key0, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL )!=ERROR_SUCCESS ) + return false; + + if ( RegSetValueEx( hKey, key1, NULL, REG_DWORD, ( UCHAR* )&value, 4 )!=ERROR_SUCCESS ) + { + RegCloseKey( hKey ); + return false; + } + + // success + RegCloseKey( hKey ); + return true; +} + +//----------------------------------------------------------------------------- +// Sys_GetRegistryInteger +// +//----------------------------------------------------------------------------- +BOOL Sys_GetRegistryInteger( const CHAR *keyName, int defValue, int &value ) +{ + HKEY hKey; + CHAR key0[256]; + CHAR key1[256]; + CHAR keyBuff[256]; + CHAR *key; + + strcpy_s( keyBuff, sizeof( keyBuff ), g_szRegistryPrefix ); + strcat_s( keyBuff, sizeof( keyBuff ), keyName ); + key = keyBuff; + + value = defValue; + + HKEY hSlot = HKEY_CURRENT_USER; + if ( !strncmp( key, "HKEY_LOCAL_MACHINE", 18 ) ) + { + hSlot = HKEY_LOCAL_MACHINE; + key += 19; + } + else if ( !strncmp( key, "HKEY_CURRENT_USER", 17 ) ) + { + hSlot = HKEY_CURRENT_USER; + key += 18; + } + + if ( !Sys_SplitRegistryKey( key, key0, 256, key1, 256 ) ) + return false; + + if ( RegOpenKeyEx( hSlot, key0, NULL, KEY_READ, &hKey ) != ERROR_SUCCESS ) + return false; + + unsigned long len=4; + if ( RegQueryValueEx( hKey, key1, NULL, NULL, ( UCHAR* )&value, &len ) != ERROR_SUCCESS ) + { + RegCloseKey( hKey ); + return false; + } + + // success + RegCloseKey( hKey ); + return true; +} + +//----------------------------------------------------------------------------- +// Sys_MessageBox +// +//----------------------------------------------------------------------------- +void Sys_MessageBox( const CHAR* title, const CHAR* format, ... ) +{ + CHAR msg[2048]; + va_list argptr; + + va_start( argptr, format ); + vsprintf_s( msg, sizeof( msg ), format, argptr ); + va_end( argptr ); + + MessageBox( NULL, msg, title, MB_OK|MB_TASKMODAL|MB_TOPMOST ); +} + +//----------------------------------------------------------------------------- +// Sys_CopyString +// +//----------------------------------------------------------------------------- +CHAR* Sys_CopyString( const CHAR* str ) +{ + int len = (int)strlen( str ); + CHAR *ptr = ( CHAR* )Sys_Alloc( len+1 ); + memcpy( ptr,str,len+1 ); + + return ( ptr ); +} + +//----------------------------------------------------------------------------- +// Sys_Alloc +// +//----------------------------------------------------------------------------- +void* Sys_Alloc( int size ) +{ + int* ptr; + + if ( !size ) + { + Sys_Error( "Sys_Alloc(): zero size" ); + } + + size = AlignValue( size, 4 ); + + // allocate fixed zero init block + ptr = ( int* )malloc( size ); + if ( !ptr ) + { + Sys_Error( "Sys_Alloc(): %d bytes not available",size ); + } + + V_memset( ptr, 0, size ); + + return ptr; +} + +//----------------------------------------------------------------------------- +// Sys_Free +// +//----------------------------------------------------------------------------- +void Sys_Free( void* ptr ) +{ + if ( !ptr ) + { + // already freed - easier for me, not really an error + return; + } + + free( ptr ); +} + +//----------------------------------------------------------------------------- +// Sys_Error +// +//----------------------------------------------------------------------------- +void Sys_Error( const CHAR* format, ... ) +{ + va_list argptr; + CHAR msg[MAX_SYSPRINTMSG]; + + va_start( argptr, format ); + vsprintf_s( msg, sizeof( msg ), format, argptr ); + va_end( argptr ); + + MessageBox( NULL, msg, "FATAL ERROR", MB_OK|MB_ICONHAND ); +} + +//----------------------------------------------------------------------------- +// Sys_LoadFile +// +//----------------------------------------------------------------------------- +int Sys_LoadFile( const CHAR* filename, void** bufferptr, bool bText ) +{ + int handle; + long length; + CHAR* buffer; + + *bufferptr = NULL; + + if ( !Sys_Exists( filename ) ) + { + return ( -1 ); + } + + int openFlags = bText ? _O_TEXT : _O_BINARY; + _sopen_s( &handle, filename, _O_RDONLY|openFlags, _SH_DENYWR, _S_IREAD ); + if ( handle == -1 ) + { + char szError[MAX_PATH]; + strerror_s( szError, sizeof( szError ), errno ); + Sys_Error( "Sys_LoadFile(): Error opening %s: %s", filename, szError ); + } + + // allocate a buffer with an auto null terminator + length = Sys_FileLength( handle ); + buffer = ( CHAR* )Sys_Alloc( length+1 ); + + int numBytesRead = _read( handle, buffer, length ); + _close( handle ); + + if ( bText ) + { + length = numBytesRead; + } + else if ( length != numBytesRead ) + { + Sys_Error( "Sys_LoadFile(): read failure" ); + } + + // for parsing + buffer[length] = '\0'; + + *bufferptr = ( void* )buffer; + + return ( length ); +} + +//----------------------------------------------------------------------------- +// Sys_SaveFile +// +//----------------------------------------------------------------------------- +bool Sys_SaveFile( const CHAR* filename, void* buffer, long count, bool bText ) +{ + int handle; + int status; + + int openFlags = bText ? _O_TEXT : _O_BINARY; + _sopen_s( &handle, filename, _O_RDWR|_O_CREAT|_O_TRUNC|openFlags, _SH_DENYNO, _S_IREAD|_S_IWRITE ); + if ( handle == -1 ) + { + char szError[MAX_PATH]; + strerror_s( szError, sizeof( szError ), errno ); + Sys_Error( "Sys_SaveFile(): Error opening %s: %s", filename, szError ); + return false; + } + + status = _write( handle, buffer, count ); + if ( status != count ) + { + Sys_Error( "Sys_SaveFile(): write failure %d, errno=%d", status, errno ); + return false; + } + + _close( handle ); + return true; +} + +//----------------------------------------------------------------------------- +// Sys_FileLength +// +//----------------------------------------------------------------------------- +long Sys_FileLength( const CHAR* filename, bool bText ) +{ + long length; + + if ( filename ) + { + int handle; + int openFlags = bText ? _O_TEXT : _O_BINARY; + _sopen_s( &handle, filename, _O_RDONLY|openFlags, _SH_DENYWR, _S_IREAD ); + if ( handle == -1 ) + { + // file does not exist + return -1; + } + + length = _lseek( handle, 0, SEEK_END ); + _close( handle ); + } + else + { + return -1; + } + + return length; +} + +//----------------------------------------------------------------------------- +// Sys_FileLength +// +//----------------------------------------------------------------------------- +long Sys_FileLength( int handle ) +{ + long pos; + long length; + + if ( handle != -1 ) + { + pos = _lseek( handle, 0, SEEK_CUR ); + length = _lseek( handle, 0, SEEK_END ); + _lseek( handle, pos, SEEK_SET ); + } + else + { + return -1; + } + + return length; +} + +//----------------------------------------------------------------------------- +// Sys_NormalizePath +// +//----------------------------------------------------------------------------- +void Sys_NormalizePath( CHAR* path, bool forceToLower ) +{ + int i; + int srclen; + + srclen = (int)strlen( path ); + for ( i=0; i<srclen; i++ ) + { + if ( path[i] == '/' ) + path[i] = '\\'; + else if ( forceToLower && ( path[i] >= 'A' && path[i] <= 'Z' ) ) + path[i] = path[i] - 'A' + 'a'; + } +} + +//----------------------------------------------------------------------------- +// Sys_AddFileSeperator +// +//----------------------------------------------------------------------------- +void Sys_AddFileSeperator( CHAR* path, int pathLen ) +{ + int srclen; + + if ( !path[0] ) + { + strcpy_s( path, pathLen, ".\\" ); + return; + } + + srclen = (int)strlen( path ); + if ( path[srclen-1] == '\\' ) + { + return; + } + + strcat_s( path, pathLen, "\\" ); +} + +//----------------------------------------------------------------------------- +// Sys_StripFilename +// +// Removes filename from path. +//----------------------------------------------------------------------------- +void Sys_StripFilename( const CHAR* inpath, CHAR* outpath, int outPathLen ) +{ + int length; + + strcpy_s( outpath, outPathLen, inpath ); + + length = (int)strlen( outpath )-1; + while ( ( length > 0 ) && ( outpath[length] != '\\' ) && ( outpath[length] != '/' ) && ( outpath[length] != ':' ) ) + length--; + + // leave possible seperator + if ( !length ) + outpath[0] = '\0'; + else + outpath[length+1] = '\0'; +} + +//----------------------------------------------------------------------------- +// Sys_StripExtension +// +// Removes extension from path. +//----------------------------------------------------------------------------- +void Sys_StripExtension( const CHAR* inpath, CHAR* outpath, int outPathLen ) +{ + int length; + + strcpy_s( outpath, outPathLen, inpath ); + + length = (int)strlen( outpath )-1; + while ( length > 0 && outpath[length] != '.' ) + { + length--; + } + + if ( length && outpath[length] == '.' ) + { + outpath[length] = '\0'; + } +} + +//----------------------------------------------------------------------------- +// Sys_StripPath +// +// Removes path from full path. +//----------------------------------------------------------------------------- +void Sys_StripPath( const CHAR* inpath, CHAR* outpath, int outPathLen ) +{ + const CHAR* src; + + src = inpath + strlen( inpath ); + while ( ( src != inpath ) && ( *( src-1 ) != '\\' ) && ( *( src-1 ) != '/' ) && ( *( src-1 ) != ':' ) ) + { + src--; + } + + strcpy_s( outpath, outPathLen, src ); +} + +//----------------------------------------------------------------------------- +// Sys_GetExtension +// +// Gets any extension from the full path. +//----------------------------------------------------------------------------- +void Sys_GetExtension( const CHAR* inpath, CHAR* outpath, int outPathLen ) +{ + const CHAR* src; + + src = inpath + strlen( inpath ) - 1; + + // back up until a . or the start + while ( src != inpath && *( src-1 ) != '.' ) + { + src--; + } + + if ( src == inpath ) + { + *outpath = '\0'; // no extension + return; + } + + strcpy_s( outpath, outPathLen, src ); +} + +//----------------------------------------------------------------------------- +// Sys_AddExtension +// +// Adds extension to end of path. +//----------------------------------------------------------------------------- +void Sys_AddExtension( const CHAR* extension, CHAR* outpath, int outPathLen ) +{ + CHAR* src; + + if ( outpath[0] ) + { + src = outpath + strlen( outpath ) - 1; + while ( ( src != outpath ) && ( *src != '\\' ) && ( *src != '/' ) ) + { + if ( *src == '.' ) + return; + src--; + } + } + + strcat_s( outpath, outPathLen, extension ); +} + +//----------------------------------------------------------------------------- +// Sys_TempFilename +// +// Make a temporary filename at specified path. +//----------------------------------------------------------------------------- +void Sys_TempFilename( CHAR* temppath, int tempPathLen ) +{ + CHAR* ptr; + + ptr = _tempnam( "c:\\", "tmp" ); + strcpy_s( temppath, tempPathLen, ptr ); + free( ptr ); +} + +//----------------------------------------------------------------------------- +// Sys_Exists +// +// Returns TRUE if file exists. +//----------------------------------------------------------------------------- +BOOL Sys_Exists( const CHAR* filename ) +{ + FILE* test; + + fopen_s( &test, filename, "rb" ); + if ( test == NULL ) + { + return false; + } + + fclose( test ); + + return true; +} + +//----------------------------------------------------------------------------- +// Sys_SkipWhitespace +// +//----------------------------------------------------------------------------- +CHAR* Sys_SkipWhitespace( CHAR *data, BOOL *hasNewLines, int* numlines ) +{ + int c; + + while( ( c = *data ) <= ' ' ) + { + if ( c == '\n' ) + { + if ( numlines ) + ( *numlines )++; + + if ( hasNewLines ) + *hasNewLines = true; + } + else if ( !c ) + return ( NULL ); + + data++; + } + + return ( data ); +} + +//----------------------------------------------------------------------------- +// Sys_GetToken +// +//----------------------------------------------------------------------------- +CHAR* Sys_GetToken( CHAR** dataptr, BOOL allowLineBreaks, int* numlines ) +{ + CHAR c; + int len; + BOOL hasNewLines; + CHAR* data; + static CHAR token[MAX_SYSTOKENCHARS]; + + if ( numlines ) + *numlines = 0; + + c = 0; + data = *dataptr; + len = 0; + token[0] = 0; + hasNewLines = false; + + // make sure incoming data is valid + if ( !data ) + { + *dataptr = NULL; + return ( token ); + } + + for ( ;; ) + { + // skip whitespace + data = Sys_SkipWhitespace( data,&hasNewLines,numlines ); + if ( !data ) + { + *dataptr = NULL; + return ( token ); + } + + if ( hasNewLines && !allowLineBreaks ) + { + *dataptr = data; + return ( token ); + } + + c = *data; + + // skip double slash comments + if ( c == '/' && data[1] == '/' ) + { + data += 2; + while ( *data && *data != '\n' ) + data++; + } + // skip /* */ comments + else if ( c =='/' && data[1] == '*' ) + { + data += 2; + while ( *data && ( *data != '*' || data[1] != '/' ) ) + data++; + + if ( *data ) + data += 2; + } + else + break; + } + + // handle quoted strings + if ( c == '\"' ) + { + data++; + for ( ;; ) + { + c = *data++; + if ( c == '\"' || !c ) + { + token[len] = 0; + *dataptr = ( CHAR* )data; + return ( token ); + } + if ( len < MAX_SYSTOKENCHARS ) + token[len++] = c; + } + } + + // parse a regular word + do + { + if ( len < MAX_SYSTOKENCHARS ) + token[len++] = c; + + data++; + c = *data; + if ( c == '\n' && numlines ) + ( *numlines )++; + } while ( c > ' ' ); + + if ( len >= MAX_SYSTOKENCHARS ) + len = 0; + + token[len] = '\0'; + *dataptr = ( CHAR* ) data; + + return ( token ); +} + +//----------------------------------------------------------------------------- +// Sys_SkipBracedSection +// +// The next token should be an open brace. +// Skips until a matching close brace is found. +// Internal brace depths are properly skipped. +//----------------------------------------------------------------------------- +void Sys_SkipBracedSection( CHAR** dataptr, int* numlines ) +{ + CHAR* token; + int depth; + + depth = 0; + do + { + token = Sys_GetToken( dataptr, true, numlines ); + if ( token[1] == '\0' ) + { + if ( token[0] == '{' ) + depth++; + else if ( token[0] == '}' ) + depth--; + } + } + while( depth && *dataptr ); +} + +//----------------------------------------------------------------------------- +// Sys_SkipRestOfLine +// +//----------------------------------------------------------------------------- +void Sys_SkipRestOfLine( CHAR** dataptr, int* numlines ) +{ + CHAR* p; + int c; + + p = *dataptr; + while ( ( c = *p++ ) != '\0' ) + { + if ( c == '\n' ) + { + if ( numlines ) + ( *numlines )++; + break; + } + } + *dataptr = p; +} + +//----------------------------------------------------------------------------- +// Sys_FileTime +// +// Returns a file's last write time +//----------------------------------------------------------------------------- +BOOL Sys_FileTime( CHAR* filename, FILETIME* time ) +{ + HANDLE hFile; + + hFile = CreateFile( + filename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if ( hFile == INVALID_HANDLE_VALUE ) + return ( false ); + + // Retrieve the file times for the file. + if ( !GetFileTime( hFile, NULL, NULL, time ) ) + { + CloseHandle( hFile ); + return ( false ); + } + + CloseHandle( hFile ); + return ( true ); +} + +//----------------------------------------------------------------------------- +// Sys_GetSystemTime +// +// Current time marker in milliseconds +//----------------------------------------------------------------------------- +DWORD Sys_GetSystemTime( void ) +{ + LARGE_INTEGER qwTime; + LARGE_INTEGER qwTicksPerSec; + float msecsPerTick; + + // Get the frequency of the timer + QueryPerformanceFrequency( &qwTicksPerSec ); + msecsPerTick = 1000.0f/( FLOAT )qwTicksPerSec.QuadPart; + + QueryPerformanceCounter( &qwTime ); + return ( ( DWORD )( msecsPerTick * ( FLOAT )qwTime.QuadPart ) ); +} + +//----------------------------------------------------------------------------- +// Sys_ColorScale +// +//----------------------------------------------------------------------------- +COLORREF Sys_ColorScale( COLORREF color, float scale ) +{ + int r; + int g; + int b; + + r = color & 0xFF; + g = ( color >> 8 ) & 0xFF; + b = ( color >> 16 ) & 0xFF; + + r = ( int )( ( float )r * scale ); + g = ( int )( ( float )g * scale ); + b = ( int )( ( float )b * scale ); + + if ( r > 255 ) + r = 255; + if ( g > 255 ) + g = 255; + if ( b > 255 ) + b = 255; + + color = RGB( r, g, b ); + return ( color ); +} + +//----------------------------------------------------------------------------- +// Sys_IsWildcardMatch +// +// See if a string matches a wildcard specification that uses * or ? +//----------------------------------------------------------------------------- +bool Sys_IsWildcardMatch( const CHAR *wildcardString, const CHAR *stringToCheck, bool caseSensitive ) +{ + CHAR wcChar; + CHAR strChar; + + if ( !_stricmp( wildcardString, "*.*" ) || !_stricmp( wildcardString, "*" ) ) + { + // matches everything + return true; + } + + // use the starMatchesZero variable to determine whether an asterisk + // matches zero or more characters ( TRUE ) or one or more characters + // ( FALSE ) + bool starMatchesZero = true; + + for ( ;; ) + { + strChar = *stringToCheck; + if ( !strChar ) + { + break; + } + + wcChar = *wildcardString; + if ( !wcChar ) + { + break; + } + + // we only want to advance the pointers if we successfully assigned + // both of our char variables, so we'll do it here rather than in the + // loop condition itself + *stringToCheck++; + *wildcardString++; + + // if this isn't a case-sensitive match, make both chars uppercase + // ( thanks to David John Fielder ( Konan ) at http://innuendo.ev.ca + // for pointing out an error here in the original code ) + if ( !caseSensitive ) + { + wcChar = (CHAR)toupper( wcChar ); + strChar = (CHAR)toupper( strChar ); + } + + // check the wcChar against our wildcard list + switch ( wcChar ) + { + // an asterisk matches zero or more characters + case '*' : + // do a recursive call against the rest of the string, + // until we've either found a match or the string has + // ended + if ( starMatchesZero ) + *stringToCheck--; + + while ( *stringToCheck ) + { + if ( Sys_IsWildcardMatch( wildcardString, stringToCheck++, caseSensitive ) ) + return true; + } + + break; + + // a question mark matches any single character + case '?' : + break; + + // if we fell through, we want an exact match + default : + if ( wcChar != strChar ) + return false; + break; + } + } + + // if we have any asterisks left at the end of the wildcard string, we can + // advance past them if starMatchesZero is TRUE ( so "blah*" will match "blah" ) + while ( ( *wildcardString ) && ( starMatchesZero ) ) + { + if ( *wildcardString == '*' ) + wildcardString++; + else + break; + } + + // if we got to the end but there's still stuff left in either of our strings, + // return false; otherwise, we have a match + if ( ( *stringToCheck ) || ( *wildcardString ) ) + return false; + else + return true; +} + +//----------------------------------------------------------------------------- +// Sys_NumberToCommaString +// +// Add commas to number +//----------------------------------------------------------------------------- +char *Sys_NumberToCommaString( __int64 number, char *buffer, int bufferSize ) +{ + char temp[256]; + char temp2[256]; + int inLen; + char *inPtr; + char *outPtr; + int i; + + sprintf_s( temp, sizeof( temp ), "%I64d", number ); + + // build string backwards + inLen = (int)strlen( temp ); + inPtr = temp+inLen-1; + outPtr = temp2; + while ( inLen > 0 ) + { + for ( i=0; i<3 && inLen > 0; i++, inLen-- ) + { + *outPtr++ = *inPtr--; + } + if ( inLen > 0 ) + *outPtr++ = ','; + } + *outPtr++ = '\0'; + + // reverse string + inLen = (int)strlen( temp2 ); + inPtr = temp2; + outPtr = temp; + for ( i=inLen-1; i>=0; i-- ) + { + *outPtr++ = inPtr[i]; + } + *outPtr++ = '\0'; + + _snprintf_s( buffer, bufferSize, _TRUNCATE, temp ); + + return buffer; +} + +//----------------------------------------------------------------------------- +// Sys_CreatePath +// +//----------------------------------------------------------------------------- +void Sys_CreatePath( const char* pInPath ) +{ + char* ptr; + char dirPath[MAX_PATH]; + + // prime and skip to first seperator + strcpy_s( dirPath, sizeof( dirPath ), pInPath ); + + if ( dirPath[0] == '\\' && dirPath[1] == '\\' ) + { + ptr = strchr( dirPath+1, '\\' ); + } + else + { + ptr = strchr( dirPath, '\\' ); + } + + while ( ptr ) + { + ptr = strchr( ptr+1, '\\' ); + if ( ptr ) + { + *ptr = '\0'; + CreateDirectory( dirPath, NULL ); + *ptr = '\\'; + } + } +} + diff --git a/utils/xbox/vxconsole/sys_utils.h b/utils/xbox/vxconsole/sys_utils.h new file mode 100644 index 0000000..a91c208 --- /dev/null +++ b/utils/xbox/vxconsole/sys_utils.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// SYS_UTILS.H +// +// System Utilities. +//=====================================================================================// +#pragma once + +#include "vxconsole.h" + +#pragma warning(disable : 4100) // warning C4100: unreferenced formal parameter + +#define MAX_SYSPRINTMSG 1024 +#define MAX_SYSTOKENCHARS 1024 + +#define MAKEINT64( hiword, loword ) ( ( __int64 )( ( ( ( __int64 )( hiword ) ) << 32 ) | ( __int64 )( loword ) ) ) + +extern void Sys_MessageBox( const CHAR *title, const CHAR *format, ... ); +extern void Sys_Error( const CHAR *format, ... ); + +extern void *Sys_Alloc( int size ); +extern void Sys_Free( void *ptr ); +extern CHAR *Sys_CopyString( const CHAR *str ); + +extern int Sys_LoadFile( const CHAR *filename, void **bufferptr, bool bText = false ); +extern bool Sys_SaveFile( const CHAR *filename, void *buffer, long count, bool bText = false ); +extern long Sys_FileLength( const CHAR *filename, bool bText = false ); +extern long Sys_FileLength( int handle ); +extern BOOL Sys_FileTime( CHAR *filename, FILETIME *time ); +extern void Sys_CreatePath( const char* pInPath ); + +extern void Sys_AddFileSeperator( CHAR *path, int outPathLen ); +extern void Sys_NormalizePath( CHAR *path, bool forceToLower ); +extern void Sys_StripFilename( const CHAR *path, CHAR *outpath, int outPathLen ); +extern void Sys_StripExtension( const CHAR *path, CHAR *outpath, int outPathLen ); +extern void Sys_StripPath( const CHAR *path, CHAR *outpath, int outPathLen ); +extern void Sys_GetExtension( const CHAR *path, CHAR *outpath, int outPathLen ); +extern void Sys_AddExtension( const CHAR *extension, CHAR *outpath, int outPathLen ); +extern void Sys_TempFilename( CHAR *outpath, int outPathLen ); +extern BOOL Sys_Exists( const CHAR *filename ); + +extern CHAR *Sys_GetToken( CHAR **dataptr, BOOL crossline, int *numlines ); +extern CHAR *Sys_SkipWhitespace( CHAR *data, BOOL *hasNewLines, int *numlines ); +extern void Sys_SkipBracedSection( CHAR **dataptr, int *numlines ); +extern void Sys_SkipRestOfLine( CHAR **dataptr, int *numlines ); + +extern void Sys_SetRegistryPrefix( const CHAR *pPrefix ); +extern BOOL Sys_SetRegistryString( const CHAR *key, const CHAR *value ); +extern BOOL Sys_GetRegistryString( const CHAR *key, CHAR *value, const CHAR *defValue, int valueLen ); +extern BOOL Sys_SetRegistryInteger( const CHAR *key, int value ); +extern BOOL Sys_GetRegistryInteger( const CHAR *key, int defValue, int &value ); + +extern DWORD Sys_GetSystemTime( void ); +extern COLORREF Sys_ColorScale( COLORREF color, float scale ); +extern bool Sys_IsWildcardMatch( const CHAR *wildcardString, const CHAR *stringToCheck, bool caseSensitive ); +extern char *Sys_NumberToCommaString( __int64 number, char *buffer, int bufferSize ); + + + + + + + + + diff --git a/utils/xbox/vxconsole/tex_profile.cpp b/utils/xbox/vxconsole/tex_profile.cpp new file mode 100644 index 0000000..8c3ddf1 --- /dev/null +++ b/utils/xbox/vxconsole/tex_profile.cpp @@ -0,0 +1,993 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// TEX_PROFILE.CPP +// +// Texture Profiling Display. +//=====================================================================================// +#include "vxconsole.h" + +#define TEXPROFILE_MAXCOUNTERS 64 +#define TEXPROFILE_MAXSAMPLES 512 + +#define TEXPROFILE_MAJORTICKSIZE 4 +#define TEXPROFILE_MAJORTICKBYTES ( TEXPROFILE_MAJORTICKSIZE*1024.0f*1024.0f ) + +#define TEXPROFILE_HISTORY_MAJORTICKHEIGHT 100 +#define TEXPROFILE_HISTORY_NUMMINORTICKS 3 +#define TEXPROFILE_HISTORY_LABELWIDTH 50 +#define TEXPROFILE_HISTORY_SCALESTEPS 5 +#define TEXPROFILE_HISTORY_MINSCALE 0.3f +#define TEXPROFILE_HISTORY_MAXSCALE 3.0f + +#define TEXPROFILE_SAMPLES_ITEMHEIGHT 15 +#define TEXPROFILE_SAMPLES_BARHEIGHT 10 +#define TEXPROFILE_SAMPLES_MAJORTICKWIDTH 200 +#define TEXPROFILE_SAMPLES_LABELWIDTH 150 +#define TEXPROFILE_SAMPLES_LABELGAP 5 +#define TEXPROFILE_SAMPLES_NUMMINORTICKS 3 +#define TEXPROFILE_SAMPLES_PEAKHOLDTIME 3000 +#define TEXPROFILE_SAMPLES_SCALESTEPS 10 +#define TEXPROFILE_SAMPLES_MINSCALE 0.3f +#define TEXPROFILE_SAMPLES_MAXSCALE 3.0f + +#define ID_TEXPROFILE_SAMPLES 1 +#define ID_TEXPROFILE_HISTORY 2 + +typedef struct +{ + unsigned int samples[TEXPROFILE_MAXSAMPLES]; + unsigned int peakSample; + char label[64]; + COLORREF color; +} profileCounter_t; + +HWND g_texProfile_hWndSamples; +HWND g_texProfile_hWndHistory; +int g_texProfile_numCounters; +profileCounter_t g_texProfile_counters[TEXPROFILE_MAXCOUNTERS]; +RECT g_texProfile_samplesWindowRect; +RECT g_texProfile_historyWindowRect; +DWORD g_texProfile_lastPeakTime; +bool g_texProfile_history_tickMarks = true; +bool g_texProfile_history_colors = true; +int g_texProfile_history_scale; +bool g_texProfile_samples_tickMarks = true; +bool g_texProfile_samples_colors = true; +int g_texProfile_samples_scale; +int g_texProfile_numSamples; +int g_texProfile_currentFrame; + +//----------------------------------------------------------------------------- +// TexProfile_LoadConfig +// +//----------------------------------------------------------------------------- +void TexProfile_LoadConfig() +{ + int numArgs; + char buff[256]; + + // profile samples + Sys_GetRegistryString( "texProfileSamplesWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_texProfile_samplesWindowRect.left, &g_texProfile_samplesWindowRect.top, &g_texProfile_samplesWindowRect.right, &g_texProfile_samplesWindowRect.bottom ); + if ( numArgs != 4 || g_texProfile_samplesWindowRect.left < 0 || g_texProfile_samplesWindowRect.top < 0 || g_texProfile_samplesWindowRect.right < 0 || g_texProfile_samplesWindowRect.bottom < 0 ) + memset( &g_texProfile_samplesWindowRect, 0, sizeof( g_texProfile_samplesWindowRect ) ); + Sys_GetRegistryInteger( "texProfileSamplesScale", 0, g_texProfile_samples_scale ); + if ( g_texProfile_samples_scale < -TEXPROFILE_SAMPLES_SCALESTEPS || g_texProfile_samples_scale > TEXPROFILE_SAMPLES_SCALESTEPS ) + g_texProfile_samples_scale = 0; + + // profile history + Sys_GetRegistryString( "texProfileHistoryWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_texProfile_historyWindowRect.left, &g_texProfile_historyWindowRect.top, &g_texProfile_historyWindowRect.right, &g_texProfile_historyWindowRect.bottom ); + if ( numArgs != 4 || g_texProfile_historyWindowRect.left < 0 || g_texProfile_historyWindowRect.top < 0 || g_texProfile_historyWindowRect.right < 0 || g_texProfile_historyWindowRect.bottom < 0 ) + memset( &g_texProfile_historyWindowRect, 0, sizeof( g_texProfile_historyWindowRect ) ); + Sys_GetRegistryInteger( "texProfileHistoryScale", 0, g_texProfile_history_scale ); + if ( g_texProfile_history_scale < -TEXPROFILE_HISTORY_SCALESTEPS || g_texProfile_history_scale > TEXPROFILE_HISTORY_SCALESTEPS ) + g_texProfile_history_scale = 0; + + Sys_GetRegistryInteger( "texProfileCurrentFrame", 0, g_texProfile_currentFrame ); +} + +//----------------------------------------------------------------------------- +// TexProfile_SaveConfig +// +//----------------------------------------------------------------------------- +void TexProfile_SaveConfig() +{ + char buff[256]; + WINDOWPLACEMENT wp; + + // profile samples + if ( g_texProfile_hWndSamples ) + { + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_texProfile_hWndSamples, &wp ); + g_texProfile_samplesWindowRect = wp.rcNormalPosition; + sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom ); + Sys_SetRegistryString( "texProfileSamplesWindowRect", buff ); + } + Sys_SetRegistryInteger( "texProfileSamplesScale", g_texProfile_samples_scale ); + + // profile history + if ( g_texProfile_hWndHistory ) + { + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_texProfile_hWndHistory, &wp ); + g_texProfile_historyWindowRect = wp.rcNormalPosition; + sprintf( buff, "%d %d %d %d", wp.rcNormalPosition.left, wp.rcNormalPosition.top, wp.rcNormalPosition.right, wp.rcNormalPosition.bottom ); + Sys_SetRegistryString( "texProfileHistoryWindowRect", buff ); + } + Sys_SetRegistryInteger( "texProfileHistoryScale", g_texProfile_history_scale ); + + Sys_SetRegistryInteger( "texProfileCurrentFrame", g_texProfile_currentFrame ); +} + +//----------------------------------------------------------------------------- +// TexProfile_SetTitle +// +//----------------------------------------------------------------------------- +void TexProfile_SetTitle() +{ + char titleBuff[128]; + + if ( g_texProfile_hWndSamples ) + { + strcpy( titleBuff, "D3D Usage Snapshot" ); + if ( VProf_GetState() == VPROF_TEXTURE || VProf_GetState() == VPROF_TEXTUREFRAME ) + strcat( titleBuff, " [ON]" ); + if ( g_texProfile_currentFrame ) + strcat( titleBuff, " [FRAME]" ); + + SetWindowText( g_texProfile_hWndSamples, titleBuff ); + } + + if ( g_texProfile_hWndHistory ) + { + strcpy( titleBuff, "D3D Usage History" ); + if ( VProf_GetState() == VPROF_TEXTURE || VProf_GetState() == VPROF_TEXTUREFRAME ) + strcat( titleBuff, " [ON]" ); + if ( g_texProfile_currentFrame ) + strcat( titleBuff, " [FRAME]" ); + + SetWindowText( g_texProfile_hWndHistory, titleBuff ); + } +} + +//----------------------------------------------------------------------------- +// TexProfile_UpdateWindow +// +//----------------------------------------------------------------------------- +void TexProfile_UpdateWindow() +{ + if ( g_texProfile_hWndSamples && !IsIconic( g_texProfile_hWndSamples ) ) + { + // visible - force a client repaint + InvalidateRect( g_texProfile_hWndSamples, NULL, true ); + } + + if ( g_texProfile_hWndHistory && !IsIconic( g_texProfile_hWndHistory ) ) + { + // visible - force a client repaint + InvalidateRect( g_texProfile_hWndHistory, NULL, true ); + } +} + +//----------------------------------------------------------------------------- +// rc_SetTexProfile +// +//----------------------------------------------------------------------------- +int rc_SetTexProfile( char* commandPtr ) +{ + int i; + char* cmdToken; + int retAddr; + int retVal; + int errCode = -1; + xrProfile_t* localList; + int profileList; + int numProfiles; + + // get numProfiles + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken,"%x",&numProfiles ); + + // get profile attributes + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &profileList ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken,"%x",&retAddr ); + + localList = new xrProfile_t[numProfiles]; + memset( localList, 0, numProfiles*sizeof( xrProfile_t ) ); + + // get the caller's profile list + DmGetMemory( ( void* )profileList, numProfiles*sizeof( xrProfile_t ), localList, NULL ); + + g_texProfile_numCounters = numProfiles; + if ( g_texProfile_numCounters > TEXPROFILE_MAXCOUNTERS-1 ) + g_texProfile_numCounters = TEXPROFILE_MAXCOUNTERS-1; + + for ( i=0; i<g_texProfile_numCounters; i++ ) + { + // swap the structure + localList[i].color = BigDWord( localList[i].color ); + + // clear the old counter + memset( &g_texProfile_counters[i], 0, sizeof( profileCounter_t ) ); + + V_strncpy( g_texProfile_counters[i].label, localList[i].labelString, sizeof( g_texProfile_counters[i].label ) ); + g_texProfile_counters[i].color = localList[i].color; + } + + // build out the reserved last counter as total count + memset( &g_texProfile_counters[g_texProfile_numCounters], 0, sizeof( profileCounter_t ) ); + strcpy( g_texProfile_counters[g_texProfile_numCounters].label, "Total" ); + g_texProfile_counters[i].color = RGB( 255,255,255 ); + g_texProfile_numCounters++; + + // set the return code + retVal = g_texProfile_numCounters-1; + int xboxRetVal = BigDWord( retVal ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + DebugCommand( "0x%8.8x = SetTexProfile( 0x%8.8x, 0x%8.8x )\n", retVal, numProfiles, profileList ); + + delete [] localList; + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} + +//----------------------------------------------------------------------------- +// rc_SetTexProfileData +// +//----------------------------------------------------------------------------- +int rc_SetTexProfileData( char* commandPtr ) +{ + int i; + char* cmdToken; + int errCode = -1; + int counters; + int currentSample; + int total; + bool newPeaks; + unsigned int localCounters[TEXPROFILE_MAXCOUNTERS]; + DWORD newTime; + + // get profiles + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &counters ); + + // get the caller's profile list + if ( g_texProfile_numCounters ) + DmGetMemory( ( void* )counters, ( g_texProfile_numCounters-1 )*sizeof( int ), localCounters, NULL ); + + // timeout peaks + newTime = Sys_GetSystemTime(); + if ( newTime - g_texProfile_lastPeakTime > TEXPROFILE_SAMPLES_PEAKHOLDTIME ) + { + g_texProfile_lastPeakTime = newTime; + newPeaks = true; + } + else + newPeaks = false; + + // next sample + currentSample = g_texProfile_numSamples % TEXPROFILE_MAXSAMPLES; + g_texProfile_numSamples++; + + total = 0; + for ( i=0; i<g_texProfile_numCounters; i++ ) + { + if ( i != g_texProfile_numCounters-1 ) + { + g_texProfile_counters[i].samples[currentSample] = localCounters[i]; + total += localCounters[i]; + } + else + { + // reserved total counter + g_texProfile_counters[i].samples[currentSample] = total; + } + + if ( newPeaks || g_texProfile_counters[i].peakSample < g_texProfile_counters[i].samples[currentSample] ) + g_texProfile_counters[i].peakSample = g_texProfile_counters[i].samples[currentSample]; + } + + DebugCommand( "SetTexProfileData( 0x%8.8x )\n", counters ); + + TexProfile_UpdateWindow(); + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} + +//----------------------------------------------------------------------------- +// TexProfile_ZoomIn +// +//----------------------------------------------------------------------------- +void TexProfile_ZoomIn( int& scale, int numSteps ) +{ + scale++; + if ( scale > numSteps ) + { + scale = numSteps; + return; + } + TexProfile_UpdateWindow(); +} + +//----------------------------------------------------------------------------- +// TexProfile_ZoomOut +// +//----------------------------------------------------------------------------- +void TexProfile_ZoomOut( int& scale, int numSteps ) +{ + scale--; + if ( scale < -numSteps ) + { + scale = -numSteps; + return; + } + TexProfile_UpdateWindow(); +} + +//----------------------------------------------------------------------------- +// TexProfile_CalcScale +// +//----------------------------------------------------------------------------- +float TexProfile_CalcScale( int scale, int numSteps, float min, float max ) +{ + float t; + + // from integral scale [-numSteps..numSteps] to float scale [min..max] + t = ( float )( scale + numSteps )/( float )( 2*numSteps ); + t = min + t*( max-min ); + + return t; +} + +//----------------------------------------------------------------------------- +// TexProfileSamples_Draw +// +//----------------------------------------------------------------------------- +void TexProfileSamples_Draw( HDC hdc, RECT* clientRect ) +{ + int i; + int j; + int x; + int y; + int x0; + int y0; + int w; + float t; + float scale; + float sample; + char labelBuff[128]; + HPEN hBlackPen; + HPEN hPenOld; + HPEN hGreyPen; + HBRUSH hColoredBrush; + HBRUSH hbrushOld; + HFONT hFontOld; + RECT rect; + int currentSample; + int numTicks; + int tickWidth; + int windowWidth; + int windowHeight; + + hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) ); + hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) ); + hPenOld = ( HPEN )SelectObject( hdc, hBlackPen ); + hFontOld = SelectFont( hdc, g_hProportionalFont ); + + SetBkColor( hdc, g_backgroundColor ); + + // zoom + scale = TexProfile_CalcScale( g_texProfile_samples_scale, TEXPROFILE_SAMPLES_SCALESTEPS, TEXPROFILE_SAMPLES_MINSCALE, TEXPROFILE_SAMPLES_MAXSCALE ); + tickWidth = ( int )( TEXPROFILE_SAMPLES_MAJORTICKWIDTH*scale ); + windowWidth = clientRect->right-clientRect->left; + windowHeight = clientRect->bottom-clientRect->top; + + numTicks = ( windowWidth-TEXPROFILE_SAMPLES_LABELWIDTH )/tickWidth + 1; + if ( numTicks < 0 ) + numTicks = 1; + + rect.left = 0; + rect.right = TEXPROFILE_SAMPLES_LABELWIDTH; + rect.top = 0; + rect.bottom = TEXPROFILE_SAMPLES_ITEMHEIGHT; + DrawText( hdc, "Name", -1, &rect, DT_LEFT ); + + // draw size ticks + x = TEXPROFILE_SAMPLES_LABELWIDTH; + y = 0; + for ( i=0; i<numTicks; i++ ) + { + // tick labels + rect.left = x-40; + rect.right = x+40; + rect.top = y; + rect.bottom = y+TEXPROFILE_SAMPLES_ITEMHEIGHT; + sprintf( labelBuff, "%dMB", i*TEXPROFILE_MAJORTICKSIZE ); + DrawText( hdc, labelBuff, -1, &rect, DT_CENTER ); + + // major ticks + x0 = x; + y0 = y + TEXPROFILE_SAMPLES_ITEMHEIGHT; + SelectObject( hdc, hBlackPen ); + MoveToEx( hdc, x0, y0, NULL ); + LineTo( hdc, x0, y0+windowHeight ); + + if ( g_texProfile_samples_tickMarks && g_texProfile_samples_scale > -TEXPROFILE_SAMPLES_SCALESTEPS ) + { + // minor ticks + x0 = x; + y0 = y + TEXPROFILE_SAMPLES_ITEMHEIGHT; + SelectObject( hdc, hGreyPen ); + for ( j=0; j<TEXPROFILE_SAMPLES_NUMMINORTICKS; j++ ) + { + x0 += tickWidth/( TEXPROFILE_SAMPLES_NUMMINORTICKS+1 ); + + MoveToEx( hdc, x0, y0, NULL ); + LineTo( hdc, x0, y0+windowHeight ); + } + } + x += tickWidth; + } + + // seperator + SelectObject( hdc, hBlackPen ); + MoveToEx( hdc, 0, TEXPROFILE_SAMPLES_ITEMHEIGHT, NULL ); + LineTo( hdc, windowWidth, TEXPROFILE_SAMPLES_ITEMHEIGHT ); + + // draw labels + x = 0; + y = TEXPROFILE_SAMPLES_ITEMHEIGHT; + for ( i=0; i<g_texProfile_numCounters; i++ ) + { + if ( !g_texProfile_counters[i].label ) + continue; + + rect.left = x; + rect.right = x+TEXPROFILE_SAMPLES_LABELWIDTH-TEXPROFILE_SAMPLES_LABELGAP; + rect.top = y; + rect.bottom = y+TEXPROFILE_SAMPLES_ITEMHEIGHT; + DrawText( hdc, g_texProfile_counters[i].label, -1, &rect, DT_VCENTER|DT_RIGHT|DT_SINGLELINE|DT_END_ELLIPSIS|DT_MODIFYSTRING ); + + // draw the under line + MoveToEx( hdc, x, y+TEXPROFILE_SAMPLES_ITEMHEIGHT, NULL ); + LineTo( hdc, x+TEXPROFILE_SAMPLES_LABELWIDTH, y+TEXPROFILE_SAMPLES_ITEMHEIGHT ); + + y += TEXPROFILE_SAMPLES_ITEMHEIGHT; + } + + // draw bars + SelectObject( hdc, hBlackPen ); + x = TEXPROFILE_SAMPLES_LABELWIDTH; + y = TEXPROFILE_SAMPLES_ITEMHEIGHT; + currentSample = g_texProfile_numSamples-1; + if ( currentSample < 0 ) + currentSample = 0; + else + currentSample %= TEXPROFILE_MAXSAMPLES; + for ( i=0; i<g_texProfile_numCounters; i++ ) + { + if ( !g_texProfile_counters[i].label ) + continue; + + hColoredBrush = CreateSolidBrush( g_texProfile_samples_colors ? g_texProfile_counters[i].color : g_backgroundColor ); + hbrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush ); + + // bar - count is in bytes, scale to major tick + t = ( float )g_texProfile_counters[i].samples[currentSample]/TEXPROFILE_MAJORTICKBYTES; + w = ( int )( t * ( float )tickWidth ); + if ( w > windowWidth ) + w = windowWidth; + x0 = x; + y0 = y + ( TEXPROFILE_SAMPLES_ITEMHEIGHT-TEXPROFILE_SAMPLES_BARHEIGHT )/2 + 1; + Rectangle( hdc, x0, y0, x0 + w, y0 + TEXPROFILE_SAMPLES_BARHEIGHT ); + + // peak + t = ( float )g_texProfile_counters[i].peakSample/TEXPROFILE_MAJORTICKBYTES; + w = ( int )( t * ( float )tickWidth ); + if ( w > windowWidth ) + w = windowWidth; + x0 = x + w; + y0 = y + TEXPROFILE_SAMPLES_ITEMHEIGHT/2 + 1; + + POINT points[4]; + points[0].x = x0; + points[0].y = y0-4; + points[1].x = x0+4; + points[1].y = y0; + points[2].x = x0; + points[2].y = y0+4; + points[3].x = x0-4; + points[3].y = y0; + Polygon( hdc, points, 4 ); + + SelectObject( hdc, hbrushOld ); + DeleteObject( hColoredBrush ); + + // draw peak sizes + sample = ( float )g_texProfile_counters[i].peakSample/1024.0f; + if ( sample >= 0.01F ) + { + sprintf( labelBuff, "%.2f MB", sample/1024.0f ); + rect.left = x0 + 8; + rect.right = x0 + 8 + 100; + rect.top = y; + rect.bottom = y + TEXPROFILE_SAMPLES_ITEMHEIGHT; + DrawText( hdc, labelBuff, -1, &rect, DT_VCENTER|DT_LEFT|DT_SINGLELINE ); + } + + y += TEXPROFILE_SAMPLES_ITEMHEIGHT; + } + + SelectObject( hdc, hFontOld ); + SelectObject( hdc, hPenOld ); + DeleteObject( hBlackPen ); + DeleteObject( hGreyPen ); +} + +//----------------------------------------------------------------------------- +// TexProfileHistory_Draw +// +//----------------------------------------------------------------------------- +void TexProfileHistory_Draw( HDC hdc, RECT* clientRect ) +{ + char labelBuff[128]; + HPEN hBlackPen; + HPEN hPenOld; + HPEN hNullPen; + HPEN hGreyPen; + HBRUSH hColoredBrush; + HBRUSH hBrushOld; + HFONT hFontOld; + int currentSample; + int numTicks; + int tickHeight; + int windowWidth; + int windowHeight; + int x; + int y; + int y0; + int i; + int j; + int h; + int numbars; + RECT rect; + float t; + float scale; + + hBlackPen = CreatePen( PS_SOLID, 1, RGB( 0,0,0 ) ); + hGreyPen = CreatePen( PS_SOLID, 1, Sys_ColorScale( g_backgroundColor, 0.85f ) ); + hNullPen = CreatePen( PS_NULL, 0, RGB( 0,0,0 ) ); + hPenOld = ( HPEN )SelectObject( hdc, hBlackPen ); + hFontOld = SelectFont( hdc, g_hProportionalFont ); + + // zoom + scale = TexProfile_CalcScale( g_texProfile_history_scale, TEXPROFILE_HISTORY_SCALESTEPS, TEXPROFILE_HISTORY_MINSCALE, TEXPROFILE_HISTORY_MAXSCALE ); + tickHeight = ( int )( TEXPROFILE_HISTORY_MAJORTICKHEIGHT*scale ); + windowWidth = clientRect->right-clientRect->left; + windowHeight = clientRect->bottom-clientRect->top; + + numTicks = windowHeight/tickHeight + 2; + if ( numTicks < 0 ) + numTicks = 1; + + SetBkColor( hdc, g_backgroundColor ); + + x = 0; + y = windowHeight; + for ( i=0; i<numTicks; i++ ) + { + // major ticks + SelectObject( hdc, hBlackPen ); + MoveToEx( hdc, 0, y, NULL ); + LineTo( hdc, windowWidth, y ); + + if ( g_texProfile_history_tickMarks && g_texProfile_history_scale > -TEXPROFILE_HISTORY_SCALESTEPS ) + { + // minor ticks + y0 = y; + SelectObject( hdc, hGreyPen ); + for ( j=0; j<TEXPROFILE_HISTORY_NUMMINORTICKS; j++ ) + { + y0 += tickHeight/( TEXPROFILE_SAMPLES_NUMMINORTICKS+1 ); + MoveToEx( hdc, 0, y0, NULL ); + LineTo( hdc, windowWidth, y0 ); + } + } + + // tick labels + if ( i ) + { + rect.left = windowWidth-50; + rect.right = windowWidth; + rect.top = y-20; + rect.bottom = y; + sprintf( labelBuff, "%dMB", i*TEXPROFILE_MAJORTICKSIZE ); + DrawText( hdc, labelBuff, -1, &rect, DT_RIGHT|DT_SINGLELINE|DT_BOTTOM ); + } + + y -= tickHeight; + } + + // vertical bars + if ( g_texProfile_numSamples ) + { + SelectObject( hdc, hNullPen ); + + numbars = windowWidth-TEXPROFILE_HISTORY_LABELWIDTH; + currentSample = g_texProfile_numSamples-1; + for ( x=numbars-1; x>=0; x-=4 ) + { + // all the counters at this sample + y = windowHeight; + for ( j=0; j<g_texProfile_numCounters-1; j++ ) + { + if ( !g_texProfile_counters[j].label ) + continue; + + t = ( float )g_texProfile_counters[j].samples[currentSample % TEXPROFILE_MAXSAMPLES]/TEXPROFILE_MAJORTICKBYTES; + h = ( int )( t * ( float )tickHeight ); + if ( h ) + { + if ( h > windowHeight ) + h = windowHeight; + + hColoredBrush = CreateSolidBrush( g_texProfile_history_colors ? g_texProfile_counters[j].color : RGB( 80,80,80 ) ); + hBrushOld = ( HBRUSH )SelectObject( hdc, hColoredBrush ); + + Rectangle( hdc, x-4, y-h, x, y+1 ); + y -= h; + + SelectObject( hdc, hBrushOld ); + DeleteObject( hColoredBrush ); + } + } + currentSample--; + if ( currentSample < 0 ) + { + // no data + break; + } + } + } + + SelectObject( hdc, hFontOld ); + SelectObject( hdc, hPenOld ); + DeleteObject( hBlackPen ); + DeleteObject( hGreyPen ); +} + +//----------------------------------------------------------------------------- +// TexProfile_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK TexProfile_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + HDC hdc; + PAINTSTRUCT ps; + RECT rect; + int id; + bool bIsSamples; + bool bIsHistory; + CREATESTRUCT *createStructPtr; + bool bIsEnabled; + + // identify window + id = ( int )GetWindowLong( hwnd, GWL_USERDATA+0 ); + bIsSamples = ( id == ID_TEXPROFILE_SAMPLES ); + bIsHistory = ( id == ID_TEXPROFILE_HISTORY ); + + switch ( message ) + { + case WM_CREATE: + // set the window identifier + createStructPtr = ( CREATESTRUCT* )lParam; + SetWindowLong( hwnd, GWL_USERDATA+0, ( LONG )createStructPtr->lpCreateParams ); + + // reset peaks + g_texProfile_lastPeakTime = 0; + return 0L; + + case WM_DESTROY: + TexProfile_SaveConfig(); + + if ( bIsSamples ) + g_texProfile_hWndSamples = NULL; + else if ( bIsHistory ) + g_texProfile_hWndHistory = NULL; + + if ( VProf_GetState() == VPROF_TEXTURE || VProf_GetState() == VPROF_TEXTUREFRAME ) + { + VProf_Enable( VPROF_OFF ); + } + return 0L; + + case WM_INITMENU: + if ( bIsSamples ) + { + CheckMenuItem( ( HMENU )wParam, IDM_TEXPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_texProfile_samples_tickMarks ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_TEXPROFILE_COLORS, MF_BYCOMMAND | ( g_texProfile_samples_colors ? MF_CHECKED : MF_UNCHECKED ) ); + } + else if ( bIsHistory ) + { + CheckMenuItem( ( HMENU )wParam, IDM_TEXPROFILE_TICKMARKS, MF_BYCOMMAND | ( g_texProfile_history_tickMarks ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_TEXPROFILE_COLORS, MF_BYCOMMAND | ( g_texProfile_history_colors ? MF_CHECKED : MF_UNCHECKED ) ); + } + CheckMenuItem( ( HMENU )wParam, IDM_TEXPROFILE_ENABLE, MF_BYCOMMAND | ( ( VProf_GetState() == VPROF_TEXTURE || VProf_GetState() == VPROF_TEXTUREFRAME ) ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_TEXPROFILE_CURRENTFRAME, MF_BYCOMMAND | ( g_texProfile_currentFrame ? MF_CHECKED : MF_UNCHECKED ) ); + return 0L; + + case WM_PAINT: + GetClientRect( hwnd, &rect ); + hdc = BeginPaint( hwnd, &ps ); + if ( bIsSamples ) + TexProfileSamples_Draw( hdc, &rect ); + else if ( bIsHistory ) + TexProfileHistory_Draw( hdc, &rect ); + EndPaint( hwnd, &ps ); + return 0L; + + case WM_SIZE: + // force a redraw + TexProfile_UpdateWindow(); + return 0L; + + case WM_KEYDOWN: + switch ( wParam ) + { + case VK_INSERT: + if ( bIsSamples ) + TexProfile_ZoomIn( g_texProfile_samples_scale, TEXPROFILE_SAMPLES_SCALESTEPS ); + else if ( bIsHistory ) + TexProfile_ZoomIn( g_texProfile_history_scale, TEXPROFILE_HISTORY_SCALESTEPS ); + return 0L; + + case VK_DELETE: + if ( bIsSamples ) + TexProfile_ZoomOut( g_texProfile_samples_scale, TEXPROFILE_SAMPLES_SCALESTEPS ); + else if ( bIsHistory ) + TexProfile_ZoomOut( g_texProfile_history_scale, TEXPROFILE_HISTORY_SCALESTEPS ); + return 0L; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_TEXPROFILE_TICKMARKS: + if ( bIsSamples ) + g_texProfile_samples_tickMarks ^= 1; + else if ( bIsHistory ) + g_texProfile_history_tickMarks ^= 1; + TexProfile_UpdateWindow(); + return 0L; + + case IDM_TEXPROFILE_COLORS: + if ( bIsSamples ) + g_texProfile_samples_colors ^= 1; + else if ( bIsHistory ) + g_texProfile_history_colors ^= 1; + TexProfile_UpdateWindow(); + return 0L; + + case IDM_TEXPROFILE_ZOOMIN: + if ( bIsSamples ) + TexProfile_ZoomIn( g_texProfile_samples_scale, TEXPROFILE_SAMPLES_SCALESTEPS ); + else if ( bIsHistory ) + TexProfile_ZoomIn( g_texProfile_history_scale, TEXPROFILE_HISTORY_SCALESTEPS ); + return 0L; + + case IDM_TEXPROFILE_ZOOMOUT: + if ( bIsSamples ) + TexProfile_ZoomOut( g_texProfile_samples_scale, TEXPROFILE_SAMPLES_SCALESTEPS ); + else if ( bIsHistory ) + TexProfile_ZoomOut( g_texProfile_history_scale, TEXPROFILE_HISTORY_SCALESTEPS ); + return 0L; + + case IDM_TEXPROFILE_ENABLE: + bIsEnabled = ( VProf_GetState() == VPROF_TEXTURE || VProf_GetState() == VPROF_TEXTUREFRAME ); + bIsEnabled ^= 1; + if ( !bIsEnabled ) + VProf_Enable( VPROF_OFF ); + else + { + if ( !g_texProfile_currentFrame ) + VProf_Enable( VPROF_TEXTURE ); + else + VProf_Enable( VPROF_TEXTUREFRAME ); + } + TexProfile_SetTitle(); + return 0L; + + case IDM_TEXPROFILE_CURRENTFRAME: + bIsEnabled = ( VProf_GetState() == VPROF_TEXTURE || VProf_GetState() == VPROF_TEXTUREFRAME ); + g_texProfile_currentFrame ^= 1; + if ( bIsEnabled ) + { + if ( !g_texProfile_currentFrame ) + VProf_Enable( VPROF_TEXTURE ); + else + VProf_Enable( VPROF_TEXTUREFRAME ); + } + TexProfile_SetTitle(); + return 0L; + } + break; + } + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// TexProfileHistory_Open +// +//----------------------------------------------------------------------------- +void TexProfileHistory_Open() +{ + HWND hWnd; + + if ( g_texProfile_hWndHistory ) + { + // only one profile instance + if ( IsIconic( g_texProfile_hWndHistory ) ) + ShowWindow( g_texProfile_hWndHistory, SW_RESTORE ); + SetForegroundWindow( g_texProfile_hWndHistory ); + return; + } + + if ( VProf_GetState() == VPROF_OFF ) + { + if ( !g_texProfile_currentFrame ) + VProf_Enable( VPROF_TEXTURE ); + else + VProf_Enable( VPROF_TEXTUREFRAME ); + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "TEXPROFILEHISTORYCLASS", + "", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 600, + 500, + g_hDlgMain, + NULL, + g_hInstance, + ( void* )ID_TEXPROFILE_HISTORY ); + g_texProfile_hWndHistory = hWnd; + + TexProfile_SetTitle(); + + if ( g_texProfile_historyWindowRect.right && g_texProfile_historyWindowRect.bottom ) + MoveWindow( g_texProfile_hWndHistory, g_texProfile_historyWindowRect.left, g_texProfile_historyWindowRect.top, g_texProfile_historyWindowRect.right-g_texProfile_historyWindowRect.left, g_texProfile_historyWindowRect.bottom-g_texProfile_historyWindowRect.top, FALSE ); + ShowWindow( g_texProfile_hWndHistory, SHOW_OPENWINDOW ); +} + +//----------------------------------------------------------------------------- +// TexProfileSamples_Open +// +//----------------------------------------------------------------------------- +void TexProfileSamples_Open() +{ + HWND hWnd; + + if ( g_texProfile_hWndSamples ) + { + // only one profile instance + if ( IsIconic( g_texProfile_hWndSamples ) ) + ShowWindow( g_texProfile_hWndSamples, SW_RESTORE ); + SetForegroundWindow( g_texProfile_hWndSamples ); + return; + } + + if ( VProf_GetState() == VPROF_OFF ) + { + if ( !g_texProfile_currentFrame ) + VProf_Enable( VPROF_TEXTURE ); + else + VProf_Enable( VPROF_TEXTUREFRAME ); + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "TEXPROFILESAMPLESCLASS", + "", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 600, + 500, + g_hDlgMain, + NULL, + g_hInstance, + ( void* )ID_TEXPROFILE_SAMPLES ); + g_texProfile_hWndSamples = hWnd; + + TexProfile_SetTitle(); + + if ( g_texProfile_samplesWindowRect.right && g_texProfile_samplesWindowRect.bottom ) + MoveWindow( g_texProfile_hWndSamples, g_texProfile_samplesWindowRect.left, g_texProfile_samplesWindowRect.top, g_texProfile_samplesWindowRect.right-g_texProfile_samplesWindowRect.left, g_texProfile_samplesWindowRect.bottom-g_texProfile_samplesWindowRect.top, FALSE ); + ShowWindow( g_texProfile_hWndSamples, SHOW_OPENWINDOW ); +} + +//----------------------------------------------------------------------------- +// TexProfile_Clear +// +//----------------------------------------------------------------------------- +void TexProfile_Clear() +{ + // clear counters and history + g_texProfile_numCounters = 0; + g_texProfile_numSamples = 0; + + TexProfile_UpdateWindow(); +} + +//----------------------------------------------------------------------------- +// TexProfile_Init +// +//----------------------------------------------------------------------------- +bool TexProfile_Init() +{ + WNDCLASS wndclass; + + // set up our window class + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = TexProfile_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_TEXPROFILE ); + wndclass.lpszClassName = "TEXPROFILESAMPLESCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + // set up our window class + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = TexProfile_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_TEXPROFILE ); + wndclass.lpszClassName = "TEXPROFILEHISTORYCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + TexProfile_LoadConfig(); + + return true; +}
\ No newline at end of file diff --git a/utils/xbox/vxconsole/timestamp_log.cpp b/utils/xbox/vxconsole/timestamp_log.cpp new file mode 100644 index 0000000..1cc45ef --- /dev/null +++ b/utils/xbox/vxconsole/timestamp_log.cpp @@ -0,0 +1,623 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// TIMESTAMP_LOG.CPP +// +// TimeStamp Log Display. +//=====================================================================================// +#include "vxconsole.h" + +#define ID_TIMESTAMPLOG_LISTVIEW 100 + +// column id +#define ID_TSL_TIME 0 +#define ID_TSL_DELTATIME 1 +#define ID_TSL_MEMORY 2 +#define ID_TSL_DELTAMEMORY 3 +#define ID_TSL_MESSAGE 4 + +typedef struct +{ const CHAR* name; + int width; + int subItemIndex; + CHAR nameBuff[32]; +} label_t; + +struct timeStampLogNode_t +{ + int index; + float time; + float deltaTime; + int memory; + int deltaMemory; + char timeBuff[32]; + char deltaTimeBuff[32]; + char memoryBuff[32]; + char deltaMemoryBuff[32]; + char *pMessage; + timeStampLogNode_t *pNext; +}; + +HWND g_timeStampLog_hWnd; +HWND g_timeStampLog_hWndListView; +RECT g_timeStampLog_windowRect; +timeStampLogNode_t *g_timeStampLog_pNodes; +int g_timeStampLog_sortColumn; +int g_timeStampLog_sortDescending; + +label_t g_timeStampLog_Labels[] = +{ + {"Time", 100, ID_TSL_TIME}, + {"Delta Time", 100, ID_TSL_DELTATIME}, + {"Memory", 100, ID_TSL_MEMORY}, + {"Delta Memory", 100, ID_TSL_DELTAMEMORY}, + {"Message", 400, ID_TSL_MESSAGE}, +}; + +//----------------------------------------------------------------------------- +// TimeStampLog_CompareFunc +// +//----------------------------------------------------------------------------- +int CALLBACK TimeStampLog_CompareFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) +{ + timeStampLogNode_t* pNodeA = ( timeStampLogNode_t* )lParam1; + timeStampLogNode_t* pNodeB = ( timeStampLogNode_t* )lParam2; + + int sort = 0; + switch ( g_timeStampLog_sortColumn ) + { + case ID_TSL_TIME: + sort = ( int )( 1000.0f*pNodeA->time - 1000.0f*pNodeB->time ); + break; + + case ID_TSL_DELTATIME: + sort = ( int )( 1000.0f*pNodeA->deltaTime - 1000.0f*pNodeB->deltaTime ); + break; + + case ID_TSL_MEMORY: + sort = pNodeA->memory - pNodeB->memory; + break; + + case ID_TSL_DELTAMEMORY: + sort = pNodeA->deltaMemory - pNodeB->deltaMemory; + break; + + case ID_TSL_MESSAGE: + sort = stricmp( pNodeA->pMessage, pNodeB->pMessage ); + break; + } + + // flip the sort order + if ( g_timeStampLog_sortDescending ) + sort *= -1; + + return ( sort ); +} + +//----------------------------------------------------------------------------- +// TimeStampLog_SortItems +// +//----------------------------------------------------------------------------- +void TimeStampLog_SortItems() +{ + LVITEM lvitem; + timeStampLogNode_t *pNode; + int i; + + if ( !g_timeStampLog_hWnd ) + { + // only sort if window is visible + return; + } + + ListView_SortItems( g_timeStampLog_hWndListView, TimeStampLog_CompareFunc, 0 ); + + memset( &lvitem, 0, sizeof( lvitem ) ); + lvitem.mask = LVIF_PARAM; + + // get each item and reset its list index + int itemCount = ListView_GetItemCount( g_timeStampLog_hWndListView ); + for ( i=0; i<itemCount; i++ ) + { + lvitem.iItem = i; + ListView_GetItem( g_timeStampLog_hWndListView, &lvitem ); + + pNode = ( timeStampLogNode_t* )lvitem.lParam; + pNode->index = i; + } + + // update list view columns with sort key + for ( i=0; i<sizeof( g_timeStampLog_Labels )/sizeof( g_timeStampLog_Labels[0] ); i++ ) + { + char symbol; + LVCOLUMN lvc; + + if ( i == g_timeStampLog_sortColumn ) + symbol = g_timeStampLog_sortDescending ? '<' : '>'; + else + symbol = ' '; + sprintf( g_timeStampLog_Labels[i].nameBuff, "%s %c", g_timeStampLog_Labels[i].name, symbol ); + + memset( &lvc, 0, sizeof( lvc ) ); + lvc.mask = LVCF_TEXT; + lvc.pszText = ( LPSTR )g_timeStampLog_Labels[i].nameBuff; + + ListView_SetColumn( g_timeStampLog_hWndListView, i, &lvc ); + } +} + +//----------------------------------------------------------------------------- +// TimeStampLog_AddViewItem +// +//----------------------------------------------------------------------------- +void TimeStampLog_AddViewItem( timeStampLogNode_t* pNode ) +{ + LVITEM lvi; + + if ( !g_timeStampLog_hWnd ) + { + // only valid if log window is visible + return; + } + + // update the text callback buffers + sprintf( pNode->timeBuff, "%2.2d:%2.2d:%2.2d:%3.3d", ( int )pNode->time/3600, ( ( int )pNode->time/60 )%60, ( int )pNode->time%60, ( int )( 1000*( pNode->time-( int )pNode->time ) )%1000 ); + sprintf( pNode->deltaTimeBuff, "%.3f", pNode->deltaTime ); + sprintf( pNode->memoryBuff, "%.2f MB", pNode->memory/( 1024.0f*1024.0f ) ); + sprintf( pNode->deltaMemoryBuff, "%d", pNode->deltaMemory ); + + int itemCount = ListView_GetItemCount( g_timeStampLog_hWndListView ); + + // setup and insert at end of list + memset( &lvi, 0, sizeof( lvi ) ); + lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; + lvi.iItem = itemCount; + lvi.iSubItem = 0; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; + lvi.lParam = ( LPARAM )pNode; + + // insert + pNode->index = ListView_InsertItem( g_timeStampLog_hWndListView, &lvi ); +} + +//----------------------------------------------------------------------------- +// TimeStampLog_AddItem +// +//----------------------------------------------------------------------------- +void TimeStampLog_AddItem( float time, float deltaTime, int memory, int deltaMemory, const char* pMessage ) +{ + timeStampLogNode_t* pNode; + + // create and init + pNode = new timeStampLogNode_t; + memset( pNode, 0, sizeof( timeStampLogNode_t ) ); + + pNode->time = time; + pNode->deltaTime = deltaTime; + pNode->memory = memory; + pNode->deltaMemory = deltaMemory; + pNode->pMessage = Sys_CopyString( pMessage ? pMessage : "" ); + + // link in + pNode->pNext = g_timeStampLog_pNodes; + g_timeStampLog_pNodes = pNode; + + TimeStampLog_AddViewItem( pNode ); +} + +//----------------------------------------------------------------------------- +// TimeStampLog_Clear +// +//----------------------------------------------------------------------------- +void TimeStampLog_Clear() +{ + timeStampLogNode_t* pNode; + timeStampLogNode_t* pNextNode; + + // delete all the list view entries + if ( g_timeStampLog_hWnd ) + ListView_DeleteAllItems( g_timeStampLog_hWndListView ); + + // delete nodes in chain + pNode = g_timeStampLog_pNodes; + while ( pNode ) + { + pNextNode = pNode->pNext; + + Sys_Free( pNode->pMessage ); + delete pNode; + + pNode = pNextNode; + } + g_timeStampLog_pNodes = NULL; +} + +//----------------------------------------------------------------------------- +// TimeStampLog_SaveConfig +// +//----------------------------------------------------------------------------- +void TimeStampLog_SaveConfig() +{ + char buff[256]; + + Sys_SetRegistryInteger( "timeStampLogSortColumn", g_timeStampLog_sortColumn ); + Sys_SetRegistryInteger( "timeStampLogSortDescending", g_timeStampLog_sortDescending ); + + WINDOWPLACEMENT wp; + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_timeStampLog_hWnd, &wp ); + g_timeStampLog_windowRect = wp.rcNormalPosition; + + sprintf( buff, "%d %d %d %d", g_timeStampLog_windowRect.left, g_timeStampLog_windowRect.top, g_timeStampLog_windowRect.right, g_timeStampLog_windowRect.bottom ); + Sys_SetRegistryString( "timeStampLogWindowRect", buff ); +} + +//----------------------------------------------------------------------------- +// TimeStampLog_LoadConfig +// +//----------------------------------------------------------------------------- +void TimeStampLog_LoadConfig() +{ + int numArgs; + char buff[256]; + + Sys_GetRegistryInteger( "timeStampLogSortColumn", ID_TSL_TIME, g_timeStampLog_sortColumn ); + Sys_GetRegistryInteger( "timeStampLogSortDescending", false, g_timeStampLog_sortDescending ); + + Sys_GetRegistryString( "timeStampLogWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_timeStampLog_windowRect.left, &g_timeStampLog_windowRect.top, &g_timeStampLog_windowRect.right, &g_timeStampLog_windowRect.bottom ); + if ( numArgs != 4 || g_timeStampLog_windowRect.left < 0 || g_timeStampLog_windowRect.top < 0 || g_timeStampLog_windowRect.right < 0 || g_timeStampLog_windowRect.bottom < 0 ) + memset( &g_timeStampLog_windowRect, 0, sizeof( g_timeStampLog_windowRect ) ); +} + +//----------------------------------------------------------------------------- +// TimeStampLog_SizeWindow +// +//----------------------------------------------------------------------------- +void TimeStampLog_SizeWindow( HWND hwnd, int width, int height ) +{ + if ( width==0 || height==0 ) + { + RECT rcClient; + GetClientRect( hwnd, &rcClient ); + width = rcClient.right; + height = rcClient.bottom; + } + + // position the ListView + SetWindowPos( g_timeStampLog_hWndListView, NULL, 0, 0, width, height, SWP_NOZORDER ); +} + +//----------------------------------------------------------------------------- +// TimeStampLog_Export +// +//----------------------------------------------------------------------------- +void TimeStampLog_Export() +{ + OPENFILENAME ofn; + char logFilename[MAX_PATH]; + int retval; + FILE* fp; + int i; + int count; + + memset( &ofn, 0, sizeof( ofn ) ); + ofn.lStructSize = sizeof( ofn ); + ofn.hwndOwner = g_timeStampLog_hWnd; + ofn.lpstrFile = logFilename; + ofn.lpstrFile[0] = '\0'; + ofn.nMaxFile = sizeof( logFilename ); + ofn.lpstrFilter = "Excel CSV\0*.CSV\0All Files\0*.*\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = "c:\\"; + ofn.Flags = OFN_PATHMUSTEXIST; + + // display the open dialog box + retval = GetOpenFileName( &ofn ); + if ( !retval ) + return; + + Sys_AddExtension( ".csv", logFilename, sizeof( logFilename ) ); + + fp = fopen( logFilename, "wt+" ); + if ( !fp ) + return; + + // labels + count = ARRAYSIZE( g_timeStampLog_Labels ); + for ( i=0; i<count; i++ ) + { + fprintf( fp, "\"%s\"", g_timeStampLog_Labels[i].name ); + if ( i != count-1 ) + fprintf( fp, "," ); + } + fprintf( fp, "\n" ); + + // build a list for easy reverse traversal + CUtlVector< timeStampLogNode_t* > nodeList; + timeStampLogNode_t *pNode; + pNode = g_timeStampLog_pNodes; + while ( pNode ) + { + nodeList.AddToTail( pNode ); + pNode = pNode->pNext; + } + + // dump to the log + for ( int i=nodeList.Count()-1; i>=0; i-- ) + { + pNode = nodeList[i]; + + fprintf( fp, "\"%s\"", pNode->timeBuff ); + fprintf( fp, ",\"%s\"", pNode->deltaTimeBuff ); + fprintf( fp, ",\"%s\"", pNode->memoryBuff ); + fprintf( fp, ",\"%s\"", pNode->deltaMemoryBuff ); + fprintf( fp, ",\"%s\"", pNode->pMessage ); + fprintf( fp, "\n" ); + } + + fclose( fp ); +} + +//----------------------------------------------------------------------------- +// TimeStampLog_WndProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK TimeStampLog_WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + timeStampLogNode_t *pNode; + + switch ( message ) + { + case WM_CREATE: + return 0L; + + case WM_DESTROY: + TimeStampLog_SaveConfig(); + g_timeStampLog_hWnd = NULL; + return 0L; + + case WM_SIZE: + TimeStampLog_SizeWindow( hwnd, LOWORD( lParam ), HIWORD( lParam ) ); + return 0L; + + case WM_NOTIFY: + switch ( ( ( LPNMHDR )lParam )->code ) + { + case LVN_COLUMNCLICK: + NMLISTVIEW* pnmlv; + pnmlv = ( NMLISTVIEW* )lParam; + if ( g_timeStampLog_sortColumn == pnmlv->iSubItem ) + { + // user has clicked on same column - flip the sort + g_timeStampLog_sortDescending ^= 1; + } + else + { + // sort by new column + g_timeStampLog_sortColumn = pnmlv->iSubItem; + } + TimeStampLog_SortItems(); + return 0L; + + case LVN_GETDISPINFO: + NMLVDISPINFO* plvdi; + plvdi = ( NMLVDISPINFO* )lParam; + pNode = ( timeStampLogNode_t * )plvdi->item.lParam; + switch ( plvdi->item.iSubItem ) + { + case ID_TSL_TIME: + plvdi->item.pszText = pNode->timeBuff; + return 0L; + + case ID_TSL_DELTATIME: + plvdi->item.pszText = pNode->deltaTimeBuff; + return 0L; + + case ID_TSL_MEMORY: + plvdi->item.pszText = pNode->memoryBuff; + return 0L; + + case ID_TSL_DELTAMEMORY: + plvdi->item.pszText = pNode->deltaMemoryBuff; + return 0L; + + case ID_TSL_MESSAGE: + plvdi->item.pszText = pNode->pMessage; + return 0L; + + default: + break; + } + break; + } + break; + + case WM_COMMAND: + switch ( wID ) + { + case IDM_OPTIONS_CLEAR: + TimeStampLog_Clear(); + return 0L; + + case IDM_OPTIONS_EXPORT: + TimeStampLog_Export(); + return 0L; + } + break; + } + + return ( DefWindowProc( hwnd, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// TimeStampLog_Init +// +//----------------------------------------------------------------------------- +bool TimeStampLog_Init() +{ + // set up our window class + WNDCLASS wndclass; + + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = TimeStampLog_WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_APPLICATION]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_TIMESTAMPLOG ); + wndclass.lpszClassName = "TIMESTAMPLOGCLASS"; + if ( !RegisterClass( &wndclass ) ) + return false; + + TimeStampLog_LoadConfig(); + + return true; +} + +//----------------------------------------------------------------------------- +// TimeStampLog_Open +// +//----------------------------------------------------------------------------- +void TimeStampLog_Open() +{ + RECT clientRect; + HWND hWnd; + int i; + timeStampLogNode_t *pNode; + + if ( g_timeStampLog_hWnd ) + { + // only one file log instance + if ( IsIconic( g_timeStampLog_hWnd ) ) + ShowWindow( g_timeStampLog_hWnd, SW_RESTORE ); + SetForegroundWindow( g_timeStampLog_hWnd ); + return; + } + + hWnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + "TIMESTAMPLOGCLASS", + "TimeStamp Log", + WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX, + 0, + 0, + 600, + 300, + g_hDlgMain, + NULL, + g_hInstance, + NULL ); + g_timeStampLog_hWnd = hWnd; + + GetClientRect( g_timeStampLog_hWnd, &clientRect ); + hWnd = CreateWindow( + WC_LISTVIEW, + "", + WS_VISIBLE|WS_CHILD|LVS_REPORT, + 0, + 0, + clientRect.right-clientRect.left, + clientRect.bottom-clientRect.top, + g_timeStampLog_hWnd, + ( HMENU )ID_TIMESTAMPLOG_LISTVIEW, + g_hInstance, + NULL ); + g_timeStampLog_hWndListView = hWnd; + + // init list view columns + for ( i=0; i<sizeof( g_timeStampLog_Labels )/sizeof( g_timeStampLog_Labels[0] ); i++ ) + { + LVCOLUMN lvc; + memset( &lvc, 0, sizeof( lvc ) ); + + lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; + lvc.iSubItem = 0; + lvc.cx = g_timeStampLog_Labels[i].width; + lvc.fmt = LVCFMT_LEFT; + lvc.pszText = ( LPSTR )g_timeStampLog_Labels[i].name; + + ListView_InsertColumn( g_timeStampLog_hWndListView, i, &lvc ); + } + + ListView_SetBkColor( g_timeStampLog_hWndListView, g_backgroundColor ); + ListView_SetTextBkColor( g_timeStampLog_hWndListView, g_backgroundColor ); + + DWORD style = LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP; + ListView_SetExtendedListViewStyleEx( g_timeStampLog_hWndListView, style, style ); + + // populate list view + pNode = g_timeStampLog_pNodes; + while ( pNode ) + { + TimeStampLog_AddViewItem( pNode ); + pNode = pNode->pNext; + } + TimeStampLog_SortItems(); + + if ( g_timeStampLog_windowRect.right && g_timeStampLog_windowRect.bottom ) + MoveWindow( g_timeStampLog_hWnd, g_timeStampLog_windowRect.left, g_timeStampLog_windowRect.top, g_timeStampLog_windowRect.right-g_timeStampLog_windowRect.left, g_timeStampLog_windowRect.bottom-g_timeStampLog_windowRect.top, FALSE ); + ShowWindow( g_timeStampLog_hWnd, SHOW_OPENWINDOW ); +} + + +//----------------------------------------------------------------------------- +// rc_TimeStampLog +// +// Sent from application with time stamp log +//----------------------------------------------------------------------------- +int rc_TimeStampLog( char* commandPtr ) +{ + char *cmdToken; + int timeStampAddr; + int retAddr; + int retVal; + int errCode = -1; + xrTimeStamp_t timeStamp; + + // get data + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &timeStampAddr ); + + // get retAddr + cmdToken = GetToken( &commandPtr ); + if ( !cmdToken[0] ) + goto cleanUp; + sscanf( cmdToken, "%x", &retAddr ); + + // get the caller's data + DmGetMemory( ( void* )timeStampAddr, sizeof( xrTimeStamp_t ), &timeStamp, NULL ); + + // swap the structure + BigFloat( &timeStamp.time, &timeStamp.time ); + BigFloat( &timeStamp.deltaTime, &timeStamp.deltaTime ); + timeStamp.memory = BigDWord( timeStamp.memory ); + timeStamp.deltaMemory = BigDWord( timeStamp.deltaMemory ); + + // add to log + TimeStampLog_AddItem( timeStamp.time, timeStamp.deltaTime, timeStamp.memory, timeStamp.deltaMemory, timeStamp.messageString ); + TimeStampLog_SortItems(); + + // return the result + retVal = 0; + int xboxRetVal = BigDWord( retVal ); + DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL ); + + DebugCommand( "0x%8.8x = TimeStampLog( 0x%8.8x )\n", retVal, timeStampAddr ); + + // success + errCode = 0; + +cleanUp: + return ( errCode ); +} diff --git a/utils/xbox/vxconsole/vxconsole.cpp b/utils/xbox/vxconsole/vxconsole.cpp new file mode 100644 index 0000000..976f3da --- /dev/null +++ b/utils/xbox/vxconsole/vxconsole.cpp @@ -0,0 +1,1528 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// VXCONSOLE.CPP +// +// Valve XBox Console. +//=====================================================================================// +#include "vxconsole.h" + +HWND g_hDlgMain; +HWND g_hwndCommandCombo; +HWND g_hwndOutputWindow; +HWND g_hwndCommandHint; +WNDPROC g_hwndCommandSubclassed; +BOOL g_connectedToXBox; +BOOL g_connectedToApp; +PDMN_SESSION g_pdmnSession; +PDM_CONNECTION g_pdmConnection; +printQueue_t g_PrintQueue; +UINT_PTR g_autoConnectTimer; +BOOL g_autoConnect; +BOOL g_debugCommands; +BOOL g_captureDebugSpew; +BOOL g_captureGameSpew = TRUE; +CHAR g_xboxName[MAX_XBOXNAMELEN]; +DWORD g_xboxAddress; +HINSTANCE g_hInstance; +HICON g_hIcons[MAX_ICONS]; +HBRUSH g_hBackgroundBrush; +HFONT g_hFixedFont; +BOOL g_reboot; +char* g_rebootArgv[MAX_ARGVELEMS]; +int g_rebootArgc; +COLORREF g_backgroundColor; +TEXTMETRIC g_fixedFontMetrics; +int g_connectCount; +int g_currentIcon = -1; +HACCEL g_hAccel; +HMODULE g_hRichEdit; +DWORD g_connectedTime; +RECT g_mainWindowRect; +HFONT g_hProportionalFont; +HANDLE g_hCommandReadyEvent; +int g_currentCommandSelection; +int g_connectFailure; +int g_configID; +bool g_bSuppressBlink = false; +BOOL g_bPlayTestMode = TRUE; + +LRESULT CALLBACK Main_DlgProc( HWND, UINT, WPARAM, LPARAM ); +LRESULT CALLBACK CommandWindow_SubclassedProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ); + +bool ParseCommandLineArg( const char *pCmdLine, const char *pKey, char *pValueBuff, int valueBuffSize ) +{ + const char* pArg = V_stristr( (char*)pCmdLine, pKey ); + if ( !pArg ) + { + return false; + } + + if ( pValueBuff ) + { + // caller wants next token + pArg += strlen( pKey ); + + int i; + for ( i=0; i<valueBuffSize; i++ ) + { + pValueBuff[i] = *pArg; + if ( *pArg == '\0' || *pArg == ' ' ) + { + break; + } + pArg++; + } + pValueBuff[i] = '\0'; + } + + return true; +} + +void MakeConfigString( const char *pString, int configID, char *pOutBuff, int outBuffSize ) +{ + if ( configID <= 0 ) + { + // as-is, undecorated + V_snprintf( pOutBuff, outBuffSize, "%s", pString ); + return; + } + + int len = strlen( pString ); + bool bAddTerminalSlash = ( len > 1 && pString[len-1] == '\\' ); + + V_snprintf( pOutBuff, outBuffSize, "%s_%d", pString, configID ); + + if ( bAddTerminalSlash ) + { + V_strncat( pOutBuff, "\\", outBuffSize ); + } +} + +//----------------------------------------------------------------------------- +// LoadConfig +// +//----------------------------------------------------------------------------- +void LoadConfig() +{ + char buff[256]; + int numArgs; + + ConfigDlg_LoadConfig(); + + // initial menu state is from persisted config + g_captureDebugSpew = g_captureDebugSpew_StartupState; + + Sys_GetRegistryString( "mainWindowRect", buff, "", sizeof( buff ) ); + numArgs = sscanf( buff, "%d %d %d %d", &g_mainWindowRect.left, &g_mainWindowRect.top, &g_mainWindowRect.right, &g_mainWindowRect.bottom ); + if ( numArgs != 4 || g_mainWindowRect.left < 0 || g_mainWindowRect.top < 0 || g_mainWindowRect.right < 0 || g_mainWindowRect.bottom < 0 ) + memset( &g_mainWindowRect, 0, sizeof( g_mainWindowRect ) ); +} + +//----------------------------------------------------------------------------- +// SaveConfig +// +//----------------------------------------------------------------------------- +void SaveConfig() +{ + char buff[256]; + + // get window placement + WINDOWPLACEMENT wp; + memset( &wp, 0, sizeof( wp ) ); + wp.length = sizeof( WINDOWPLACEMENT ); + GetWindowPlacement( g_hDlgMain, &wp ); + g_mainWindowRect = wp.rcNormalPosition; + + sprintf( buff, "%d %d %d %d", g_mainWindowRect.left, g_mainWindowRect.top, g_mainWindowRect.right, g_mainWindowRect.bottom ); + Sys_SetRegistryString( "mainWindowRect", buff ); +} + +//----------------------------------------------------------------------------- +// SetConnectionIcon +// +//----------------------------------------------------------------------------- +void SetConnectionIcon( int icon ) +{ + if ( g_currentIcon == icon ) + return; + + g_currentIcon = icon; + SetClassLongPtr( g_hDlgMain, GCLP_HICON, ( LONG_PTR )g_hIcons[icon] ); +} + +//----------------------------------------------------------------------------- +// SetMainWindowTitle +// +//----------------------------------------------------------------------------- +void SetMainWindowTitle() +{ + if ( !g_hDlgMain ) + { + return; + } + + char titleBuff[128]; + if ( !g_xboxTargetName[0] ) + { + strcpy( titleBuff, VXCONSOLE_TITLE ); + } + else + { + sprintf( titleBuff, "%s: %s", VXCONSOLE_TITLE, g_xboxTargetName ); + if ( g_configID ) + { + char configBuff[32]; + sprintf( configBuff, " (%d)", g_configID ); + V_strncat( titleBuff, configBuff, sizeof( titleBuff ) ); + } + } + SetWindowText( g_hDlgMain, titleBuff ); +} + +//----------------------------------------------------------------------------- +// DmAPI_DisplayError +// +//----------------------------------------------------------------------------- +VOID DmAPI_DisplayError( const CHAR* message, HRESULT hr ) +{ + CHAR strError[128]; + + ConsoleWindowPrintf( RGB( 255,0,0 ), "%s\n", message ); + + HRESULT hrError = DmTranslateError( hr, strError, sizeof( strError ) ); + if ( !FAILED( hrError ) && strError[0] ) + ConsoleWindowPrintf( RGB( 255,0,0 ), "Reason: '%s'\n", strError ); + else + ConsoleWindowPrintf( RGB( 255,0,0 ), "Reason: 0x%08lx\n", hr ); +} + +//----------------------------------------------------------------------------- +// DmAPI_SendCommand +// +// Send the specified string across the debugger channel to the application +//----------------------------------------------------------------------------- +HRESULT DmAPI_SendCommand( const char* strCommand, bool wait ) +{ + DWORD dwResponseLen; + CHAR strResponse[MAX_PATH]; + int retval; + bool bIgnorePingResponse; + char* ptr; + + retval = WaitForSingleObject( g_hCommandReadyEvent, wait ? INFINITE : 0 ); + if ( retval != WAIT_OBJECT_0 ) + { + // cannot send command + // some other previous command has not responded and signaled the release + // testing has shown DmSendCommand() is not re-entrant and callers get + // their responses out of sync + return XBDM_UNDEFINED; + } + + // clear the event mutex until ready + ResetEvent( g_hCommandReadyEvent ); + + bIgnorePingResponse = false; + dwResponseLen = sizeof( strResponse ); + strResponse[0] = '\0'; + + if ( strCommand[0] == '*' ) + { + // skip past internal command identifier + strCommand++; + } + else if ( !stricmp( strCommand, VXCONSOLE_COMMAND_PREFIX "!" ) ) + { + // empty ping command + // must be done as a synchronous command with a response because there + // is no way to bind an asynch response to the owner + bIgnorePingResponse = true; + } + + HRESULT hr = DmSendCommand( g_pdmConnection, strCommand, strResponse, &dwResponseLen ); + if ( !FAILED( hr ) ) + { + // success + switch ( hr ) + { + case XBDM_NOERR: + if ( !bIgnorePingResponse ) + { + // skip past possible ack prefix + ptr = strstr( strResponse, VXCONSOLE_COMMAND_ACK ); + if ( ptr ) + { + ptr += strlen( VXCONSOLE_COMMAND_ACK ); + + // ignore remote acknowledge response + if ( !stricmp( ptr, "OK" ) ) + break; + } + else + { + ptr = strResponse; + } + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", ptr ); + } + break; + + case XBDM_MULTIRESPONSE: + // multi-line response - loop, looking for end of response + while ( 1 ) + { + dwResponseLen = sizeof( strResponse ); + + hr = DmReceiveSocketLine( g_pdmConnection, strResponse, &dwResponseLen ); + if ( FAILED( hr ) || strResponse[0] == '.' ) + break; + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", strResponse ); + } + break; + + case XBDM_BINRESPONSE: + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Binary response - not implemented\n" ); + break; + + case XBDM_READYFORBIN: + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Ready for binary - not implemented\n" ); + break; + + default: + ConsoleWindowPrintf( XBX_CLR_RED, "Unknown Response: ( %s ).\n", strResponse ); + break; + } + } + + SetEvent( g_hCommandReadyEvent ); + return hr; +} + +//----------------------------------------------------------------------------- +// PrintToQueue +// +// Formats the string and adds it to the print queue +//----------------------------------------------------------------------------- +void PrintToQueue( COLORREF rgb, LPCTSTR strFormat, ... ) +{ + char buffer[MAX_QUEUEDSTRINGLEN]; + + // enter critical section so we don't try to process the list + EnterCriticalSection( &g_PrintQueue.CriticalSection ); + + assert( g_PrintQueue.numMessages <= MAX_QUEUEDSTRINGS ); + + // when the queue is full, the main thread is probably blocked and not dequeing + if ( !g_captureGameSpew || g_PrintQueue.numMessages == MAX_QUEUEDSTRINGS ) + { + LeaveCriticalSection( &g_PrintQueue.CriticalSection ); + return; + } + + va_list arglist; + va_start( arglist, strFormat ); + int len = _vsnprintf( buffer, MAX_QUEUEDSTRINGLEN, strFormat, arglist ); + if ( len == -1 ) + { + buffer[sizeof(buffer)-1] = '\0'; + } + va_end( arglist ); + + // queue the message into the next slot + g_PrintQueue.pMessages[g_PrintQueue.numMessages] = Sys_CopyString( buffer ); + g_PrintQueue.aColors[g_PrintQueue.numMessages++] = rgb; + + // ensure we post a message to process the print queue + if ( g_PrintQueue.numMessages == 1 ) + PostMessage( g_hDlgMain, WM_USER, 0, 0 ); + + // the main thread can now safely process the list + LeaveCriticalSection( &g_PrintQueue.CriticalSection ); +} + +//----------------------------------------------------------------------------- +// ProcessPrintQueue +// +//----------------------------------------------------------------------------- +void ProcessPrintQueue() +{ + // enter critical section so we don't try to add anything while we're processing + EnterCriticalSection( &g_PrintQueue.CriticalSection ); + + // dequeue all entries + for ( int i = 0; i < g_PrintQueue.numMessages; i++ ) + { + ConsoleWindowPrintf( g_PrintQueue.aColors[i], "%s", g_PrintQueue.pMessages[i] ); + Sys_Free( g_PrintQueue.pMessages[i] ); + } + + g_PrintQueue.numMessages = 0; + + // now we can safely add to the list + LeaveCriticalSection( &g_PrintQueue.CriticalSection ); +} + +//----------------------------------------------------------------------------- +// ConsoleWindowPrintf +// +// Writes out a string directly to the console window +//----------------------------------------------------------------------------- +int ConsoleWindowPrintf( COLORREF rgb, LPCTSTR strFormat, ... ) +{ + int dwStrLen; + char strTemp[512]; + va_list arglist; + CHARRANGE cr = { -1, -2 }; + + if ( rgb != XBX_CLR_DEFAULT ) + { + // set whatever colors, etc. they want + CHARFORMAT cf = {0}; + cf.cbSize = sizeof( cf ); + cf.dwMask = CFM_COLOR; + cf.dwEffects = 0; + cf.crTextColor = rgb; + SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_SETCHARFORMAT, SCF_SELECTION, ( LPARAM )&cf ); + } + + // Get our string to print + va_start( arglist, strFormat ); + dwStrLen = _vsnprintf( strTemp, sizeof( strTemp ), strFormat, arglist ); + va_end( arglist ); + + // Move the selection to the end + SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_EXSETSEL, 0, ( LPARAM )&cr ); + + // Add the text and scroll it into view + SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_REPLACESEL, 0, ( LONG )( LPSTR )strTemp ); + SendDlgItemMessage( g_hDlgMain, IDC_OUTPUT, EM_SCROLLCARET, 0, 0L ); + + if ( g_bPlayTestMode ) + { + char szLogPath[MAX_PATH]; + char szLogName[MAX_PATH]; + V_snprintf( szLogName, sizeof( szLogName ), "vxconsole_%s.log", g_xboxTargetName ); + V_ComposeFileName( g_localPath, szLogName, szLogPath, sizeof( szLogPath ) ); + FILE *fp = fopen( szLogPath, "at+" ); + if ( fp ) + { + fprintf( fp, strTemp ); + fclose( fp ); + } + } + + return dwStrLen; +} + +//----------------------------------------------------------------------------- +// ProcessCommand +// +//----------------------------------------------------------------------------- +bool ProcessCommand( const char* strCmdIn ) +{ + char strRemoteCmd[MAX_PATH + 10]; + TCHAR strCmdBak[MAX_PATH]; + char strCmd[MAX_PATH]; + char* argv[MAX_ARGVELEMS]; + BOOL isXCommand = FALSE; + BOOL isLocal = FALSE; + BOOL isRemote = FALSE; + int iIndex; + + // local copy for destructive purposes + strcpy( strCmd, strCmdIn ); + + // copy of the original command string + lstrcpyA( strCmdBak, strCmdIn ); + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "] %s\n", strCmd ); + + // parse argstring into components + int argc = CmdToArgv( strCmd, argv, MAX_ARGVELEMS ); + if ( !argc ) + { + // empty command + return true; + } + + if ( ( iIndex = ComboBox_GetCount( g_hwndCommandCombo ) ) >= MAX_COMMANDHISTORY ) + { + // Limit the history of items, purge oldest + ComboBox_DeleteString( g_hwndCommandCombo, 0 ); + } + + // add to end of list + iIndex = ComboBox_InsertItemData( g_hwndCommandCombo, -1, strCmdBak ); + ComboBox_SetCurSel( g_hwndCommandCombo, -1 ); + + // find command in local list + for ( int i=0; i<g_numLocalCommands; i++ ) + { + if ( lstrcmpiA( g_localCommands[i].strCommand, argv[0] ) ) + { + // no match + continue; + } + + isLocal = TRUE; + if ( !g_localCommands[i].pfnHandler ) + { + // no handler, remote xcommand + isXCommand = TRUE; + } + + if ( ( g_localCommands[i].flags & FN_XBOX ) && !g_connectedToXBox ) + { + // not allowed yet + ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to XBox.\n", argv[0] ); + return true; + } + else if ( ( g_localCommands[i].flags & FN_APP ) && !g_connectedToApp ) + { + // not allowed yet + ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to Application.\n", argv[0] ); + return true; + } + + if ( isXCommand ) + break; + + // do local command + g_localCommands[i].pfnHandler( argc, argv ); + return true; + } + + // find command in remote list + if ( !isLocal && !isXCommand && g_connectedToApp ) + { + for ( int i=0; i<g_numRemoteCommands; i++ ) + { + if ( lstrcmpiA( g_remoteCommands[i]->strCommand, argv[0] ) ) + { + // no match + continue; + } + + isRemote = TRUE; + + if ( !g_connectedToApp ) + { + // not allowed yet + ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not available until connected to Application.\n", argv[0] ); + return true; + } + break; + } + } + + if ( !isLocal && !isXCommand && !isRemote ) + { + if ( !g_connectedToApp || g_numRemoteCommands != 0 ) + { + // unrecognized + ConsoleWindowPrintf( RGB( 255,0,0 ), "'%s' is not a recognized command.\n", argv[0] ); + return true; + } + } + + if ( isXCommand ) + { + // send the xcommand directly + lstrcpyA( strRemoteCmd, strCmdBak ); + } + else + { + // add remote command prefix + lstrcpyA( strRemoteCmd, VXCONSOLE_COMMAND_PREFIX "!" ); + lstrcatA( strRemoteCmd, strCmdBak ); + } + + // send the command to the Xbox + HRESULT hr = DmAPI_SendCommand( strRemoteCmd, true ); + if ( FAILED( hr ) ) + { + DmAPI_DisplayError( "DmSendCommand", hr ); + return false; + } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// CommandWindow_HandleKey +// +// Handle a WM_KEYDOWN in our RTF cmd window +//----------------------------------------------------------------------------- +BOOL CommandWindow_HandleKey( WPARAM wParam ) +{ + BOOL bHandled = FALSE; + int curSel; + int numItems; + + if ( wParam >= VK_F1 && wParam <= VK_F12 ) + { + if ( Bindings_TranslateKey( wParam ) ) + { + // handled + return true; + } + } + + switch ( wParam ) + { + case VK_TAB: + case VK_UP: + case VK_DOWN: + if ( IsWindowVisible( g_hwndCommandHint ) ) + { + // hint window open + char hintCmd[MAX_PATH]; + char userCmd[MAX_PATH]; + + // scroll through the hint selections + curSel = SendMessage( g_hwndCommandHint, (UINT)LB_GETCURSEL, NULL, NULL ); + SendMessage( g_hwndCommandHint, (UINT)LB_GETTEXT, (WPARAM)curSel, (LPARAM)hintCmd ); + + numItems = SendMessage( g_hwndCommandHint, (UINT)LB_GETCOUNT, NULL, NULL ); + if ( numItems < 0 ) + numItems = 0; + + if ( wParam == VK_TAB ) + { + // get command typed so far + ComboBox_GetText( g_hwndCommandCombo, userCmd, MAX_PATH ); + + // strip the auto-space off the end + int len = Q_strlen(userCmd); + if ( userCmd[len-1] == ' ' ) + { + userCmd[len-1] = '\0'; + } + + if ( !stricmp( userCmd, hintCmd ) ) + { + // cycle to next or prev command with tab or shift-tab + if ( GetKeyState(VK_SHIFT) < 0 ) + { + wParam = VK_UP; + } + else + { + wParam = VK_DOWN; + } + } + } + + // move the selection + if ( wParam == VK_UP ) + curSel--; + else if ( wParam == VK_DOWN ) + curSel++; + if ( curSel < 0 ) + curSel = numItems - 1; + else if ( curSel > numItems-1 ) + curSel = 0; + if ( curSel < 0 ) + curSel = 0; + + // set the selection and get highlighted command + SendMessage( g_hwndCommandHint, (UINT)LB_SETCURSEL, (WPARAM)curSel, NULL ); + SendMessage( g_hwndCommandHint, (UINT)LB_GETTEXT, (WPARAM)curSel, (LPARAM)hintCmd ); + + // add a space to the end for easier parameter setting + Q_strncat( hintCmd, " ", sizeof(hintCmd), 1 ); + + // replace command string + ComboBox_SetText( g_hwndCommandCombo, hintCmd ); + + // set cursor to end of command + SendMessage( g_hwndCommandCombo, (UINT)CB_SETEDITSEL, (WPARAM)0, MAKELONG( MAX_PATH,MAX_PATH ) ); + + bHandled = TRUE; + } + else + { + curSel = SendMessage( g_hwndCommandCombo, (UINT)CB_GETCURSEL, NULL, NULL ); + if ( curSel < 0 ) + { + // combo box has no selection + // override combo box behavior and set selection + numItems = SendMessage( g_hwndCommandCombo, (UINT)CB_GETCOUNT, NULL, NULL ); + if ( numItems > 0 ) + { + if ( wParam == VK_UP ) + { + // set to bottom of list + curSel = numItems-1; + } + else if ( wParam == VK_DOWN ) + { + // set to top of list + curSel = 0; + } + + SendMessage( g_hwndCommandCombo, (UINT)CB_SETCURSEL, (WPARAM)curSel, NULL ); + bHandled = TRUE; + } + } + } + break; + + case VK_RETURN: + // user hit return in the combo box + if ( ComboBox_GetDroppedState( g_hwndCommandCombo ) ) + { + ComboBox_ShowDropdown( g_hwndCommandCombo, FALSE ); + } + else + { + PostMessage( g_hDlgMain, WM_APP, 0, 0 ); + bHandled = TRUE; + } + break; + } + + return bHandled; +} + +//----------------------------------------------------------------------------- +// CommandWindow_SubclassedProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK CommandWindow_SubclassedProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + switch ( msg ) + { + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + if ( CommandWindow_HandleKey( wParam ) ) + return 0; + break; + + case WM_CHAR: + if ( wParam == VK_RETURN ) + return 0; + break; + } + + return CallWindowProc( g_hwndCommandSubclassed, hDlg, msg, wParam, lParam ); +} + +//----------------------------------------------------------------------------- +// Main_SizeWindow +// +// Handles a WM_SIZE message by resizing all our child windows to match the main window +//----------------------------------------------------------------------------- +void Main_SizeWindow( HWND hDlg, UINT wParam, int cx, int cy ) +{ + if ( cx==0 || cy==0 ) + { + RECT rcClient; + GetClientRect( hDlg, &rcClient ); + cx = rcClient.right; + cy = rcClient.bottom; + } + + // if we're big enough, position our child windows + if ( g_hwndCommandCombo && cx > 64 && cy > 64 ) + { + RECT rcCmd; + RECT rcHint; + RECT rcOut; + + // fit the "command" combo box into our window + GetWindowRect( g_hwndCommandCombo, &rcCmd ); + ScreenToClient( hDlg, ( LPPOINT )&rcCmd ); + ScreenToClient( hDlg, ( LPPOINT )&rcCmd + 1 ); + int x = rcCmd.left; + int dx = cx - 8 - x; + int dy = rcCmd.bottom - rcCmd.top; + int y = cy - 8 - dy; + SetWindowPos( + g_hwndCommandCombo, + NULL, + x, + y, + dx, + dy, + SWP_NOZORDER ); + + // position the "hint popup" window above the "command" window + GetWindowRect( g_hwndCommandHint, &rcHint ); + ScreenToClient( g_hDlgMain, ( LPPOINT )&rcHint ); + ScreenToClient( g_hDlgMain, ( LPPOINT )&rcHint + 1 ); + SetWindowPos( + g_hwndCommandHint, + NULL, + rcCmd.left, + ( rcCmd.top - 4 ) - ( rcHint.bottom - rcHint.top + 1 ), + 0, + 0, + SWP_NOSIZE | SWP_NOZORDER ); + + // position the "Cmd" label + RECT rcStaticCmd; + HWND hStaticCmd = GetDlgItem( g_hDlgMain, IDC_LABEL ); + GetWindowRect( hStaticCmd, &rcStaticCmd ); + ScreenToClient( hDlg, ( LPPOINT )&rcStaticCmd ); + ScreenToClient( hDlg, ( LPPOINT )&rcStaticCmd + 1 ); + SetWindowPos( + hStaticCmd, + NULL, + 8, + y + ( dy - ( rcStaticCmd.bottom - rcStaticCmd.top ) ) / 2 - 1, + 0, + 0, + SWP_NOSIZE | SWP_NOZORDER ); + + // position the "output" window + GetWindowRect( g_hwndOutputWindow, &rcOut ); + ScreenToClient( hDlg, ( LPPOINT )&rcOut ); + int dwWidth = cx - rcOut.left - 8; + int dwHeight = y - rcOut.top - 8; + SetWindowPos( g_hwndOutputWindow, NULL, 0, 0, dwWidth, dwHeight, SWP_NOMOVE | SWP_NOZORDER ); + } +} + +//----------------------------------------------------------------------------- +// _SortCommands +// +//----------------------------------------------------------------------------- +int _SortCommands( const void* a, const void* b ) +{ + const char* strA = *( const char** )a; + const char* strB = *( const char** )b; + + return ( stricmp( strA, strB ) ); +} + +//----------------------------------------------------------------------------- +// EnableCommandHint +// +// Open/Close the command hint popup +//----------------------------------------------------------------------------- +void EnableCommandHint( bool enable ) +{ + int w = 0; + int h = 0; + int itemHeight; + int i; + int maxLen; + int len; + const char* cmds[256]; + int numLocalCommands; + int numRemoteCommands; + int curSel; + + if ( !enable ) + goto cleanUp; + + // get the current command + char strCmd[MAX_PATH]; + ComboBox_GetText( g_hwndCommandCombo, strCmd, MAX_PATH ); + if ( !strCmd[0] ) + { + // user has typed nothing + enable = false; + goto cleanUp; + } + + SendMessage( g_hwndCommandHint, ( UINT )LB_RESETCONTENT, NULL, NULL ); + + // get a list of possible matches + maxLen = 0; + numLocalCommands = MatchLocalCommands( strCmd, cmds, 256 ); + numRemoteCommands = MatchRemoteCommands( strCmd, cmds+numLocalCommands, 256-numLocalCommands ); + for ( i=0; i<numLocalCommands+numRemoteCommands; i++ ) + { + len = strlen( cmds[i] ); + if ( maxLen < len ) + maxLen = len; + } + if ( !maxLen ) + { + // no matches + enable = false; + goto cleanUp; + } + + // sort the list ( eschew listbox's autosorting ) + qsort( cmds, numLocalCommands+numRemoteCommands, sizeof( const char* ), _SortCommands ); + + curSel = -1; + len = strlen( strCmd ); + for ( i=0; i<numLocalCommands+numRemoteCommands; i++ ) + { + // populate the listbox + SendMessage( g_hwndCommandHint, ( UINT )LB_ADDSTRING, 0, ( LPARAM )cmds[i] ); + + // determine first best match + if ( curSel == -1 && !strnicmp( strCmd, cmds[i], len ) ) + curSel = i; + } + + if ( curSel != -1 ) + { + // set the selection to the first best string + // ensure the top string is shown ( avoids odd auto-vscroll choices ) + SendMessage( g_hwndCommandHint, ( UINT )LB_SETCURSEL, ( WPARAM )curSel, NULL ); + if ( !curSel ) + SendMessage( g_hwndCommandHint, ( UINT )LB_SETTOPINDEX, 0, NULL ); + } + + RECT rcCmd; + GetWindowRect( g_hwndCommandCombo, &rcCmd ); + ScreenToClient( g_hDlgMain, ( LPPOINT )&rcCmd ); + ScreenToClient( g_hDlgMain, ( LPPOINT )&rcCmd + 1 ); + + // clamp listbox height to client space + itemHeight = SendMessage( g_hwndCommandHint, ( UINT )LB_GETITEMHEIGHT, 0, NULL ); + if ( itemHeight <= 0 ) + { + // oops, shouldn't happen + enable = false; + goto cleanUp; + } + + h = ( numLocalCommands + numRemoteCommands )*itemHeight + 2; + if ( h > rcCmd.top - 8) + { + h = rcCmd.top - 8; + } + + // clamp listbox width + w = ( maxLen + 5 ) * g_fixedFontMetrics.tmMaxCharWidth; + + // position the "hint popup" window above the "command" window + SetWindowPos( + g_hwndCommandHint, + NULL, + rcCmd.left, + ( rcCmd.top - 4 ) - h, + w, + h, + SWP_NOZORDER ); + +cleanUp: + BOOL isVisible = IsWindowVisible( g_hwndCommandHint ); + if ( !enable && isVisible ) + ShowWindow( g_hwndCommandHint, SW_HIDE ); + else if ( enable && !isVisible ) + ShowWindow( g_hwndCommandHint, SW_SHOWNA ); +} + +//----------------------------------------------------------------------------- +// Main_DlgProc +// +//----------------------------------------------------------------------------- +LRESULT CALLBACK Main_DlgProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) +{ + WORD wID = LOWORD( wParam ); + BOOL isConnect; + + switch ( message ) + { + case WM_APP: + // user has pressed enter + // take the string from the command window and process it + // extra room for \r\n + char strCmd[MAX_PATH + 3]; + ComboBox_GetText( g_hwndCommandCombo, strCmd, MAX_PATH ); + ProcessCommand( strCmd ); + ComboBox_SetText( g_hwndCommandCombo, "" ); + EnableCommandHint( false ); + break; + + case WM_USER: + ProcessPrintQueue(); + break; + + case WM_TIMER: + // Don't do auto-connect stuff while the Assert dialog is up + // (it uses a synchronous command, so calling 'Dm' funcs here can cause a lockup) + if ( !g_AssertDialogActive ) + { + if ( wID == TIMERID_AUTOCONNECT ) + { + AutoConnectTimerProc( hDlg, TIMERID_AUTOCONNECT ); + return 0L; + } + } + break; + + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLOREDIT: + SetBkColor( ( HDC )wParam,g_backgroundColor ); + return ( BOOL )g_hBackgroundBrush; + + case WM_SIZE: + Main_SizeWindow( hDlg, wParam, LOWORD( lParam ), HIWORD( lParam ) ); + break; + + case WM_SYSCOMMAND: + if ( wID == SC_CLOSE ) + { + PostMessage( hDlg, WM_CLOSE, 0, 0 ); + return 0L; + } + break; + + case WM_CLOSE: + // disconnect before closing + lc_disconnect( 0, NULL ); + + SaveConfig(); + DestroyWindow( hDlg ); + break; + + case WM_DESTROY: + SubclassWindow( g_hwndCommandCombo, g_hwndCommandSubclassed ); + PostQuitMessage( 0 ); + return 0L; + + case WM_INITMENU: + isConnect = g_connectedToXBox || g_connectedToApp; + CheckMenuItem( ( HMENU )wParam, IDM_AUTOCONNECT, MF_BYCOMMAND | ( g_autoConnect ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_CAPTUREGAMESPEW, MF_BYCOMMAND | ( g_captureGameSpew ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_CAPTUREDEBUGSPEW, MF_BYCOMMAND | ( g_captureDebugSpew ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_DEBUGCOMMANDS, MF_BYCOMMAND | ( g_debugCommands ? MF_CHECKED : MF_UNCHECKED ) ); + CheckMenuItem( ( HMENU )wParam, IDM_PLAYTESTMODE, MF_BYCOMMAND | ( g_bPlayTestMode ? MF_CHECKED : MF_UNCHECKED ) ); + EnableMenuItem( ( HMENU )wParam, IDM_SYNCFILES, MF_BYCOMMAND | ( g_connectedToXBox ? MF_ENABLED : MF_GRAYED ) ); + EnableMenuItem( ( HMENU )wParam, IDM_SYNCINSTALL, MF_BYCOMMAND | ( g_connectedToXBox ? MF_ENABLED : MF_GRAYED ) ); + return 0L; + + case WM_COMMAND: + switch ( wID ) + { + case IDC_COMMAND: + switch ( HIWORD( wParam ) ) + { + case CBN_EDITCHANGE: + case CBN_SETFOCUS: + EnableCommandHint( true ); + break; + + case CBN_KILLFOCUS: + EnableCommandHint( false ); + break; + } + break; + + case IDM_CONFIG: + ConfigDlg_Open(); + return 0L; + + case IDM_CAPTUREGAMESPEW: + g_captureGameSpew ^= 1; + return 0L; + + case IDM_CAPTUREDEBUGSPEW: + g_captureDebugSpew ^= 1; + return 0L; + + case IDM_DEBUGCOMMANDS: + g_debugCommands ^= 1; + return 0L; + + case IDM_BUG: + BugDlg_Open(); + return 0L; + + case IDM_MEMORYDUMP: + ShowMemDump_Open(); + return 0L; + + case IDM_TIMESTAMPLOG: + TimeStampLog_Open(); + return 0L; + + case IDM_SYNCFILES: + SyncFilesDlg_Open(); + return 0L; + + case IDM_SYNCINSTALL: + InstallDlg_Open(); + return 0L; + + case IDM_EXCLUDEPATHS: + ExcludePathsDlg_Open(); + return 0L; + + case IDM_CPU_SAMPLES: + CpuProfileSamples_Open(); + return 0L; + + case IDM_CPU_HISTORY: + CpuProfileHistory_Open(); + return 0L; + + case IDM_D3D_SAMPLES: + TexProfileSamples_Open(); + return 0L; + + case IDM_D3D_HISTORY: + TexProfileHistory_Open(); + return 0L; + + case IDM_SHOWMEMORYUSAGE: + MemProfile_Open(); + return 0L; + + case IDM_PLAYTESTMODE: + g_bPlayTestMode ^= 1; + return 0L; + + case IDM_SHOWRESOURCES_TEXTURES: + ShowTextures_Open(); + return 0L; + + case IDM_SHOWRESOURCES_MATERIALS: + ShowMaterials_Open(); + return 0L; + + case IDM_SHOWRESOURCES_SOUNDS: + ShowSounds_Open(); + return 0L; + + case IDM_SHOWRESOURCES_MODELS: + NotImplementedYet(); + return 0L; + + case IDM_AUTOCONNECT: + if ( g_connectedToXBox || g_connectedToApp || g_autoConnect ) + lc_disconnect( 0, NULL ); + else + lc_autoConnect( 0, NULL ); + return 0L; + + case IDM_BINDINGS_EDIT: + Bindings_Open(); + return 0L; + + case IDM_BINDINGS_BIND1: + case IDM_BINDINGS_BIND2: + case IDM_BINDINGS_BIND3: + case IDM_BINDINGS_BIND4: + case IDM_BINDINGS_BIND5: + case IDM_BINDINGS_BIND6: + case IDM_BINDINGS_BIND7: + case IDM_BINDINGS_BIND8: + case IDM_BINDINGS_BIND9: + case IDM_BINDINGS_BIND10: + case IDM_BINDINGS_BIND11: + case IDM_BINDINGS_BIND12: + Bindings_MenuSelection( wID ); + return 0L; + + case IDM_EXIT: + PostMessage( hDlg, WM_CLOSE, 0, 0 ); + return 0L; + } + break; + } + + return ( DefDlgProc( hDlg, message, wParam, lParam ) ); +} + +//----------------------------------------------------------------------------- +// CmdToArgv +// +// Parses a string into argv and return # of args. +//----------------------------------------------------------------------------- +int CmdToArgv( char* str, char* argv[], int maxargs ) +{ + int argc = 0; + int argcT = 0; + char* strNil = str + lstrlenA( str ); + + while ( argcT < maxargs ) + { + // Eat whitespace + while ( *str && ( *str==' ' ) ) + str++; + + if ( !*str ) + { + argv[argcT++] = strNil; + } + else + { + // Find the end of this arg + char chEnd = ( *str == '"' || *str == '\'' ) ? *str++ : ' '; + char* strArgEnd = str; + while ( *strArgEnd && ( *strArgEnd != chEnd ) ) + strArgEnd++; + + // Record this argument + argv[argcT++] = str; + argc = argcT; + + // Move strArg to the next argument ( or not, if we hit the end ) + str = *strArgEnd ? strArgEnd + 1 : strArgEnd; + *strArgEnd = 0; + } + } + + return argc; +} + +//----------------------------------------------------------------------------- +// CreateCommandHint +// +//----------------------------------------------------------------------------- +void CreateCommandHint() +{ + // create the "hint" popup + g_hwndCommandHint = CreateWindowEx( + WS_EX_NOPARENTNOTIFY, + "LISTBOX", + "", + WS_BORDER|WS_CHILD|LBS_HASSTRINGS|WS_VSCROLL, + 0, 0, 100, 0, + g_hDlgMain, + ( HMENU )IDC_COMMANDHINT, + g_hInstance, + NULL ); + + // force the popup to head of z-order + // to draw over all other children + BringWindowToTop( g_hwndCommandHint ); + + // set font + SendDlgItemMessage( g_hDlgMain, IDC_COMMANDHINT, WM_SETFONT, ( WPARAM )g_hFixedFont, TRUE ); +} + +//----------------------------------------------------------------------------- +// CreateResources +// +//----------------------------------------------------------------------------- +bool CreateResources() +{ + LOGFONT lf; + HFONT hFontOld; + HDC hDC; + int i; + + // pull in common controls + INITCOMMONCONTROLSEX initCommon; + initCommon.dwSize = sizeof( INITCOMMONCONTROLSEX ); + initCommon.dwICC = ICC_LISTVIEW_CLASSES|ICC_USEREX_CLASSES; + if ( !InitCommonControlsEx( &initCommon ) ) + return false; + + // pull in rich edit controls + g_hRichEdit = LoadLibrary( "Riched32.dll" ); + if ( !g_hRichEdit ) + return false; + + g_backgroundColor = XBX_CLR_LTGREY; + g_hBackgroundBrush = CreateSolidBrush( g_backgroundColor ); + + // get icons + g_hIcons[ICON_APPLICATION] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_VXCONSOLE ) ); + g_hIcons[ICON_DISCONNECTED] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_DISCONNECTED ) ); + g_hIcons[ICON_CONNECTED_XBOX] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT1_ON ) ); + g_hIcons[ICON_CONNECTED_APP0] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT2_OFF ) ); + g_hIcons[ICON_CONNECTED_APP1] = LoadIcon( g_hInstance, MAKEINTRESOURCE( IDI_CONNECT2_ON ) ); + for ( i=0; i<MAX_ICONS; i++ ) + { + if ( !g_hIcons[i] ) + return false; + } + + // get the font feight + hDC = GetWindowDC( NULL ); + int nHeight = -MulDiv( VXCONSOLE_FONTSIZE, GetDeviceCaps( hDC, LOGPIXELSY ), 72 ); + ReleaseDC( NULL, hDC ); + + // create fixed font + memset( &lf, 0, sizeof( LOGFONT ) ); + lf.lfHeight = nHeight; + lf.lfWeight = 400; + strcpy( lf.lfFaceName, VXCONSOLE_FONT ); + g_hFixedFont = CreateFontIndirect( &lf ); + if ( !g_hFixedFont ) + return false; + + // create proportional font + memset( &lf, 0, sizeof( LOGFONT ) ); + lf.lfHeight = -11; + lf.lfWeight = 400; + strcpy( lf.lfFaceName, "Tahoma" ); + g_hProportionalFont = CreateFontIndirect( &lf ); + if ( !g_hProportionalFont ) + return false; + + // get the font metrics + hDC = GetWindowDC( NULL ); + hFontOld = ( HFONT )SelectObject( hDC, g_hFixedFont ); + GetTextMetrics( hDC, &g_fixedFontMetrics ); + SelectObject( hDC, hFontOld ); + ReleaseDC( NULL, hDC ); + + return true; +} + +//----------------------------------------------------------------------------- +// Shutdown +// +// Free all resources +//----------------------------------------------------------------------------- +void Shutdown() +{ + BugReporter_FreeInterfaces(); + + if ( g_PrintQueue.bInit ) + { + DeleteCriticalSection( &g_PrintQueue.CriticalSection ); + g_PrintQueue.bInit = false; + } + + if ( g_hCommandReadyEvent ) + { + CloseHandle( g_hCommandReadyEvent ); + g_hCommandReadyEvent = 0; + } + + if ( g_hRichEdit ) + { + FreeLibrary( g_hRichEdit ); + g_hRichEdit = 0; + } + + if ( g_hBackgroundBrush ) + { + DeleteObject( g_hBackgroundBrush ); + g_hBackgroundBrush = 0; + } + + if ( g_hFixedFont ) + { + DeleteObject( g_hFixedFont ); + g_hFixedFont = 0; + } + + if ( g_hProportionalFont ) + { + DeleteObject( g_hProportionalFont ); + g_hProportionalFont = 0; + } +} + +//----------------------------------------------------------------------------- +// Startup +// +//----------------------------------------------------------------------------- +bool Startup() +{ + // Load the xenon debugging dll (xbdm.dll) manually due to its absence from system path + const char *pPath = getenv( "path" ); + const char *pXEDKDir = getenv( "xedk" ); + if ( !pXEDKDir ) + pXEDKDir = ""; + + int len = strlen( pPath ) + strlen( pXEDKDir ) + 256; + char *pNewPath = (char*)_alloca( len ); + sprintf( pNewPath, "path=%s;%s\\bin\\win32", pPath, pXEDKDir ); + _putenv( pNewPath ); + + HMODULE hXBDM = LoadLibrary( TEXT( "xbdm.dll" ) ); + if ( !hXBDM ) + { + if ( pXEDKDir[0] ) + Sys_Error( "Couldn't load xbdm.dll" ); + else + Sys_Error( "Couldn't load xbdm.dll\nXEDK environment variable not set." ); + } + + LoadConfig(); + + if ( !CreateResources() ) + return false; + + // set up our print queue + InitializeCriticalSection( &g_PrintQueue.CriticalSection ); + g_PrintQueue.bInit = true; + + // manual reset, initially signaled + g_hCommandReadyEvent = CreateEvent( NULL, TRUE, TRUE, NULL ); + + // set up our window class + WNDCLASS wndclass; + memset( &wndclass, 0, sizeof( wndclass ) ); + wndclass.style = 0; + wndclass.lpfnWndProc = Main_DlgProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = VXCONSOLE_WINDOWBYTES; + wndclass.hInstance = g_hInstance; + wndclass.hIcon = g_hIcons[ICON_DISCONNECTED]; + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = g_hBackgroundBrush; + wndclass.lpszMenuName = MAKEINTRESOURCE( MENU_VXCONSOLE ); + wndclass.lpszClassName = VXCONSOLE_CLASSNAME; + if ( !RegisterClass( &wndclass ) ) + return false; + + g_hAccel = LoadAccelerators( g_hInstance, MAKEINTRESOURCE( IDR_MAIN_ACCEL ) ); + if ( !g_hAccel ) + return false; + + // Create our main dialog + g_hDlgMain = CreateDialog( g_hInstance, MAKEINTRESOURCE( IDD_VXCONSOLE ), 0, NULL ); + if ( !g_hDlgMain ) + return false; + SetWindowLong( g_hDlgMain, VXCONSOLE_CONFIGID, g_configID ); + + if ( !BugDlg_Init() ) + return false; + + if ( !CpuProfile_Init() ) + return false; + + if ( !TexProfile_Init() ) + return false; + + if ( !MemProfile_Init() ) + return false; + + if ( !Bindings_Init() ) + return false; + + if ( !SyncFilesDlg_Init() ) + return false; + + if ( !ShowMaterials_Init() ) + return false; + + if ( !ShowTextures_Init() ) + return false; + + if ( !ShowSounds_Init() ) + return false; + + if ( !ShowMemDump_Init() ) + return false; + + if ( !TimeStampLog_Init() ) + return false; + + if ( !ExcludePathsDlg_Init() ) + return false; + + g_hwndOutputWindow = GetDlgItem( g_hDlgMain, IDC_OUTPUT ); + g_hwndCommandCombo = GetDlgItem( g_hDlgMain, IDC_COMMAND ); + + CreateCommandHint(); + + // subclass our dropdown command listbox to handle return key + g_hwndCommandSubclassed = SubclassWindow( GetWindow( g_hwndCommandCombo, GW_CHILD ), CommandWindow_SubclassedProc ); + + // Change the font type of the output window to courier + CHARFORMAT cf; + cf.cbSize = sizeof( CHARFORMAT ); + SendMessage( g_hwndOutputWindow, EM_GETCHARFORMAT, 0, ( LPARAM )&cf ); + cf.dwMask &= ~CFM_COLOR; + cf.yHeight = VXCONSOLE_FONTSIZE*20; + lstrcpyA( cf.szFaceName, VXCONSOLE_FONT ); + SendMessage( g_hwndOutputWindow, EM_SETCHARFORMAT, SCF_ALL, ( LPARAM )&cf ); + SendMessage( g_hwndOutputWindow, EM_SETBKGNDCOLOR, 0, g_backgroundColor ); + + // ensure the output window adheres to its z ordering + LONG style = GetWindowLong( g_hwndOutputWindow, GWL_STYLE ); + style |= WS_CLIPSIBLINGS; + SetWindowLong( g_hwndOutputWindow, GWL_STYLE, style ); + + // change the font of the command and its hint window to courier + SendDlgItemMessage( g_hDlgMain, IDC_COMMAND, WM_SETFONT, ( WPARAM )g_hFixedFont, TRUE ); + + // set the window title + SetMainWindowTitle(); + + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "VXConsole %s [%s Build: %s %s] [Protocol: %d]\n", VXCONSOLE_VERSION, VXCONSOLE_BUILDTYPE, __DATE__, __TIME__, VXCONSOLE_PROTOCOL_VERSION ); + ConsoleWindowPrintf( XBX_CLR_DEFAULT, "type '*help' for list of commands...\n\n" ); + + g_currentIcon = -1; + SetConnectionIcon( ICON_DISCONNECTED ); + + if ( g_alwaysAutoConnect) + { + // user wants to auto-connect at startup + lc_autoConnect( 0, NULL ); + } + + if ( g_mainWindowRect.right && g_mainWindowRect.bottom ) + MoveWindow( g_hDlgMain, g_mainWindowRect.left, g_mainWindowRect.top, g_mainWindowRect.right-g_mainWindowRect.left, g_mainWindowRect.bottom-g_mainWindowRect.top, FALSE ); + + // ready for display + int cmdShow = SW_SHOWNORMAL; + if ( g_startMinimized ) + cmdShow = SW_SHOWMINIMIZED; + ShowWindow( g_hDlgMain, cmdShow ); + + // success + return true; +} + +//----------------------------------------------------------------------------- +// WinMain +// +// Entry point for program +//----------------------------------------------------------------------------- +int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow ) +{ + bool error = true; + MSG msg = {0}; + + g_hInstance = hInstance; + + g_bSuppressBlink = ParseCommandLineArg( pCmdLine, "-noblink", NULL, 0 ); + + // optional -config <ID> can specify a specific configuration + char buff[128]; + buff[0] = '\0'; + ParseCommandLineArg( pCmdLine, "-config ", buff, sizeof( buff ) ); + g_configID = atoi( buff ); + + MakeConfigString( VXCONSOLE_REGISTRY, g_configID, buff, sizeof( buff ) ); + Sys_SetRegistryPrefix( buff ); + + HWND hwnd = FindWindow( VXCONSOLE_CLASSNAME, NULL ); + if ( hwnd && GetWindowLong( hwnd, VXCONSOLE_CONFIGID ) == g_configID ) + { + // single instance only + // bring other version to foreground + if ( IsIconic( hwnd ) ) + ShowWindow( hwnd, SW_RESTORE ); + SetForegroundWindow( hwnd ); + return ( FALSE ); + } + + if ( !Startup() ) + goto cleanUp; + + // message pump + while ( GetMessage( &msg, NULL, 0, 0 ) ) + { + if ( !TranslateAccelerator( g_hDlgMain, g_hAccel, &msg ) ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } + + // no-error, end of app + error = false; + +cleanUp: + if ( error ) + { + char str[255]; + FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, str, 255, NULL ); + MessageBox( NULL, str, NULL, MB_OK ); + } + + Shutdown(); + + return ( msg.wParam ); +} + + diff --git a/utils/xbox/vxconsole/vxconsole.h b/utils/xbox/vxconsole/vxconsole.h new file mode 100644 index 0000000..6ff1afc --- /dev/null +++ b/utils/xbox/vxconsole/vxconsole.h @@ -0,0 +1,479 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// VXCONSOLE.H +// +// Master Header. +//=====================================================================================// +#pragma once + +#include "tier0/platform.h" + +#include <winsock2.h> +#include <windows.h> +#include <windowsx.h> +#include <commctrl.h> +#include <stdio.h> +#include <stdarg.h> +#include <io.h> +#include <fcntl.h> +#include <string.h> +#include <share.h> +#include <richedit.h> +#include <assert.h> +#include <xbdm.h> +#include <time.h> +#include <sys/stat.h> + +#include "resource.h" +#include "assert_resource.h" +#include "sys_utils.h" +#include "sys_scriptlib.h" +#include "bugreporter/bugreporter.h" +#include "jpeglib/jpeglib.h" +#include "UtlBuffer.h" +#include "strtools.h" +#include "xbox/xbox_vxconsole.h" +#include "UtlRBTree.h" +#include "UtlSymbol.h" +#include "UtlVector.h" +#include "UtlString.h" + +#define VXCONSOLE_VERSION "1.2" +#define VXCONSOLE_CLASSNAME "VXConsole" +#define VXCONSOLE_TITLE "VXConsole" +#define VXCONSOLE_FONT "Courier" +#define VXCONSOLE_FONTSIZE 10 +#define VXCONSOLE_MAGIC "3\\" +#define VXCONSOLE_REGISTRY "HKEY_CURRENT_USER\\Software\\VXConsole\\" VXCONSOLE_MAGIC +#ifdef _DEBUG +#define VXCONSOLE_BUILDTYPE "Debug" +#else +#define VXCONSOLE_BUILDTYPE "Release" +#endif + +#define VXCONSOLE_WINDOWBYTES ( DLGWINDOWEXTRA + 4 ) +#define VXCONSOLE_CONFIGID ( VXCONSOLE_WINDOWBYTES - 4 ) + +#define MAX_QUEUEDSTRINGS 4096 +#define MAX_QUEUEDSTRINGLEN 512 +#define MAX_RCMDNAMELEN 32 +#define MAX_RCMDS 4096 +#define MAX_TOKENCHARS 256 +#define MAX_XBOXNAMELEN 64 +#define MAX_ARGVELEMS 20 +#define MAX_COMMANDHISTORY 25 + +#define TIMERID_AUTOCONNECT 0x1000 +#define TIMERID_MEMPROFILE 0x1001 + +#define IDC_COMMANDHINT 666 + +#define XBX_CLR_RED ( RGB( 255,0,0 ) ) +#define XBX_CLR_GREEN ( RGB( 0,255,0 ) ) +#define XBX_CLR_WHITE ( RGB( 255,255,255 ) ) +#define XBX_CLR_BLACK ( RGB( 0,0,0 ) ) +#define XBX_CLR_BLUE ( RGB( 0,0,255 ) ) +#define XBX_CLR_YELLOW ( RGB( 255,255,0 ) ) +#define XBX_CLR_LTGREY ( RGB( 180,180,180 ) ) +#define XBX_CLR_DEFAULT XBX_CLR_BLACK + +// The command prefix that is prepended to all communication between the Xbox +// app and the debug console app +#define VXCONSOLE_PRINT_PREFIX "XPRT" +#define VXCONSOLE_COMMAND_PREFIX "XCMD" +#define VXCONSOLE_COMMAND_ACK "XACK" +#define VXCONSOLE_COLOR_PREFIX "XCLR" + +#define ICON_APPLICATION 0 +#define ICON_DISCONNECTED 1 +#define ICON_CONNECTED_XBOX 2 +#define ICON_CONNECTED_APP0 3 +#define ICON_CONNECTED_APP1 4 +#define MAX_ICONS 5 + +typedef BOOL ( *cmdHandler_t )( int argc, char* argv[] ); + +#define IDM_BINDINGS 50000 +#define IDM_BINDINGS_EDIT ( IDM_BINDINGS+1 ) +#define IDM_BINDINGS_BIND1 ( IDM_BINDINGS+2 ) +#define IDM_BINDINGS_BIND2 ( IDM_BINDINGS+3 ) +#define IDM_BINDINGS_BIND3 ( IDM_BINDINGS+4 ) +#define IDM_BINDINGS_BIND4 ( IDM_BINDINGS+5 ) +#define IDM_BINDINGS_BIND5 ( IDM_BINDINGS+6 ) +#define IDM_BINDINGS_BIND6 ( IDM_BINDINGS+7 ) +#define IDM_BINDINGS_BIND7 ( IDM_BINDINGS+8 ) +#define IDM_BINDINGS_BIND8 ( IDM_BINDINGS+9 ) +#define IDM_BINDINGS_BIND9 ( IDM_BINDINGS+10 ) +#define IDM_BINDINGS_BIND10 ( IDM_BINDINGS+11 ) +#define IDM_BINDINGS_BIND11 ( IDM_BINDINGS+12 ) +#define IDM_BINDINGS_BIND12 ( IDM_BINDINGS+13 ) +#define MAX_BINDINGS ( VK_F12-VK_F1+1 ) + +// file serving +#define FSERVE_LOCALONLY 0 +#define FSERVE_REMOTEONLY 1 +#define FSERVE_LOCALFIRST 2 + +// file sync +#define FSYNC_OFF 0x00000000 +#define FSYNC_ALWAYS 0x00000001 +#define FSYNC_IFNEWER 0x00000002 +#define FSYNC_TYPEMASK 0x0000000F +#define FSYNC_ANDEXISTSONTARGET 0x80000000 + +// track function invocations +typedef enum +{ + FL_INVALID, + FL_STAT, + FL_FOPEN, + FL_FSEEK, + FL_FTELL, + FL_FREAD, + FL_FWRITE, + FL_FCLOSE, + FL_FEOF, + FL_FERROR, + FL_FFLUSH, + FL_FGETS, + FL_MAXFUNCTIONCOUNTS, +} fileLogFunctions_e; + +typedef enum +{ + VPROF_OFF = 0, + VPROF_CPU, + VPROF_TEXTURE, + VPROF_TEXTUREFRAME, +} vprofState_e; + +// funtion command types +#define FN_CONSOLE 0x00 // command runs at console +#define FN_XBOX 0x01 // command requires xbox +#define FN_APP 0x02 // command requires application + +// shorthand +#define FA_NORMAL FILE_ATTRIBUTE_NORMAL +#define FA_DIRECTORY FILE_ATTRIBUTE_DIRECTORY +#define FA_READONLY FILE_ATTRIBUTE_READONLY + +typedef struct +{ + const CHAR* strCommand; + int flags; + cmdHandler_t pfnHandler; + const CHAR* strHelp; +} localCommand_t; + +typedef struct +{ + char* strCommand; + char* strHelp; +} remoteCommand_t; + +typedef struct +{ + CRITICAL_SECTION CriticalSection; + int numMessages; + bool bInit; + COLORREF aColors[MAX_QUEUEDSTRINGS]; + CHAR *pMessages[MAX_QUEUEDSTRINGS]; +} printQueue_t; + +class CProgress +{ +public: + CProgress(); + ~CProgress(); + void Open( const char* title, bool canCancel, bool bHasMeter ); + void SetStatus( const char *line1, const char *line2, const char *line3 ); + void SetMeter( int currentPos, int range ); + bool IsCancel(); + HWND m_hWnd; + HWND m_hWndStatus1; + HWND m_hWndStatus2; + HWND m_hWndStatus3; + HWND m_hWndPercent; + HWND m_hWndMeter; + HWND m_hWndCancel; + bool m_bCancelPressed; + int m_range; + +private: + void Update(); +}; + +typedef struct fileNode_s +{ + char *filename; + FILETIME creationTime; + FILETIME changeTime; + DWORD sizeHigh; + DWORD sizeLow; + DWORD attributes; + int level; + struct fileNode_s *nextPtr; + bool needsUpdate; +} +fileNode_t; + +//----------------------------------------------------------------------------- +// FILEIO.CPP +//----------------------------------------------------------------------------- +extern void RemoteToLocalFilename( const char* inFilename, char* outFilename, int outSize ); +extern void RemoteToTargetFilename( const char* inFilename, char* outFilename, int outSize ); +extern void FreeTargetFileList( fileNode_t* pFileList ); +extern bool GetTargetFileList_r( char* targetPath, bool recurse, int attributes, int level, fileNode_t** pFileList ); +extern char *SystemTimeToString( SYSTEMTIME *systemTime, char *buffer, int bufferSize ); +extern bool CreateTargetPath( const char *pTargetFilename ); + +//----------------------------------------------------------------------------- +// BINDINGS.CPP +//----------------------------------------------------------------------------- +extern bool Bindings_TranslateKey( int vkKeyCode ); +extern bool Bindings_MenuSelection( int wID ); +extern void Bindings_LoadConfig(); +extern void Bindings_SaveConfig(); +extern void Bindings_Open(); +extern bool Bindings_Init(); + +//----------------------------------------------------------------------------- +// COMMON.CPP +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// VXCONSOLE.CPP +//----------------------------------------------------------------------------- +extern void SetConnectionIcon( int icon ); +extern void PrintToQueue( COLORREF color, const CHAR* strFormat, ... ); +extern void ProcessPrintQueue(); +extern void DmAPI_DisplayError( const char* strApiName, HRESULT hr ); +extern int ConsoleWindowPrintf( COLORREF rgb, LPCTSTR lpFmt, ... ); +extern int CmdToArgv( char* str, char* argv[], int maxargs ); +extern char* GetToken( char** tokenStreamPtr ); +extern void DebugCommand( const char* strFormat, ... ); +extern bool ProcessCommand( const char* strCmd ); +extern HRESULT DmAPI_SendCommand( const char* strCommand, bool wait ); +extern void NotImplementedYet(); +extern void SetMainWindowTitle(); +extern HWND g_hDlgMain; +extern HWND g_hwndOutputWindow; +extern UINT_PTR g_autoConnectTimer; +extern BOOL g_autoConnect; +extern CHAR g_xboxName[]; +extern DWORD g_xboxAddress; +extern CHAR g_remotePath[]; +extern CHAR g_localPath[]; +extern CHAR g_targetPath[]; +extern CHAR g_installPath[]; +extern CHAR g_xboxTargetName[]; +extern BOOL g_connectedToApp; +extern BOOL g_connectedToXBox; +extern PDMN_SESSION g_pdmnSession; +extern PDM_CONNECTION g_pdmConnection; +extern BOOL g_debugCommands; +extern BOOL g_captureDebugSpew; +extern HINSTANCE g_hInstance; +extern HICON g_hIcons[]; +extern BOOL g_reboot; +extern int g_rebootArgc; +extern char* g_rebootArgv[]; +extern int g_connectCount; +extern int g_currentIcon; +extern BOOL g_clsOnConnect; +extern DWORD g_connectedTime; +extern HBRUSH g_hBackgroundBrush; +extern COLORREF g_backgroundColor; +extern HFONT g_hFixedFont; +extern HFONT g_hProportionalFont; +extern HANDLE g_hCommandReadyEvent; +extern BOOL g_loadSymbolsOnConnect; +extern HACCEL g_hAccel; +extern BOOL g_alwaysAutoConnect; +extern BOOL g_startMinimized; +extern int g_connectFailure; +extern BOOL g_captureDebugSpew_StartupState; +extern bool g_bSuppressBlink; +extern BOOL g_bPlayTestMode; + +//----------------------------------------------------------------------------- +// LOCAL_CMDS.CPP +//----------------------------------------------------------------------------- +extern BOOL lc_bug( int argc, char* argv[] ); +extern BOOL lc_dir( int argc, char* argv[] ); +extern BOOL lc_del( int argc, char* argv[] ); +extern BOOL lc_memory( int argc, char* argv[] ); +extern BOOL lc_screenshot( int argc, char* argv[] ); +extern BOOL lc_help( int argc, char* argv[] ); +extern BOOL lc_cls( int argc, char* argv[] ); +extern BOOL lc_connect( int argc, char* argv[] ); +extern BOOL lc_autoConnect( int argc, char* argv[] ); +extern BOOL lc_disconnect( int argc, char* argv[] ); +extern BOOL lc_quit( int argc, char* argv[] ); +extern BOOL lc_crashdump( int argc, char* argv[] ); +extern BOOL lc_listen( int argc, char* argv[] ); +extern BOOL lc_run( int argc, char* argv[] ); +extern BOOL lc_reset( int argc, char* argv[] ); +extern BOOL lc_modules( int argc, char* argv[] ); +extern BOOL lc_sections( int argc, char* argv[] ); +extern BOOL lc_threads( int argc, char* argv[] ); +extern BOOL lc_ClearConfigs( int argc, char* argv[] ); +extern void AutoConnectTimerProc( HWND hwnd, UINT_PTR idEvent ); +extern int MatchLocalCommands( char* cmdStr, const char* cmdList[], int maxCmds ); +extern void DoDisconnect( BOOL bKeepConnection, int waitTime = 15 ); +extern localCommand_t g_localCommands[]; +extern const int g_numLocalCommands; + +//----------------------------------------------------------------------------- +// REMOTE_CMDS.CPP +//----------------------------------------------------------------------------- +extern int rc_AddCommands( char* commandPtr ); +extern void Remote_DeleteCommands(); +extern DWORD __stdcall Remote_NotifyDebugString( ULONG dwNotification, DWORD dwParam ); +extern DWORD __stdcall Remote_NotifyPrintFunc( const CHAR* strNotification ); +extern DWORD __stdcall Remote_NotifyCommandFunc( const CHAR* strNotification ); +extern int MatchRemoteCommands( char* cmdStr, const char* cmdList[], int maxCmds ); +extern remoteCommand_t* g_remoteCommands[]; +extern int g_numRemoteCommands; + +//----------------------------------------------------------------------------- +// BUG.CPP +//----------------------------------------------------------------------------- +extern bool BugDlg_Init( void ); +extern void BugDlg_Open( void ); +extern void BugReporter_FreeInterfaces(); +extern int rc_MapInfo( char* commandPtr ); + +//----------------------------------------------------------------------------- +// CONFIG.CPP +//----------------------------------------------------------------------------- +extern void ConfigDlg_Open( void ); +extern void ConfigDlg_LoadConfig(); + +//----------------------------------------------------------------------------- +// FILELOG.CPP +//----------------------------------------------------------------------------- +extern void FileLog_Open(); +extern bool FileLog_Init(); +extern void FileLog_Clear(); +extern unsigned int FileLog_AddItem( const char* filename, unsigned int fp ); +extern void FileLog_UpdateItem( unsigned int log, unsigned int fp, fileLogFunctions_e functionId, int value ); +extern void FileLog_SaveConfig(); +extern void FileLog_LoadConfig(); +extern bool g_fileLogEnable; + +//----------------------------------------------------------------------------- +// CPU_PROFILE.CPP +//----------------------------------------------------------------------------- +extern void CpuProfileSamples_Open(); +extern void CpuProfileHistory_Open(); +extern void CpuProfile_SetTitle(); +extern bool CpuProfile_Init(); +extern void CpuProfile_Clear(); +extern int rc_SetCpuProfile( char* commandPtr ); +extern int rc_SetCpuProfileData( char* commandPtr ); + +//----------------------------------------------------------------------------- +// TEX_PROFILE.CPP +//----------------------------------------------------------------------------- +extern void TexProfile_SetTitle(); +extern void TexProfileSamples_Open(); +extern void TexProfileHistory_Open(); +extern bool TexProfile_Init(); +extern int rc_SetTexProfile( char* commandPtr ); +extern int rc_SetTexProfileData( char* commandPtr ); + +//----------------------------------------------------------------------------- +// MEM_PROFILE.CPP +//----------------------------------------------------------------------------- +extern void MemProfile_Open(); +extern void MemProfile_SetTitle(); +extern bool MemProfile_Init(); +extern void MemProfile_Clear(); +extern int rc_FreeMemory( char* commandPtr ); + +//----------------------------------------------------------------------------- +// MEMLOG.CPP +//----------------------------------------------------------------------------- +extern void MemoryLog_Open(); +extern bool MemoryLog_Init(); +extern void MemoryLog_Clear(); +extern void MemoryLog_SaveConfig(); +extern void MemoryLog_LoadConfig(); +extern void MemoryLog_TreeView( bool enable ); +extern void MemoryLog_RefreshItems(); +extern int rc_MemoryLog( char* commandPtr ); +extern bool g_memoryLog_enable; + +//----------------------------------------------------------------------------- +// SYNC_FILES.CPP +//----------------------------------------------------------------------------- +extern int FileSyncEx( const char* localFilename, const char* remoteFilename, int fileSyncMode, bool bVerbose, bool bNoWrite ); +extern bool SyncFilesDlg_Init( void ); +extern void SyncFilesDlg_Open( void ); +extern void InstallDlg_Open( void ); + +//----------------------------------------------------------------------------- +// FILEIO.CPP +//----------------------------------------------------------------------------- +extern int CompareFileTimes_NTFStoFATX( FILETIME* ntfsFileTime, char *ntfsTimeString, int ntfsStringSize, FILETIME* fatxFileTime, char *fatxTimeString, int fatxStringSize ); +extern bool LoadTargetFile( const char *pTargetPath, int *pFileSize, void **pData ); + +//----------------------------------------------------------------------------- +// PROGRESS.CPP +//----------------------------------------------------------------------------- +extern bool Progress_Init(); + +//----------------------------------------------------------------------------- +// SHOW_TEXTURES.CPP +//----------------------------------------------------------------------------- +extern void ShowTextures_Open(); +extern bool ShowTextures_Init(); +extern int rc_TextureList( char* commandPtr ); + +//----------------------------------------------------------------------------- +// TIMESTAMP_LOG.CPP +//----------------------------------------------------------------------------- +extern void TimeStampLog_Open(); +extern bool TimeStampLog_Init(); +extern void TimeStampLog_Clear(); +extern int rc_TimeStampLog( char* commandPtr ); + +//----------------------------------------------------------------------------- +// COMMON.CPP +//----------------------------------------------------------------------------- +extern vprofState_e VProf_GetState(); +extern void VProf_Enable( vprofState_e state ); + +//----------------------------------------------------------------------------- +// SHOW_MATERIALS.CPP +//----------------------------------------------------------------------------- +extern void ShowMaterials_Open(); +extern bool ShowMaterials_Init(); +extern int rc_MaterialList( char* commandPtr ); + +//----------------------------------------------------------------------------- +// SHOW_SOUNDS.CPP +//----------------------------------------------------------------------------- +extern void ShowSounds_Open(); +extern bool ShowSounds_Init(); +extern int rc_SoundList( char* commandPtr ); + +//----------------------------------------------------------------------------- +// SHOW_MEMDUMP.CPP +//----------------------------------------------------------------------------- +extern void ShowMemDump_Open(); +extern bool ShowMemDump_Init(); +extern int rc_MemDump( char* commandPtr ); + +//----------------------------------------------------------------------------- +// EXCLUDE_PATHS.CPP +//----------------------------------------------------------------------------- +extern bool ExcludePathsDlg_Init( void ); +extern void ExcludePathsDlg_Open( void ); + +//----------------------------------------------------------------------------- +// ASSERT_DIALOG.CPP +//----------------------------------------------------------------------------- +extern bool g_AssertDialogActive; +int rc_Assert( char *commandPtr ); diff --git a/utils/xbox/vxconsole/vxconsole.ico b/utils/xbox/vxconsole/vxconsole.ico Binary files differnew file mode 100644 index 0000000..48c0d4c --- /dev/null +++ b/utils/xbox/vxconsole/vxconsole.ico diff --git a/utils/xbox/vxconsole/vxconsole.rc b/utils/xbox/vxconsole/vxconsole.rc new file mode 100644 index 0000000..2e62120 --- /dev/null +++ b/utils/xbox/vxconsole/vxconsole.rc @@ -0,0 +1,557 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_VXCONSOLE ICON "VXConsole.ico" +IDI_CONNECT1_ON ICON "icon_connect1.ico" +IDI_DISCONNECTED ICON "icon_disconnect.ico" +IDI_CONNECT2_OFF ICON "icon_connect2.ico" +IDI_CONNECT2_ON ICON "icon_connect2a.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_VXCONSOLE DIALOGEX 7, 18, 416, 203 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CLIENTEDGE +MENU MENU_VXCONSOLE +CLASS "VXConsole" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + COMBOBOX IDC_COMMAND,26,182,386,130,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP + LTEXT "&Cmd:",IDC_LABEL,5,184,17,8,SS_CENTERIMAGE + CONTROL "",IDC_OUTPUT,"RichEdit20A",ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_NOHIDESEL | ES_READONLY | WS_BORDER | WS_VSCROLL | WS_HSCROLL,5,7,404,170 +END + +IDD_CONFIG DIALOGEX 0, 0, 412, 151 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDC_OK,355,130,50,14 + PUSHBUTTON "Cancel",IDC_CANCEL,296,130,50,14 + LTEXT "Target XBox Name:",IDC_STATIC,7,7,126,9 + EDITTEXT IDC_CONFIG_XBOXNAME,7,18,148,13,ES_AUTOHSCROLL + PUSHBUTTON "Ping",IDC_CONFIG_PING,163,18,43,13 + CONTROL "Clear Log On Connect",IDC_CONFIG_CLEARONCONNECT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,17,149,12 + CONTROL "Always Auto-Connect At Startup",IDC_CONFIG_ALWAYSAUTOCONNECT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,33,149,12 + CONTROL "Start Minimized",IDC_CONFIG_STARTMINIMIZED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,49,149,12 + EDITTEXT IDC_CONFIG_INSTALLPATH,7,117,199,13,ES_AUTOHSCROLL + LTEXT "PC Local Game Path: (Example: u:\\dev\\game)",IDC_STATIC,7,37,199,9 + EDITTEXT IDC_CONFIG_LOCALPATH,7,49,199,13,ES_AUTOHSCROLL + LTEXT "XBox Target HDD Path: (Example: e:\\valve)",IDC_STATIC,7,70,199,9 + EDITTEXT IDC_CONFIG_TARGETPATH,7,81,199,13,ES_AUTOHSCROLL + LTEXT "Installation Depot:",IDC_STATIC,7,105,116,9 + CONTROL "Enable Capture Debug Spew At Startup",IDC_CONFIG_CAPTUREDEBUGSPEW, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,65,149,12 +END + +IDD_SYNCFILES DIALOGEX 0, 0, 227, 154 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Sync Files" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Sync",IDC_OK,170,132,50,14 + PUSHBUTTON "Cancel",IDC_CANCEL,111,132,50,14 + LTEXT "XBox Target Path (To):",IDC_STATIC,7,39,116,9 + EDITTEXT IDC_SYNCFILES_TARGETPATH,7,51,213,13,ES_AUTOHSCROLL + LTEXT "PC Source Path (From):",IDC_STATIC,7,7,142,9 + EDITTEXT IDC_SYNCFILES_LOCALPATH,7,19,213,13,ES_AUTOHSCROLL + CONTROL "Force Sync",IDC_SYNCFILES_FORCESYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,89,116,10 + CONTROL "Skip Writing Files (Test Mode)",IDC_SYNCFILES_NOWRITE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,105,116,10 + CONTROL "Verbose",IDC_SYNCFILES_VERBOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,73,116,10 +END + +IDD_MODIFYBIND DIALOGEX 0, 0, 260, 106 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDC_OK,202,86,50,14 + PUSHBUTTON "Cancel",IDCANCEL,144,86,50,14 + LTEXT "Key:",IDC_STATIC,7,7,16,8 + LTEXT "Static",IDC_MODIFYBIND_KEYCODE,28,7,51,8 + LTEXT "Menu Name:",IDC_STATIC,7,21,41,8 + EDITTEXT IDC_MODIFYBIND_MENUNAME,7,31,245,14,ES_AUTOHSCROLL + LTEXT "Command:",IDC_STATIC,7,50,35,8 + EDITTEXT IDC_MODIFYBIND_COMMAND,7,60,243,14,ES_AUTOHSCROLL +END + +IDD_BUG DIALOGEX 0, 0, 441, 375 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Bug Reporter" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_BUG_TITLE,70,7,361,14,ES_AUTOHSCROLL + EDITTEXT IDC_BUG_DESCRIPTION,70,26,361,90,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL + PUSHBUTTON "Take Shot",IDC_BUG_TAKESHOT,7,122,56,14 + PUSHBUTTON "Save Game",IDC_BUG_SAVEGAME,7,141,56,14 + PUSHBUTTON "Include .bsp",IDC_BUG_INCLUDEBSP,7,159,56,14 + PUSHBUTTON "Include .vmf",IDC_BUG_INCLUDEVMF,7,178,56,14 + CONTROL "Compress Screenshot",IDC_BUG_COMPRESS_SCREENSHOT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,70,298,104,10 + COMBOBOX IDC_BUG_OWNER,282,202,152,195,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_BUG_SEVERITY,282,221,152,77,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_BUG_REPORTTYPE,282,240,152,76,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_BUG_PRIORITY,282,259,152,76,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_BUG_GAME,282,278,152,195,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_BUG_AREA,282,297,152,125,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_BUG_MAPNUMBER,282,316,152,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Clear Form",IDC_BUG_CLEARFORM,7,354,50,14 + PUSHBUTTON "Update",IDC_BUG_UPDATE,67,354,50,14 + PUSHBUTTON "Cancel",IDC_CANCEL,321,354,50,14 + DEFPUSHBUTTON "Submit",IDC_BUG_SUBMIT,384,354,50,14 + LTEXT "Title:",IDC_STATIC,7,7,45,8 + LTEXT "Description:",IDC_STATIC,7,26,45,8 + LTEXT "Position:",IDC_STATIC,7,204,44,8 + LTEXT "Orientation:",IDC_STATIC,7,223,44,8 + LTEXT "Map:",IDC_STATIC,7,242,44,8 + LTEXT "Build:",IDC_STATIC,7,261,44,8 + LTEXT "Submitter:",IDC_STATIC,7,280,40,8 + LTEXT "",IDC_BUG_POSITION_LABEL,70,201,152,14,SS_SUNKEN + LTEXT "",IDC_BUG_ORIENTATION_LABEL,70,220,152,14,SS_SUNKEN + LTEXT "",IDC_BUG_MAP_LABEL,70,239,152,14,SS_SUNKEN + LTEXT "",IDC_BUG_BUILD_LABEL,70,258,152,14,SS_SUNKEN + LTEXT "",IDC_BUG_SUBMITTER_LABEL,70,277,152,14,SS_SUNKEN + LTEXT "Owner:",IDC_STATIC,232,204,40,8 + LTEXT "Severity:",IDC_STATIC,232,223,40,8 + LTEXT "Report Type:",IDC_STATIC,232,242,44,8 + LTEXT "Priority:",IDC_STATIC,232,261,26,8 + LTEXT "Game:",IDC_STATIC,231,280,40,8 + LTEXT "Area:",IDC_STATIC,232,299,19,8 + LTEXT "Map Number:",IDC_STATIC,232,318,44,8 + LTEXT "",IDC_BUG_TAKESHOT_LABEL,70,122,364,14,SS_SUNKEN | SS_PATHELLIPSIS + LTEXT "",IDC_BUG_SAVEGAME_LABEL,70,141,364,14,SS_SUNKEN | SS_PATHELLIPSIS + LTEXT "",IDC_BUG_INCLUDEBSP_LABEL,70,159,364,14,SS_SUNKEN | SS_PATHELLIPSIS + LTEXT "",IDC_BUG_INCLUDEVMF_LABEL,70,178,364,14,SS_SUNKEN | SS_PATHELLIPSIS +END + +IDD_EXCLUDEPATHS DIALOGEX 0, 0, 412, 313 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Exclude Xbox HDD Paths" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_PATHS_TREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_CHECKBOXES | WS_BORDER | WS_TABSTOP,7,7,398,276,WS_EX_CLIENTEDGE + PUSHBUTTON "Re-Scan",IDC_PATHS_RESCAN,7,292,50,14 + PUSHBUTTON "Expand All",IDC_PATHS_EXPAND,64,292,50,14 + PUSHBUTTON "Collapse All",IDC_PATHS_COLLAPSE,122,292,50,14 + PUSHBUTTON "Cancel",IDC_CANCEL,294,292,50,14 + DEFPUSHBUTTON "OK",IDC_OK,355,292,50,14 + CONTROL "Link Game Directories",IDC_PATHS_LINKGAMEDIRS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,188,294,91,10 +END + +IDD_INSTALL DIALOGEX 0, 0, 492, 261 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Sync to DVD Image" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_INSTALL_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,477,215 + PUSHBUTTON "Refresh",IDC_INSTALL_REFRESH,7,234,50,14 + CONTROL "Force Sync",IDC_INSTALL_FORCESYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,236,51,10 + CONTROL "Exact Image (Deletes Unrelated Files)",IDC_INSTALL_CLEANTARGET, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,185,236,137,10 + PUSHBUTTON "Cancel",IDC_CANCEL,373,234,50,14 + DEFPUSHBUTTON "OK",IDC_OK,434,234,50,14 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_MAIN_ACCEL ACCELERATORS +BEGIN + "X", IDM_AUTOCONNECT, VIRTKEY, CONTROL, NOINVERT + "H", IDM_PROFILEHISTORY, VIRTKEY, CONTROL, NOINVERT + "S", IDM_PROFILESAMPLES, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MENU_VXCONSOLE MENU +BEGIN + POPUP "Main" + BEGIN + MENUITEM "Configuration..", IDM_CONFIG + MENUITEM SEPARATOR + MENUITEM "Exit", IDM_EXIT + END + POPUP "Connection" + BEGIN + MENUITEM "Capture Game Spew", IDM_CAPTUREGAMESPEW + MENUITEM "Capture Debug Spew", IDM_CAPTUREDEBUGSPEW + MENUITEM "Show Remote Command Traffic", IDM_DEBUGCOMMANDS + MENUITEM SEPARATOR + MENUITEM "Bug Reporter...", IDM_BUG + MENUITEM SEPARATOR + MENUITEM "Sync Xbox HDD Files...", IDM_SYNCFILES + MENUITEM "Sync Xbox HDD To DVD Image...", IDM_SYNCINSTALL + MENUITEM SEPARATOR + MENUITEM "Exclude Xbox HDD Paths...", IDM_EXCLUDEPATHS + MENUITEM SEPARATOR + MENUITEM "&Auto Connect\tCtrl+X", IDM_AUTOCONNECT + END + POPUP "Profiling" + BEGIN + MENUITEM "TimeStamp Log", IDM_TIMESTAMPLOG + MENUITEM "Memory Dump", IDM_MEMORYDUMP + MENUITEM SEPARATOR + POPUP "Show CPU Usage" + BEGIN + MENUITEM "Snapshot", IDM_CPU_SAMPLES + MENUITEM " History", IDM_CPU_HISTORY + END + POPUP "Show D3D Usage" + BEGIN + MENUITEM "Snapshot", IDM_D3D_SAMPLES + MENUITEM "History", IDM_D3D_HISTORY + END + MENUITEM "Show Memory Usage", IDM_SHOWMEMORYUSAGE + MENUITEM SEPARATOR + MENUITEM "Playtest Mode", IDM_PLAYTESTMODE + END + POPUP "Resources" + BEGIN + MENUITEM "List Materials", IDM_SHOWRESOURCES_MATERIALS + MENUITEM "List Models", IDM_SHOWRESOURCES_MODELS + MENUITEM "List Textures", IDM_SHOWRESOURCES_TEXTURES + MENUITEM "List Sounds", IDM_SHOWRESOURCES_SOUNDS + END +END + +MENU_CPUPROFILE MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Tick Marks", IDM_CPUPROFILE_TICKMARKS + MENUITEM "Colors", IDM_CPUPROFILE_COLORS + MENUITEM "FPS", IDM_CPUPROFILE_FPSLABELS + MENUITEM SEPARATOR + MENUITEM "Zoom In\tINS", IDM_CPUPROFILE_ZOOMIN + MENUITEM "Zoom Out\tDEL", IDM_CPUPROFILE_ZOOMOUT + MENUITEM SEPARATOR + MENUITEM "Enable", IDM_CPUPROFILE_ENABLE + END +END + +MENU_SHOWTEXTURES MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Summary...", IDM_OPTIONS_SUMMARY + MENUITEM "Refresh", IDM_OPTIONS_REFRESH + MENUITEM "Export...", IDM_OPTIONS_EXPORT + MENUITEM SEPARATOR + MENUITEM "Current Frame", IDM_OPTIONS_CURRENTFRAME + MENUITEM "Full Path", IDM_OPTIONS_FULLPATH + MENUITEM SEPARATOR + MENUITEM "Draw Texture", IDM_OPTIONS_DRAWTEXTURE + END +END + +MENU_TEXPROFILE MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Tick Marks", IDM_TEXPROFILE_TICKMARKS + MENUITEM "Colors", IDM_TEXPROFILE_COLORS + MENUITEM SEPARATOR + MENUITEM "Zoom In\tINS", IDM_TEXPROFILE_ZOOMIN + MENUITEM "Zoom Out\tDEL", IDM_TEXPROFILE_ZOOMOUT + MENUITEM SEPARATOR + MENUITEM "Current Frame", IDM_TEXPROFILE_CURRENTFRAME + MENUITEM "Enable", IDM_TEXPROFILE_ENABLE + END +END + +MENU_BINDOPTIONS MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Modify...", IDM_BINDOPTIONS_MODIFY + MENUITEM "Delete", IDM_BINDOPTIONS_DELETE + END +END + +MENU_SHOWMATERIALS MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Refresh", IDM_OPTIONS_REFRESH + MENUITEM "Export", IDM_OPTIONS_EXPORT + MENUITEM SEPARATOR + MENUITEM "Current Frame", IDM_OPTIONS_CURRENTFRAME + END +END + +MENU_SHOWSOUNDS MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Summary...", IDM_OPTIONS_SUMMARY + MENUITEM "Refresh", IDM_OPTIONS_REFRESH + MENUITEM "Export...", IDM_OPTIONS_EXPORT + MENUITEM SEPARATOR + MENUITEM "Play", IDM_OPTIONS_PLAYSOUND + END +END + +MENU_SHOWMEMORYDUMP MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Refresh", IDM_OPTIONS_REFRESH + MENUITEM "Export...", IDM_OPTIONS_EXPORT + MENUITEM "Summary...", IDM_OPTIONS_SUMMARY + MENUITEM SEPARATOR + MENUITEM "Size as Bytes", IDM_OPTIONS_BYTES + MENUITEM "Size as KB", IDM_OPTIONS_KILOBYTES + MENUITEM "Size as MB", IDM_OPTIONS_MEGABYTES + MENUITEM "Collapse Output", IDM_OPTIONS_COLLAPSEOUTPUT + END +END + +MENU_TIMESTAMPLOG MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Clear", IDM_OPTIONS_CLEAR + MENUITEM "Export", IDM_OPTIONS_EXPORT + END +END + +MENU_MEMPROFILE MENU +BEGIN + POPUP "Options" + BEGIN + MENUITEM "Tick Marks", IDM_MEMPROFILE_TICKMARKS + MENUITEM "Colors", IDM_MEMPROFILE_COLORS + MENUITEM SEPARATOR + MENUITEM "Zoom In\tINS", IDM_MEMPROFILE_ZOOMIN + MENUITEM "Zoom Out\t INS", IDM_MEMPROFILE_ZOOMOUT + MENUITEM SEPARATOR + MENUITEM "Enable", IDM_MEMPROFILE_ENABLE + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 405 + TOPMARGIN, 7 + BOTTOMMARGIN, 144 + END + + IDD_SYNCFILES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 220 + TOPMARGIN, 7 + BOTTOMMARGIN, 146 + END + + IDD_MODIFYBIND, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 252 + TOPMARGIN, 7 + BOTTOMMARGIN, 99 + END + + IDD_BUG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 434 + TOPMARGIN, 7 + BOTTOMMARGIN, 368 + END + + IDD_EXCLUDEPATHS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 405 + TOPMARGIN, 7 + BOTTOMMARGIN, 306 + END + + IDD_INSTALL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 485 + TOPMARGIN, 7 + BOTTOMMARGIN, 254 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + 10004 "Interrupted system call." + 10009 "Bad file number." + 10013 "Permission denied." + 10014 "Bad address." +END + +STRINGTABLE +BEGIN + 10022 "Invalid argument." + 10024 "Too many open files." +END + +STRINGTABLE +BEGIN + 10035 "Operation would block." + 10036 "Operation now in progress." + 10037 "Operation already in progress." + 10038 "Socket operation on nonsocket." + 10039 "Destination address required." + 10040 "Message too long." + 10041 "Protocol wrong type for socket." + 10042 "Protocol not available." + 10043 "Protocol not supported." + 10044 "Socket type not supported." + 10045 "Operation not supported on socket." + 10046 "Protocol family not supported." + 10047 "Address family not supported by protocol family." +END + +STRINGTABLE +BEGIN + 10048 "Address already in use." + 10049 "Cannot assign requested address." + 10050 "Network is down." + 10051 "Network is unreachable." + 10052 "Network dropped connection on reset." + 10053 "Software caused connection abort." + 10054 "Connection reset by peer." + 10055 "No buffer space available." + 10056 "Socket is already connected." + 10057 "Socket is not connected." + 10058 "Cannot send after socket shutdown." + 10059 "Too many references: cannot splice." + 10060 "Connection timed out." + 10061 "Connection refused." + 10062 "Too many levels of symbolic links." + 10063 "File name too long." +END + +STRINGTABLE +BEGIN + 10064 "Host is down." + 10065 "No route to host." +END + +STRINGTABLE +BEGIN + 10091 "The network subsystem is unusable." + 10092 "The Windows Sockets DLL cannot support this application." + 10093 "Winsock not initialized." +END + +STRINGTABLE +BEGIN + 10101 "Disconnect." +END + +STRINGTABLE +BEGIN + 11001 "Host not found." + 11002 "Nonauthoritative host not found. Name service maybe not be functioning." + 11003 "Nonrecoverable error. Name service maybe not be functioning." + 11004 "Valid name, no data record of requested type." +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/utils/xbox/vxconsole/vxconsole.vpc b/utils/xbox/vxconsole/vxconsole.vpc new file mode 100644 index 0000000..5e9424c --- /dev/null +++ b/utils/xbox/vxconsole/vxconsole.vpc @@ -0,0 +1,85 @@ +//----------------------------------------------------------------------------- +// VXCONSOLE.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_win_win32_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;$SRCDIR\x360xdk\include\win32\vs2005" + } + + $Linker + { + $AdditionalDependencies "wsock32.lib comctl32.lib odbc32.lib odbccp32.lib xbdm.lib" + $AdditionalLibraryDirectories "$SRCDIR\x360xdk\lib\win32\vs2005" + $DelayLoadedDLLs "xbdm.dll" + } +} + +$Project "VXConsole" +{ + $Folder "Source Files" + { + $File "bindings.cpp" + $File "bug.cpp" + $File "common.cpp" + $File "config.cpp" + $File "cpu_profile.cpp" + $File "exclude_paths.cpp" + $File "fileio.cpp" + $File "local_cmds.cpp" + $File "progress.cpp" + $File "remote_cmds.cpp" + $File "show_materials.cpp" + $File "show_memdump.cpp" + $File "show_sounds.cpp" + $File "show_textures.cpp" + $File "sync_files.cpp" + $File "sys_scriptlib.cpp" + $File "sys_utils.cpp" + $File "tex_profile.cpp" + $File "timestamp_log.cpp" + $File "vxconsole.cpp" + $File "assert_dialog.cpp" + $File "mem_profile.cpp" + } + + $Folder "Header Files" + { + $File "$SRCDIR\common\bugreporter\bugreporter.h" + $File "$SRCDIR\common\xbox\xbox_vxconsole.h" + $File "$SRCDIR\public\tier1\interface.h" + $File "$SRCDIR\public\jpeglib\jpeglib.h" + $File "$SRCDIR\public\tier0\platform.h" + $File "$SRCDIR\public\tier1\strtools.h" + $File "resource.h" + $File "assert_resource.h" + $File "sys_scriptlib.h" + $File "sys_utils.h" + $File "vxconsole.h" + } + + $Folder "Resource Files" + { + $File "icon_connect1.ico" + $File "icon_connect2.ico" + $File "icon_connect2a.ico" + $File "icon_disconnect.ico" + $File "vxconsole.ico" + $File "vxconsole.rc" + $File "assert_dialog.rc" + } + + $Folder "Link Libraries" + { + $DynamicFile "$SRCDIR\lib\common\jpeglib.lib" + } +} diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_english.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_english.tga Binary files differnew file mode 100644 index 0000000..5c61f95 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_english.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_french.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_french.tga Binary files differnew file mode 100644 index 0000000..0116d18 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_french.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_german.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_german.tga Binary files differnew file mode 100644 index 0000000..629524e --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_german.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_italian.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_italian.tga Binary files differnew file mode 100644 index 0000000..c37b3a2 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_italian.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_spanish.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_spanish.tga Binary files differnew file mode 100644 index 0000000..a935072 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_spanish.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LoadingIcon.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LoadingIcon.tga Binary files differnew file mode 100644 index 0000000..ae2134d --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LoadingIcon.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/SourceScreen.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/SourceScreen.tga Binary files differnew file mode 100644 index 0000000..4acd064 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/SourceScreen.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.abc b/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.abc Binary files differnew file mode 100644 index 0000000..bcbc925 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.abc diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.tga Binary files differnew file mode 100644 index 0000000..103fb95 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/footer.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/footer.tga Binary files differnew file mode 100644 index 0000000..340f4a5 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/footer.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.bmp b/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.bmp Binary files differnew file mode 100644 index 0000000..29e905e --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.bmp diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.rdf b/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.rdf new file mode 100644 index 0000000..e31fa3a --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.rdf @@ -0,0 +1,7 @@ +Texture MyTex +{ + Source loader_icon.bmp + Format D3DFMT_DXT1 + Width 128 + Height 128 +} diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_english.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_english.tga Binary files differnew file mode 100644 index 0000000..b45b3a1 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_english.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_french.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_french.tga Binary files differnew file mode 100644 index 0000000..2963e36 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_french.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_german.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_german.tga Binary files differnew file mode 100644 index 0000000..2636bec --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_german.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_italian.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_italian.tga Binary files differnew file mode 100644 index 0000000..a09efae --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_italian.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_spanish.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_spanish.tga Binary files differnew file mode 100644 index 0000000..ade8343 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_spanish.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow2.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow2.tga Binary files differnew file mode 100644 index 0000000..52e952b --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow2.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow3.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow3.tga Binary files differnew file mode 100644 index 0000000..76b3700 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow3.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow4.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow4.tga Binary files differnew file mode 100644 index 0000000..1bc591d --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow4.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow5.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow5.tga Binary files differnew file mode 100644 index 0000000..040a8ac --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow5.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow6.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow6.tga Binary files differnew file mode 100644 index 0000000..1edbb6e --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow6.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow7.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow7.tga Binary files differnew file mode 100644 index 0000000..4f47769 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow7.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow8.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow8.tga Binary files differnew file mode 100644 index 0000000..30dabe8 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow8.tga diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow9.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow9.tga Binary files differnew file mode 100644 index 0000000..a9cfb82 --- /dev/null +++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow9.tga diff --git a/utils/xbox/xbox_loader/loader.rdf b/utils/xbox/xbox_loader/loader.rdf new file mode 100644 index 0000000..33e7552 --- /dev/null +++ b/utils/xbox/xbox_loader/loader.rdf @@ -0,0 +1,173 @@ +// List of resources to bundle. +// +// The output will be a header file (.h) used at compile time, +// and a packed resource file (.xpr) used at runtime. + +out_packedresource LoaderMedia\loader.xpr +out_error loader.err + +Texture Font +{ + Source LoaderMedia_Source\Tahoma_16.tga + Format D3DFMT_A4R4G4B4 + Levels 1 +} + +UserData FontData +{ + DataFile LoaderMedia_Source\Tahoma_16.abc +} + +Texture Footer +{ + Source LoaderMedia_Source\Footer.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture MainLegal_english +{ + Source LoaderMedia_Source\LegalScreen_english.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture MainLegal_french +{ + Source LoaderMedia_Source\LegalScreen_french.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture MainLegal_italian +{ + Source LoaderMedia_Source\LegalScreen_italian.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture MainLegal_german +{ + Source LoaderMedia_Source\LegalScreen_german.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture MainLegal_spanish +{ + Source LoaderMedia_Source\LegalScreen_spanish.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SourceLegal +{ + Source LoaderMedia_Source\SourceScreen.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture LoadingIcon +{ + Source LoaderMedia_Source\LoadingIcon.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow1_english +{ + Source LoaderMedia_Source\SlideShow1_english.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow1_french +{ + Source LoaderMedia_Source\SlideShow1_french.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow1_italian +{ + Source LoaderMedia_Source\SlideShow1_italian.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow1_german +{ + Source LoaderMedia_Source\SlideShow1_german.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow1_spanish +{ + Source LoaderMedia_Source\SlideShow1_spanish.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow2 +{ + Source LoaderMedia_Source\SlideShow2.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow3 +{ + Source LoaderMedia_Source\SlideShow3.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow4 +{ + Source LoaderMedia_Source\SlideShow4.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow5 +{ + Source LoaderMedia_Source\SlideShow5.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow6 +{ + Source LoaderMedia_Source\SlideShow6.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow7 +{ + Source LoaderMedia_Source\SlideShow7.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow8 +{ + Source LoaderMedia_Source\SlideShow8.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + +Texture SlideShow9 +{ + Source LoaderMedia_Source\SlideShow9.tga + Format D3DFMT_LIN_A8R8G8B8 + Levels 1 +} + + + + + + + diff --git a/utils/xbox/xbox_loader/xbox_fileCopy.cpp b/utils/xbox/xbox_loader/xbox_fileCopy.cpp new file mode 100644 index 0000000..39d0c65 --- /dev/null +++ b/utils/xbox/xbox_loader/xbox_fileCopy.cpp @@ -0,0 +1,595 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Copies a file using overlapped async IO. +// +// Stub executeable +//=====================================================================================// +#include "xbox_loader.h" + +#define BUFFER_SIZE (1*1024*1024) +#define NUM_BUFFERS 4 +#define ALIGN(x,y) (((x)+(y)-1) & ~((y)-1)) + +struct CopyFile_t +{ + // source file + HANDLE m_hSrcFile; + DWORD m_srcFileSize; + int m_readBufferSize; + unsigned int m_numReadCycles; + + // target file + HANDLE m_hDstFile; + DWORD m_dstFileSize; + + // source file gets decompressed + bool m_bInflate; + unsigned char *m_pInflateBuffer; + int m_inflateBufferSize; + + bool m_bCopyError; + CopyStats_t *m_pCopyStats; +}; + +struct Buffer_t +{ + unsigned char *pData; + DWORD dwSize; + Buffer_t* pNext; + int id; +}; + +Buffer_t *g_pReadBuffers = NULL; +Buffer_t *g_pWriteBuffers = NULL; + +CRITICAL_SECTION g_criticalSection; +HANDLE g_hReadEvent; +HANDLE g_hWriteEvent; +DWORD *g_pNumReadBuffers; +DWORD *g_pNumWriteBuffers; + +//----------------------------------------------------------------------------- +// CreateFilePath +// +// Create full path to specified file. +//----------------------------------------------------------------------------- +bool CreateFilePath( const char *inPath ) +{ + char* ptr; + char dirPath[MAX_PATH]; + BOOL bSuccess; + + // prime and skip to first seperator after the drive path + strcpy( dirPath, inPath ); + ptr = strchr( dirPath, '\\' ); + while ( ptr ) + { + ptr = strchr( ptr+1, '\\' ); + if ( ptr ) + { + *ptr = '\0'; + bSuccess = ::CreateDirectory( dirPath, NULL ); + *ptr = '\\'; + } + } + + // ensure read-only is cleared + SetFileAttributes( inPath, FILE_ATTRIBUTE_NORMAL ); + + return true; +} + +//----------------------------------------------------------------------------- +// LockBufferForRead +// +//----------------------------------------------------------------------------- +Buffer_t *LockBufferForRead() +{ + if ( !g_pReadBuffers ) + { + // out of data, wait for it + WaitForSingleObject( g_hReadEvent, INFINITE ); + } + else + { + ResetEvent( g_hReadEvent ); + } + + EnterCriticalSection( &g_criticalSection ); + + Buffer_t *pBuffer = g_pReadBuffers; + g_pReadBuffers = pBuffer->pNext; + + (*g_pNumReadBuffers)--; + + LeaveCriticalSection( &g_criticalSection ); + + return pBuffer; +} + +//----------------------------------------------------------------------------- +// LockBufferForWrite +// +//----------------------------------------------------------------------------- +Buffer_t* LockBufferForWrite() +{ + if ( !g_pWriteBuffers ) + { + // out of data, wait for more + WaitForSingleObject( g_hWriteEvent, INFINITE ); + } + else + { + ResetEvent( g_hWriteEvent ); + } + + EnterCriticalSection( &g_criticalSection ); + + Buffer_t *pBuffer = g_pWriteBuffers; + g_pWriteBuffers = pBuffer->pNext; + + (*g_pNumWriteBuffers)--; + + LeaveCriticalSection( &g_criticalSection ); + + return pBuffer; +} + +//----------------------------------------------------------------------------- +// AddBufferForRead +// +//----------------------------------------------------------------------------- +void AddBufferForRead( Buffer_t *pBuffer ) +{ + EnterCriticalSection( &g_criticalSection ); + + // add to end of list + Buffer_t *pCurrent = g_pReadBuffers; + while ( pCurrent && pCurrent->pNext ) + { + pCurrent = pCurrent->pNext; + } + if ( pCurrent ) + { + pBuffer->pNext = pCurrent->pNext; + pCurrent->pNext = pBuffer; + } + else + { + pBuffer->pNext = NULL; + g_pReadBuffers = pBuffer; + } + + (*g_pNumReadBuffers)++; + + LeaveCriticalSection( &g_criticalSection ); + + SetEvent( g_hReadEvent ); +} + +//----------------------------------------------------------------------------- +// AddBufferForWrite +// +//----------------------------------------------------------------------------- +void AddBufferForWrite( Buffer_t *pBuffer ) +{ + EnterCriticalSection( &g_criticalSection ); + + // add to end of list + Buffer_t* pCurrent = g_pWriteBuffers; + while ( pCurrent && pCurrent->pNext ) + { + pCurrent = pCurrent->pNext; + } + if ( pCurrent ) + { + pBuffer->pNext = pCurrent->pNext; + pCurrent->pNext = pBuffer; + } + else + { + pBuffer->pNext = NULL; + g_pWriteBuffers = pBuffer; + } + + (*g_pNumWriteBuffers)++; + + LeaveCriticalSection( &g_criticalSection ); + + SetEvent( g_hWriteEvent ); +} + +//----------------------------------------------------------------------------- +// ReadFileThread +// +//----------------------------------------------------------------------------- +DWORD WINAPI ReadFileThread( LPVOID lParam ) +{ + CopyFile_t *pCopyFile; + OVERLAPPED overlappedRead = {0}; + DWORD startTime; + DWORD dwBytesRead; + DWORD dwError; + BOOL bResult; + Buffer_t *pBuffer; + + pCopyFile = (CopyFile_t*)lParam; + + // Copy from the buffer to the Hard Drive + for ( unsigned int readCycle = 0; readCycle < pCopyFile->m_numReadCycles; ++readCycle ) + { + pBuffer = LockBufferForRead(); + + startTime = GetTickCount(); + dwBytesRead = 0; + + int numAttempts = 0; +retry: + // read file from DVD + bResult = ReadFile( pCopyFile->m_hSrcFile, pBuffer->pData, pCopyFile->m_readBufferSize, NULL, &overlappedRead ); + dwError = GetLastError(); + if ( !bResult && dwError != ERROR_IO_PENDING ) + { + if ( dwError == ERROR_HANDLE_EOF ) + { + // nothing more to read + break; + } + + numAttempts++; + if ( numAttempts == 3 ) + { + // error + pCopyFile->m_bCopyError = true; + break; + } + else + { + goto retry; + } + } + else + { + // Wait for the operation to finish + GetOverlappedResult( pCopyFile->m_hSrcFile, &overlappedRead, &dwBytesRead, TRUE ); + overlappedRead.Offset += dwBytesRead; + } + + if ( !dwBytesRead ) + { + pCopyFile->m_bCopyError = true; + break; + } + + pCopyFile->m_pCopyStats->m_bufferReadSize = dwBytesRead; + pCopyFile->m_pCopyStats->m_bufferReadTime = GetTickCount() - startTime; + pCopyFile->m_pCopyStats->m_totalReadSize += pCopyFile->m_pCopyStats->m_bufferReadSize; + pCopyFile->m_pCopyStats->m_totalReadTime += pCopyFile->m_pCopyStats->m_bufferReadTime; + + pBuffer->dwSize = dwBytesRead; + AddBufferForWrite( pBuffer ); + } + + return 0; +} + +//----------------------------------------------------------------------------- +// WriteFileThread +// +//----------------------------------------------------------------------------- +DWORD WINAPI WriteFileThread( LPVOID lParam ) +{ + CopyFile_t *pCopyFile; + OVERLAPPED overlappedWrite = {0}; + DWORD startTime; + DWORD dwBytesWrite; + DWORD dwWriteSize; + DWORD dwError; + BOOL bResult; + Buffer_t *pBuffer; + unsigned char *pWriteBuffer; + + pCopyFile = (CopyFile_t*)lParam; + + while ( overlappedWrite.Offset < pCopyFile->m_dstFileSize ) + { + // wait for wake-up event + pBuffer = LockBufferForWrite(); + + if ( pCopyFile->m_bInflate ) + { + startTime = GetTickCount(); + + DWORD dwSkip = overlappedWrite.Offset ? 0 : sizeof( xCompressHeader ); + dwWriteSize = JCALG1_Decompress_Formatted_Buffer( pBuffer->dwSize - dwSkip, pBuffer->pData + dwSkip, pCopyFile->m_inflateBufferSize, pCopyFile->m_pInflateBuffer ); + if ( dwWriteSize == (DWORD)-1 ) + { + pCopyFile->m_bCopyError = true; + break; + } + + pCopyFile->m_pCopyStats->m_inflateSize = dwWriteSize; + pCopyFile->m_pCopyStats->m_inflateTime = GetTickCount() - startTime; + + pWriteBuffer = pCopyFile->m_pInflateBuffer; + } + else + { + // straight copy + dwWriteSize = pBuffer->dwSize; + pWriteBuffer = pBuffer->pData; + } + + if ( overlappedWrite.Offset + dwWriteSize >= pCopyFile->m_dstFileSize ) + { + // last buffer, ensure all data is written + dwWriteSize = ALIGN( dwWriteSize, 512 ); + } + + startTime = GetTickCount(); + dwBytesWrite = 0; + + int numAttempts = 0; +retry: + // write file to HDD + bResult = WriteFile( pCopyFile->m_hDstFile, pWriteBuffer, (dwWriteSize/512) * 512, NULL, &overlappedWrite ); + dwError = GetLastError(); + if ( !bResult && dwError != ERROR_IO_PENDING ) + { + numAttempts++; + if ( numAttempts == 3 ) + { + // error + pCopyFile->m_bCopyError = true; + break; + } + else + { + goto retry; + } + } + else + { + // Wait for the operation to finish + GetOverlappedResult( pCopyFile->m_hDstFile, &overlappedWrite, &dwBytesWrite, TRUE ); + overlappedWrite.Offset += dwBytesWrite; + } + + if ( dwBytesWrite ) + { + // track expected size + pCopyFile->m_pCopyStats->m_bytesCopied += dwBytesWrite; + pCopyFile->m_pCopyStats->m_writeSize += dwBytesWrite; + } + else + { + pCopyFile->m_bCopyError = true; + break; + } + + pCopyFile->m_pCopyStats->m_bufferWriteSize = dwBytesWrite; + pCopyFile->m_pCopyStats->m_bufferWriteTime = GetTickCount() - startTime; + pCopyFile->m_pCopyStats->m_totalWriteSize += pCopyFile->m_pCopyStats->m_bufferWriteSize; + pCopyFile->m_pCopyStats->m_totalWriteTime += pCopyFile->m_pCopyStats->m_bufferWriteTime; + + AddBufferForRead( pBuffer ); + } + + return 0; +} + +//----------------------------------------------------------------------------- +// CopyFileInit +// +//----------------------------------------------------------------------------- +void CopyFileInit() +{ + static bool init = false; + if ( !init ) + { + InitializeCriticalSection( &g_criticalSection ); + g_hReadEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + g_hWriteEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + init = true; + } + else + { + // expected startup state + ResetEvent( g_hReadEvent ); + ResetEvent( g_hWriteEvent ); + + g_pReadBuffers = NULL; + g_pWriteBuffers = NULL; + } +} + +//----------------------------------------------------------------------------- +// CopyFileOverlapped +// +//----------------------------------------------------------------------------- +bool CopyFileOverlapped( const char *pSrcFilename, const char *pDstFilename, xCompressHeader *pxcHeader, CopyStats_t *pCopyStats ) +{ + CopyFile_t copyFile = {0}; + Buffer_t buffers[NUM_BUFFERS] = {0}; + HANDLE hReadThread = NULL; + HANDLE hWriteThread = NULL; + bool bSuccess = false; + DWORD startCopyTime; + DWORD dwResult; + int i; + + startCopyTime = GetTickCount(); + + CopyFileInit(); + + g_pNumReadBuffers = &pCopyStats->m_numReadBuffers; + g_pNumWriteBuffers = &pCopyStats->m_numWriteBuffers; + + strcpy( pCopyStats->m_srcFilename, pSrcFilename ); + strcpy( pCopyStats->m_dstFilename, pDstFilename ); + + copyFile.m_hSrcFile = INVALID_HANDLE_VALUE; + copyFile.m_hDstFile = INVALID_HANDLE_VALUE; + copyFile.m_pCopyStats = pCopyStats; + copyFile.m_bCopyError = false; + + // validate the source file + copyFile.m_hSrcFile = CreateFile( pSrcFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING, NULL ); + if ( copyFile.m_hSrcFile == INVALID_HANDLE_VALUE ) + { + // failure + goto cleanUp; + } + + copyFile.m_srcFileSize = GetFileSize( copyFile.m_hSrcFile, NULL ); + if ( copyFile.m_srcFileSize == (DWORD)-1 ) + { + // failure + goto cleanUp; + } + + // ensure the target file path exists + CreateFilePath( pDstFilename ); + + // validate the target file + copyFile.m_hDstFile = CreateFile( pDstFilename, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING, NULL ); + if ( copyFile.m_hDstFile == INVALID_HANDLE_VALUE ) + { + // failure + goto cleanUp; + } + + pCopyStats->m_readSize = copyFile.m_srcFileSize; + pCopyStats->m_writeSize = 0; + + if ( pxcHeader ) + { + // read in chunks of compressed blocks + copyFile.m_readBufferSize = pxcHeader->nReadBlockSize; + copyFile.m_dstFileSize = pxcHeader->nUncompressedFileSize; + } + else + { + // setup for copy + copyFile.m_readBufferSize = BUFFER_SIZE; + copyFile.m_dstFileSize = copyFile.m_srcFileSize; + } + + // setup read buffers + for ( i=0; i<NUM_BUFFERS; i++) + { + buffers[i].pData = new unsigned char[copyFile.m_readBufferSize]; + buffers[i].dwSize = 0; + buffers[i].pNext = NULL; + AddBufferForRead( &buffers[i] ); + } + copyFile.m_numReadCycles = (copyFile.m_srcFileSize + copyFile.m_readBufferSize - 1)/copyFile.m_readBufferSize; + + // setup write buffer + if ( pxcHeader ) + { + copyFile.m_pInflateBuffer = new unsigned char[pxcHeader->nDecompressionBufferSize]; + copyFile.m_inflateBufferSize = pxcHeader->nDecompressionBufferSize; + copyFile.m_bInflate = true; + } + else + { + copyFile.m_bInflate = false; + } + + // pre-size the target file in aligned buffers + DWORD dwAligned = ALIGN( copyFile.m_dstFileSize, 512 ); + dwResult = SetFilePointer( copyFile.m_hDstFile, dwAligned, NULL, FILE_BEGIN ); + if ( dwResult == INVALID_SET_FILE_POINTER ) + { + // failure + goto cleanUp; + } + SetEndOfFile( copyFile.m_hDstFile ); + + // start the read thread + hReadThread = CreateThread( 0, 0, &ReadFileThread, ©File, 0, 0 ); + if ( !hReadThread ) + { + // failure + goto cleanUp; + } + + // wait for buffers to populate + + // start the write thread + hWriteThread = CreateThread( 0, 0, &WriteFileThread, ©File, 0, 0 ); + if ( !hWriteThread ) + { + // failure + goto cleanUp; + } + + // wait for write thread to finish + WaitForSingleObject( hWriteThread, INFINITE ); + WaitForSingleObject( hReadThread, INFINITE ); + + if ( copyFile.m_bCopyError ) + { + goto cleanUp; + } + + // Fixup the file size + CloseHandle( copyFile.m_hDstFile ); + copyFile.m_hDstFile = INVALID_HANDLE_VALUE; + + if ( copyFile.m_dstFileSize % 512 ) + { + // re-open file as non-buffered to adjust to correct file size + HANDLE hFile = CreateFile( pDstFilename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + SetFilePointer( hFile, copyFile.m_dstFileSize, NULL, FILE_BEGIN ); + SetEndOfFile( hFile ); + CloseHandle( hFile ); + } + + // finished + bSuccess = true; + +cleanUp: + if ( copyFile.m_hSrcFile != INVALID_HANDLE_VALUE ) + { + CloseHandle( copyFile.m_hSrcFile ); + } + + if ( copyFile.m_hDstFile != INVALID_HANDLE_VALUE ) + { + CloseHandle( copyFile.m_hDstFile ); + } + + if ( hReadThread ) + { + CloseHandle( hReadThread ); + } + + if ( hWriteThread ) + { + CloseHandle( hWriteThread ); + } + + for ( i=0; i<NUM_BUFFERS; i++ ) + { + if ( buffers[i].pData ) + { + delete [] buffers[i].pData; + } + } + + if ( copyFile.m_pInflateBuffer ) + { + delete [] copyFile.m_pInflateBuffer; + } + + if ( !bSuccess ) + { + pCopyStats->m_copyErrors++; + } + + pCopyStats->m_copyTime = GetTickCount() - startCopyTime; + + return bSuccess; +} diff --git a/utils/xbox/xbox_loader/xbox_loader.cpp b/utils/xbox/xbox_loader/xbox_loader.cpp new file mode 100644 index 0000000..7cbeb77 --- /dev/null +++ b/utils/xbox/xbox_loader/xbox_loader.cpp @@ -0,0 +1,2019 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// APPLOADER.CPP +// +// Stub executeable +//=====================================================================================// +#include "xbox_loader.h" + +struct installData_t +{ + char **m_ppSrcFiles; + char **m_ppDstFiles; + DWORD *m_pDstFileSizes; + int m_numFiles; + DWORD m_totalSize; + xCompressHeader **m_ppxcHeaders; +}; + +DWORD g_installStartTime; +DWORD g_installElapsedTime; +installData_t g_installData; +CopyStats_t g_copyStats; +int g_activeDevice; +__int64 g_loaderStartTime; + + +//----------------------------------------------------------------------------- +// GetLocalizedLoadingString +//----------------------------------------------------------------------------- +const wchar_t *GetLocalizedLoadingString() +{ + switch( XGetLanguage() ) + { + case XC_LANGUAGE_FRENCH: + return L"CHARGEMENT..."; + case XC_LANGUAGE_ITALIAN: + return L"CARICAMENTO..."; + case XC_LANGUAGE_GERMAN: + return L"L�DT..."; + case XC_LANGUAGE_SPANISH: + return L"CARGANDO..."; + } + return L"LOADING..."; +} + +//----------------------------------------------------------------------------- +// GetNextLangauge +// Start at -1 +//----------------------------------------------------------------------------- +int GetNextLanguage( int languageID ) +{ + if ( languageID < 0 ) + return XC_LANGUAGE_ENGLISH; + + // cycle to end + switch ( languageID ) + { + case XC_LANGUAGE_ENGLISH: + return XC_LANGUAGE_FRENCH; + case XC_LANGUAGE_FRENCH: + return XC_LANGUAGE_ITALIAN; + case XC_LANGUAGE_ITALIAN: + return XC_LANGUAGE_GERMAN; + case XC_LANGUAGE_GERMAN: + return XC_LANGUAGE_SPANISH; + case XC_LANGUAGE_SPANISH: + return -1; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// GetLanguageString +//----------------------------------------------------------------------------- +const char *GetLanguageString( int languageID ) +{ + switch( languageID ) + { + case XC_LANGUAGE_FRENCH: + return "french"; + case XC_LANGUAGE_ITALIAN: + return "italian"; + case XC_LANGUAGE_GERMAN: + return "german"; + case XC_LANGUAGE_SPANISH: + return "spanish"; + } + return "english"; +} + +//----------------------------------------------------------------------------- +// FixupNamespaceFilename +//----------------------------------------------------------------------------- +bool FixupNamespaceFilename( const char *pFilename, char *pOutFilename, int languageID ) +{ + char newFilename[MAX_PATH]; + + bool bFixup = false; + int dstLen = 0; + int srcLen = strlen( pFilename ); + for ( int i=0; i<srcLen+1; i++ ) + { + // replace every occurrence of % with language + if ( pFilename[i] == '%' ) + { + int len = strlen( GetLanguageString( languageID ) ); + memcpy( newFilename + dstLen, GetLanguageString( languageID ), len ); + dstLen += len; + bFixup = true; + } + else + { + newFilename[dstLen] = pFilename[i]; + dstLen++; + } + } + + strcpy( pOutFilename, newFilename ); + return bFixup; +} + +//----------------------------------------------------------------------------- +// DeleteOtherLocalizedFiles +//----------------------------------------------------------------------------- +void DeleteOtherLocalizedFiles( const char *pFilename, int languageIDToKeep ) +{ + char newFilename[MAX_PATH]; + char mrkFilename[MAX_PATH]; + bool bFixup; + + int languageID = -1; + while ( 1 ) + { + languageID = GetNextLanguage( languageID ); + if ( languageID == -1 ) + { + // cycled through + break; + } + + if ( languageID == languageIDToKeep ) + { + // skip + continue; + } + + bFixup = FixupNamespaceFilename( pFilename, newFilename, languageID ); + if ( !bFixup ) + { + // nothing to do + continue; + } + + SetFileAttributes( newFilename, FILE_ATTRIBUTE_NORMAL ); + DeleteFile( newFilename ); + + // delete marker + strcpy( mrkFilename, newFilename ); + strcat( mrkFilename, ".mrk" ); + SetFileAttributes( mrkFilename, FILE_ATTRIBUTE_NORMAL ); + DeleteFile( mrkFilename ); + } +} + +//----------------------------------------------------------------------------- +// LerpColor +//----------------------------------------------------------------------------- +unsigned int LerpColor( unsigned int c0, unsigned int c1, float t ) +{ + int i; + float a; + float b; + unsigned char* c; + unsigned int newcolor; + + if ( t <= 0.0f ) + return c0; + else if ( t >= 1.0f ) + return c1; + + // lerp each component + c = (unsigned char*)&newcolor; + for ( i=0; i<4; i++ ) + { + a = (float)(c0 & 0xFF); + b = (float)(c1 & 0xFF); + *c++ = (unsigned char)(a + t*(b-a)); + + // next color component + c0 >>= 8; + c1 >>= 8; + } + + return newcolor; +} + +//----------------------------------------------------------------------------- +// ConvertToWideString +//----------------------------------------------------------------------------- +void ConvertToWideString( wchar_t *pDst, const char *pSrc ) +{ + int len = strlen( pSrc )+1; + for (int i=0; i<len; i++) + { + pDst[i] = pSrc[i]; + } +} + +//----------------------------------------------------------------------------- +// CopyString +//----------------------------------------------------------------------------- +char *CopyString( const char *pString ) +{ + char *pNewString = (char *)malloc( strlen( pString ) + 1 ); + strcpy( pNewString, pString ); + + return pNewString; +} + +//----------------------------------------------------------------------------- +// FixFilename +//----------------------------------------------------------------------------- +void FixFilename( char *pPath ) +{ + int len = strlen( pPath ); + for (int i=0; i<len; ++i) + { + if ( pPath[i] == '/') + pPath[i] = '\\'; + } +} + +//----------------------------------------------------------------------------- +// StripQuotes +//----------------------------------------------------------------------------- +void StripQuotes( char *pToken ) +{ + int len = strlen( pToken ); + if ( pToken[0] == '"' && pToken[len-1] == '"' ) + { + memcpy( pToken, pToken+1, len-2 ); + pToken[len-2] = '\0'; + } +} + +//----------------------------------------------------------------------------- +// DoesFileExist +//----------------------------------------------------------------------------- +bool DoesFileExist( const char *pFilename, DWORD *pSize ) +{ + HANDLE hFile = CreateFile( pFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( hFile != INVALID_HANDLE_VALUE ) + { + if ( pSize ) + { + *pSize = GetFileSize( hFile, NULL ); + if ( *pSize == (DWORD)-1 ) + { + *pSize = 0; + } + } + + // exists + CloseHandle( hFile ); + return true; + } + + // not present + return false; +} + +//----------------------------------------------------------------------------- +// NormalizePath +// +//----------------------------------------------------------------------------- +void NormalizePath( char* path, bool forceToLower ) +{ + int i; + int srclen; + + srclen = strlen( path ); + for ( i=0; i<srclen; i++ ) + { + if ( path[i] == '/' ) + path[i] = '\\'; + else if ( forceToLower && ( path[i] >= 'A' && path[i] <= 'Z' ) ) + path[i] = path[i] - 'A' + 'a'; + } +} + +//----------------------------------------------------------------------------- +// DeleteAllFiles +// +//----------------------------------------------------------------------------- +void DeleteAllFiles( const char* pDirectory, int level, bool bRecurse ) +{ + HANDLE hFind; + WIN32_FIND_DATA findData; + char basepath[MAX_PATH]; + char searchpath[MAX_PATH]; + char filename[MAX_PATH]; + + TL_AddSeperatorToPath( (char*)pDirectory, basepath ); + strcpy( searchpath, basepath ); + strcat( searchpath, "*.*" ); + + hFind = FindFirstFile( searchpath, &findData ); + if ( hFind != INVALID_HANDLE_VALUE ) + { + do + { + if ( !stricmp( findData.cFileName, "." ) || !stricmp( findData.cFileName, ".." ) ) + { + continue; + } + + strcpy( filename, basepath ); + strcat( filename, findData.cFileName ); + NormalizePath( filename, false ); + + if ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + if ( bRecurse ) + { + DeleteAllFiles( filename, level+1, true ); + RemoveDirectory( filename ); + continue; + } + } + + SetFileAttributes( filename, FILE_ATTRIBUTE_NORMAL ); + DeleteFile( filename ); + } + while ( FindNextFile( hFind, &findData ) ); + FindClose( hFind ); + } +} + +//----------------------------------------------------------------------------- +// GetXCompressedHeader +//----------------------------------------------------------------------------- +bool GetXCompressedHeader( const char *pFilename, xCompressHeader *pHeader ) +{ + HANDLE hFile = CreateFile( pFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( hFile != INVALID_HANDLE_VALUE ) + { + DWORD dwBytesRead = 0; + ReadFile( hFile, pHeader, sizeof( xCompressHeader ), &dwBytesRead, NULL ); + CloseHandle( hFile ); + if ( pHeader->nMagic == xCompressHeader::MAGIC && pHeader->nVersion == xCompressHeader::VERSION ) + { + // valid + return true; + } + } + + // invalid + return false; +} + +//----------------------------------------------------------------------------- +// IsTargetFileValid +// +// Optional non-zero expected source file size must matcg +//----------------------------------------------------------------------------- +bool IsTargetFileValid( const char *pFilename, DWORD dwSrcFileSize ) +{ + char mrkFilename[MAX_PATH]; + DWORD dwTargetFileSize = 0; + DWORD dwSize = 0; + DWORD dwAttributes; + + // all valid target files are non-zero + if ( !DoesFileExist( pFilename, &dwTargetFileSize ) || !dwTargetFileSize ) + { + return false; + } + + dwAttributes = GetFileAttributes( pFilename ); + if ( dwAttributes != (DWORD)-1 && ( dwAttributes & FILE_ATTRIBUTE_READONLY ) ) + { + // target files marked read only don't get overwritten + return true; + } + + // all valid target files must have marker file + // presence ensures file was successfully copied + strcpy( mrkFilename, pFilename ); + strcat( mrkFilename, ".mrk" ); + if ( !DoesFileExist( mrkFilename, NULL ) ) + { + // cannot rely on contents, regardless of size match + DeleteFile( pFilename ); + return false; + } + + if ( dwSrcFileSize && dwSrcFileSize != dwTargetFileSize ) + { + DeleteFile( pFilename ); + return false; + } + + // assume valid + return true; +} + +//----------------------------------------------------------------------------- +// Constructor for CXBoxLoader class +//----------------------------------------------------------------------------- +CXBoxLoader::CXBoxLoader() : CXBApplication() +{ + // need a persistent time base, use the RTC + // all other tick counters reset across relaunch + FILETIME fileTime; + GetSystemTimeAsFileTime( &fileTime ); + g_loaderStartTime = ((ULARGE_INTEGER*)&fileTime)->QuadPart; + + m_contextCode = 0; + m_pLastMovieFrame = NULL; + m_pVB = NULL; + m_bAllowAttractAbort = false; + m_numFiles = 0; + m_bLaunch = false; + m_dwLoading = 0; + m_bDrawLegal = false; + m_LegalTime = 0; + m_installThread = NULL; + m_State = 0; + m_bDrawLoading = false; + m_bDrawProgress = false; + m_bInstallComplete = false; + m_FrameCounter = 0; + m_MovieCount = 0; + m_bMovieErrorIsFatal = false; + m_bDrawDebug = false; + m_LoadingBarStartTime = 0; + m_LoadingBarEndTime = 0; + m_LegalStartTime = 0; + m_bCaptureLastMovieFrame = 0; + m_bDrawSlideShow = false; + m_SlideShowStartTime = 0; + m_pLogData = NULL; + m_pDefaultTrueTypeFont = NULL; +} + +//----------------------------------------------------------------------------- +// FatalMediaError +//----------------------------------------------------------------------------- +void CXBoxLoader::FatalMediaError() +{ + m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, 0x00000000, 1.0f, 0L ); + + LPDIRECT3DSURFACE8 pBackBuffer; + m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer ); + + LPCWSTR pLine1; + LPCWSTR pLine2; + switch( XGetLanguage() ) + { + case XC_LANGUAGE_FRENCH: + pLine1 = L"Le disque utilis� pr�sente une anomalie."; + pLine2 = L"Il est peut-�tre sale ou endommag�."; + break; + case XC_LANGUAGE_ITALIAN: + pLine1 = L"Il disco in uso ha qualche problema."; + pLine2 = L"Potrebbe essere sporco o danneggiato."; + break; + case XC_LANGUAGE_GERMAN: + pLine1 = L"Bei der benutzten CD ist ein Problem aufgetreten."; + pLine2 = L"M�glicherweise ist sie verschmutzt oder besch�digt."; + break; + case XC_LANGUAGE_SPANISH: + pLine1 = L"Hay un problema con el disco que est� usando."; + pLine2 = L"Puede estar sucio o da�ado."; + break; + default: + pLine1 = L"There is a problem with the disc you are using."; + pLine2 = L"It may be dirty or damaged."; + break; + } + + if ( m_pDefaultTrueTypeFont ) + { + m_pDefaultTrueTypeFont->SetTextAlignment( XFONT_CENTER|XFONT_TOP ); + m_pDefaultTrueTypeFont->TextOut( pBackBuffer, pLine1, (unsigned)-1, 320, 240-15 ); + m_pDefaultTrueTypeFont->TextOut( pBackBuffer, pLine2, (unsigned)-1, 320, 240+15 ); + } + + // Present the scene + m_pd3dDevice->Present( NULL, NULL, NULL, NULL ); + + pBackBuffer->Release(); + + // forever + while (1); +} + +//----------------------------------------------------------------------------- +// LoadTexture +//----------------------------------------------------------------------------- +D3DTexture *CXBoxLoader::LoadTexture( int resourceID ) +{ + // Get access to the texture + return ( m_xprResource.GetTexture( resourceID ) ); +} + +//----------------------------------------------------------------------------- +// LoadFont +//----------------------------------------------------------------------------- +HRESULT CXBoxLoader::LoadFont( CXBFont *pFont, int resourceID ) +{ + return pFont->Create( m_xprResource.GetTexture( resourceID ), + m_xprResource.GetData( resourceID + sizeof(D3DTexture) ) ); +} + +//----------------------------------------------------------------------------- +// DrawRect +//----------------------------------------------------------------------------- +void CXBoxLoader::DrawRect( int x, int y, int w, int h, DWORD color ) +{ + // Set states + D3DDevice::SetTexture( 0, NULL ); + D3DDevice::SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE ); + D3DDevice::SetRenderState( D3DRS_ZENABLE, FALSE ); + D3DDevice::SetRenderState( D3DRS_FOGENABLE, FALSE ); + D3DDevice::SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE ); + D3DDevice::SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); + D3DDevice::SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); + D3DDevice::SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ); + D3DDevice::SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); + D3DDevice::SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); + D3DDevice::SetVertexShader( D3DFVF_XYZRHW|D3DFVF_DIFFUSE ); + + FLOAT fX1 = x; + FLOAT fY1 = y; + FLOAT fX2 = x + w - 1; + FLOAT fY2 = y + h - 1; + + D3DDevice::Begin( D3DPT_QUADLIST ); + D3DDevice::SetVertexDataColor( D3DVSDE_DIFFUSE, color ); + D3DDevice::SetVertexData4f( D3DVSDE_VERTEX, fX1, fY1, 1.0f, 1.0f ); + D3DDevice::SetVertexData4f( D3DVSDE_VERTEX, fX2, fY1, 1.0f, 1.0f ); + D3DDevice::SetVertexData4f( D3DVSDE_VERTEX, fX2, fY2, 1.0f, 1.0f ); + D3DDevice::SetVertexData4f( D3DVSDE_VERTEX, fX1, fY2, 1.0f, 1.0f ); + D3DDevice::End(); +} + + +//----------------------------------------------------------------------------- +// DrawTexture +//----------------------------------------------------------------------------- +void CXBoxLoader::DrawTexture( D3DTexture *pD3DTexture, int x, int y, int w, int h, int color ) +{ + struct VERTEX { D3DXVECTOR4 p; D3DCOLOR c; FLOAT tu, tv; }; + if ( !m_pVB ) + { + // Create a vertex buffer for rendering the help screen + D3DDevice::CreateVertexBuffer( 4*sizeof(VERTEX), D3DUSAGE_WRITEONLY, 0L, D3DPOOL_DEFAULT, &m_pVB ); + } + + VERTEX* v; + m_pVB->Lock( 0, 0, (BYTE**)&v, 0L ); + + // Calculate vertex positions + FLOAT fLeft = x + 0.5f; + FLOAT fTop = y + 0.5f; + FLOAT fRight = x+w - 0.5f; + FLOAT fBottom = y+h - 0.5f; + + // position + v[0].p = D3DXVECTOR4( fLeft, fTop, 0, 0 ); + v[1].p = D3DXVECTOR4( fRight, fTop, 0, 0 ); + v[2].p = D3DXVECTOR4( fRight, fBottom, 0, 0 ); + v[3].p = D3DXVECTOR4( fLeft, fBottom, 0, 0 ); + + // color + v[0].c = color; + v[1].c = color; + v[2].c = color; + v[3].c = color; + + D3DSURFACE_DESC desc; + pD3DTexture->GetLevelDesc( 0, &desc ); + + // linear texcoords + v[0].tu = 0; + v[0].tv = 0; + v[1].tu = desc.Width; + v[1].tv = 0; + v[2].tu = desc.Width; + v[2].tv = desc.Height; + v[3].tu = 0; + v[3].tv = desc.Height; + + m_pVB->Unlock(); + + // Set state to render the image + D3DDevice::SetTexture( 0, pD3DTexture ); + D3DDevice::SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + D3DDevice::SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + D3DDevice::SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + D3DDevice::SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + D3DDevice::SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + D3DDevice::SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + D3DDevice::SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP ); + D3DDevice::SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP ); + D3DDevice::SetTextureStageState( 0, D3DTSS_ADDRESSW, D3DTADDRESS_CLAMP ); + D3DDevice::SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); + D3DDevice::SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); + D3DDevice::SetRenderState( D3DRS_ZENABLE, FALSE ); + D3DDevice::SetRenderState( D3DRS_ZWRITEENABLE, FALSE ); + D3DDevice::SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_ALWAYS ); + D3DDevice::SetRenderState( D3DRS_FOGENABLE, FALSE ); + D3DDevice::SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE ); + D3DDevice::SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); + D3DDevice::SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); + D3DDevice::SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); + D3DDevice::SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); + D3DDevice::SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); + D3DDevice::SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ); + D3DDevice::SetVertexShader( D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1 ); + + // Render the image + D3DDevice::SetStreamSource( 0, m_pVB, sizeof(VERTEX) ); + D3DDevice::DrawPrimitive( D3DPT_QUADLIST, 0, 1 ); +} + +//----------------------------------------------------------------------------- +// StartVideo +// +// May take a few ms. +//----------------------------------------------------------------------------- +HRESULT CXBoxLoader::StartVideo( const CHAR* strFilename, bool bFromMemory, bool bFatalOnError ) +{ + HRESULT hr; + if ( bFromMemory ) + { + // play from memory, so as no to interfere with disc access + hr = m_player.OpenMovieFromMemory( strFilename, D3DFMT_LIN_A8R8G8B8, m_pd3dDevice, TRUE ); + } + else + { + // play from disc + hr = m_player.OpenFile( strFilename, D3DFMT_LIN_A8R8G8B8, m_pd3dDevice, TRUE ); + } + + // can fail anytime + m_bMovieErrorIsFatal = bFatalOnError; + + m_MovieCount++; + + if ( FAILED( hr ) ) + { + OUTPUT_DEBUG_STRING( "Video playback failed!\n" ); + + if ( bFatalOnError ) + { + FatalMediaError(); + } + } + + return hr; +} + +//----------------------------------------------------------------------------- +// StopVideo +// +// May take a few ms. +//----------------------------------------------------------------------------- +void CXBoxLoader::StopVideo() +{ + m_player.TerminatePlayback(); +} + +//----------------------------------------------------------------------------- +// LoadInstallScript +// +// Parse filenames to be copied +//----------------------------------------------------------------------------- +bool CXBoxLoader::LoadInstallScript() +{ + void *pFileData = NULL; + DWORD fileSize = 0; + DWORD dwSrcSize; + HRESULT hr; + char srcFile[MAX_PATH]; + char dstFile[MAX_PATH]; + char localizedFile[MAX_PATH]; + HANDLE hFind; + char sourceFilename[MAX_PATH]; + char sourcePath[MAX_PATH]; + char targetFilename[MAX_PATH]; + char filename[MAX_PATH]; + WIN32_FIND_DATA findData; + bool bCompressed; + xCompressHeader xcHeader; + char *pVersion; + bool bTargetIsLocalized; + int languageID; + + memset( &g_installData, 0, sizeof( installData_t ) ); + + hr = XBUtil_LoadFile( "D:\\LoaderMedia\\install.txt", &pFileData, &fileSize ); + if ( hr != S_OK || !fileSize ) + { + return false; + } + + languageID = XGetLanguage(); + + // full re-install + bool bForce = true; + + // scan + TL_SetScriptData( (char*)pFileData, fileSize ); + while ( 1 ) + { + char *pToken = TL_GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + StripQuotes( pToken ); + strcpy( srcFile, pToken); + + pToken = TL_GetToken( true ); + if ( !pToken || !pToken[0] ) + break; + StripQuotes( pToken ); + strcpy( dstFile, pToken); + + // replace with language token + FixupNamespaceFilename( srcFile, srcFile, languageID ); + bTargetIsLocalized = FixupNamespaceFilename( dstFile, localizedFile, languageID ); + + if ( bTargetIsLocalized ) + { + // localized files are allowed to change without requiring a full re-install + bool bDeleteMapCache = false; + if ( !IsTargetFileValid( localizedFile, 0 ) ) + { + // must delete map cache to ensure localized files have enough room + bDeleteMapCache = true; + } + + // only allowing one localized file of this type, delete all others + DeleteOtherLocalizedFiles( dstFile, languageID ); + strcpy( dstFile, localizedFile ); + + if ( bDeleteMapCache ) + { + char mapPath[MAX_PATH]; + strcpy( mapPath, localizedFile ); + TL_StripFilename( mapPath ); + TL_AddSeperatorToPath( mapPath, mapPath ); + strcat( mapPath, "maps\\" ); + DeleteAllFiles( mapPath, 0, false ); + } + } + + pVersion = strstr( dstFile, "version_" ); + if ( pVersion ) + { + if ( m_numFiles ) + { + // version statement out of sequence + return false; + } + + m_Version = atoi( pVersion + strlen( "version_" ) ); + + if ( IsTargetFileValid( dstFile, 0 ) ) + { + // version file exists, files should be same + bForce = false; + } + + if ( bForce ) + { + // delete all files at the specified directory + strcpy( targetFilename, dstFile ); + TL_StripFilename( targetFilename ); + DeleteAllFiles( targetFilename, 0, true ); + } + } + + // source file could be wildcard, get path only + strcpy( sourcePath, srcFile ); + TL_StripFilename( sourcePath ); + + hFind = FindFirstFile( srcFile, &findData ); + if ( hFind != INVALID_HANDLE_VALUE ) + { + do + { + if ( !stricmp( findData.cFileName, "." ) || !stricmp( findData.cFileName, ".." ) ) + { + continue; + } + if ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + continue; + } + + TL_AddSeperatorToPath( sourcePath, sourceFilename ); + strcat( sourceFilename, findData.cFileName ); + NormalizePath( sourceFilename, false ); + + // target filename may be path or absolute file + strcpy( targetFilename, dstFile ); + + TL_StripPath( dstFile, filename ); + if ( !filename[0] ) + { + // target filename is path only + TL_AddSeperatorToPath( dstFile, targetFilename ); + strcat( targetFilename, findData.cFileName ); + NormalizePath( targetFilename, false ); + } + + if ( !DoesFileExist( sourceFilename, &dwSrcSize ) ) + { + // can't validate source + return false; + } + + if ( strstr( sourceFilename, ".xz_" ) && strstr( targetFilename, ".xzp" ) ) + { + bCompressed = true; + if ( GetXCompressedHeader( sourceFilename, &xcHeader ) ) + { + g_installData.m_totalSize += xcHeader.nUncompressedFileSize; + + if ( !bForce && IsTargetFileValid( targetFilename, xcHeader.nUncompressedFileSize ) ) + { + // target already exists, no need to recopy + g_copyStats.m_bytesCopied += xcHeader.nUncompressedFileSize; + continue; + } + } + else + { + // invalid + return false; + } + } + else + { + g_installData.m_totalSize += dwSrcSize; + + bCompressed = false; + if ( !bForce && IsTargetFileValid( targetFilename, dwSrcSize ) ) + { + // target already exists, no need to recopy + g_copyStats.m_bytesCopied += dwSrcSize; + continue; + } + } + + if ( m_numFiles < MAX_FILES ) + { + m_fileSrc[m_numFiles] = CopyString( sourceFilename ); + m_fileDest[m_numFiles] = CopyString( targetFilename ); + + if ( bCompressed ) + { + xCompressHeader *pxcHeader = new xCompressHeader; + memcpy( pxcHeader, &xcHeader, sizeof( xCompressHeader ) ); + m_fileCompressionHeaders[m_numFiles] = pxcHeader; + m_fileDestSizes[m_numFiles] = pxcHeader->nUncompressedFileSize; + } + else + { + m_fileCompressionHeaders[m_numFiles] = NULL; + m_fileDestSizes[m_numFiles] = dwSrcSize; + } + + m_numFiles++; + } + } + while ( FindNextFile( hFind, &findData ) ); + FindClose( hFind ); + } + else + { + // source file not found, invalid + return false; + } + } + + // finsihed with install script + free( pFileData ); + + g_installData.m_ppSrcFiles = m_fileSrc; + g_installData.m_ppDstFiles = m_fileDest; + g_installData.m_ppxcHeaders = m_fileCompressionHeaders; + g_installData.m_pDstFileSizes = m_fileDestSizes; + g_installData.m_numFiles = m_numFiles; + + return true; +} + +//----------------------------------------------------------------------------- +// Copies all install files to the hard drive +//----------------------------------------------------------------------------- +DWORD WINAPI InstallThreadFunc( LPVOID lpParam ) +{ + char mrkFilename[MAX_PATH]; + bool bSuccess; + HANDLE hFile; + + g_installStartTime = GetTickCount(); + + // started loading + *(DWORD*)lpParam = 1; + + for ( int i = 0; i < g_installData.m_numFiles; ++i ) + { + DWORD bytesCopied = g_copyStats.m_bytesCopied; + + // install has already validated, if it's in the list, copy it + bSuccess = CopyFileOverlapped( g_installData.m_ppSrcFiles[i], g_installData.m_ppDstFiles[i], g_installData.m_ppxcHeaders[i], &g_copyStats ); + + strcpy( mrkFilename, g_installData.m_ppDstFiles[i] ); + strcat( mrkFilename, ".mrk" ); + + SetFileAttributes( mrkFilename, FILE_ATTRIBUTE_NORMAL ); + if ( bSuccess ) + { + // add marker + hFile = CreateFile( mrkFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( hFile != INVALID_HANDLE_VALUE ) + { + CloseHandle( hFile ); + } + } + else + { + // remove marker + DeleteFile( mrkFilename ); + DeleteFile( g_installData.m_ppDstFiles[i] ); + + // errors can't stop install + // snap progress to expected completion + g_copyStats.m_bytesCopied = bytesCopied + g_installData.m_pDstFileSizes[i]; + } + } + + g_installElapsedTime = GetTickCount() - g_installStartTime; + + // finished loading + *(DWORD*)lpParam = 0; + + return 0; +} + +//----------------------------------------------------------------------------- +// Verify disk space +//----------------------------------------------------------------------------- +bool CXBoxLoader::VerifyInstall( void ) +{ + memset( &g_copyStats, 0, sizeof( CopyStats_t ) ); + + LoadLogFile(); + + if ( !LoadInstallScript() ) + { + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Look for possible forensic log file +//----------------------------------------------------------------------------- +void CXBoxLoader::LoadLogFile( void ) +{ +#if defined( XBOX_FORENSIC_LOG ) + HRESULT hr; + char *pFileData = NULL; + DWORD fileSize = 0; + + hr = XBUtil_LoadFile( "Z:\\hl2fatal.log", (void**)&pFileData, &fileSize ); + if ( hr != S_OK || !fileSize ) + { + return; + } + + // copy and null terminate + m_pLogData = (char *)malloc( fileSize+1 ); + + int j = 0; + for (int i=0; i<(int)fileSize; i++) + { + if ( pFileData[i] == 0x0D ) + continue; + m_pLogData[j++] = pFileData[i]; + } + m_pLogData[j] = '\0'; + + free( pFileData ); +#endif +} + +//----------------------------------------------------------------------------- +// Starts installation to disk +//----------------------------------------------------------------------------- +bool CXBoxLoader::StartInstall( void ) +{ + // Start the install thread + m_installThread = CreateThread( NULL, 0, &InstallThreadFunc, &m_dwLoading, 0, 0 ); + if ( !m_installThread ) + { + // failed + return false; + } + + // success + return true; +} + +//----------------------------------------------------------------------------- +// Shows the legal text +//----------------------------------------------------------------------------- +void CXBoxLoader::StartLegalScreen( int legal ) +{ + m_bDrawLegal = true; + m_LegalTime = GetTickCount(); + m_LegalStartTime = 0; + + switch ( legal ) + { + case LEGAL_MAIN: + m_pLegalTexture = m_pMainLegalTexture; + break; + case LEGAL_SOURCE: + m_pLegalTexture = m_pSourceLegalTexture; + break; + } +} + +//----------------------------------------------------------------------------- +// DrawLegals +//----------------------------------------------------------------------------- +void CXBoxLoader::DrawLegals() +{ + unsigned int color; + float t; + + if ( !m_bDrawLegal ) + return; + + if ( !m_LegalStartTime ) + { + m_LegalStartTime = GetTickCount(); + } + + // fade legals + t = (float)(GetTickCount() - m_LegalStartTime)/LEGAL_DISPLAY_TIME; + if ( t < 0.1f ) + { + // fade up + color = LerpColor( 0xFF000000, 0xFFFFFFFF, t*10.0f ); + } + else if ( t < 0.9f ) + { + // hold + color = 0xFFFFFFFF; + } + else + { + // fade out + color = LerpColor( 0xFFFFFFFF, 0xFF000000, (t-0.9f)*10.0f ); + } + + DrawTexture( m_pLegalTexture, 0, 0, 640, 480, color ); +} + +//----------------------------------------------------------------------------- +// DrawSlideshow +//----------------------------------------------------------------------------- +void CXBoxLoader::DrawSlideshow() +{ + float t; + + if ( !m_bDrawSlideShow ) + return; + + if ( !m_SlideShowStartTime ) + { + m_SlideShowStartTime = GetTickCount(); + m_SlideShowCount = -1; + m_bFinalSlide = false; + } + + if ( !m_bInstallComplete && ( GetTickCount() - m_SlideShowStartTime > SLIDESHOW_SLIDETIME ) ) + { + // next slide + m_SlideShowCount++; + m_SlideShowStartTime = GetTickCount(); + } + + t = ( GetTickCount() - m_SlideShowStartTime )/(float)SLIDESHOW_FLIPTIME; + if ( t >= 1.0f ) + t = 1.0f; + + if ( m_bInstallComplete && !m_bFinalSlide && t >= 1.0f ) + { + // wait for current slide to complete + // final slide must transition back to transition screen + m_SlideShowStartTime = GetTickCount(); + m_bFinalSlide = true; + t = 0; + } + + if ( !m_bFinalSlide ) + { + // fade next slide in + unsigned int fadeInColor = LerpColor( 0x00FFFFFF, 0xFFFFFFFF, t ); + if ( fadeInColor != 0xFFFFFFFF && m_SlideShowCount != -1 ) + DrawTexture( m_pSlideShowTextures[m_SlideShowCount % MAX_SLIDESHOW_TEXTURES], 0, 0, 640, 480, 0xFFFFFFFF ); + DrawTexture( m_pSlideShowTextures[(m_SlideShowCount + 1) % MAX_SLIDESHOW_TEXTURES], 0, 0, 640, 480, fadeInColor ); + } + else + { + // fade last slide out + unsigned int fadeInColor = LerpColor( 0xFFFFFFFF, 0x00FFFFFF, t ); + DrawTexture( m_pSlideShowTextures[(m_SlideShowCount + 1) % MAX_SLIDESHOW_TEXTURES], 0, 0, 640, 480, fadeInColor ); + } + + if ( m_bInstallComplete && m_bFinalSlide && t >= 1.0f ) + { + // end of slideshow + m_bDrawSlideShow = false; + } +} + +//----------------------------------------------------------------------------- +// DrawDebug +//----------------------------------------------------------------------------- +void CXBoxLoader::DrawDebug() +{ +#ifndef _RETAIL + if ( !m_bDrawDebug ) + return; + + DrawRect( 0, 0, 640, 480, 0xC0000000 ); + + m_Font.Begin(); + m_Font.SetScaleFactors( 0.8f, 0.8f ); + + int xPos = SCREEN_WIDTH/2; + int yPos = SCREEN_HEIGHT/4; + float rate; + + wchar_t textBuffer[256]; + swprintf( textBuffer, L"Version: %d", m_Version ); + m_Font.DrawText( 40, 40, 0xffffffff, textBuffer, 0 ); + + wchar_t srcFilename[MAX_PATH]; + wchar_t dstFilename[MAX_PATH]; + ConvertToWideString( srcFilename, g_copyStats.m_srcFilename ); + ConvertToWideString( dstFilename, g_copyStats.m_dstFilename ); + swprintf( textBuffer, L"From: %s (%.2f MB)", srcFilename, (float)g_copyStats.m_readSize/(1024.0f*1024.0f) ); + m_Font.DrawText( xPos, yPos + 20, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + swprintf( textBuffer, L"To: %s (%.2f MB)", dstFilename, (float)g_copyStats.m_writeSize/(1024.0f*1024.0f) ); + m_Font.DrawText( xPos, yPos + 40, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + + if ( g_copyStats.m_bufferReadTime && m_dwLoading ) + rate = ( g_copyStats.m_bufferReadSize/(1024.0f*1024.0f) ) / ( g_copyStats.m_bufferReadTime * 0.001f ); + else + rate = 0; + swprintf( textBuffer, L"Buffer Read: %.2f MB (%.2f MB/s) (%d)", g_copyStats.m_bufferReadSize/(1024.0f*1024.0f), rate, g_copyStats.m_numReadBuffers ); + m_Font.DrawText( xPos, yPos + 80, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + + rate = g_copyStats.m_inflateTime && m_dwLoading ? (float)g_copyStats.m_inflateSize/(g_copyStats.m_inflateTime * 0.001f) : 0; + swprintf( textBuffer, L"Inflate: %.2f MB (%.2f MB/s)", g_copyStats.m_inflateSize/(1024.0f*1024.0f), rate/(1024.0f*1024.0f) ); + m_Font.DrawText( xPos, yPos + 100, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + + if ( g_copyStats.m_bufferWriteTime && m_dwLoading ) + rate = ( g_copyStats.m_bufferWriteSize/(1024.0f*1024.0f) ) / ( g_copyStats.m_bufferWriteTime * 0.001f ); + else + rate = 0; + swprintf( textBuffer, L"Buffer Write: %.2f MB (%.2f MB/s) (%d)", g_copyStats.m_bufferWriteSize/(1024.0f*1024.0f), rate, g_copyStats.m_numWriteBuffers ); + m_Font.DrawText( xPos, yPos + 120, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + + rate = g_copyStats.m_totalReadTime && m_dwLoading ? (float)g_copyStats.m_totalReadSize/(g_copyStats.m_totalReadTime * 0.001f) : 0; + swprintf( textBuffer, L"Total Read: %d MB (%.2f MB/s)", g_copyStats.m_totalReadSize/(1024*1024), rate/(1024.0f*1024.0f) ); + m_Font.DrawText( xPos, yPos + 160, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + + rate = g_copyStats.m_totalWriteTime && m_dwLoading ? (float)g_copyStats.m_totalWriteSize/(g_copyStats.m_totalWriteTime * 0.001f) : 0; + swprintf( textBuffer, L"Total Write: %d MB (%.2f MB/s)", g_copyStats.m_totalWriteSize/(1024*1024), rate/(1024.0f*1024.0f) ); + m_Font.DrawText( xPos, yPos + 180, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + + float elapsed = (float)(GetTickCount() - g_installStartTime) * 0.001f; + if ( m_dwLoading ) + { + if ( elapsed ) + rate = g_copyStats.m_totalWriteSize/elapsed; + else + rate = 0; + } + else + { + if ( g_installElapsedTime ) + rate = g_copyStats.m_totalWriteSize/(g_installElapsedTime * 0.001f); + else + rate = 0; + } + swprintf( textBuffer, L"Progress: %d/%d MB Elapsed: %d secs (%.2f MB/s)", g_copyStats.m_bytesCopied/(1024*1024), g_installData.m_totalSize/(1024*1024), (int)elapsed, rate/(1024.0f*1024.0f) ); + m_Font.DrawText( xPos, yPos + 220, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + + swprintf( textBuffer, L"Errors: %d", g_copyStats.m_copyErrors ); + m_Font.DrawText( xPos, yPos + 240, 0xffffffff, textBuffer, XBFONT_CENTER_X ); + + m_Font.End(); +#endif +} + +void CXBoxLoader::DrawLog() +{ +#if defined( XBOX_FORENSIC_LOG ) + wchar_t textBuffer[1024]; + int numChars; + + if ( !m_pLogData ) + return; + + DrawRect( 0, 0, 640, 480, 0xC0000000 ); + + m_Font.Begin(); + m_Font.SetScaleFactors( 0.8f, 0.8f ); + + char *pStart = m_pLogData; + char *pEnd = pStart; + int yPos = 40; + for (int i=0; i<20; i++) + { + pEnd = strstr( pStart, "\n" ); + if ( !pEnd ) + numChars = strlen( pStart ); + else + numChars = pEnd-pStart; + + if ( numChars ) + { + for (int j=0; j<numChars; j++) + { + textBuffer[j] = pStart[j]; + } + textBuffer[j] = 0; + m_Font.DrawText( 40, yPos, 0xffffffff, textBuffer, 0 ); + } + + if ( !pEnd ) + break; + + // next line + pStart = pEnd+1; + yPos += 10; + } + + m_Font.End(); +#endif +} + +//----------------------------------------------------------------------------- +// DrawLoadingMarquee +//----------------------------------------------------------------------------- +void CXBoxLoader::DrawLoadingMarquee() +{ + if ( !m_bDrawLoading ) + return; + + int y = 0.80f*480; + DrawTexture( m_pLoadingIconTexture, (640-64)/2, y-64, 64, 64, 0xFFFFFFFF ); + + // draw loading text + m_Font.Begin(); + m_Font.SetScaleFactors( 0.8f, 0.8f ); + m_Font.DrawText( 320, y, PROGRESS_TEXT_COLOR, GetLocalizedLoadingString(), XBFONT_CENTER_X ); + m_Font.End(); +} + +//----------------------------------------------------------------------------- +// DrawProgressBar +//----------------------------------------------------------------------------- +void CXBoxLoader::DrawProgressBar() +{ + if ( !m_bDrawProgress ) + return; + + if ( !m_LoadingBarStartTime ) + { + m_LoadingBarStartTime = GetTickCount(); + } + + // slide the loading bar up + float tUp = (float)(GetTickCount() - m_LoadingBarStartTime)/LOADINGBAR_UPTIME; + if ( tUp > 1.0f) + tUp = 1.0f; + float y = 480.0f + tUp*((float)PROGRESS_Y - 480.0f); + + float t0 = 0; + float t1 = 0; + int numSegments = 0; + if ( tUp == 1.0f ) + { + // loading bar is up + // don't snap, animate progress to current level of completion + t0 = (float)g_copyStats.m_bytesCopied/(float)g_installData.m_totalSize; + if ( t0 > 1.0f ) + t0 = 1.0f; + t1 = (float)(GetTickCount() - m_LoadingBarStartTime - LOADINGBAR_WAITTIME)/LOADINGBAR_SLIDETIME; + if ( t1 < 0.0f ) + t1 = 0.0f; + else if ( t1 > 1.0f) + t1 = 1.0f; + numSegments = t0 * t1 * (float)SEGMENT_COUNT; + } + +#if 0 + float tDown = 0; + if ( t0 == 1.0f && t1 == 1.0f && !m_dwLoading ) + { + // loading anim and copying of data are finished + // slide the loading bar down + if ( !m_LoadingBarEndTime ) + { + m_LoadingBarEndTime = GetTickCount(); + } + tDown = (float)(GetTickCount() - m_LoadingBarEndTime - LOADINGBAR_WAITTIME)/LOADINGBAR_UPTIME; + if ( tDown < 0.0f ) + tDown = 0.0f; + else if ( tDown > 1.0f) + tDown = 1.0f; + y = PROGRESS_Y + tDown*(480.0f - (float)PROGRESS_Y); + } + + if ( tDown == 1.0f ) + { + // loading bar is offscreen + m_bInstallComplete = true; + } +#else + if ( t0 == 1.0f && t1 == 1.0f && !m_dwLoading ) + { + m_bInstallComplete = true; + } +#endif + + int x = (640-FOOTER_W)/2; + DrawTexture( m_pFooterTexture, x, y, FOOTER_W, 480 - PROGRESS_Y, PROGRESS_FOOTER_COLOR ); + x += FOOTER_W - 35; + + // draw left justified loading text + m_Font.Begin(); + m_Font.SetScaleFactors( 0.8f, 0.8f ); + int textWidth = m_Font.GetTextWidth( GetLocalizedLoadingString() ); + x -= SEGMENT_W + textWidth; + m_Font.DrawText( x, y+20, PROGRESS_TEXT_COLOR, GetLocalizedLoadingString(), XBFONT_LEFT ); + m_Font.End(); + + // draw progess bar + x -= SEGMENT_W + PROGRESS_W; + DrawRect( x, y+25, PROGRESS_W, PROGRESS_H, PROGRESS_INSET_COLOR ); + for ( int i =0; i<numSegments; i++ ) + { + DrawRect( x, y+25+2, SEGMENT_W, PROGRESS_H-4, PROGRESS_SEGMENT_COLOR ); + x += SEGMENT_W+SEGMENT_GAP; + } + +} + +//----------------------------------------------------------------------------- +// Name: PlayVideoFrame() +// Desc: Plays one frame of video if a movie is currently open and if there is +// a frame available. This function is safe to call at any time. +//----------------------------------------------------------------------------- +BOOL CXBoxLoader::PlayVideoFrame() +{ + if ( !m_player.IsPlaying() ) + return FALSE; + + const FLOAT fMovieWidth = FLOAT( m_player.GetWidth() ); + const FLOAT fMovieHeight = FLOAT( m_player.GetHeight() ); + + // Move to the next frame. + LPDIRECT3DTEXTURE8 pTexture = 0; + pTexture = m_player.AdvanceFrameForTexturing( m_pd3dDevice ); + + // See if the movie is over now. + if ( !m_player.IsPlaying() ) + { + if ( m_bCaptureLastMovieFrame ) + { + m_bCaptureLastMovieFrame = false; + + // Copy Texture + if ( m_pLastMovieFrame ) + { + m_pLastMovieFrame->Release(); + m_pLastMovieFrame = NULL; + } + + if ( pTexture ) + { + // copy the last frame + D3DSURFACE_DESC d3dSurfaceDesc; + D3DLOCKED_RECT srcRect; + D3DLOCKED_RECT dstRect; + pTexture->GetLevelDesc( 0, &d3dSurfaceDesc ); + m_pd3dDevice->CreateTexture( d3dSurfaceDesc.Width, d3dSurfaceDesc.Height, 0, 0, d3dSurfaceDesc.Format, 0, &m_pLastMovieFrame ); + pTexture->LockRect( 0, &srcRect, NULL, D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE ); + m_pLastMovieFrame->LockRect( 0, &dstRect, NULL, D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE ); + memcpy( dstRect.pBits, srcRect.pBits, srcRect.Pitch*d3dSurfaceDesc.Height ); + } + } + + // Clean up the movie, then return. + m_player.Destroy(); + return FALSE; + } + + // If no texture is ready, return TRUE to indicate that a movie is playing, + // but don't render anything yet. + if ( !pTexture ) + return TRUE; + + const FLOAT fSizeY = 480.0f; + const FLOAT fOriginX = 320.0f - ( fSizeY * .5f * fMovieWidth / fMovieHeight ); + const FLOAT fOriginY = 240.0f - fSizeY * .5f; + + // Draw the texture. + m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); + m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); + m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); + + // Draw the texture as a quad. + m_pd3dDevice->SetTexture( 0, pTexture ); + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + + // Wrapping isn't allowed on linear textures. + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP ); + m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP ); + + FLOAT fLeft = fOriginX + 0.5f; + FLOAT fRight = fOriginX + ( fSizeY * fMovieWidth) / fMovieHeight - 0.5f; + FLOAT fTop = fOriginY + 0.5f; + FLOAT fBottom = fOriginY + fSizeY - 0.5f; + + // On linear textures the texture coordinate range is from 0,0 to width,height, instead + // of 0,0 to 1,1. + m_pd3dDevice->SetVertexShader( D3DFVF_XYZRHW|D3DFVF_TEX1 ); + m_pd3dDevice->Begin( D3DPT_QUADLIST ); + m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, fMovieHeight ); + m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, fLeft, fBottom, 0.0f, 1.0f ); + m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, 0 ); + m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, fLeft, fTop, 0.0f, 1.0f ); + m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, 0 ); + m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, fRight, fTop, 0.0f, 1.0f ); + m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, fMovieHeight ); + m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, fRight, fBottom, 0.0f, 1.0f ); + m_pd3dDevice->End(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// LaunchHL2 +//----------------------------------------------------------------------------- +void CXBoxLoader::LaunchHL2( unsigned int contextCode ) +{ + LAUNCH_DATA launchData; + RelaunchHeader_t *pRelaunch; + const char *pHL2Name; + + memset( &launchData, 0, sizeof( LAUNCH_DATA ) ); + + // build the relaunch structure that HL2 uses + pRelaunch = GetRelaunchHeader( launchData.Data ); + + pRelaunch->magicNumber = RELAUNCH_MAGIC_NUMBER; + pRelaunch->nBytesRelaunchData = 0; + + if ( ( contextCode & CONTEXTCODE_MAGICMASK ) == CONTEXTCODE_HL2MAGIC ) + { + // ok to re-establish persistent data + pRelaunch->bRetail = (contextCode & CONTEXTCODE_RETAIL_MODE) > 0; + pRelaunch->bInDebugger = (contextCode & CONTEXTCODE_INDEBUGGER) > 0; + } + else + { + // ensure we launch under retail conditions + contextCode = CONTEXTCODE_NO_XBDM; + g_activeDevice = -1; + pRelaunch->bRetail = true; + pRelaunch->bInDebugger = false; + } + + pRelaunch->contextCode = contextCode; + pRelaunch->activeDevice = g_activeDevice; + pRelaunch->startTime = g_loaderStartTime; + + // launch the xbe that is expected + if ( contextCode & CONTEXTCODE_DEBUG_XBE ) + { + // debug xbe + pHL2Name = "D:\\hl2d_xbox.xbe"; + } + else if ( contextCode & CONTEXTCODE_RELEASE_XBE ) + { + // release xbe + pHL2Name = "D:\\hl2r_xbox.xbe"; + } + else + { + // default launch to retail xbe + pHL2Name = "D:\\hl2_xbox.xbe"; + } + + XLaunchNewImage( pHL2Name, &launchData ); + + // failed + FatalMediaError(); +} + +//----------------------------------------------------------------------------- +// Performs initialization +//----------------------------------------------------------------------------- +HRESULT CXBoxLoader::Initialize() +{ + DWORD launchType; + LAUNCH_DATA launchData; + + // no active device until set + g_activeDevice = -1; + + // get launch info and command line params needed for early setting of systems + LPSTR pCmdLine = ""; + DWORD retVal = XGetLaunchInfo( &launchType, &launchData ); + if ( retVal == ERROR_SUCCESS ) + { + if ( launchType == LDT_FROM_DASHBOARD ) + { + // launched from dashboard + LD_FROM_DASHBOARD *pLaunchFromDashboard = (LD_FROM_DASHBOARD *)(&launchData); + m_contextCode = pLaunchFromDashboard->dwContext; + } + else if ( launchType == LDT_TITLE ) + { + // launched directly from HL2 to do something + LAUNCH_DATA* pLaunchData = (LAUNCH_DATA *)(&launchData); + pCmdLine = (char *)pLaunchData->Data; + + RelaunchHeader_t *pHeader = GetRelaunchHeader( pLaunchData->Data ); + if ( pHeader->magicNumber == RELAUNCH_MAGIC_NUMBER ) + { + m_contextCode = pHeader->contextCode; + g_activeDevice = pHeader->activeDevice; + } + } + else if ( launchType == LDT_FROM_DEBUGGER_CMDLINE ) + { + // launched from the debugger + LAUNCH_DATA* pLaunchData = (LAUNCH_DATA *)(&launchData); + pCmdLine = (char *)pLaunchData->Data; + strlwr( pCmdLine ); + + // assume retail mode + m_contextCode |= CONTEXTCODE_HL2MAGIC; + m_contextCode |= CONTEXTCODE_RETAIL_MODE; + + if ( strstr( pCmdLine, "-indebugger" ) ) + { + m_contextCode |= CONTEXTCODE_INDEBUGGER; + } +#ifndef _RETAIL + if ( DmIsDebuggerPresent() ) + { + m_contextCode |= CONTEXTCODE_INDEBUGGER; + } +#endif + if ( strstr( pCmdLine, "-debug" ) ) + { + // launch to debug xbe + m_contextCode |= CONTEXTCODE_DEBUG_XBE; + } + else if ( strstr( pCmdLine, "-release" ) ) + { + // launch to release xbe + m_contextCode |= CONTEXTCODE_RELEASE_XBE; + } + else + { + // default launch to retail xbe + m_contextCode |= CONTEXTCODE_RETAIL_XBE|CONTEXTCODE_NO_XBDM; + if ( strstr( pCmdLine, "-dev" ) ) + { + // force dev link + m_contextCode &= ~CONTEXTCODE_NO_XBDM; + } + } + + if ( strstr( pCmdLine, "-attract" ) ) + { + // running the attract sequence + m_contextCode |= CONTEXTCODE_ATTRACT; + } + } + } + + if ( ( m_contextCode & CONTEXTCODE_MAGICMASK ) != CONTEXTCODE_HL2MAGIC ) + { + // unknown, run the install normally + // 0 is a special indicator, due to lack of valid magic + m_contextCode = 0; + } + else + { + if ( m_contextCode & CONTEXTCODE_DASHBOARD ) + { + // coming from dashboard, back to HL2 - immediately! + LaunchHL2( m_contextCode ); + return S_OK; + } + } + + if ( FAILED( XFONT_OpenDefaultFont( &m_pDefaultTrueTypeFont ) ) ) + { + return XBAPPERR_MEDIANOTFOUND; + } + + // load install resources for context + // Load resource file + if ( FAILED( m_xprResource.Create( "D:\\LoaderMedia\\loader.xpr" ) ) ) + { + return XBAPPERR_MEDIANOTFOUND; + } + + if ( FAILED( LoadFont( &m_Font, loader_Font_OFFSET ) ) ) + { + return XBAPPERR_MEDIANOTFOUND; + } + + if ( !( m_contextCode & CONTEXTCODE_ATTRACT ) ) + { + m_pFooterTexture = LoadTexture( loader_Footer_OFFSET ); + if ( !m_pFooterTexture ) + { + return XBAPPERR_MEDIANOTFOUND; + } + + switch( XGetLanguage() ) + { + case XC_LANGUAGE_FRENCH: + m_pMainLegalTexture = LoadTexture( loader_MainLegal_french_OFFSET ); + break; + case XC_LANGUAGE_ITALIAN: + m_pMainLegalTexture = LoadTexture( loader_MainLegal_italian_OFFSET ); + break; + case XC_LANGUAGE_GERMAN: + m_pMainLegalTexture = LoadTexture( loader_MainLegal_german_OFFSET ); + break; + case XC_LANGUAGE_SPANISH: + m_pMainLegalTexture = LoadTexture( loader_MainLegal_spanish_OFFSET ); + break; + default: + m_pMainLegalTexture = LoadTexture( loader_MainLegal_english_OFFSET ); + break; + } + if ( !m_pMainLegalTexture ) + { + return XBAPPERR_MEDIANOTFOUND; + } + + m_pSourceLegalTexture = LoadTexture( loader_SourceLegal_OFFSET ); + if ( !m_pSourceLegalTexture ) + { + return XBAPPERR_MEDIANOTFOUND; + } + + switch( XGetLanguage() ) + { + case XC_LANGUAGE_FRENCH: + m_pSlideShowTextures[0] = LoadTexture( loader_SlideShow1_french_OFFSET ); + break; + case XC_LANGUAGE_ITALIAN: + m_pSlideShowTextures[0] = LoadTexture( loader_SlideShow1_italian_OFFSET ); + break; + case XC_LANGUAGE_GERMAN: + m_pSlideShowTextures[0] = LoadTexture( loader_SlideShow1_german_OFFSET ); + break; + case XC_LANGUAGE_SPANISH: + m_pSlideShowTextures[0] = LoadTexture( loader_SlideShow1_spanish_OFFSET ); + break; + default: + m_pSlideShowTextures[0] = LoadTexture( loader_SlideShow1_english_OFFSET ); + break; + } + m_pSlideShowTextures[1] = LoadTexture( loader_SlideShow2_OFFSET ); + m_pSlideShowTextures[2] = LoadTexture( loader_SlideShow3_OFFSET ); + m_pSlideShowTextures[3] = LoadTexture( loader_SlideShow4_OFFSET ); + m_pSlideShowTextures[4] = LoadTexture( loader_SlideShow5_OFFSET ); + m_pSlideShowTextures[5] = LoadTexture( loader_SlideShow6_OFFSET ); + m_pSlideShowTextures[6] = LoadTexture( loader_SlideShow7_OFFSET ); + m_pSlideShowTextures[7] = LoadTexture( loader_SlideShow8_OFFSET ); + m_pSlideShowTextures[8] = LoadTexture( loader_SlideShow9_OFFSET ); + for ( int i=0; i<MAX_SLIDESHOW_TEXTURES; i++ ) + { + if ( !m_pSlideShowTextures ) + return XBAPPERR_MEDIANOTFOUND; + } + + if ( !VerifyInstall() ) + { + OUTPUT_DEBUG_STRING( "Install failed!\n" ); + return -1; + } + } + + m_pLoadingIconTexture = LoadTexture( loader_LoadingIcon_OFFSET ); + if ( !m_pLoadingIconTexture ) + { + return XBAPPERR_MEDIANOTFOUND; + } + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Performs per-frame video checks +//----------------------------------------------------------------------------- +void CXBoxLoader::TickVideo() +{ + if ( m_bMovieErrorIsFatal && m_player.IsFailed() ) + { + FatalMediaError(); + } +} + +//----------------------------------------------------------------------------- +// Performs per-frame updates +//----------------------------------------------------------------------------- +HRESULT CXBoxLoader::FrameMove() +{ + bool bFailed = false; + + TickVideo(); + + if ( m_State >= 10 && g_copyStats.m_copyErrors ) + { + FatalMediaError(); + } + + if ( m_State >= 10 && ( m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_START ) ) + { + m_bDrawDebug ^= 1; + } + + if ( m_bAllowAttractAbort && ( m_DefaultGamepad.bPressedAnalogButtons[XINPUT_GAMEPAD_A] || ( m_DefaultGamepad.wPressedButtons & XINPUT_GAMEPAD_START ) ) ) + { + StopVideo(); + + // allow only once, until reset + m_bAllowAttractAbort = false; + } + + switch ( m_State ) + { + case 0: + if ( m_contextCode & CONTEXTCODE_ATTRACT ) + { + // play attract mode + m_State = 1; + } + else + { + // normal installation + m_State = 9; + } + break; + + case 1: + // Play the attract video + if ( FAILED( StartVideo( "D:\\LoaderMedia\\Demo_Attract.xmv", false, false ) ) ) + { + // jump to finish + m_State = 4; + } + else + { + m_State = 2; + } + break; + + case 2: + if ( m_player.IsPlaying() || m_player.IsFailed() ) + { + // attract is playing, wait for finish + m_State = 3; + m_bAllowAttractAbort = true; + } + break; + + case 3: + if ( !m_player.IsPlaying() || m_player.IsFailed() ) + { + // attract is over or aborted + m_State = 4; + } + break; + + case 4: + // place loading + m_bDrawLoading = true; + m_FrameCounter = 0; + m_State = 5; + break; + + case 5: + // wait for two frames to pass to ensure loading is rendered + if ( m_FrameCounter > 2 ) + { + m_bLaunch = true; + m_State = 6; + } + break; + + case 6: + // idle + m_State = 6; + break; + + case 9: + // Play the opening Valve video + StartVideo( "D:\\LoaderMedia\\Valve_Leader.xmv", true, true ); + + // Start the async installation process + if ( !StartInstall() ) + { + OUTPUT_DEBUG_STRING( "Install failed!\n" ); + bFailed = true; + break; + } + m_State = 10; + break; + + case 10: + if ( m_player.IsPlaying() ) + { + // intro is playing, wait for finish + m_State = 15; + } + break; + + case 15: + if ( !m_player.IsPlaying() ) + { + // intro is over + m_State = 20; + } + break; + + case 20: + // start legals + StartLegalScreen( LEGAL_SOURCE ); + m_State = 25; + break; + + case 25: + if ( m_bDrawLegal && GetTickCount() - m_LegalTime > LEGAL_DISPLAY_TIME ) + { + // advance to next legal + StartLegalScreen( LEGAL_MAIN ); + m_State = 30; + } + break; + + case 30: + if ( m_bDrawLegal && GetTickCount() - m_LegalTime > LEGAL_DISPLAY_TIME ) + { + // end of all legals + if ( IsTargetFileValid( "Z:\\LoaderMedia\\Title_Load.xmv", 0 ) ) + { + m_bDrawLegal = false; + m_State = 40; + } + } + break; + + case 40: + // play the gordon/alyx hl2 game movie + m_bCaptureLastMovieFrame = true; + StartVideo( "Z:\\LoaderMedia\\Title_Load.xmv", true, true ); + m_State = 50; + break; + + case 50: + if ( m_player.IsPlaying() ) + { + // title movie is playing, wait for finish + m_State = 60; + } + break; + + case 60: + if ( m_player.GetElapsedTime() >= 8000 && !m_bDrawProgress ) + { + // wait for known audio click, then put up progress bar + // start the loading bar animation + m_bDrawProgress = true; + } + + if ( m_bInstallComplete && m_bDrawProgress ) + { + // install has completed + if ( m_player.IsPlaying() ) + { + // force the movie to end + m_player.TerminatePlayback(); + } + m_State = 70; + } + else if ( !m_bInstallComplete && !m_player.IsPlaying() ) + { + // intro movie has finished, but install is still running + // start up slideshow cycler + m_bDrawSlideShow = true; + m_State = 70; + } + break; + + case 70: + // wait for movie or slideshow to stop + if ( !m_player.IsPlaying() && !m_bDrawSlideShow ) + { + m_bLaunch = true; + m_State = 80; + } + break; + + case 80: + // idle + break; + } + + + if ( bFailed ) + { + FatalMediaError(); + } + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Renders the scene +//----------------------------------------------------------------------------- +HRESULT CXBoxLoader::Render() +{ + m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, 0x00000000, 1.0f, 0L ); + + // Play a frame from a video. + BOOL bPlayedFrame = PlayVideoFrame(); + + // hold the last frame of the title movie + if ( m_State >= 60 && !bPlayedFrame ) + { + DrawTexture( m_pLastMovieFrame, 0, 0, 640, 480, 0xFFFFFFFF ); + } + + DrawSlideshow(); + DrawLoadingMarquee(); + DrawProgressBar(); + DrawLegals(); + DrawDebug(); + DrawLog(); + + if ( m_bLaunch ) + { + // The installation has finished + // Persist the image before launching hl2 + m_pd3dDevice->Present( NULL, NULL, NULL, NULL ); + m_pd3dDevice->PersistDisplay(); + + // Make sure the installation thread has completely exited + if ( m_installThread ) + { + WaitForSingleObject( m_installThread, INFINITE ); + CloseHandle( m_installThread ); + } + + LaunchHL2( m_contextCode ); + return S_OK; + } + + // Present the scene + m_pd3dDevice->Present( NULL, NULL, NULL, NULL ); + + m_FrameCounter++; + + return S_OK; +} + +//----------------------------------------------------------------------------- +// Entry point to the program. +//----------------------------------------------------------------------------- +VOID __cdecl main() +{ + CXBoxLoader xbApp; + if ( FAILED( xbApp.Create() ) ) + { + xbApp.FatalMediaError(); + } + xbApp.Run(); +} + diff --git a/utils/xbox/xbox_loader/xbox_loader.h b/utils/xbox/xbox_loader/xbox_loader.h new file mode 100644 index 0000000..b37b2d5 --- /dev/null +++ b/utils/xbox/xbox_loader/xbox_loader.h @@ -0,0 +1,171 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// XBOX_LOADER.H +// +// Master Include +//=====================================================================================// + +#pragma once + +#include <xtl.h> +#include <XBApp.h> +#include <XBFont.h> +#include <XBHelp.h> +#include <xgraphics.h> +#include <xfont.h> +#include <xmv.h> +#include <xbdm.h> +#include <math.h> +#include "XBResource.h" +#include "xmvhelper.h" +#include "toollib.h" +#include "scriplib.h" +#include "loader.h" +#include "jcalg1.h" +#include "xbox/xbox_launch.h" + +#define XBOX_FORENSIC_LOG + +#define SCREEN_WIDTH 640 +#define SCREEN_HEIGHT 480 +#define MAX_FILES 500 +#define MAX_SLIDESHOW_TEXTURES 9 + +#define LEGAL_DISPLAY_TIME 6000 +#define LOADINGBAR_UPTIME 500.0f // slid up or down +#define LOADINGBAR_SLIDETIME 1500.0f // progress speed +#define LOADINGBAR_WAITTIME 500.0f // delay after up to begin slide +#define SLIDESHOW_SLIDETIME 7000 +#define SLIDESHOW_FLIPTIME 1000 + +#define LEGAL_MAIN 0 +#define LEGAL_SOURCE 1 + +#define FOOTER_W 512 + +#define SEGMENT_W 10 +#define SEGMENT_GAP 1 +#define SEGMENT_COUNT 26 + +#define PROGRESS_Y 405 +#define PROGRESS_W (SEGMENT_COUNT*(SEGMENT_W+SEGMENT_GAP)) +#define PROGRESS_H 15 +#define PROGRESS_X 124 + +#define PROGRESS_FOOTER_COLOR 0x88FFFFFF +#define PROGRESS_INSET_COLOR 0xFF222222 +#define PROGRESS_SEGMENT_COLOR 0xFFCC6C00 +#define PROGRESS_TEXT_COLOR 0xFFFFFFFF + +//----------------------------------------------------------------------------- +// Main class to run this application. Most functionality is inherited +// from the CXBApplication base class. +//----------------------------------------------------------------------------- +class CXBoxLoader : public CXBApplication +{ +public: + CXBoxLoader(); + + virtual HRESULT Initialize( void ); + virtual HRESULT Render( void ); + virtual HRESULT FrameMove( void ); + + void DrawRect( int x, int y, int w, int h, DWORD color ); + void DrawLegals(); + void DrawDebug(); + BOOL PlayVideoFrame(); + HRESULT StartVideo( const CHAR* strFilename, bool bFromMemory, bool bFatalOnError ); + void StopVideo(); + bool StartInstall( void ); + bool LoadInstallScript( void ); + D3DTexture *LoadTexture( int resourceID ); + HRESULT LoadFont( CXBFont *pFont, int resourceID ); + void DrawTexture( D3DTexture *pD3DTexture, int x, int y, int w, int h, int color ); + void StartLegalScreen( int legal ); + void DrawProgressBar(); + void DrawLoadingMarquee(); + void DrawSlideshow(); + bool VerifyInstall(); + void StartDashboard( bool bGotoMemory ); + void LoadLogFile(); + void DrawLog(); + void FatalMediaError(); + void LaunchHL2( unsigned int contextCode ); + void TickVideo(); + +private: + IDirect3DTexture8 *m_pLastMovieFrame; + D3DTexture *m_pFooterTexture; + D3DTexture *m_pLoadingIconTexture; + D3DTexture *m_pMainLegalTexture; + D3DTexture *m_pSourceLegalTexture; + D3DTexture *m_pLegalTexture; + D3DTexture *m_pSlideShowTextures[MAX_SLIDESHOW_TEXTURES]; + + CXMVPlayer m_player; + + D3DVertexBuffer *m_pVB; + CXBPackedResource m_xprResource; + + CXBFont m_Font; + + int m_contextCode; + + char *m_fileSrc[MAX_FILES]; + char *m_fileDest[MAX_FILES]; + xCompressHeader *m_fileCompressionHeaders[MAX_FILES]; + DWORD m_fileDestSizes[MAX_FILES]; + int m_numFiles; + + bool m_bAllowAttractAbort; + bool m_bDrawLoading; + bool m_bDrawProgress; + bool m_bDrawDebug; + bool m_bLaunch; + DWORD m_dwLoading; + bool m_bDrawLegal; + HANDLE m_installThread; + DWORD m_LegalTime; + int m_State; + DWORD m_LoadingBarStartTime; + DWORD m_LoadingBarEndTime; + DWORD m_LegalStartTime; + bool m_bInstallComplete; + int m_Version; + int m_FrameCounter; + int m_MovieCount; + bool m_bMovieErrorIsFatal; + bool m_bCaptureLastMovieFrame; + DWORD m_SlideShowStartTime; + bool m_bDrawSlideShow; + int m_SlideShowCount; + bool m_bFinalSlide; + char *m_pLogData; + XFONT* m_pDefaultTrueTypeFont; +}; + +struct CopyStats_t +{ + char m_srcFilename[MAX_PATH]; + char m_dstFilename[MAX_PATH]; + DWORD m_readSize; + DWORD m_writeSize; + DWORD m_bytesCopied; + DWORD m_totalReadTime; + DWORD m_totalWriteTime; + DWORD m_totalReadSize; + DWORD m_totalWriteSize; + DWORD m_bufferReadSize; + DWORD m_bufferWriteSize; + DWORD m_bufferReadTime; + DWORD m_bufferWriteTime; + DWORD m_inflateSize; + DWORD m_inflateTime; + DWORD m_copyTime; + DWORD m_copyErrors; + DWORD m_numReadBuffers; + DWORD m_numWriteBuffers; +}; + +extern bool CopyFileOverlapped( const char *pSrc, const char *pDest, xCompressHeader *pxcHeader, CopyStats_t *pCopyStats ); +extern bool CreateFilePath( const char *inPath ); diff --git a/utils/xbox/xbox_loader/xbox_loader.sln b/utils/xbox/xbox_loader/xbox_loader.sln new file mode 100644 index 0000000..e702a04 --- /dev/null +++ b/utils/xbox/xbox_loader/xbox_loader.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xbox_loader", "xbox_loader.vcproj", "{652C7D60-BC02-4E09-96DD-9300FFFF3403}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug_XBox = Debug_XBox + Release_XBox = Release_XBox + Retail_XBox = Retail_XBox + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {652C7D60-BC02-4E09-96DD-9300FFFF3403}.Debug_XBox.ActiveCfg = Debug_XBox|Xbox + {652C7D60-BC02-4E09-96DD-9300FFFF3403}.Debug_XBox.Build.0 = Debug_XBox|Xbox + {652C7D60-BC02-4E09-96DD-9300FFFF3403}.Release_XBox.ActiveCfg = Release_XBox|Xbox + {652C7D60-BC02-4E09-96DD-9300FFFF3403}.Release_XBox.Build.0 = Release_XBox|Xbox + {652C7D60-BC02-4E09-96DD-9300FFFF3403}.Retail_XBox.ActiveCfg = Retail_XBox|Xbox + {652C7D60-BC02-4E09-96DD-9300FFFF3403}.Retail_XBox.Build.0 = Retail_XBox|Xbox + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/utils/xbox/xbox_loader/xbox_loader.vcproj b/utils/xbox/xbox_loader/xbox_loader.vcproj new file mode 100644 index 0000000..f4a3fef --- /dev/null +++ b/utils/xbox/xbox_loader/xbox_loader.vcproj @@ -0,0 +1,366 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="xbox_loader" + ProjectGUID="{652C7D60-BC02-4E09-96DD-9300FFFF3403}" + RootNamespace="xbox_loader" + SccProjectName="" + SccLocalPath=""> + <Platforms> + <Platform + Name="Xbox"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug_XBox|Xbox" + OutputDirectory=".\Debug_XBox" + IntermediateDirectory=".\Debug_XBox" + ConfigurationType="1" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + OptimizeForProcessor="2" + AdditionalIncludeDirectories="..\..\..\public;..\..\..\common;..\Common\include;..\toollib" + PreprocessorDefinitions="_USE_XGMATH,_XBOX,XBOX_SAMPLE,_DEBUG," + ExceptionHandling="FALSE" + RuntimeLibrary="1" + EnableEnhancedInstructionSet="1" + UsePrecompiledHeader="0" + PrecompiledHeaderThrough="xtl.h" + PrecompiledHeaderFile="$(IntDir)/apploader.pch" + AssemblerListingLocation="$(IntDir)/" + ObjectFile="$(IntDir)/" + ProgramDataBaseFileName="$(IntDir)/" + WarningLevel="3" + SuppressStartupBanner="TRUE" + DebugInformationFormat="4" + CompileAs="0" + DisableSpecificWarnings="4244"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/MACHINE:I386 /FIXED:NO" + AdditionalDependencies="xperf.lib xbdm.lib xapilibd.lib d3d8d.lib d3dx8d.lib xmv.lib xgraphicsd.lib dsoundd.lib xboxkrnl.lib" + OutputFile="$(OutDir)/xbox_loader.exe" + LinkIncremental="2" + SuppressStartupBanner="TRUE" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/xbox_loader.pdb" + GenerateMapFile="TRUE"/> + <Tool + Name="VCPostBuildEventTool" + Description="Copying LoaderMedia to \\Fileserver" + CommandLine="copy LoaderMedia\*.* \\FileServer\user\XBox\DVD\LoaderMedia + +"/> + <Tool + Name="VCPreBuildEventTool" + CommandLine="bundler LoaderMedia_Source\loader_icon.rdf -o LoaderMedia_Source\loader_icon.xbx"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="XboxDeploymentTool" + RemotePath="xe:\hl2\default.xbe" + AdditionalFiles=""/> + <Tool + Name="XboxImageTool" + StackSize="0x10000" + IncludeDebugInfo="TRUE" + LimitAvailableMemoryTo64MB="TRUE" + SuppressStartupBanner="TRUE" + NoLibWarn="TRUE" + TitleID="0x45410091" + TitleName="Half - Life 2 (Debug Build)" + TitleImage="LoaderMedia_Source\loader_icon.xbx" + XBEVersion="4096"/> + </Configuration> + <Configuration + Name="Release_XBox|Xbox" + OutputDirectory="$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE"> + <Tool + Name="VCCLCompilerTool" + OmitFramePointers="TRUE" + OptimizeForProcessor="2" + AdditionalIncludeDirectories="..\..\..\public;..\..\..\common;..\Common\include;..\toollib" + PreprocessorDefinitions="_USE_XGMATH;_XBOX;NDEBUG" + StringPooling="TRUE" + ExceptionHandling="FALSE" + RuntimeLibrary="0" + EnableFunctionLevelLinking="TRUE" + EnableEnhancedInstructionSet="1" + UsePrecompiledHeader="0" + PrecompiledHeaderThrough="" + PrecompiledHeaderFile="" + AssemblerListingLocation="$(IntDir)/" + ObjectFile="$(IntDir)/" + ProgramDataBaseFileName="$(IntDir)/" + WarningLevel="3" + SuppressStartupBanner="TRUE" + DisableSpecificWarnings="4244"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/MACHINE:I386 /FIXED:NO" + AdditionalDependencies="xapilib.lib d3d8.lib d3dx8.lib xgraphics.lib dsound.lib xmv.lib xboxkrnl.lib" + OutputFile="$(OutDir)/xbox_loader.exe" + SuppressStartupBanner="TRUE" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/xbox_loader.pdb" + GenerateMapFile="TRUE" + MapExports="TRUE" + MapLines="TRUE" + OptimizeReferences="2" + EnableCOMDATFolding="2" + SetChecksum="TRUE"/> + <Tool + Name="VCPostBuildEventTool" + Description="Copying LoaderMedia to \\Fileserver" + CommandLine="copy LoaderMedia\*.* \\FileServer\user\XBox\DVD\LoaderMedia +copy $(TargetDir)$(TargetName).xbe \\FileServer\user\XBox\DVD\default.xbe +"/> + <Tool + Name="VCPreBuildEventTool" + CommandLine="bundler LoaderMedia_Source\loader_icon.rdf -o LoaderMedia_Source\loader_icon.xbx"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="XboxDeploymentTool" + RemotePath="xe:\hl2\default.xbe" + AdditionalFiles=""/> + <Tool + Name="XboxImageTool" + StackSize="0x10000" + LimitAvailableMemoryTo64MB="TRUE" + SuppressStartupBanner="TRUE" + TitleID="0x45410091" + TitleName="Half - Life 2 (Release Build)" + TitleImage="LoaderMedia_Source\loader_icon.xbx" + XBEVersion="4096"/> + </Configuration> + <Configuration + Name="Retail_XBox|Xbox" + OutputDirectory="$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + UseOfMFC="0" + ATLMinimizesCRunTimeLibraryUsage="FALSE"> + <Tool + Name="VCCLCompilerTool" + OmitFramePointers="TRUE" + OptimizeForProcessor="2" + AdditionalIncludeDirectories="..\..\..\public;..\..\..\common;..\Common\include;..\toollib" + PreprocessorDefinitions="_USE_XGMATH;_XBOX;NDEBUG;_RETAIL" + StringPooling="TRUE" + ExceptionHandling="FALSE" + RuntimeLibrary="0" + EnableFunctionLevelLinking="TRUE" + EnableEnhancedInstructionSet="1" + UsePrecompiledHeader="0" + PrecompiledHeaderThrough="xtl.h" + PrecompiledHeaderFile="$(IntDir)/apploader.pch" + AssemblerListingLocation="$(IntDir)/" + ObjectFile="$(IntDir)/" + ProgramDataBaseFileName="$(IntDir)/" + WarningLevel="3" + SuppressStartupBanner="TRUE" + DisableSpecificWarnings="4244"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/MACHINE:I386 /FIXED:NO" + AdditionalDependencies="xapilib.lib d3d8.lib d3dx8.lib xgraphics.lib dsound.lib xmv.lib xboxkrnl.lib" + OutputFile="$(OutDir)/xbox_loader.exe" + SuppressStartupBanner="TRUE" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/xbox_loader.pdb" + GenerateMapFile="TRUE" + MapExports="TRUE" + MapLines="TRUE" + OptimizeReferences="2" + EnableCOMDATFolding="2" + SetChecksum="TRUE"/> + <Tool + Name="VCPostBuildEventTool" + Description="Copying LoaderMedia to \\Fileserver" + CommandLine="copy LoaderMedia\*.* \\FileServer\user\XBox\DVD\LoaderMedia +copy $(TargetDir)$(TargetName).xbe \\FileServer\user\XBox\DVD\default.xbe +"/> + <Tool + Name="VCPreBuildEventTool" + CommandLine="bundler LoaderMedia_Source\loader_icon.rdf -o LoaderMedia_Source\loader_icon.xbx"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="XboxDeploymentTool" + RemotePath="xe:\hl2\default.xbe" + AdditionalFiles=""/> + <Tool + Name="XboxImageTool" + StackSize="0x10000" + LimitAvailableMemoryTo64MB="TRUE" + SuppressStartupBanner="TRUE" + TitleID="0x45410091" + TitleName="Half - Life 2" + TitleImage="LoaderMedia_Source\loader_icon.xbx" + XBEVersion="4096"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"> + <File + RelativePath=".\xbox_fileCopy.cpp"> + </File> + <File + RelativePath=".\xbox_loader.cpp"> + </File> + <File + RelativePath=".\xmvhelper.cpp"> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc"> + <File + RelativePath=".\font.h"> + </File> + <File + RelativePath="..\..\..\public\jcalg1.h"> + </File> + <File + RelativePath=".\loader.h"> + </File> + <File + RelativePath="..\..\..\common\xbox\xbox_launch.h"> + </File> + <File + RelativePath=".\xbox_loader.h"> + </File> + <File + RelativePath=".\xmvhelper.h"> + </File> + </Filter> + <Filter + Name="Common Files" + Filter=""> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"> + <File + RelativePath="..\toollib\scriplib.cpp"> + </File> + <File + RelativePath="..\toollib\scriplib.h"> + </File> + <File + RelativePath="..\toollib\toollib.cpp"> + </File> + <File + RelativePath="..\toollib\toollib.h"> + </File> + <File + RelativePath="..\Common\src\XBApp.cpp"> + </File> + <File + RelativePath="..\Common\src\XBFont.cpp"> + </File> + <File + RelativePath="..\Common\src\XBInput.cpp"> + </File> + <File + RelativePath="..\Common\src\XBMesh.cpp"> + </File> + <File + RelativePath="..\Common\src\XBResource.cpp"> + </File> + <File + RelativePath="..\Common\src\XBUtil.cpp"> + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc"> + <File + RelativePath="..\Common\include\XBApp.h"> + </File> + <File + RelativePath="..\Common\include\XBFont.h"> + </File> + <File + RelativePath="..\Common\include\XBHelp.h"> + </File> + <File + RelativePath="..\Common\include\XBInput.h"> + </File> + <File + RelativePath="..\Common\include\XBMesh.h"> + </File> + <File + RelativePath="..\Common\include\XBProfiling.h"> + </File> + <File + RelativePath="..\Common\include\XBResource.h"> + </File> + <File + RelativePath="..\Common\include\XBUtil.h"> + </File> + </Filter> + </Filter> + <Filter + Name="Resources" + Filter="*.rdf"> + <File + RelativePath=".\loader.rdf"> + <FileConfiguration + Name="Debug_XBox|Xbox"> + <Tool + Name="VCCustomBuildTool" + Description="bundler "$(InputPath)"" + CommandLine="bundler "$(InputPath)"" + Outputs="$(ProjectDir)Media\$(InputName).xpr;$(ProjectDir)$(InputName).h"/> + </FileConfiguration> + <FileConfiguration + Name="Release_XBox|Xbox"> + <Tool + Name="VCCustomBuildTool" + Description="bundler "$(InputPath)"" + CommandLine="bundler "$(InputPath)"" + Outputs="$(ProjectDir)Media\$(InputName).xpr;$(ProjectDir)$(InputName).h"/> + </FileConfiguration> + <FileConfiguration + Name="Retail_XBox|Xbox"> + <Tool + Name="VCCustomBuildTool" + Description="bundler "$(InputPath)"" + CommandLine="bundler "$(InputPath)"" + Outputs="$(ProjectDir)Media\$(InputName).xpr;$(ProjectDir)$(InputName).h"/> + </FileConfiguration> + </File> + <File + RelativePath=".\LoaderMedia_Source\loader_icon.rdf"> + </File> + </Filter> + <Filter + Name="Libraries" + Filter=""> + <File + RelativePath="..\..\..\lib\public\jcalg1_static.lib"> + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/utils/xbox/xbox_loader/xmvhelper.cpp b/utils/xbox/xbox_loader/xmvhelper.cpp new file mode 100644 index 0000000..74060de --- /dev/null +++ b/utils/xbox/xbox_loader/xmvhelper.cpp @@ -0,0 +1,788 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//----------------------------------------------------------------------------- +// File: WMVPlayer.cpp +// +// Desc: This helper class provides simple WMV decoding and playback +// functionality. It will be expanded as new playback methods are +// exposed +// +// Hist: 2.7.03 - Created, based on work by Jeff Sullivan +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- + +#include "xbox_loader.h" +#include <xtl.h> +#include "XMVHelper.h" +#include "XBUtil.h" +#include <stdio.h> + + +// Funtion Prototypes for packet loading functions for loading from a file. +HRESULT CALLBACK GetNextPacket( DWORD dwContext, + void **ppPacket, + DWORD* pOffsetToNextPacket ); + +HRESULT CALLBACK ReleasePreviousPacket( DWORD dwContext, + LONGLONG llNextReadByteOffset, + DWORD dwNextPacketSize ); + +// Funtion Prototypes for packet loading functions for loading from a block of memory. +HRESULT CALLBACK GetNextMemoryPacket( DWORD dwContext, + void **ppPacket, + DWORD* pOffsetToNextPacket ); + +HRESULT CALLBACK ReleasePreviousMemoryPacket( DWORD dwContext, + LONGLONG llNextReadByteOffset, + DWORD dwNextPacketSize ); + + + + +//----------------------------------------------------------------------------- +// Name: CXMVPlayer() +// Desc: Constructor for CXMVPlayer +//----------------------------------------------------------------------------- +CXMVPlayer::CXMVPlayer() +{ + m_pXMVDecoder = NULL; + ZeroMemory( &m_VideoDesc, sizeof( m_VideoDesc ) ); + ZeroMemory( &m_AudioDesc, sizeof( m_AudioDesc ) ); + for ( UINT i=0; i<XMVPLAYER_NUMTEXTURES; i++ ) + { + m_pTextures[i] = NULL; + } + + m_dwCurrentFrame = -1; // Will be zero after we decode the first frame. + + m_bPlaying = FALSE; + m_bOverlaysEnabled = FALSE; + + m_loadContext.hFile = INVALID_HANDLE_VALUE; + m_loadContext.pInputBuffer = 0; + m_physicalBuffer = 0; + m_bError = FALSE; +} + + + + +//----------------------------------------------------------------------------- +// Name: ~CXMVPlayer() +// Desc: Destructor for CXMVPlayer +//----------------------------------------------------------------------------- +CXMVPlayer::~CXMVPlayer() +{ + Destroy(); +} + + + + +//----------------------------------------------------------------------------- +// Name: Destroy() +// Desc: Free all resources and clear are resource pointers and handles. +//----------------------------------------------------------------------------- +HRESULT CXMVPlayer::Destroy() +{ + // Disable overlays if we were using them. + if ( m_bOverlaysEnabled ) + { + m_pDevice->EnableOverlay( FALSE ); + m_bOverlaysEnabled = FALSE; + } + + // Free the XMV decoder. + if ( NULL != m_pXMVDecoder ) + { + m_pXMVDecoder->CloseDecoder(); + m_pXMVDecoder = NULL; + } + + ZeroMemory( &m_VideoDesc, sizeof( m_VideoDesc ) ); + ZeroMemory( &m_AudioDesc, sizeof( m_AudioDesc ) ); + + // Release our textures. + for ( UINT i=0; i<XMVPLAYER_NUMTEXTURES; i++ ) + { + if ( m_pTextures[i] ) + m_pTextures[i]->Release(); + m_pTextures[i] = 0; + } + + m_dwCurrentFrame = -1; + m_dwStartTime = 0; + + m_bPlaying = FALSE; + + // Release any file handles we were using. + if( INVALID_HANDLE_VALUE != m_loadContext.hFile ) + { + CloseHandle( m_loadContext.hFile ); + m_loadContext.hFile = INVALID_HANDLE_VALUE; + } + + // Free up memory used for playing a movie from memory. + if ( m_loadContext.pInputBuffer ) + { + free( m_loadContext.pInputBuffer ); + m_loadContext.pInputBuffer = 0; + } + + // Be sure to release the physical memory last! + if( m_physicalBuffer ) + { + XPhysicalFree( m_physicalBuffer ); + m_physicalBuffer = 0; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: FinishOpeningFile() +// Desc: Helper function for the three Open functions. Enables the audio streams, +// initializes the video descriptor, and allocates textures if needed. +//----------------------------------------------------------------------------- +HRESULT CXMVPlayer::FinishOpeningFile( D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures ) +{ + assert( format == D3DFMT_YUY2 || format == D3DFMT_LIN_A8R8G8B8 ); + assert( XMVPLAYER_NUMTEXTURES >= 2); + + HRESULT hr = S_OK; + + m_pXMVDecoder->GetVideoDescriptor( &m_VideoDesc ); + + // Enable the audio streams + for ( unsigned i=0; i < m_VideoDesc.AudioStreamCount; i++ ) + { + m_pXMVDecoder->GetAudioDescriptor( i, &m_AudioDesc ); + hr = m_pXMVDecoder->EnableAudioStream( i, 0, NULL, NULL); + if ( FAILED( hr ) ) + { + XBUtil_DebugPrint( "Unable to enable audio stream 0 (error %x)\n", hr ); + Destroy(); + return hr; + } + } + + for ( int i = 0; i < XMVPLAYER_NUMTEXTURES; i++ ) + { + m_pTextures[i] = 0; + if ( bAllocateTextures ) + { + hr = pDevice->CreateTexture( m_VideoDesc.Width, m_VideoDesc.Height, 1, 0, format, 0, &m_pTextures[i] ); + if ( FAILED( hr ) ) + { + XBUtil_DebugPrint( "Unable to create texture %d (error %x)\n", i, hr ); + Destroy(); + return hr; + } + } + } + + // Initialize what texture we are decoding to, if decoding for texture mapping. + m_nDecodeTextureIndex = 0; + + // Initialize the various texture pointers for use when decoding for overlays. + pShowingTexture = m_pTextures[0]; + pDecodingTexture = m_pTextures[1]; + pSubmittedTexture = 0; + + m_bPlaying = TRUE; + m_dwStartTime = GetTickCount(); + + return hr; +} + + + + +//----------------------------------------------------------------------------- +// Name: OpenFile() +// Desc: Create an XMV decoder object that reads from a file. +//----------------------------------------------------------------------------- +HRESULT CXMVPlayer::OpenFile( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures ) +{ + HRESULT hr = S_OK; + + m_bError = FALSE; + + if ( NULL == lpFilename || NULL == pDevice ) + { + XBUtil_DebugPrint( "Bad parameter to OpenFile()\n" ); + m_bError = TRUE; + return E_FAIL; + } + + hr = XMVDecoder_CreateDecoderForFile( XMVFLAG_SYNC_ON_NEXT_VBLANK, ( CHAR* )lpFilename, &m_pXMVDecoder ); + if ( FAILED( hr ) ) + { + XBUtil_DebugPrint( "Unable to create XMV Decoder for %s (error: %x)\n", lpFilename, hr ); + m_bError = TRUE; + return hr; + } + + hr = FinishOpeningFile( format, pDevice, bAllocateTextures ); + + if ( FAILED( hr ) ) + { + m_bError = TRUE; + } + + return hr; +} + + + + +//----------------------------------------------------------------------------- +// Name: OpenFileForPackets() +// Desc: Create an XMV decoder object that uses the packet reading interface. +// Currently this just reads from a file, but it can be altered to read from +// custom formats, start partway through a file, etc. +//----------------------------------------------------------------------------- +HRESULT CXMVPlayer::OpenFileForPackets( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures ) +{ + HRESULT hr = S_OK; + + // We need to read in the first 4K of data for the XMV player to initialize + // itself from. This is most conveniently read as an array of DWORDS. + DWORD first4Kbytes[4096 / sizeof( DWORD )]; + + // Clear entire context struct to zero + ZeroMemory( &m_loadContext, sizeof( m_loadContext ) ); + + // Open the input file. + m_loadContext.hFile = CreateFile( lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, + NULL ); + + if( m_loadContext.hFile == INVALID_HANDLE_VALUE ) + { + Destroy(); + return E_INVALIDARG; + } + + // Read the first page from the file. We opened it for + // overlapped IO so we do a pair of reads. + m_loadContext.Overlapped.Offset = 0; + m_loadContext.Overlapped.OffsetHigh = 0; + + // Start the read. + if( 0 == ReadFile( m_loadContext.hFile, first4Kbytes, sizeof( first4Kbytes ), NULL, &m_loadContext.Overlapped ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + { + Destroy(); + return E_FAIL; + } + } + + // Wait for the read to finish. + DWORD dwBytesRead; + if( !GetOverlappedResult( m_loadContext.hFile, &m_loadContext.Overlapped, &dwBytesRead, TRUE ) ) + { + Destroy(); + return E_FAIL; + } + + // Check size to make sure input is a valid XMV file. + if( dwBytesRead != 4096 ) + { + Destroy(); + return E_FAIL; + } + + // Create an XMV decoder + hr = XMVDecoder_CreateDecoderForPackets( XMVFLAG_SYNC_ON_NEXT_VBLANK, first4Kbytes, ( DWORD )&m_loadContext, + GetNextPacket, ReleasePreviousPacket, &m_pXMVDecoder ); + if( FAILED( hr ) ) + { + Destroy(); + return E_FAIL; + } + + // The size of the first packet and the minimum size of the two packet buffers are stored in the + // second and third DWORDS of the file. From xmv.h: + // * DWORD NextPacketSize // The size of the next packet + // * DWORD ThisPacketSize // The size of this packet + // * DWORD MaxPacketSize // The size of the largest packet in the file + DWORD dwThisPacketSize = first4Kbytes[1]; + DWORD dwRequiredPacketSize = first4Kbytes[2]; + + // Check for illegal parameters. + if( dwThisPacketSize > dwRequiredPacketSize ) + { + Destroy(); + return E_FAIL; + } + + // XPhysicalAlloc is used so that 5.1 or compressed audio streams can be played. + m_physicalBuffer = ( BYTE* )XPhysicalAlloc( dwRequiredPacketSize * 2, MAXULONG_PTR, 0, PAGE_READWRITE ); + + // Save our information. + m_loadContext.dwPacketSize = dwRequiredPacketSize; + m_loadContext.pLoadingPacket = m_physicalBuffer; + m_loadContext.pDecodingPacket = m_physicalBuffer + dwRequiredPacketSize; + + // Read the first packet. We wind up re-reading the first 4096 + // bytes but it makes the logic for figuring out how much we read + // a little bit easier... + m_loadContext.Overlapped.Offset = 0; + m_loadContext.Overlapped.OffsetHigh = 0; + + if( 0 == ReadFile( m_loadContext.hFile, m_physicalBuffer, dwThisPacketSize, NULL, + &m_loadContext.Overlapped ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + { + Destroy(); + return E_FAIL; + } + } + + // Note - at this point the preceding read has *not* necessarily completed. + // Don't try reading anything from that buffer until GetNextPacket has been + // successfully called. + + hr = FinishOpeningFile( format, pDevice, bAllocateTextures ); + + return hr; +} + + + + +//----------------------------------------------------------------------------- +// Name: OpenMovieFromMemory() +// Desc: Create an XMV decoder object that uses the packet reading interface to +// read from a block of memory. To simplify the memory management this function +// also allocates this block of memory and initializes it from a file. +//----------------------------------------------------------------------------- +HRESULT CXMVPlayer::OpenMovieFromMemory( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures ) +{ + HRESULT hr = S_OK; + + m_bError = FALSE; + + // Read the entire file into memory. + void* data; + hr = XBUtil_LoadFile( lpFilename, &data, &m_loadContext.inputSize ); + if ( FAILED( hr ) ) + { + m_bError = TRUE; + return hr; + } + + m_loadContext.pInputBuffer = ( BYTE* )data; + + // Check size to make sure input is a valid XMV file. + if( m_loadContext.inputSize < 4096 ) + { + Destroy(); + m_bError = TRUE; + return E_FAIL; + } + + // Get a DWORD pointer to the first 4K - needed by CreateDecoderForPackets + DWORD* first4Kbytes = ( DWORD* )data; + + // Create an XMV decoder + hr = XMVDecoder_CreateDecoderForPackets( XMVFLAG_SYNC_ON_NEXT_VBLANK, first4Kbytes, ( DWORD )&m_loadContext, GetNextMemoryPacket, + ReleasePreviousMemoryPacket, &m_pXMVDecoder ); + if ( FAILED( hr ) ) + { + Destroy(); + m_bError = TRUE; + return E_FAIL; + } + + // The size of the first packet and the minimum size of the two packet buffers are stored in the + // second and third DWORDS of the file. From xmv.h: + // * DWORD NextPacketSize // The size of the next packet + // * DWORD ThisPacketSize // The size of this packet + // * DWORD MaxPacketSize // The size of the largest packet in the file + DWORD dwThisPacketSize = first4Kbytes[1]; + DWORD dwRequiredPacketSize = first4Kbytes[2]; + + // Check for illegal parameters. + if( dwThisPacketSize > dwRequiredPacketSize ) + { + Destroy(); + m_bError = TRUE; + return E_FAIL; + } + + // XPhysicalAlloc is used so that 5.1 or compressed audio streams can be played. + m_physicalBuffer = ( BYTE* )XPhysicalAlloc( dwRequiredPacketSize * 2, MAXULONG_PTR, 0, PAGE_READWRITE ); + + // Save our information for the callback functions. + // The size of our two memory blocks. + m_loadContext.dwPacketSize = dwRequiredPacketSize; + // The addresses of our two memory blocks. + m_loadContext.pLoadingPacket = m_physicalBuffer; + m_loadContext.pDecodingPacket = m_physicalBuffer + dwRequiredPacketSize; + + // Information about the block of memory the movie is stored in. + m_loadContext.pInputBuffer = ( BYTE* )data; + m_loadContext.inputSize = m_loadContext.inputSize; + m_loadContext.readOffset = 0; + m_loadContext.currentPacketSize = dwThisPacketSize; + + hr = FinishOpeningFile( format, pDevice, bAllocateTextures ); + + if ( FAILED( hr ) ) + { + m_bError = TRUE; + } + + return hr; +} + + + + +//----------------------------------------------------------------------------- +// Name: AdvanceFrameForTexturing() +// Desc: Unpack the appropriate frames of data for use as textures. +//----------------------------------------------------------------------------- +LPDIRECT3DTEXTURE8 CXMVPlayer::AdvanceFrameForTexturing( LPDIRECT3DDEVICE8 pDevice ) +{ + // You must pass bAllocateTextures==TRUE to Open if you're going to use GetTexture/AdvanceFrame. + assert( m_pTextures[0] ); + + LPDIRECT3DSURFACE8 pSurface; + pDecodingTexture->GetSurfaceLevel( 0, &pSurface ); + + // Decode some information to the current draw texture. + XMVRESULT xr = XMV_NOFRAME; + m_pXMVDecoder->GetNextFrame( pSurface, &xr, NULL ); + + switch ( xr ) + { + case XMV_NOFRAME: + // Do nothing - we didn't get a frame. + break; + + case XMV_NEWFRAME: + ++m_dwCurrentFrame; + // GetNextFrame produced a new frame. So, the texture we were decoding + // to becomes available for drawing as a texture. + pShowingTexture = pDecodingTexture; + + // Setup for decoding to the next texture. + m_nDecodeTextureIndex = ( m_nDecodeTextureIndex + 1 ) % XMVPLAYER_NUMTEXTURES; + pDecodingTexture = m_pTextures[ m_nDecodeTextureIndex ]; + break; + + case XMV_ENDOFFILE: + m_bPlaying = FALSE; + break; + + case XMV_FAIL: + // Data corruption or file read error. We'll treat that the same as + // end of file. + m_bPlaying = FALSE; + m_bError = TRUE; + break; + } + + SAFE_RELEASE( pSurface ); + + // If we haven't decoded the first frame then return zero. + if ( m_dwCurrentFrame < 0 ) + return 0; + + return pShowingTexture; +} + + + + +//----------------------------------------------------------------------------- +// Name: AdvanceFrameForOverlays() +// Desc: Unpack the appropriate frames of data for use as an overlay. +//----------------------------------------------------------------------------- +LPDIRECT3DTEXTURE8 CXMVPlayer::AdvanceFrameForOverlays( LPDIRECT3DDEVICE8 pDevice ) +{ + // You must pass bAllocateTextures==TRUE to Open if you're going to use GetTexture/AdvanceFrame. + assert( m_pTextures[0] ); + + // You have to call CXMVPlayer::EnableOverlays() if you are going to use overlays. + assert( m_bOverlaysEnabled ); + + // If a texture has been submitted to be used as an overlay then we have to + // wait for GetUpdateOverlayState() to return TRUE before we can assume that + // the previous texture has *stopped* being displayed. Once GetUpdateOverlayState() + // returns TRUE then we know that pSubmittedTexture is being displayed, which + // means that, pShowingTexture is available as a decoding target. + if ( pSubmittedTexture ) + { + // If GetOverlayUpdateStatus() returns FALSE then we can still proceed and + // call GetNextFrame(), but we will pass NULL for the surface parameter. + // Some work will still be done, but none of the surfaces will be altered. + if ( pDevice->GetOverlayUpdateStatus() ) + { + // The call to UpdateOverlay() with pSubmittedTexture must have taken + // effect now, so pShowingTexture is available as a decoding target. + assert( !pDecodingTexture ); + pDecodingTexture = pShowingTexture; + pShowingTexture = pSubmittedTexture; + pSubmittedTexture = NULL; + } + } + + LPDIRECT3DSURFACE8 pSurface = NULL; + if ( pDecodingTexture ) + pDecodingTexture->GetSurfaceLevel( 0, &pSurface ); + + // Decode some information to the current draw texture, which may be NULL. + // pDecodingTexture will be NULL if one texture has been submitted as a new + // overlay but the other one is still being displayed as an overlay. + // If pSurface is NULL GetNextFrame() will still do some work. + XMVRESULT xr = XMV_NOFRAME; + m_pXMVDecoder->GetNextFrame( pSurface, &xr, NULL ); + + switch ( xr ) + { + case XMV_NOFRAME: + // Do nothing - we didn't get a frame. + break; + + case XMV_NEWFRAME: + ++m_dwCurrentFrame; + // GetNextFrame produced a new frame. So, the texture we were decoding + // to becomes available for displaying as an overlay. + + // The other texture is not ready to be a decoding target. It is still + // being displayed as an overlay. So, we assign the newly decoded + // texture to pSubmittedTexture for the program to submit as an overlay, + // but we don't yet move the previously submitted texture from pShowing + // to pDecoding. That happens on a subsequent call to this function, after + // GetOverlayUpdateStatus() returns TRUE to tell us that there are no + // overlay swaps pending. + assert( pDecodingTexture ); + assert( !pSubmittedTexture ); + pSubmittedTexture = pDecodingTexture; + pDecodingTexture = NULL; + break; + + case XMV_ENDOFFILE: + m_bPlaying = FALSE; + break; + + case XMV_FAIL: + // Data corruption or file read error. We'll treat that the same as + // end of file. + m_bPlaying = FALSE; + m_bError = TRUE; + break; + } + + SAFE_RELEASE( pSurface ); + + // If we just unpacked a new frame then we return that texture + // and the program must call UpdateOverlay() with the surface + // from that texture. + // If we didn't unpack a frame then the program should do nothing - + // the previous overlay will continue to be displayed. + if ( XMV_NEWFRAME == xr ) + return pSubmittedTexture; + + // No new frame to display. + return 0; +} + + + + +//----------------------------------------------------------------------------- +// Name: TerminatePlayback() +// Desc: Calls XMVDecoder::TerminatePlayback() +//----------------------------------------------------------------------------- +void CXMVPlayer::TerminatePlayback() +{ + m_pXMVDecoder->TerminatePlayback(); +} + + + + +//----------------------------------------------------------------------------- +// Name: Play() +// Desc: Calls XMVDecoder::Play() to play the entire movie. +//----------------------------------------------------------------------------- +HRESULT CXMVPlayer::Play( DWORD Flags, RECT* pRect ) +{ + // You have to call Open before calling Play. + assert( m_pXMVDecoder ); + + // Don't pass bAllocateTextures==TRUE to Open if you're going to use Play. + assert( !m_pTextures[0] ); + + return m_pXMVDecoder->Play( Flags, pRect ); +} + + + + +//----------------------------------------------------------------------------- +// Name: EnableOverlays() +// Desc: Enable the overlay planes for playing the movie in them, and record +// that the overlays should be disabled when Destroy() is called. +//----------------------------------------------------------------------------- +void CXMVPlayer::EnableOverlays( LPDIRECT3DDEVICE8 pDevice ) +{ + m_pDevice = pDevice; + pDevice->EnableOverlay( TRUE ); + m_bOverlaysEnabled = TRUE; +} + + + + +//----------------------------------------------------------------------------- +// Name: GetNextPacket() +// Desc: Callback function to get next packet from a file +//----------------------------------------------------------------------------- +static HRESULT CALLBACK GetNextPacket( DWORD dwContext, VOID** ppPacket, + DWORD* pOffsetToNextPacket ) +{ + LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext; + if( NULL == pContext ) + return E_FAIL; + + // If the next packet is fully loaded then return it, + // otherwise return NULL. + DWORD dwBytesRead; + if( GetOverlappedResult( pContext->hFile, &pContext->Overlapped, + &dwBytesRead, FALSE ) ) + { + // Make the old decoding packet pending. + pContext->pPendingReleasePacket = pContext->pDecodingPacket; + pContext->pDecodingPacket = pContext->pLoadingPacket; + pContext->pLoadingPacket = NULL; + + // Offset to the next packet. + *pOffsetToNextPacket = dwBytesRead; + + // Set *ppPacket to the data we just loaded. + *ppPacket = pContext->pDecodingPacket; + } + else + { + DWORD dwError = GetLastError(); + + // If we're waiting on the IO to finish, just do nothing. + if( dwError != ERROR_IO_INCOMPLETE ) + return HRESULT_FROM_WIN32( dwError ); + + *ppPacket = NULL; + *pOffsetToNextPacket = 0; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: ReleasePreviousPacket() +// Desc: Callback function to release previous packet from a file +//----------------------------------------------------------------------------- +static HRESULT CALLBACK ReleasePreviousPacket( DWORD dwContext, LONGLONG llNextReadByteOffset, + DWORD dwNextPacketSize ) +{ + LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext; + if( NULL == pContext ) + return E_FAIL; + + if( dwNextPacketSize != 0 ) + { + // Start the next load. + pContext->Overlapped.Offset = ( DWORD )( llNextReadByteOffset & 0xFFFFFFFF ); + pContext->Overlapped.OffsetHigh = ( DWORD )( llNextReadByteOffset >> 32 ); + + // Check for bad input file - buffer overrun + if( dwNextPacketSize > pContext->dwPacketSize ) + return E_FAIL; + + pContext->pLoadingPacket = pContext->pPendingReleasePacket; + pContext->pPendingReleasePacket = NULL; + + if( 0 == ReadFile( pContext->hFile, pContext->pLoadingPacket, + dwNextPacketSize, NULL, &pContext->Overlapped ) ) + { + if( GetLastError() != ERROR_IO_PENDING ) + return HRESULT_FROM_WIN32( GetLastError() ); + } + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: GetNextMemoryPacket() +// Desc: Callback function to get next packet from a file, +// and setup for the next packet. +//----------------------------------------------------------------------------- +static HRESULT CALLBACK GetNextMemoryPacket( DWORD dwContext, VOID** ppPacket, + DWORD* pOffsetToNextPacket ) +{ + LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext; + if( NULL == pContext ) + return E_FAIL; + + DWORD dwBytesRead = pContext->inputSize - pContext->readOffset; + if ( pContext->currentPacketSize < dwBytesRead ) + dwBytesRead = pContext->currentPacketSize; + + memcpy( pContext->pLoadingPacket, pContext->pInputBuffer + pContext->readOffset , dwBytesRead ); + pContext->readOffset +=dwBytesRead; + + // Swap pointers so that next time we load it goes into the other packet block. + BYTE* temp = pContext->pLoadingPacket; + pContext->pLoadingPacket = pContext->pDecodingPacket; + pContext->pDecodingPacket = temp; + + // Offset to the next packet. + *pOffsetToNextPacket = dwBytesRead; + + // Set *ppPacket to the data we just loaded. + *ppPacket = pContext->pDecodingPacket; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: ReleasePreviousMemoryPacket() +// Desc: Callback function to release previous packet from a block of memory, +// and setup for the next packet. +//----------------------------------------------------------------------------- +static HRESULT CALLBACK ReleasePreviousMemoryPacket( DWORD dwContext, LONGLONG llNextReadByteOffset, + DWORD dwNextPacketSize ) +{ + LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext; + if( NULL == pContext ) + return E_FAIL; + + // Check for bad input file - buffer overrun + if( dwNextPacketSize > pContext->dwPacketSize ) + return E_FAIL; + + // Record the size of the next packet we are supposed to read, for GetNextMemoryPacket. + pContext->currentPacketSize = dwNextPacketSize; + + return S_OK; +} diff --git a/utils/xbox/xbox_loader/xmvhelper.h b/utils/xbox/xbox_loader/xmvhelper.h new file mode 100644 index 0000000..59dd390 --- /dev/null +++ b/utils/xbox/xbox_loader/xmvhelper.h @@ -0,0 +1,177 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//----------------------------------------------------------------------------- +// File: XMVHelper.h +// +// Desc: Definition of XMV playback helper class for playing XMVs in a number +// of different ways. +// +// Hist: 2.7.03 - Created, based on work by Jeff Sullivan +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- + +#ifndef _XMVHELPER_H_ +#define _XMVHELPER_H_ + +#include <xtl.h> +#include <xmv.h> + +// Number of textures to allocate for decoding. A larger number may help to +// smooth out any frame rate variations if you are decoding to a texture. +// When decoding to overlays two textures are always used. +const DWORD XMVPLAYER_NUMTEXTURES = 2; + + + + +//----------------------------------------------------------------------------- +// Name: LOAD_CONTEXT +// Desc: This structure is used to hold information used by the packet callbacks. +//----------------------------------------------------------------------------- +struct LOAD_CONTEXT +{ + // Memory available for loading packets - maximum packet size. + DWORD dwPacketSize; + + // Packet that XMV was decoding out of, and might still be, that + // we want to load into as soon as we can. + BYTE* pPendingReleasePacket; + // Packet that XMV is decoding out of. + BYTE* pDecodingPacket; + // Packet we are currently loading into. + BYTE* pLoadingPacket; + + + // Information for when reading packets out of a file. + // Handle to the file we are reading from. + HANDLE hFile; + + // Overlapped structure to control asynchronous reading. + OVERLAPPED Overlapped; + + + // Information for when copying packets out of a memory buffer. + // The size and location of the buffer we are reading from if we are + // playing a movie from memory. + BYTE* pInputBuffer; + DWORD inputSize; + // The offset in the memory buffer that we are currently reading from. + DWORD readOffset; + // The size of the packet that we have 'queued up' for reading. This + // is a packet that we have warned about via ReleasePreviousMemoryPacket + // but have not yet been asked to load. + DWORD currentPacketSize; +}; + + + + +class CXMVPlayer +{ +public: + CXMVPlayer(); + ~CXMVPlayer(); + + // Open a .wmv file and prepare it for playing. + // The format parameter specifies what type of texture it should be unpacked into ( if allocateTextures + // is TRUE ). Only YUY2, LIN_X8R8G8B8 and LIN_A8R8G8B8 are supported as formats. + // If you plan to play the movie with Play() or otherwise use overlays then format must be D3DFMT_YUY2 + // pDevice is needed in order to create textures. + // allocateTextures should be TRUE if you plan to play the movie manually with AdvanceFrame. + // It should be FALSE if you plan to play the movie with Play(). + // IsPlaying() will return TRUE if the movie opened successfully. + HRESULT OpenFile( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures ); + + // Open a file using the packet interface. This method of opening a .wmv file can be easily + // customized to read the data from game specific file formats. The GetNextPacket and + // ReleasePreviousPacket functions from XMVHelper.cpp are used to read the packets. See above for + // information about the other parameters. + HRESULT OpenFileForPackets( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures ); + + // Open a block of memory for playing using the packet interface. This method of opening a .wmv file can be easily + // customized to read the data from game specific file formats, or to retain the block of data in memory. + // The GetNextMemoryPacket and ReleasePreviousMemoryPacket functions from XMVHelper.cpp are used to read + // the packets. See above for information about the other parameters. + HRESULT OpenMovieFromMemory( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures ); + + // Destroy frees up all the movie resources. IsPlaying() will return FALSE afterwards. Destroy() + // can be called during movie playback, but is not thread safe. + HRESULT Destroy(); + + // The AdvanceFrame functions move to the next frame if it is time for that. Call this + // function frequently - typically 30-60 times per second. + + // AdvanceFrameForTexturing returns the most recent frame decoded, for texturing. + // It will return zero if the first frame has not been decoded, but otherwise + // will always return a texture. + LPDIRECT3DTEXTURE8 AdvanceFrameForTexturing( LPDIRECT3DDEVICE8 pDevice ); + + // AdvanceFrameForOverlays returns newly decoded frames, for use as an overlays. + // You MUST call UpdateOverlay() with the texture's surface. + // It will return zero if there is not a *new* frame available. + LPDIRECT3DTEXTURE8 AdvanceFrameForOverlays( LPDIRECT3DDEVICE8 pDevice ); + + // Get information about the movie playing. + DWORD GetWidth() const { return m_VideoDesc.Width; } + DWORD GetHeight() const { return m_VideoDesc.Height; } + DWORD GetCurrentFrame() const { return m_dwCurrentFrame; } + DWORD GetElapsedTime() const { return m_bPlaying ? GetTickCount() - m_dwStartTime : 0; } + + // IsPlaying returns TRUE if a movie has been opened but has not ended or been destroyed. + BOOL IsPlaying() const { return m_bPlaying; } + BOOL IsFailed() const { return m_bError; } + + // Call TerminatePlayback on the decoder. It may take a few hundred ms before the movie stops. + // This function is thread safe, as long as you ensure that you don't call Destroy() in another + // thread simultaneously. + void TerminatePlayback(); + HRESULT Play( DWORD Flags, RECT* pRect ); + + // Call this to enable overlays if you will be playing the movie in an overlay using + // AdvanceFrame. The overlays will be disabled when Destroy() is called. + void EnableOverlays( LPDIRECT3DDEVICE8 pDevice ); + +private: + XMVDecoder* m_pXMVDecoder; // Pointer to the XMV decoder object. + XMVVIDEO_DESC m_VideoDesc; // Description of the .xmv files video data. + XMVAUDIO_DESC m_AudioDesc; // Description of the .xmv files audio data. + LPDIRECT3DTEXTURE8 m_pTextures[XMVPLAYER_NUMTEXTURES]; // Textures to cycle through. + DWORD m_nDecodeTextureIndex; // Index of the current texture to decode to. + + // These texture pointers are copies of the values in m_pTextures. They are used to track + // the decode/display/pending status. + // When displaying using textures pShowingTexture points to the texture to display, + // pDecodingTexture points to the texture to decode into, and pSubmittedTexture is always + // zero. + // When displaying using overlays pShowingTexture points to the texture that the hardware + // is currently displaying, pDecodingTexture points to the texture to decode into, and + // pSubmittedTexture is a surface that has been submitted to the overlay system, but not + // necessarily displayed yet. At any given time one of these is always zero. When + // pDecodingTexture is zero that means that pShowingTexture might be being displayed, or + // the hardware might have switched to pSubmittedTexture, we don't know yet. + LPDIRECT3DTEXTURE8 pShowingTexture; + LPDIRECT3DTEXTURE8 pDecodingTexture; + LPDIRECT3DTEXTURE8 pSubmittedTexture; + + int m_dwCurrentFrame; // Current frame number - minus one if not yet started. + DWORD m_dwStartTime; + + BOOL m_bPlaying; // Is a movie currently playing? + BOOL m_bOverlaysEnabled; // Are overlays enabled? For disabling them on destroy. + LPDIRECT3DDEVICE8 m_pDevice; // For use by Destroy to disable overlays. + BOOL m_bError; + + LOAD_CONTEXT m_loadContext; // Data for communicating with packet callback functions. + + BYTE* m_physicalBuffer; // Pointer to block of physical memory used for loading packets. + + // Helper function for opening files. + HRESULT FinishOpeningFile( D3DFORMAT Format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures ); + + // Copy constructor and assignment operator are private and unimplemented + // to prevent unintentional, unsupported, and disastrous copying. + CXMVPlayer( const CXMVPlayer& source ); + CXMVPlayer& operator=( const CXMVPlayer& source ); +}; + +#endif //#ifndef _XMVPLAYER_H_ diff --git a/utils/xbox/xbspinfo/xbspinfo.cpp b/utils/xbox/xbspinfo/xbspinfo.cpp new file mode 100644 index 0000000..8a968ff --- /dev/null +++ b/utils/xbox/xbspinfo/xbspinfo.cpp @@ -0,0 +1,430 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Spews BSP Info +// +//=====================================================================================// + +#include "xbspinfo.h" + +BEGIN_BYTESWAP_DATADESC( dheader_t ) + DEFINE_FIELD( ident, FIELD_INTEGER ), + DEFINE_FIELD( version, FIELD_INTEGER ), + DEFINE_EMBEDDED_ARRAY( lumps, HEADER_LUMPS ), + DEFINE_FIELD( mapRevision, FIELD_INTEGER ), +END_BYTESWAP_DATADESC() + +BEGIN_BYTESWAP_DATADESC( lump_t ) + DEFINE_FIELD( fileofs, FIELD_INTEGER ), + DEFINE_FIELD( filelen, FIELD_INTEGER ), + DEFINE_FIELD( version, FIELD_INTEGER ), + DEFINE_ARRAY( fourCC, FIELD_CHARACTER, 4 ), +END_BYTESWAP_DATADESC() + +typedef struct +{ + const char *pFriendlyName; + const char *pName; + int lumpNum; +} lumpName_t; + +lumpName_t g_lumpNames[] = +{ + {"Entities", "LUMP_ENTITIES", LUMP_ENTITIES}, + {"Planes", "LUMP_PLANES", LUMP_PLANES}, + {"TexData", "LUMP_TEXDATA", LUMP_TEXDATA}, + {"Vertexes", "LUMP_VERTEXES", LUMP_VERTEXES}, + {"Visibility", "LUMP_VISIBILITY", LUMP_VISIBILITY}, + {"Nodes", "LUMP_NODES", LUMP_NODES}, + {"TexInfo", "LUMP_TEXINFO", LUMP_TEXINFO}, + {"Faces", "LUMP_FACES", LUMP_FACES}, + {"Face IDs", "LUMP_FACEIDS", LUMP_FACEIDS}, + {"Lighting", "LUMP_LIGHTING", LUMP_LIGHTING}, + {"Occlusion", "LUMP_OCCLUSION", LUMP_OCCLUSION}, + {"Leafs", "LUMP_LEAFS", LUMP_LEAFS}, + {"Edges", "LUMP_EDGES", LUMP_EDGES}, + {"Surf Edges", "LUMP_SURFEDGES", LUMP_SURFEDGES}, + {"Models", "LUMP_MODELS", LUMP_MODELS}, + {"World Lights", "LUMP_WORLDLIGHTS", LUMP_WORLDLIGHTS}, + {"Leaf Faces", "LUMP_LEAFFACES", LUMP_LEAFFACES}, + {"Leaf Brushes", "LUMP_LEAFBRUSHES", LUMP_LEAFBRUSHES}, + {"Brushes", "LUMP_BRUSHES", LUMP_BRUSHES}, + {"Brush Sides", "LUMP_BRUSHSIDES", LUMP_BRUSHSIDES}, + {"Areas", "LUMP_AREAS", LUMP_AREAS}, + {"Area Portals", "LUMP_AREAPORTALS", LUMP_AREAPORTALS}, + {"Disp Info", "LUMP_DISPINFO", LUMP_DISPINFO}, + {"Original Faces", "LUMP_ORIGINALFACES", LUMP_ORIGINALFACES}, + {"Phys Disp", "LUMP_PHYSDISP", LUMP_PHYSDISP}, + {"Phys Collide", "LUMP_PHYSCOLLIDE", LUMP_PHYSCOLLIDE}, + {"Vert Normals", "LUMP_VERTNORMALS", LUMP_VERTNORMALS}, + {"Vert Normal Indices", "LUMP_VERTNORMALINDICES", LUMP_VERTNORMALINDICES}, + {"Disp Lightmap Alphas", "LUMP_DISP_LIGHTMAP_ALPHAS", LUMP_DISP_LIGHTMAP_ALPHAS}, + {"Disp Verts", "LUMP_DISP_VERTS", LUMP_DISP_VERTS}, + {"Disp Lightmap Sample Positions", "LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS", LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS}, + {"Game Lump", "LUMP_GAME_LUMP", LUMP_GAME_LUMP}, + {"Leaf Water Data", "LUMP_LEAFWATERDATA", LUMP_LEAFWATERDATA}, + {"Primitives", "LUMP_PRIMITIVES", LUMP_PRIMITIVES}, + {"Prim Verts", "LUMP_PRIMVERTS", LUMP_PRIMVERTS}, + {"Prim Indices", "LUMP_PRIMINDICES", LUMP_PRIMINDICES}, + {"Pak File", "LUMP_PAKFILE", LUMP_PAKFILE}, + {"Clip Portal Verts", "LUMP_CLIPPORTALVERTS", LUMP_CLIPPORTALVERTS}, + {"Cube Maps", "LUMP_CUBEMAPS", LUMP_CUBEMAPS}, + {"Tex Data String Data", "LUMP_TEXDATA_STRING_DATA", LUMP_TEXDATA_STRING_DATA}, + {"Tex Data String Table", "LUMP_TEXDATA_STRING_TABLE", LUMP_TEXDATA_STRING_TABLE}, + {"Overlays", "LUMP_OVERLAYS", LUMP_OVERLAYS}, + {"Leaf Min Dist To Water", "LUMP_LEAFMINDISTTOWATER", LUMP_LEAFMINDISTTOWATER}, + {"Face Macro Texture Info", "LUMP_FACE_MACRO_TEXTURE_INFO", LUMP_FACE_MACRO_TEXTURE_INFO}, + {"Disp Tris", "LUMP_DISP_TRIS", LUMP_DISP_TRIS}, + {"Phys Collide Surface", "LUMP_PHYSCOLLIDESURFACE", LUMP_PHYSCOLLIDESURFACE}, + {"Water Overlays", "LUMP_WATEROVERLAYS", LUMP_WATEROVERLAYS}, + {"Leaf Ambient index HDR", "LUMP_LEAF_AMBIENT_INDEX_HDR", LUMP_LEAF_AMBIENT_INDEX_HDR}, + {"Leaf Ambient index", "LUMP_LEAF_AMBIENT_INDEX", LUMP_LEAF_AMBIENT_INDEX}, + {"Lighting (HDR)", "LUMP_LIGHTING_HDR", LUMP_LIGHTING_HDR}, + {"World Lights (HDR)", "LUMP_WORLDLIGHTS_HDR", LUMP_WORLDLIGHTS_HDR}, + {"Leaf Ambient Lighting (HDR)", "LUMP_LEAF_AMBIENT_LIGHTING_HDR", LUMP_LEAF_AMBIENT_LIGHTING_HDR}, + {"Leaf Ambient Lighting", "LUMP_LEAF_AMBIENT_LIGHTING", LUMP_LEAF_AMBIENT_LIGHTING}, + {"*** DEAD ***", "LUMP_XZIPPAKFILE", LUMP_XZIPPAKFILE}, + {"Faces (HDR)", "LUMP_FACES_HDR", LUMP_FACES_HDR}, + {"Flags", "LUMP_MAP_FLAGS", LUMP_MAP_FLAGS}, + {"Fade Overlays", "LUMP_OVERLAY_FADES", LUMP_OVERLAY_FADES}, +}; + +bool g_bQuiet; +bool g_bAsPercent; +bool g_bAsBytes; +bool g_bSortByOffset; +bool g_bSortBySize; +bool g_bFriendlyNames; + +//----------------------------------------------------------------------------- +// Convert lump ID to descriptive Name +//----------------------------------------------------------------------------- +const char *BSP_LumpNumToName( int lumpNum ) +{ + int i; + + for ( i=0; i<ARRAYSIZE( g_lumpNames ); ++i ) + { + if ( g_lumpNames[i].lumpNum == lumpNum ) + { + if ( g_bFriendlyNames ) + { + return g_lumpNames[i].pFriendlyName; + } + else + { + return g_lumpNames[i].pName; + } + } + } + + return "???"; +} + +//----------------------------------------------------------------------------- +// Extract Lump Pak +//----------------------------------------------------------------------------- +void ExtractZip( const char *pFilename, void *pBSPFile ) +{ + dheader_t *pBSPHeader = (dheader_t *)pBSPFile; + + if ( pBSPHeader->lumps[LUMP_PAKFILE].filelen ) + { + Msg( "Extracting Zip to %s\n", pFilename ); + + FILE *fp = fopen( pFilename, "wb" ); + if ( !fp ) + { + Warning( "Failed to create %s\n", pFilename ); + return; + } + + fwrite( (unsigned char *)pBSPFile + pBSPHeader->lumps[LUMP_PAKFILE].fileofs, pBSPHeader->lumps[LUMP_PAKFILE].filelen, 1, fp ); + fclose( fp ); + } + else + { + Msg( "Nothing to do!\n" ); + } +} + +// compare function for qsort below +static dheader_t *g_pSortBSPHeader; +static int LumpCompare( const void *pElem1, const void *pElem2 ) +{ + int lump1 = *(byte *)pElem1; + int lump2 = *(byte *)pElem2; + + int fileOffset1 = g_pSortBSPHeader->lumps[lump1].fileofs; + int fileOffset2 = g_pSortBSPHeader->lumps[lump2].fileofs; + + int fileSize1 = g_pSortBSPHeader->lumps[lump1].filelen; + int fileSize2 = g_pSortBSPHeader->lumps[lump2].filelen; + + if ( g_bSortByOffset ) + { + // invalid or empty lumps will get sorted together + if ( !fileSize1 ) + { + fileOffset1 = 0; + } + + if ( !fileSize2 ) + { + fileOffset2 = 0; + } + + // compare by offset + if ( fileOffset1 < fileOffset2 ) + { + return -1; + } + else if ( fileOffset1 > fileOffset2 ) + { + return 1; + } + } + else if ( g_bSortBySize ) + { + if ( fileSize1 < fileSize2 ) + { + return -1; + } + else if ( fileSize1 > fileSize2 ) + { + return 1; + } + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Spew Info +//----------------------------------------------------------------------------- +void DumpInfo( const char *pFilename, void *pBSPFile, int bspSize ) +{ + const char *pName; + dheader_t *pBSPHeader; + + pBSPHeader = (dheader_t *)pBSPFile; + + Msg( "\n" ); + Msg( "%s\n", pFilename ); + + // sort by offset order + int readOrder[HEADER_LUMPS]; + for ( int i=0; i<HEADER_LUMPS; i++ ) + { + readOrder[i] = i; + } + + if ( g_bSortByOffset || g_bSortBySize ) + { + g_pSortBSPHeader = pBSPHeader; + qsort( readOrder, HEADER_LUMPS, sizeof( int ), LumpCompare ); + } + + for ( int i=0; i<HEADER_LUMPS; ++i ) + { + int lump = readOrder[i]; + pName = BSP_LumpNumToName( lump ); + if ( !pName ) + continue; + + if ( g_bSortByOffset ) + { + Msg( "[Offset: 0x%8.8x] ", pBSPHeader->lumps[lump].fileofs ); + } + + if ( g_bAsPercent ) + { + Msg( "%5.2f%s (%2d) %s\n", 100.0f*pBSPHeader->lumps[lump].filelen/( float )bspSize, "%%", lump, pName ); + } + else if ( g_bAsBytes ) + { + Msg( "%8d: (%2d) %s\n", pBSPHeader->lumps[lump].filelen, lump, pName ); + } + else + { + Msg( "%5.2f MB: (%2d) %s\n", pBSPHeader->lumps[lump].filelen/( 1024.0f*1024.0f ), lump, pName ); + } + } + + Msg( "-------\n" ); + if ( g_bAsBytes ) + { + Msg( "%8d: %s\n", bspSize, "Total Bytes" ); + } + else + { + Msg( "%6.2f MB %s\n", bspSize/( 1024.0f*1024.0f ), "Total" ); + } +} + +//----------------------------------------------------------------------------- +// Load the bsp file +//----------------------------------------------------------------------------- +bool LoadBSPFile( const char* pFilename, void **ppBSPBuffer, int *pBSPSize ) +{ + CByteswap byteSwap; + + *ppBSPBuffer = NULL; + *pBSPSize = 0; + + FILE *fp = fopen( pFilename, "rb" ); + if ( fp ) + { + fseek( fp, 0, SEEK_END ); + int size = ftell( fp ); + fseek( fp, 0, SEEK_SET ); + + *ppBSPBuffer = malloc( size ); + if ( !*ppBSPBuffer ) + { + Warning( "Failed to alloc %d bytes\n", size ); + goto cleanUp; + } + + *pBSPSize = size; + fread( *ppBSPBuffer, size, 1, fp ); + fclose( fp ); + } + else + { + if ( !g_bQuiet ) + { + Warning( "Missing %s\n", pFilename ); + } + goto cleanUp; + } + + dheader_t *pBSPHeader = (dheader_t *)*ppBSPBuffer; + + if ( pBSPHeader->ident != IDBSPHEADER ) + { + if ( pBSPHeader->ident != BigLong( IDBSPHEADER ) ) + { + if ( !g_bQuiet ) + { + Warning( "BSP %s has bad id: got %d, expected %d\n", pFilename, pBSPHeader->ident, IDBSPHEADER ); + } + goto cleanUp; + } + else + { + // bsp is for 360, swap the header + byteSwap.ActivateByteSwapping( true ); + byteSwap.SwapFieldsToTargetEndian( pBSPHeader ); + } + } + + if ( pBSPHeader->version < MINBSPVERSION || pBSPHeader->version > BSPVERSION ) + { + if ( !g_bQuiet ) + { + Warning( "BSP %s has bad version: got %d, expected %d\n", pFilename, pBSPHeader->version, BSPVERSION ); + } + goto cleanUp; + } + + // sucess + return true; + +cleanUp: + if ( *ppBSPBuffer ) + { + free( *ppBSPBuffer ); + *ppBSPBuffer = NULL; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Usage +//----------------------------------------------------------------------------- +void Usage( void ) +{ + Msg( "usage: bspinfo <bspfile> [options]\n" ); + Msg( "options:\n" ); + Msg( "-percent, -p: Show as percentages\n" ); + Msg( "-bytes, -b: Show as bytes\n" ); + Msg( "-q: Quiet, no header, no errors\n" ); + Msg( "-names: Show friendly lump names\n" ); + Msg( "-so: Sort by offset\n" ); + Msg( "-ss: Sort by size\n" ); + Msg( "-extract <zipname>: Extract pak file\n" ); + + exit( -1 ); +} + +//----------------------------------------------------------------------------- +// Purpose: default output func +//----------------------------------------------------------------------------- +SpewRetval_t OutputFunc( SpewType_t spewType, char const *pMsg ) +{ + printf( pMsg ); + + if ( spewType == SPEW_ERROR ) + { + return SPEW_ABORT; + } + return ( spewType == SPEW_ASSERT ) ? SPEW_DEBUGGER : SPEW_CONTINUE; +} + +//----------------------------------------------------------------------------- +// main +// +//----------------------------------------------------------------------------- +int main( int argc, char* argv[] ) +{ + char bspPath[MAX_PATH]; + + // set the valve library printer + SpewOutputFunc( OutputFunc ); + + CommandLine()->CreateCmdLine( argc, argv ); + + Msg( "\nXBSPINFO - Valve Xbox 360 BSP Info ( Build: %s %s )\n", __DATE__, __TIME__ ); + Msg( "( C ) Copyright 1996-2006, Valve Corporation, All rights reserved.\n\n" ); + + if ( argc < 2 || CommandLine()->FindParm( "?" ) || CommandLine()->FindParm( "-h" ) || CommandLine()->FindParm( "-help" ) ) + { + Usage(); + } + + if ( argc >= 2 && argv[1][0] != '-' ) + { + strcpy( bspPath, argv[1] ); + } + else + { + Usage(); + } + + g_bQuiet = CommandLine()->FindParm( "-q" ) != 0; + g_bAsPercent = CommandLine()->FindParm( "-p" ) != 0 || CommandLine()->FindParm( "-percent" ) != 0; + g_bAsBytes = CommandLine()->FindParm( "-b" ) != 0 || CommandLine()->FindParm( "-bytes" ) != 0; + g_bSortByOffset = CommandLine()->FindParm( "-so" ) != 0; + g_bSortBySize = CommandLine()->FindParm( "-ss" ) != 0; + g_bFriendlyNames = CommandLine()->FindParm( "-names" ) != 0; + + void *pBSPBuffer; + int bspSize; + if ( LoadBSPFile( bspPath, &pBSPBuffer, &bspSize ) ) + { + const char *pZipName = CommandLine()->ParmValue( "-extract", "" ); + if ( pZipName && pZipName[0] ) + { + ExtractZip( pZipName, pBSPBuffer ); + } + else + { + DumpInfo( bspPath, pBSPBuffer, bspSize ); + } + + free( pBSPBuffer ); + } + + return ( 0 ); +}
\ No newline at end of file diff --git a/utils/xbox/xbspinfo/xbspinfo.h b/utils/xbox/xbspinfo/xbspinfo.h new file mode 100644 index 0000000..45a31a3 --- /dev/null +++ b/utils/xbox/xbspinfo/xbspinfo.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#pragma once + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <direct.h> +#include <io.h> +#include <time.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/utime.h> +#include "icommandline.h" +#include "tier1/strtools.h" +#include "tier1/utlvector.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlstring.h" +#include "datamap.h" +#include "byteswap.h" +#include "../../common/bsplib.h" + diff --git a/utils/xbox/xbspinfo/xbspinfo.vpc b/utils/xbox/xbspinfo/xbspinfo.vpc new file mode 100644 index 0000000..3b36ea8 --- /dev/null +++ b/utils/xbox/xbspinfo/xbspinfo.vpc @@ -0,0 +1,23 @@ +//----------------------------------------------------------------------------- +// XBSPINFO.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\..\.." +$Macro OUTBINDIR "$SRCDIR\devtools\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_win32_base.vpc" + +$Project "xbspinfo" +{ + $Folder "Source Files" + { + $File "xbspinfo.cpp" + } + + $Folder "Header Files" + { + $File "xbspinfo.h" + } +} diff --git a/utils/xbox/xcompress/xcompress.cpp b/utils/xbox/xcompress/xcompress.cpp new file mode 100644 index 0000000..df87f00 --- /dev/null +++ b/utils/xbox/xcompress/xcompress.cpp @@ -0,0 +1,357 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> +#include <conio.h> +#include <assert.h> +#include "../../../public/jcalg1.h" + +#define DEFAULT_BLOCK_READ_SIZE (512*1024) +#define BLOCK_SIZE (16*1024) +#define WINDOW_SIZE (16*1024) + +static unsigned g_BlockReadSize = DEFAULT_BLOCK_READ_SIZE; + + +static void * __stdcall jcalgAlloc(DWORD size) +{ + return malloc(size); +} + +static bool __stdcall jcalgDealloc(void* pointer) +{ + free(pointer); + return true; +} + +void decompress( char* filenameIn, char* filenameOut ) +{ + FILE* hIn = fopen( filenameIn, "rb" ); + if( !hIn ) + { + printf("Failed to open input file: %s\n",filenameIn); + return; + } + + FILE* hOut = fopen( filenameOut, "wb+" ); + if( !hIn ) + { + printf("Failed to open output file: %s\n",filenameOut); + fclose(hIn); + return; + } + + char* inputBuffer = (char*)malloc( g_BlockReadSize ); + + xCompressHeader header; + fread(&header,1,sizeof(header), hIn ); + fseek(hIn, 0, SEEK_SET); + + char* outputBuffer = (char *)malloc( header.nDecompressionBufferSize ); + + + for(;;) + { + + // Read in a buffer full of compressed data. + unsigned bytesRead = (unsigned)fread(inputBuffer,1,g_BlockReadSize, hIn ); + if( !bytesRead ) + break; + + unsigned outputBufferLength; + + xCompressHeader* header = (xCompressHeader*)inputBuffer; + if( header->nMagic == xCompressHeader::MAGIC + && header->VERSION == xCompressHeader::VERSION ) + { + + printf("Found header:\n" + "\t%i Version\n" + "\t%i Uncompressed Size\n" + "\t%i ReadBlockSize\n" + "\t%i DecompressionBufferSize\n",header->nVersion, header->nUncompressedFileSize,header->nReadBlockSize,header->nDecompressionBufferSize ); + + outputBufferLength = JCALG1_Decompress_Formatted_Buffer( bytesRead - sizeof(*header), inputBuffer + sizeof(*header), g_BlockReadSize * 8, outputBuffer ); + + } + else + { + outputBufferLength = JCALG1_Decompress_Formatted_Buffer( bytesRead, inputBuffer, g_BlockReadSize * 8, outputBuffer ); + } + + assert(0xFFFFFFFF != outputBufferLength ); + fwrite( outputBuffer,1,outputBufferLength, hOut); + + printf("block:%u\n", outputBufferLength); + } + + free(inputBuffer); + free(outputBuffer); + + fclose(hIn); + fclose(hOut); +} + +void compressSimple(char* filenameIn, char* filenameOut ) +{ + FILE* hIn = fopen( filenameIn, "rb" ); + if( !hIn ) + { + printf("Failed to open input file: %s\n",filenameIn); + return; + } + + fseek(hIn, 0, SEEK_END); + unsigned uncompressedSize = ftell(hIn); + fseek(hIn, 0, SEEK_SET); + + char* uncompressedData = (char*)malloc( uncompressedSize ); + fread( uncompressedData,1,uncompressedSize, hIn ); + fclose(hIn); + + char* compressedData = (char*)malloc( uncompressedSize * 4 + sizeof( xCompressSimpleHeader )); + int compressedSize = JCALG1_Compress( + uncompressedData, + uncompressedSize, + compressedData + sizeof( xCompressSimpleHeader ), + uncompressedSize, + jcalgAlloc, + jcalgDealloc, + NULL, + true); + + xCompressSimpleHeader* header = (xCompressSimpleHeader*)compressedData; + header->nMagic = xCompressSimpleHeader::MAGIC; + header->nUncompressedSize = uncompressedSize; + compressedSize += sizeof( xCompressSimpleHeader ); + + + printf("uncompressed size: %uk, compressedSize = %uk\n",uncompressedSize/1024, compressedSize / 1024); + + FILE* hOut = fopen( filenameOut, "wb+" ); + if( !hIn ) + { + printf("Failed to open output file: %s\n",filenameOut); + fclose(hIn); + return; + } + fwrite( compressedData, 1, compressedSize, hOut ); + fclose( hOut ); +} + +void decompressSimple(char* filenameIn, char* filenameOut ) +{ + FILE* hIn = fopen( filenameIn, "rb" ); + if( !hIn ) + { + printf("Failed to open input file: %s\n",filenameIn); + return; + } + + fseek(hIn, 0, SEEK_END); + unsigned compressedSize = ftell(hIn); + fseek(hIn, 0, SEEK_SET); + + char* compressedData = (char*)malloc( compressedSize ); + fread( compressedData,1,compressedSize, hIn ); + fclose(hIn); + + char* decompressedData = (char*)malloc( ((xCompressSimpleHeader*)compressedData)->nUncompressedSize ); + + unsigned decompressedSize = JCALG1_Decompress_Simple_Buffer( compressedData, decompressedData ); + FILE* hOut = fopen( filenameOut, "wb+" ); + if( !hIn ) + { + printf("Failed to open output file: %s\n",filenameOut); + fclose(hIn); + return; + } + fwrite( decompressedData, 1, decompressedSize, hOut ); + fclose( hOut ); +} + + +int main( int argc, char* argv[] ) +{ + if( argc < 4 || argc > 5) + { + puts("USAGE: xcompress [c|d|cs|ds] <inputfile> <outputfile> [readsizekb]"); + puts("\nIf cs is specified, a 'simple' archive is created. (unaligned and decompresses the entire thing to a buffer)"); + return EXIT_FAILURE; + } + + if( !strcmpi(argv[1],"d") ) + { + decompress( argv[2], argv[3] ); + return EXIT_SUCCESS; + + } + + if( !strcmpi(argv[1],"cs") ) + { + compressSimple(argv[2], argv[3]); + return EXIT_SUCCESS; + } + + if( !strcmpi(argv[1],"ds") ) + { + decompressSimple(argv[2], argv[3]); + return EXIT_SUCCESS; + } + + + FILE* hIn = fopen( argv[2], "rb" ); + if( !hIn ) + { + printf("Failed to open input file: %s\n",argv[2]); + return EXIT_FAILURE; + } + fseek( hIn, 0, SEEK_END ); + unsigned nInputLength = ftell( hIn ); + fseek( hIn, 0, SEEK_SET ); + + // Grab + if( argc >= 5 ) + { + g_BlockReadSize = atoi(argv[4]) * 1024; + if( g_BlockReadSize <= 0 ) + { + printf("Invalid block read size! %s\n", argv[4]); + return EXIT_FAILURE; + } + } + + printf("\nOptimized for read block size: %u\n",g_BlockReadSize); + + FILE* hOut = fopen( argv[3], "wb+" ); + if( !hIn ) + { + printf("Failed to open output file: %s\n",argv[3]); + fclose(hIn); + return EXIT_FAILURE; + } + + unsigned char inputBuffer[BLOCK_SIZE]; + unsigned char outputBuffer[BLOCK_SIZE * 2]; + unsigned bytesThisBlock = 0, // Total output bytes this block + inputBytesThisBlock = 0, // Total input bytes this block + totalBytes = 0, + inputBytes = 0; + + // Set up and write out the header; + xCompressHeader header; + header.nMagic = xCompressHeader::MAGIC; + header.nVersion = xCompressHeader::VERSION; + header.nUncompressedFileSize = nInputLength; + header.nReadBlockSize = g_BlockReadSize; + header.nDecompressionBufferSize = 0; + header.nWindowSize = WINDOW_SIZE; + + totalBytes = bytesThisBlock = inputBytesThisBlock = sizeof(header); + fwrite(&header,1,sizeof(header),hOut); + + + + + while(1) + { + // Read an input buffer full of data: + size_t bytesRead = fread(inputBuffer,1,sizeof(inputBuffer),hIn); + if( !bytesRead ) + break; + + inputBytes += (unsigned)bytesRead; + + unsigned compressedSize = JCALG1_Compress( + inputBuffer, + (unsigned)bytesRead, + outputBuffer + sizeof(short), + 16384, + jcalgAlloc, + jcalgDealloc, + NULL, + true); + + unsigned outputBufferSize; + + // If we couldn't compress this block, just write it out: + if( compressedSize == 0 ) + { + outputBufferSize = (unsigned)(bytesRead + sizeof(unsigned short)); + *((unsigned short*)outputBuffer) = ((unsigned short)bytesRead) | 0x8000; + memcpy(outputBuffer+2,inputBuffer,bytesRead); + } + // Tag the compression header onto this block: + else + { + outputBufferSize = compressedSize + sizeof(unsigned short); + *((unsigned short*)outputBuffer) = compressedSize; + } + + // Do we have enough room in this chunk to fit this buffer? + if( bytesThisBlock + outputBufferSize > g_BlockReadSize ) + { + // no, first align it: + while( bytesThisBlock < g_BlockReadSize ) + { + char b = 0; + fwrite( &b, 1, sizeof(b), hOut ); + bytesThisBlock++; + totalBytes++; + } + + // Compute the minimum size of the decompression buffer: + if( inputBytesThisBlock > header.nDecompressionBufferSize ) + { + header.nDecompressionBufferSize = inputBytesThisBlock; + } + + // Start a new block: + bytesThisBlock = 0; + inputBytesThisBlock = 0; + } + + // Write the chunk out: + fwrite(outputBuffer,1, outputBufferSize, hOut); + inputBytesThisBlock += bytesRead; + bytesThisBlock+=outputBufferSize; + totalBytes+=outputBufferSize; + + static int counter =0; + counter++; + + if( counter % 4 == 0 ) + { + printf("\r \rInput:%uk Output:%uk (%0.1f%%)",inputBytes / 1024,totalBytes / 1024, ( (double)totalBytes / (double)inputBytes ) * 100); + fflush(stdout); + } + } + + // Grab the last block (may be the only block)Compute the minimum size of the decompression buffer: + if( inputBytesThisBlock > header.nDecompressionBufferSize ) + { + header.nDecompressionBufferSize = inputBytesThisBlock; + inputBytesThisBlock = 0; + } + + unsigned short terminator = 0; + fwrite(&terminator, 1, sizeof(terminator), hOut ); + + // Align the file to a 2k boundary. + while( ( ftell(hOut) % 2048 ) != 0) + { + fwrite(&terminator,1,1,hOut); + } + + // Write the header out again, this time with ideal decompression size: + header.nDecompressionBufferSize += 128; + + fseek( hOut, 0, SEEK_SET ); + fwrite(&header,1,sizeof(header),hOut); + + + printf("\n"); + fclose(hIn); + fclose(hOut); + +}
\ No newline at end of file diff --git a/utils/xbox/xcompress/xcompress.sln b/utils/xbox/xcompress/xcompress.sln new file mode 100644 index 0000000..4a59466 --- /dev/null +++ b/utils/xbox/xcompress/xcompress.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xcompress", "xcompress.vcproj", "{14872A1D-B112-4092-9ABD-BFF782B80E43}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {14872A1D-B112-4092-9ABD-BFF782B80E43}.Debug.ActiveCfg = Debug|Win32 + {14872A1D-B112-4092-9ABD-BFF782B80E43}.Debug.Build.0 = Debug|Win32 + {14872A1D-B112-4092-9ABD-BFF782B80E43}.Release.ActiveCfg = Release|Win32 + {14872A1D-B112-4092-9ABD-BFF782B80E43}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/utils/xbox/xcompress/xcompress.vcproj b/utils/xbox/xcompress/xcompress.vcproj new file mode 100644 index 0000000..f9c43cc --- /dev/null +++ b/utils/xbox/xcompress/xcompress.vcproj @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="7.10" + Name="xcompress" + ProjectGUID="{14872A1D-B112-4092-9ABD-BFF782B80E43}" + Keyword="Win32Proj"> + <Platforms> + <Platform + Name="Win32"/> + </Platforms> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="..\..\..\..\game\bin" + IntermediateDirectory="Debug" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + MinimalRebuild="TRUE" + BasicRuntimeChecks="3" + RuntimeLibrary="5" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="4"/> + <Tool + Name="VCCustomBuildTool"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/xcompress.exe" + LinkIncremental="2" + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(OutDir)/xcompress.pdb" + SubSystem="1" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="1" + CharacterSet="2"> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="4" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="TRUE" + DebugInformationFormat="3"/> + <Tool + Name="VCCustomBuildTool" + CommandLine="if exist ..\..\..\..\game\bin\"$(TargetName)".exe attrib -r ..\..\..\..\game\bin\"$(TargetName)".exe +if exist "$(TargetPath)" copy "$(TargetPath)" ..\..\..\..\game\bin +" + Outputs="..\..\..\..\game\bin\$(TargetName).exe"/> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/xcompress.exe" + LinkIncremental="1" + GenerateDebugInformation="TRUE" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1"/> + <Tool + Name="VCMIDLTool"/> + <Tool + Name="VCPostBuildEventTool"/> + <Tool + Name="VCPreBuildEventTool"/> + <Tool + Name="VCPreLinkEventTool"/> + <Tool + Name="VCResourceCompilerTool"/> + <Tool + Name="VCWebServiceProxyGeneratorTool"/> + <Tool + Name="VCXMLDataGeneratorTool"/> + <Tool + Name="VCWebDeploymentTool"/> + <Tool + Name="VCManagedWrapperGeneratorTool"/> + <Tool + Name="VCAuxiliaryManagedWrapperGeneratorTool"/> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath="..\..\..\public\jcalg1.h"> + </File> + <File + RelativePath="..\..\..\lib\public\jcalg1_static.lib"> + </File> + <File + RelativePath=".\xcompress.cpp"> + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> |