summaryrefslogtreecommitdiff
path: root/utils/xbox
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/xbox
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/xbox')
-rw-r--r--utils/xbox/AppChooser/AppChooser.vpc47
-rw-r--r--utils/xbox/AppChooser/main.cpp2239
-rw-r--r--utils/xbox/AppChooser/xbox/xbox.def3
-rw-r--r--utils/xbox/FontMaker/fontmaker.cpp1119
-rw-r--r--utils/xbox/FontMaker/fontmaker.docbin0 -> 5120 bytes
-rw-r--r--utils/xbox/FontMaker/fontmaker.h145
-rw-r--r--utils/xbox/FontMaker/fontmaker.icobin0 -> 1078 bytes
-rw-r--r--utils/xbox/FontMaker/fontmaker.rc314
-rw-r--r--utils/xbox/FontMaker/fontmaker.vpc68
-rw-r--r--utils/xbox/FontMaker/fontmakerwnd.cpp396
-rw-r--r--utils/xbox/FontMaker/glyphs.cpp1484
-rw-r--r--utils/xbox/FontMaker/glyphs.h104
-rw-r--r--utils/xbox/FontMaker/resource.h80
-rw-r--r--utils/xbox/FontMaker/stdafx.cpp8
-rw-r--r--utils/xbox/FontMaker/stdafx.h27
-rw-r--r--utils/xbox/MakeGameData/MakeGameData.cpp1174
-rw-r--r--utils/xbox/MakeGameData/MakeGameData.h165
-rw-r--r--utils/xbox/MakeGameData/MakeGameData.vpc111
-rw-r--r--utils/xbox/MakeGameData/MakeMaps.cpp383
-rw-r--r--utils/xbox/MakeGameData/MakeMisc.cpp86
-rw-r--r--utils/xbox/MakeGameData/MakeModels.cpp614
-rw-r--r--utils/xbox/MakeGameData/MakeParticles.cpp37
-rw-r--r--utils/xbox/MakeGameData/MakeResources.cpp343
-rw-r--r--utils/xbox/MakeGameData/MakeScenes.cpp40
-rw-r--r--utils/xbox/MakeGameData/MakeScenesImage.vpc133
-rw-r--r--utils/xbox/MakeGameData/MakeShaders.cpp52
-rw-r--r--utils/xbox/MakeGameData/MakeSounds.cpp968
-rw-r--r--utils/xbox/MakeGameData/MakeTextures.cpp45
-rw-r--r--utils/xbox/MakeGameData/MakeZip.cpp593
-rw-r--r--utils/xbox/MakeGameData/XZipTool.h61
-rw-r--r--utils/xbox/MakeGameData/imaadpcm.cpp1531
-rw-r--r--utils/xbox/MakeGameData/imaadpcm.h153
-rw-r--r--utils/xbox/MakeGameData/resample.cpp381
-rw-r--r--utils/xbox/MakeGameData/resample.h18
-rw-r--r--utils/xbox/MakeGameData/sound_io.cpp68
-rw-r--r--utils/xbox/Test360/TriangleASM.cpp981
-rw-r--r--utils/xbox/dumpobj/dumpobj.cpp407
-rw-r--r--utils/xbox/dumpobj/dumpobj.vcproj156
-rw-r--r--utils/xbox/makephx/makephx.cpp359
-rw-r--r--utils/xbox/makephx/makephx.vcproj300
-rw-r--r--utils/xbox/makephx/phx.cpp215
-rw-r--r--utils/xbox/makephx/phxfile.cpp42
-rw-r--r--utils/xbox/makephx/phxfile.h18
-rw-r--r--utils/xbox/makephx/simplify.cpp453
-rw-r--r--utils/xbox/makephx/simplify.h38
-rw-r--r--utils/xbox/makephx/stdafx.cpp9
-rw-r--r--utils/xbox/makephx/stdafx.h20
-rw-r--r--utils/xbox/makephx/util.cpp41
-rw-r--r--utils/xbox/makephx/util.h16
-rw-r--r--utils/xbox/makexvcd/cbase.h19
-rw-r--r--utils/xbox/makexvcd/makexvcd.cpp933
-rw-r--r--utils/xbox/makexvcd/makexvcd.vcproj497
-rw-r--r--utils/xbox/toollib/piclib.cpp557
-rw-r--r--utils/xbox/toollib/piclib.h61
-rw-r--r--utils/xbox/toollib/scriplib.cpp264
-rw-r--r--utils/xbox/toollib/scriplib.h28
-rw-r--r--utils/xbox/toollib/toollib.cpp1322
-rw-r--r--utils/xbox/toollib/toollib.h114
-rw-r--r--utils/xbox/vxbdm/console.cpp763
-rw-r--r--utils/xbox/vxbdm/rcommands.cpp320
-rw-r--r--utils/xbox/vxbdm/vxbdm.vpc37
-rw-r--r--utils/xbox/vxbdm/xbox/xbox.def3
-rw-r--r--utils/xbox/vxconsole/assert_dialog.cpp155
-rw-r--r--utils/xbox/vxconsole/assert_dialog.rc107
-rw-r--r--utils/xbox/vxconsole/assert_resource.h29
-rw-r--r--utils/xbox/vxconsole/bindings.cpp591
-rw-r--r--utils/xbox/vxconsole/bug.cpp1576
-rw-r--r--utils/xbox/vxconsole/common.cpp73
-rw-r--r--utils/xbox/vxconsole/config.cpp217
-rw-r--r--utils/xbox/vxconsole/cpu_profile.cpp983
-rw-r--r--utils/xbox/vxconsole/exclude_paths.cpp1134
-rw-r--r--utils/xbox/vxconsole/fileio.cpp416
-rw-r--r--utils/xbox/vxconsole/icon_connect1.icobin0 -> 318 bytes
-rw-r--r--utils/xbox/vxconsole/icon_connect2.icobin0 -> 318 bytes
-rw-r--r--utils/xbox/vxconsole/icon_connect2a.icobin0 -> 318 bytes
-rw-r--r--utils/xbox/vxconsole/icon_disconnect.icobin0 -> 318 bytes
-rw-r--r--utils/xbox/vxconsole/local_cmds.cpp1307
-rw-r--r--utils/xbox/vxconsole/mem_profile.cpp561
-rw-r--r--utils/xbox/vxconsole/progress.cpp359
-rw-r--r--utils/xbox/vxconsole/remote_cmds.cpp484
-rw-r--r--utils/xbox/vxconsole/resource.h241
-rw-r--r--utils/xbox/vxconsole/show_materials.cpp575
-rw-r--r--utils/xbox/vxconsole/show_memdump.cpp1440
-rw-r--r--utils/xbox/vxconsole/show_sounds.cpp778
-rw-r--r--utils/xbox/vxconsole/show_textures.cpp971
-rw-r--r--utils/xbox/vxconsole/sync_files.cpp942
-rw-r--r--utils/xbox/vxconsole/sys_scriptlib.cpp292
-rw-r--r--utils/xbox/vxconsole/sys_scriptlib.h34
-rw-r--r--utils/xbox/vxconsole/sys_utils.cpp1090
-rw-r--r--utils/xbox/vxconsole/sys_utils.h65
-rw-r--r--utils/xbox/vxconsole/tex_profile.cpp993
-rw-r--r--utils/xbox/vxconsole/timestamp_log.cpp623
-rw-r--r--utils/xbox/vxconsole/vxconsole.cpp1528
-rw-r--r--utils/xbox/vxconsole/vxconsole.h479
-rw-r--r--utils/xbox/vxconsole/vxconsole.icobin0 -> 2238 bytes
-rw-r--r--utils/xbox/vxconsole/vxconsole.rc557
-rw-r--r--utils/xbox/vxconsole/vxconsole.vpc85
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_english.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_french.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_german.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_italian.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_spanish.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/LoadingIcon.tgabin0 -> 16428 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/SourceScreen.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.abcbin0 -> 5938 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.tgabin0 -> 524306 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/footer.tgabin0 -> 131116 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.bmpbin0 -> 49208 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.rdf7
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_english.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_french.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_german.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_italian.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_spanish.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow2.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow3.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow4.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow5.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow6.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow7.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow8.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/LoaderMedia_Source/slideshow9.tgabin0 -> 921644 bytes
-rw-r--r--utils/xbox/xbox_loader/loader.rdf173
-rw-r--r--utils/xbox/xbox_loader/xbox_fileCopy.cpp595
-rw-r--r--utils/xbox/xbox_loader/xbox_loader.cpp2019
-rw-r--r--utils/xbox/xbox_loader/xbox_loader.h171
-rw-r--r--utils/xbox/xbox_loader/xbox_loader.sln24
-rw-r--r--utils/xbox/xbox_loader/xbox_loader.vcproj366
-rw-r--r--utils/xbox/xbox_loader/xmvhelper.cpp788
-rw-r--r--utils/xbox/xbox_loader/xmvhelper.h177
-rw-r--r--utils/xbox/xbspinfo/xbspinfo.cpp430
-rw-r--r--utils/xbox/xbspinfo/xbspinfo.h27
-rw-r--r--utils/xbox/xbspinfo/xbspinfo.vpc23
-rw-r--r--utils/xbox/xcompress/xcompress.cpp357
-rw-r--r--utils/xbox/xcompress/xcompress.sln21
-rw-r--r--utils/xbox/xcompress/xcompress.vcproj127
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
new file mode 100644
index 0000000..f739de0
--- /dev/null
+++ b/utils/xbox/FontMaker/fontmaker.doc
Binary files differ
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
new file mode 100644
index 0000000..8046b8c
--- /dev/null
+++ b/utils/xbox/FontMaker/fontmaker.ico
Binary files differ
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\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist &quot;$(TargetPath)&quot; copy &quot;$(TargetPath)&quot; ..\..\..\..\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 &params )
+{
+ 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\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist &quot;$(TargetPath)&quot; copy &quot;$(TargetPath)&quot; ..\..\..\..\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 &params, 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 &params, 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 &params )
+{
+ 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 &params )
+{
+ 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 &params )
+{
+ 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 &params )
+{
+ 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 &params );
+
+#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\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist &quot;$(TargetPath)&quot; copy &quot;$(TargetPath)&quot; ..\..\..\..\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\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist &quot;$(TargetPath)&quot; copy &quot;$(TargetPath)&quot; ..\..\..\..\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( &ltime );
+ tm *pTime = localtime( &ltime );
+ 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
new file mode 100644
index 0000000..dd373b0
--- /dev/null
+++ b/utils/xbox/vxconsole/icon_connect1.ico
Binary files differ
diff --git a/utils/xbox/vxconsole/icon_connect2.ico b/utils/xbox/vxconsole/icon_connect2.ico
new file mode 100644
index 0000000..638dd28
--- /dev/null
+++ b/utils/xbox/vxconsole/icon_connect2.ico
Binary files differ
diff --git a/utils/xbox/vxconsole/icon_connect2a.ico b/utils/xbox/vxconsole/icon_connect2a.ico
new file mode 100644
index 0000000..61473ea
--- /dev/null
+++ b/utils/xbox/vxconsole/icon_connect2a.ico
Binary files differ
diff --git a/utils/xbox/vxconsole/icon_disconnect.ico b/utils/xbox/vxconsole/icon_disconnect.ico
new file mode 100644
index 0000000..2146fe3
--- /dev/null
+++ b/utils/xbox/vxconsole/icon_disconnect.ico
Binary files differ
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, &sectLoad );
+ 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
new file mode 100644
index 0000000..48c0d4c
--- /dev/null
+++ b/utils/xbox/vxconsole/vxconsole.ico
Binary files differ
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
new file mode 100644
index 0000000..5c61f95
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_english.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_french.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_french.tga
new file mode 100644
index 0000000..0116d18
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_french.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_german.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_german.tga
new file mode 100644
index 0000000..629524e
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_german.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_italian.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_italian.tga
new file mode 100644
index 0000000..c37b3a2
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_italian.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_spanish.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_spanish.tga
new file mode 100644
index 0000000..a935072
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LegalScreen_spanish.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/LoadingIcon.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/LoadingIcon.tga
new file mode 100644
index 0000000..ae2134d
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/LoadingIcon.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/SourceScreen.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/SourceScreen.tga
new file mode 100644
index 0000000..4acd064
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/SourceScreen.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.abc b/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.abc
new file mode 100644
index 0000000..bcbc925
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.abc
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.tga
new file mode 100644
index 0000000..103fb95
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/Tahoma_16.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/footer.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/footer.tga
new file mode 100644
index 0000000..340f4a5
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/footer.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.bmp b/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.bmp
new file mode 100644
index 0000000..29e905e
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/loader_icon.bmp
Binary files differ
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
new file mode 100644
index 0000000..b45b3a1
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_english.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_french.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_french.tga
new file mode 100644
index 0000000..2963e36
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_french.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_german.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_german.tga
new file mode 100644
index 0000000..2636bec
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_german.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_italian.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_italian.tga
new file mode 100644
index 0000000..a09efae
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_italian.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_spanish.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_spanish.tga
new file mode 100644
index 0000000..ade8343
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow1_spanish.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow2.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow2.tga
new file mode 100644
index 0000000..52e952b
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow2.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow3.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow3.tga
new file mode 100644
index 0000000..76b3700
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow3.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow4.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow4.tga
new file mode 100644
index 0000000..1bc591d
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow4.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow5.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow5.tga
new file mode 100644
index 0000000..040a8ac
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow5.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow6.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow6.tga
new file mode 100644
index 0000000..1edbb6e
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow6.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow7.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow7.tga
new file mode 100644
index 0000000..4f47769
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow7.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow8.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow8.tga
new file mode 100644
index 0000000..30dabe8
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow8.tga
Binary files differ
diff --git a/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow9.tga b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow9.tga
new file mode 100644
index 0000000..a9cfb82
--- /dev/null
+++ b/utils/xbox/xbox_loader/LoaderMedia_Source/slideshow9.tga
Binary files differ
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, &copyFile, 0, 0 );
+ if ( !hReadThread )
+ {
+ // failure
+ goto cleanUp;
+ }
+
+ // wait for buffers to populate
+
+ // start the write thread
+ hWriteThread = CreateThread( 0, 0, &WriteFileThread, &copyFile, 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 &quot;$(InputPath)&quot;"
+ CommandLine="bundler &quot;$(InputPath)&quot;"
+ Outputs="$(ProjectDir)Media\$(InputName).xpr;$(ProjectDir)$(InputName).h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_XBox|Xbox">
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="bundler &quot;$(InputPath)&quot;"
+ CommandLine="bundler &quot;$(InputPath)&quot;"
+ Outputs="$(ProjectDir)Media\$(InputName).xpr;$(ProjectDir)$(InputName).h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Retail_XBox|Xbox">
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="bundler &quot;$(InputPath)&quot;"
+ CommandLine="bundler &quot;$(InputPath)&quot;"
+ 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\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist &quot;$(TargetPath)&quot; copy &quot;$(TargetPath)&quot; ..\..\..\..\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>