//========= 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= 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= '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 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; iRelease(); 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= 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(); }