void RageFileManager::MountInitialFilesystems()
{
	/* Add file search paths, higher priority first. */
#if defined(XBOX)
	RageFileManager::Mount( "dir", "D:\\", "" );
#elif defined(LINUX)
	/* Absolute paths.  This is rarely used, eg. by Alsa9Buf::GetSoundCardDebugInfo(). 
	 * All paths that start with a slash (eg. "/proc") should use this, so put it
	 * first. */
	RageFileManager::Mount( "dir", "/", "/" );
	
	/* We can almost do this, to have machine profiles be system-global to eg. share
	 * scores.  It would need to handle permissions properly. */
/*	RageFileManager::Mount( "dir", "/var/lib/games/stepmania", "Data/Profiles" ); */
	
	// CString Home = getenv( "HOME" ) + "/" + PRODUCT_NAME;

	/*
	 * Next: path to write general mutable user data.  If the above path fails (eg.
	 * wrong permissions, doesn't exist), machine memcard data will also go in here. 
	 * XXX: It seems silly to have two ~ directories.  If we're going to create a
	 * directory on our own, it seems like it should be a dot directory, but it
	 * seems wrong to put lots of data (eg. music) in one.  Hmm. 
	 */
	/* XXX: create */
/*	RageFileManager::Mount( "dir", Home + "." PRODUCT_NAME, "Data" ); */

	/* Next, search ~/StepMania.  This is where users can put music, themes, etc. */
	/* RageFileManager::Mount( "dir", Home + PRODUCT_NAME, "" ); */

	/* Search for a directory with "Songs" in it.  Be careful: the CWD is likely to
	 * be ~, and it's possible that some users will have a ~/Songs/ directory that
	 * has nothing to do with us, so check the initial directory last. */
	CString Root = "";
	struct stat st;
	if( Root == "" && !stat( DirOfExecutable + "/Songs", &st ) && st.st_mode&S_IFDIR )
		Root = DirOfExecutable;
	if( Root == "" && !stat( InitialWorkingDirectory + "/Songs", &st ) && st.st_mode&S_IFDIR )
		Root = InitialWorkingDirectory;
	if( Root == "" )
		RageException::Throw( "Couldn't find \"Songs\"" );
			
	RageFileManager::Mount( "dir", Root, "" );
#elif defined(_WINDOWS)
	/* All Windows data goes in the directory one level above the executable. */
	CHECKPOINT_M( ssprintf( "DOE \"%s\"", DirOfExecutable.c_str()) );
	CStringArray parts;
	split( DirOfExecutable, "/", parts );
	CHECKPOINT_M( ssprintf( "... %i parts", parts.size()) );
	ASSERT_M( parts.size() > 1, ssprintf("Strange DirOfExecutable: %s", DirOfExecutable.c_str()) );
	CString Dir = join( "/", parts.begin(), parts.end()-1 );
	RageFileManager::Mount( "dir", Dir, "" );
#else
	/* Paths relative to the CWD: */
	RageFileManager::Mount( "dir", ".", "" );
#endif
}
static RString GetMountDir( const RString &sDirOfExecutable )
{
	/* All Windows data goes in the directory one level above the executable. */
	CHECKPOINT_M( ssprintf( "DOE \"%s\"", sDirOfExecutable.c_str()) );
	vector<RString> asParts;
	split( sDirOfExecutable, "/", asParts );
	CHECKPOINT_M( ssprintf( "... %i asParts", asParts.size()) );
	ASSERT_M( asParts.size() > 1, ssprintf("Strange sDirOfExecutable: %s", sDirOfExecutable.c_str()) );
	RString sDir = join( "/", asParts.begin(), asParts.end()-1 );
	return sDir;
}
Exemplo n.º 3
0
bool IniFile::ReadFile( const CString &sPath )
{
	m_sPath = sPath;
	CHECKPOINT_M( ssprintf("Reading '%s'",m_sPath.c_str()) );

	RageFile f;
	if( !f.Open( m_sPath ) )
	{
		LOG->Trace( "Reading '%s' failed: %s", m_sPath.c_str(), f.GetError().c_str() );
		m_sError = f.GetError();
		return 0;
	}

	CString keyname;
	while( 1 )
	{
		CString line;

		int ret = f.GetLine(line);
		if( ret == 0 ) /* eof */
			return true;
		if( ret < 0 )
		{
			m_sError = f.GetError();
			return false;
		}

		if( line.size() >= 3 &&
			line[0] == '\xef' &&
			line[1] == '\xbb' &&
			line[2] == '\xbf'
			)
		{
			/* Obnoxious NT marker for UTF-8.  Remove it. */
			line.erase(0, 3);
		}

		if( line == "" )
			continue;

		if( line.substr(0, 2) == "//" || line.substr(0) == "#" )
			continue; /* comment */

		if( line[0] == '[' && line[line.GetLength()-1] == ']'  )
		{
			/* New section. */
			keyname = line.substr(1, line.size()-2);
		}
		else //if a value
		{
			int iEqualIndex = line.Find("=");
			if( iEqualIndex != -1 )
			{
				CString valuename = line.Left(iEqualIndex);
				CString value = line.Right(line.GetLength()-valuename.GetLength()-1);
				SetValue(keyname,valuename,value);
			}
		}
	}
}
Exemplo n.º 4
0
void OptionRow::PrepareItemText( CString &s ) const
{
	if( s == "" )
		return;
	bool bTheme = false;
	
	// HACK: Always theme the NEXT_ROW and EXIT items, even if metrics says not to theme.
	if( s == NEXT_ROW_NAME )							bTheme = true;
	if( s == EXIT_NAME )								bTheme = true;
	if( THEME_ITEMS && m_RowDef.m_bAllowThemeItems )	bTheme = true;

	if( bTheme )
	{
		if (m_RowDef.name != "Speed")
			s = THEME_OPTION_ITEM( s, false ); 
		else
			// very hacky: we assume an ITG-related theme, so we assume a uniform way of determining
			// the display of speed mods.  Very non-standard, but allows for flexibility of changing the options
			//     --infamouspat
		{
			CHECKPOINT_M(s);
			s = THEME_OPTION_ITEM( s, true );
		}
	}
	if( CAPITALIZE_ALL_OPTION_NAMES )
		s.MakeUpper(); 
}
Exemplo n.º 5
0
/* We write the cache even if we won't use it, so we don't have to recache everything
 * if the memory or settings change. */
void BannerCache::CacheBanner( CString BannerPath )
{
	if( PREFSMAN->m_BannerCache != PrefsManager::BNCACHE_LOW_RES )
		return;

	CHECKPOINT_M( BannerPath );
	if( !DoesFileExist(BannerPath) )
		return;

	const CString CachePath = GetBannerCachePath(BannerPath);

	/* Check the full file hash.  If it's the loaded and identical, don't recache. */
	if( DoesFileExist(CachePath) )
	{
		unsigned CurFullHash;
		const unsigned FullHash = GetHashForFile( BannerPath );
		if( BannerData.GetValue( BannerPath, "FullHash", CurFullHash ) &&
			CurFullHash == FullHash )
		{
			/* It's identical.  Just load it. */
			LoadBanner( BannerPath );
			return;
		}
	}

	CacheBannerInternal( BannerPath );
}
Exemplo n.º 6
0
/* seemingly good start of an automagical way to mount a user pack based on the folder structure */
CString UserPackManager::GetPackMountPoint( const CString &sPack )
{
	enum UserPackMountType { UPACK_MOUNT_ROOT, UPACK_MOUNT_SONGS };

	RageFileDriverZip *pZip = new RageFileDriverZip;
	CHECKPOINT_M( sPack );
	// it should already be a valid zip by now...
	ASSERT( pZip->Load( sPack ) );
	UserPackMountType upmt = UPACK_MOUNT_SONGS;

	CStringArray asRootEntries;
	pZip->GetDirListing( "/", asRootEntries, true, false );
	SAFE_DELETE( pZip );

	// if we find a StepMania root folder, mount it as one
	for( unsigned i = 0; i < asRootEntries.size(); ++i )
	{
		for( unsigned j = 0; j < ARRAYLEN(asRootDirs); j++ )
		{
			if ( asRootEntries[i].CompareNoCase( asRootDirs[j] ) == 0 )
				return "/";
		}
	}

	/* for now, assume a Songs-only pack if the root dirs aren't there */
	return "/Songs";
}
Exemplo n.º 7
0
std::string MovieTexture_Generic::Init()
{
	std::string sError = m_pDecoder->Open( GetID().filename );
	if( sError != "" )
		return sError;

	CreateTexture();
	CreateFrameRects();

	/* Decode one frame, to guarantee that the texture is drawn when this function returns. */
	int ret = m_pDecoder->DecodeFrame( -1 );
	if( ret == -1 )
		return fmt::sprintf( "%s: error getting first frame", GetID().filename.c_str() );
	if( ret == 0 )
	{
		/* There's nothing there. */
		return fmt::sprintf( "%s: EOF getting first frame", GetID().filename.c_str() );
	}

	m_ImageWaiting = FRAME_DECODED;

	LOG->Trace( "Resolution: %ix%i (%ix%i, %ix%i)",
			m_iSourceWidth, m_iSourceHeight,
			m_iImageWidth, m_iImageHeight, m_iTextureWidth, m_iTextureHeight );

	UpdateFrame();

	CHECKPOINT_M("Generic initialization completed. No errors found.");

	return std::string();
}
Exemplo n.º 8
0
void StageStats::AssertValid( PlayerNumber pn ) const
{
	if( vpSongs[0] )
		CHECKPOINT_M( vpSongs[0]->GetFullTranslitTitle() );
	ASSERT( vpSteps[pn][0] );
	ASSERT_M( playMode < NUM_PLAY_MODES, ssprintf("playmode %i", playMode) );
	ASSERT( pStyle != NULL );
	ASSERT_M( vpSteps[pn][0]->GetDifficulty() < NUM_DIFFICULTIES, ssprintf("difficulty %i", vpSteps[pn][0]->GetDifficulty()) );
	ASSERT( vpSongs.size() == vpSteps[pn].size() );
}
Exemplo n.º 9
0
void ScreenOptionsMaster::ExportOptions( int r, const vector<PlayerNumber> &vpns )
{
	CHECKPOINT_M( ssprintf("%i/%i", r, int(m_pRows.size())) );

	OptionRow &row = *m_pRows[r];
	bool bRowHasFocus[NUM_PLAYERS];
	ZERO( bRowHasFocus );
	FOREACH_CONST( PlayerNumber, vpns, p )
	{
		int iCurRow = m_iCurrentRow[*p];
		bRowHasFocus[*p] = iCurRow == r;
	}
void DirectFilenameDB::CacheFile( const RString &sPath )
{
	CHECKPOINT_M( root+sPath );
	RString sDir = Dirname( sPath );
	FileSet *pFileSet = GetFileSet( sDir, false );
	if( pFileSet == NULL )
	{
		// This directory isn't cached so do nothing.
		m_Mutex.Unlock(); // Locked by GetFileSet()
		return;
	}
	while( !pFileSet->m_bFilled )
		m_Mutex.Wait();
		
#if defined(WIN32)
	// There is almost surely a better way to do this
	WIN32_FIND_DATA fd;
	HANDLE hFind = DoFindFirstFile( root+sPath, &fd );
	if( hFind == INVALID_HANDLE_VALUE )
	{
		m_Mutex.Unlock(); // Locked by GetFileSet()
		return;
	}
	File f( fd.cFileName );
	f.dir = !!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
	f.size = fd.nFileSizeLow;
	f.hash = fd.ftLastWriteTime.dwLowDateTime;
	
	pFileSet->files.insert( f );
	FindClose( hFind );
#else
	File f( Basename(sPath) );
	
	struct stat st;
	if( DoStat(root+sPath, &st) == -1 )
	{
		int iError = errno;
		/* If it's a broken symlink, ignore it.  Otherwise, warn. */
		/* Huh? */
		WARN( ssprintf("File '%s' is gone! (%s)",
			       sPath.c_str(), strerror(iError)) );
	}
	else
	{
		f.dir = (st.st_mode & S_IFDIR);
		f.size = (int)st.st_size;
		f.hash = st.st_mtime;
	}
	
	pFileSet->files.insert(f);
#endif
	m_Mutex.Unlock(); // Locked by GetFileSet()	
}
Exemplo n.º 11
0
void StageStats::AssertValid( MultiPlayer pn ) const
{
	ASSERT( m_vpPlayedSongs.size() != 0 );
	ASSERT( m_vpPossibleSongs.size() != 0 );
	if( m_vpPlayedSongs[0] )
		CHECKPOINT_M( m_vpPlayedSongs[0]->GetTranslitFullTitle() );
	ASSERT( m_multiPlayer[pn].m_vpPossibleSteps.size() != 0 );
	ASSERT( m_multiPlayer[pn].m_vpPossibleSteps[0] != NULL );
	ASSERT_M( m_playMode < NUM_PlayMode, ssprintf("playmode %i", m_playMode) );
	ASSERT_M( m_player[pn].m_vpPossibleSteps[0]->GetDifficulty() < NUM_Difficulty, ssprintf("difficulty %i", m_player[pn].m_vpPossibleSteps[0]->GetDifficulty()) );
	ASSERT( (int) m_vpPlayedSongs.size() == m_player[pn].m_iStepsPlayed );
	ASSERT( m_vpPossibleSongs.size() == m_player[pn].m_vpPossibleSteps.size() );
}
Exemplo n.º 12
0
void StageStats::AssertValid( PlayerNumber pn ) const
{
	ASSERT( m_vpPlayedSongs.size() != 0 );
	ASSERT( m_vpPossibleSongs.size() != 0 );
	if( m_vpPlayedSongs[0] )
		CHECKPOINT_M( m_vpPlayedSongs[0]->GetTranslitFullTitle() );
	ASSERT( m_player[pn].m_iStepsPlayed > 0 );
	ASSERT( m_player[pn].m_vpPossibleSteps.size() != 0 );
	ASSERT( m_player[pn].m_vpPossibleSteps[0] != NULL );
	ASSERT_M( m_playMode < NUM_PlayMode, ssprintf("playmode %i", m_playMode) );
	ASSERT_M( m_player[pn].m_vpPossibleSteps[0]->GetDifficulty() < NUM_Difficulty, ssprintf("Invalid Difficulty %i", m_player[pn].m_vpPossibleSteps[0]->GetDifficulty()) );
	ASSERT_M( (int) m_vpPlayedSongs.size() == m_player[pn].m_iStepsPlayed, ssprintf("%i Songs Played != %i Steps Played for player %i", (int)m_vpPlayedSongs.size(), (int)m_player[pn].m_iStepsPlayed, pn) );
	ASSERT_M( m_vpPossibleSongs.size() == m_player[pn].m_vpPossibleSteps.size(), ssprintf("%i Possible Songs != %i Possible Steps for player %i", (int)m_vpPossibleSongs.size(), (int)m_player[pn].m_vpPossibleSteps.size(), pn) );
}
Exemplo n.º 13
0
bool IniFile::ReadFile( const RString &sPath )
{
	m_sPath = sPath;
	CHECKPOINT_M( ssprintf("Reading '%s'",m_sPath.c_str()) );

	RageFile f;
	if( !f.Open( m_sPath ) )
	{
		LOG->Trace( "Reading '%s' failed: %s", m_sPath.c_str(), f.GetError().c_str() );
		m_sError = f.GetError();
		return 0;
	}

	return ReadFile( f );
}
Exemplo n.º 14
0
bool BitmapText::LoadFromTextureAndChars( const CString& sTexturePath, const CString& sChars )
{
	CHECKPOINT_M( ssprintf("BitmapText::LoadFromTextureAndChars(\"%s\",\"%s\")", sTexturePath.c_str(), sChars.c_str()) );

	if( m_pFont )
	{
		FONT->UnloadFont( m_pFont );
		m_pFont = NULL;
	}

	m_pFont = FONT->LoadFont( sTexturePath, sChars );

	BuildChars();

	return true;
}
Exemplo n.º 15
0
RageFileManager::RageFileManager( CString argv0 )
{
	CHECKPOINT_M( argv0 );
	ChangeToDirOfExecutable( argv0 );
	
	g_Mutex = new RageMutex("RageFileManager");

	g_Mountpoints = new RageFileDriverMountpoints;
	LoadedDriver ld;
	ld.driver = g_Mountpoints;
	ld.MountPoint = "";
	g_Drivers.push_back( ld );

	/* The mount path is unused, but must be nonempty. */
	RageFileManager::Mount( "mem", "(cache)", "@mem" );
}
Exemplo n.º 16
0
bool BitmapText::LoadFromFont( const CString& sFontFilePath )
{
	CHECKPOINT_M( ssprintf("BitmapText::LoadFromFont(%s)", sFontFilePath.c_str()) );

	if( m_pFont )
	{
		FONT->UnloadFont( m_pFont );
		m_pFont = NULL;
	}

	m_pFont = FONT->LoadFont( sFontFilePath );

	BuildChars();

	return true;
}
Exemplo n.º 17
0
bool BitmapText::LoadFromFont( const RString& sFontFilePath )
{
	CHECKPOINT_M( ssprintf("BitmapText::LoadFromFont(%s)", sFontFilePath.c_str()) );

	if( m_pFont )
	{
		FONT->UnloadFont( m_pFont );
		m_pFont = NULL;
	}

	m_pFont = FONT->LoadFont( sFontFilePath );

	this->SetStrokeColor( m_pFont->GetDefaultStrokeColor() );

	BuildChars();

	return true;
}
Exemplo n.º 18
0
void MovieTexture_Generic::UpdateFrame()
{
	/* Just in case we were invalidated: */
	CreateTexture();

	if( m_pTextureLock != nullptr )
	{
		int iHandle = m_pTextureIntermediate != nullptr? m_pTextureIntermediate->GetTexHandle(): this->GetTexHandle();
		m_pTextureLock->Lock( iHandle, m_pSurface );
	}

	m_pDecoder->GetFrame( m_pSurface );
	if( m_pTextureLock != nullptr )
		m_pTextureLock->Unlock( m_pSurface, true );

	if( m_pRenderTarget != nullptr )
	{
		CHECKPOINT_M( "About to upload the texture.");

		/* If we have no m_pTextureLock, we still have to upload the texture. */
		if( m_pTextureLock == nullptr )
		{
			DISPLAY->UpdateTexture(
				m_pTextureIntermediate->GetTexHandle(),
				m_pSurface,
				0, 0,
				m_pSurface->w, m_pSurface->h );
		}
		m_pRenderTarget->BeginRenderingTo( false );
		m_pSprite->Draw();
		m_pRenderTarget->FinishRenderingTo();
	}
	else
	{
		if( m_pTextureLock == nullptr )
		{
			DISPLAY->UpdateTexture(
				m_uTexHandle,
				m_pSurface,
				0, 0,
				m_iImageWidth, m_iImageHeight );
		}
	}
}
Exemplo n.º 19
0
void RageFileManager::Mount( CString Type, CString Root, CString MountPoint )
{
	LockMut( *g_Mutex );

	FixSlashesInPlace( Root );
	FixSlashesInPlace( MountPoint );

	if( MountPoint.size() && MountPoint.Right(1) != "/" )
		MountPoint += '/';
	ASSERT( Root != "" );

	CHECKPOINT_M( ssprintf("\"%s\", \"%s\", \"%s\"",
		Type.c_str(), Root.c_str(), MountPoint.c_str() ) );

	// Unmount anything that was previously mounted here.
	Unmount( Type, Root, MountPoint );

	CHECKPOINT;
	RageFileDriver *driver = MakeFileDriver( Type, Root );
	if( !driver )
	{
		CHECKPOINT;

		if( LOG )
			LOG->Warn("Can't mount unknown VFS type \"%s\", root \"%s\"", Type.c_str(), Root.c_str() );
		else
			fprintf( stderr, "Can't mount unknown VFS type \"%s\", root \"%s\"\n", Type.c_str(), Root.c_str() );
		return;
	}

	CHECKPOINT;

	LoadedDriver ld;
	ld.driver = driver;
	ld.Type = Type;
	ld.Root = Root;
	ld.MountPoint = MountPoint;
	g_Drivers.push_back( ld );

	CHECKPOINT;
	g_Mountpoints->LoadFromDrivers( g_Drivers );
	CHECKPOINT;
}
void RageSoundDriver::DecodeThread()
{
	SetupDecodingThread();

	while( !m_bShutdownDecodeThread )
	{
		/* Fill each playing sound, round-robin. */
		{
			int iSampleRate = GetSampleRate();
			ASSERT_M( iSampleRate > 0, ssprintf("%i", iSampleRate) );
			int iUsecs = 1000000*chunksize() / iSampleRate;
			usleep( iUsecs );
		}

		LockMut( m_Mutex );
//		LOG->Trace("begin mix");

		for( unsigned i = 0; i < ARRAYLEN(m_Sounds); ++i )
		{
			if( m_Sounds[i].m_State != Sound::PLAYING )
				continue;

			Sound *pSound = &m_Sounds[i];

			CHECKPOINT_M("Processing the sound while buffers are available.");
			while( pSound->m_Buffer.num_writable() )
			{
				int iWrote = GetDataForSound( *pSound );
				if( iWrote == RageSoundReader::WOULD_BLOCK )
					break;
				if( iWrote < 0 )
				{
					/* This sound is finishing. */
					pSound->m_State = Sound::STOPPING;
					break;
//					LOG->Trace("mixer: (#%i) eof (%p)", i, pSound->m_pSound );
				}
			}
		}
//		LOG->Trace("end mix");
	}
}
Exemplo n.º 21
0
bool GetThreadBacktraceContext( uint64_t ThreadID, BacktraceContext *ctx )
{
	/* Can't GetThreadBacktraceContext the current thread. */
	ASSERT( ThreadID != GetCurrentThreadId() );

	/* Attach to the thread.  This may fail with EPERM.  This can happen for at least
	 * two common reasons: the process might be in a debugger already, or *we* might
	 * already have attached to it via SuspendThread.
	 *
	 * If it's in a debugger, we won't be able to ptrace(PTRACE_GETREGS). If
	 * it's us that attached, we will. */
	if( PtraceAttach( int(ThreadID) ) == -1 )
	{
		if( errno != EPERM )
		{
			CHECKPOINT_M( ssprintf( "%s (pid %i tid %i locking tid %i)",
									strerror(errno), getpid(), (int)GetCurrentThreadId(), int(ThreadID) ) );
			return false;
		}
	}

	user_regs_struct regs;
	if( ptrace( PTRACE_GETREGS, pid_t(ThreadID), NULL, &regs ) == -1 )
		return false;

	ctx->pid = pid_t(ThreadID);
#if defined(CPU_X86_64)
	ctx->ip = (void *) regs.rip;
	ctx->bp = (void *) regs.rbp;
	ctx->sp = (void *) regs.rsp;
#elif defined(CPU_X86)
	ctx->ip = (void *) regs.eip;
	ctx->bp = (void *) regs.ebp;
	ctx->sp = (void *) regs.esp;
#else
#error GetThreadBacktraceContext: which arch?
#endif

	return true;
}
Exemplo n.º 22
0
void FontManager::UnloadFont( Font *fp )
{
	CHECKPOINT_M( ssprintf("FontManager::UnloadFont(%s).", fp->path.c_str()) );

	for( std::map<FontName, Font*>::iterator i = g_mapPathToFont.begin();
		i != g_mapPathToFont.end(); ++i)
	{
		if(i->second != fp)
			continue;

		i->second->m_iRefCount--;

		if( fp->m_iRefCount == 0 )
		{
			delete i->second;		// free the texture
			g_mapPathToFont.erase( i );	// and remove the key in the map
		}
		return;
	}
	
	RageException::Throw( "Unloaded an unknown font (%p)", fp );
}
Exemplo n.º 23
0
Font* FontManager::LoadFont( const CString &sFontOrTextureFilePath, CString sChars )
{
	// Convert the path to lowercase so that we don't load duplicates.
	// Really, this does not solve the duplicate problem.  We could have two copies
	// of the same bitmap if there are equivalent but different paths
	// (e.g. "graphics\blah.png" and "..\stepmania\graphics\blah.png" ).

	CHECKPOINT_M( ssprintf("FontManager::LoadFont(%s).", sFontOrTextureFilePath.c_str()) );
	const FontName NewName( sFontOrTextureFilePath, sChars );
	map<FontName, Font*>::iterator p = g_mapPathToFont.find( NewName );
	if( p != g_mapPathToFont.end() )
	{
		Font *pFont=p->second;
		pFont->m_iRefCount++;
		return pFont;
	}

	Font *f = new Font;
	f->Load(sFontOrTextureFilePath, sChars);
	g_mapPathToFont[NewName] = f;
	return f;
}
Exemplo n.º 24
0
void BannerCache::LoadBanner( CString BannerPath )
{
	if( PREFSMAN->m_BannerCache != PrefsManager::BNCACHE_LOW_RES || BannerPath == "" )
		return;

	/* Load it. */
	const CString CachePath = GetBannerCachePath(BannerPath);

	for( int tries = 0; tries < 2; ++tries )
	{
		if( g_BannerPathToImage.find(BannerPath) != g_BannerPathToImage.end() )
			return; /* already loaded */

		CHECKPOINT_M( ssprintf( "BannerCache::LoadBanner: %s", CachePath.c_str() ) );
		RageSurface *img = RageSurfaceUtils::LoadSurface( CachePath );
		if( img == NULL )
		{
			if(tries == 0)
			{
				/* The file doesn't exist.  It's possible that the banner cache file is
				 * missing, so try to create it.  Don't do this first, for efficiency. */
				LOG->Trace( "Cached banner load of '%s' ('%s') failed, trying to cache ...", BannerPath.c_str(), CachePath.c_str() );
				/* Skip the up-to-date check; it failed to load, so it can't be up
				 * to date. */
				CacheBannerInternal( BannerPath );
				continue;
			}
			else
			{
				LOG->Trace( "Cached banner load of '%s' ('%s') failed", BannerPath.c_str(), CachePath.c_str() );
				return;
			}
		}

		g_BannerPathToImage[BannerPath] = img;
	}
}
Exemplo n.º 25
0
void FontManager::UnloadFont( Font *fp )
{
	CHECKPOINT_M( ssprintf("FontManager::UnloadFont(%s).", fp->path.c_str()) );

	for( std::map<FontName, Font*>::iterator i = g_mapPathToFont.begin();
		i != g_mapPathToFont.end(); ++i)
	{
		if(i->second != fp)
			continue;

		ASSERT_M(fp->m_iRefCount > 0,"Attempting to unload a font with zero ref count!");

		i->second->m_iRefCount--;

		if( fp->m_iRefCount == 0 )
		{
			delete i->second;		// free the texture
			g_mapPathToFont.erase( i );	// and remove the key in the map
		}
		return;
	}

	FAIL_M( ssprintf("Unloaded an unknown font (%p)", fp) );
}
int RageSoundReader_Vorbisfile::Read( float *buf, int iFrames )
{
	int frames_read = 0;

	while( iFrames && !eof )
	{
		const int bytes_per_frame = sizeof(float)*channels;

		int iFramesRead = 0;

		{
			int curofs = (int) ov_pcm_tell(vf);
			if( curofs < read_offset )
			{
				/* The timestamps moved backwards.  Ignore it.  This file probably
				 * won't sync correctly. */
				LOG->Trace( "p ahead %p %i < %i, we're ahead by %i", 
					this, curofs, read_offset, read_offset-curofs );
				read_offset = curofs;
			}
			else if( curofs > read_offset )
			{
				/* Our offset doesn't match.  We have a hole in the data, or corruption.
				 * If we're reading with accurate syncing, insert silence to line it up.
				 * That way, corruptions in the file won't casue desyncs. */

				/* In bytes: */
				int iSilentFrames = curofs - read_offset;
				iSilentFrames = min( iSilentFrames, (int) iFrames );
				int silence = iSilentFrames * bytes_per_frame;
				CHECKPOINT_M( ssprintf("p %i,%i: %i frames of silence needed", curofs, read_offset, silence) );

				memset( buf, 0, silence );
				iFramesRead = iSilentFrames;
			}
		}

		if( iFramesRead == 0 )
		{
			int bstream;
#if defined(INTEGER_VORBIS)
			int ret = ov_read( vf, (char *) buf, iFrames * channels * sizeof(int16_t), &bstream );
#else // float vorbis decoder
			float **pcm;
			int ret = ov_read_float( vf, &pcm, iFrames, &bstream );
#endif

			{
				vorbis_info *vi = ov_info( vf, -1 );
				ASSERT( vi != NULL );

				if( (unsigned) vi->channels != channels )
					RageException::Throw( "File \"%s\" changes channel count from %i to %i; not supported.",
							      filename.c_str(), channels, (int)vi->channels );
			}


			if( ret == OV_HOLE )
				continue;
			if( ret == OV_EBADLINK )
			{
				SetError( ssprintf("Read: OV_EBADLINK") );
				return ERROR;
			}

			if( ret == 0 )
			{
				eof = true;
				continue;
			}

#if defined(INTEGER_VORBIS)
			if( ret > 0 )
			{
				int iSamplesRead = ret / sizeof(int16_t);
				iFramesRead = iSamplesRead / channels;

				/* Convert in reverse, so we can do it in-place. */
				const int16_t *pIn = (int16_t *) buf;
				float *pOut = (float *) buf;
				for( int i = iSamplesRead-1; i >= 0; --i )
					pOut[i] = pIn[i] / 32768.0f;
			}
#else
			if( ret > 0 )
			{
				iFramesRead = ret;

				int iNumChannels = channels;
				for( int iChannel = 0; iChannel < iNumChannels; ++iChannel )
				{
					const float *pChannelIn = pcm[iChannel];
					float *pChannelOut = &buf[iChannel];
					for( int i = 0; i < iFramesRead; ++i )
					{
						*pChannelOut = *pChannelIn;
						++pChannelIn;
						pChannelOut += iNumChannels;
					}
				}
			}
#endif
		}

		read_offset += iFramesRead;

		buf += iFramesRead * channels;
		frames_read += iFramesRead;
		iFrames -= iFramesRead;
	}

	if( !frames_read )
		return END_OF_FILE;

	return frames_read;
}
Exemplo n.º 27
0
static LRESULT CALLBACK GraphicsWindow_WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	CHECKPOINT_M( ssprintf("%p, %u, %08x, %08x", hWnd, msg, wParam, lParam) );

	// Suppress autorun.
	if( msg == g_iQueryCancelAutoPlayMessage )
		return true;

	switch( msg )
	{
		case WM_ACTIVATE:
		{
			const bool bInactive = (LOWORD(wParam) == WA_INACTIVE);
			const bool bMinimized = (HIWORD(wParam) != 0);
			const bool bHadFocus = g_bHasFocus;
			g_bHasFocus = !bInactive && !bMinimized;
			LOG->Trace( "WM_ACTIVATE (%i, %i): %s", bInactive, bMinimized, g_bHasFocus? "has focus":"doesn't have focus" );
			if( !g_bHasFocus )
			{
				RString sName = GetNewWindow();
				static set<RString> sLostFocusTo;
				sLostFocusTo.insert( sName );
				RString sStr;
				for( set<RString>::const_iterator it = sLostFocusTo.begin(); it != sLostFocusTo.end(); ++it )
					sStr += (sStr.size()?", ":"") + *it;

				LOG->MapLog( "LOST_FOCUS", "Lost focus to: %s", sStr.c_str() );
			}

			if( !g_bD3D && !g_CurrentParams.windowed && !g_bRecreatingVideoMode )
			{
				/* In OpenGL (not D3D), it's our job to unset and reset the
				 * full-screen video mode when we focus changes, and to hide
				 * and show the window. Hiding is done in WM_KILLFOCUS,
				 * because that's where most other apps seem to do it. */
				if( g_bHasFocus && !bHadFocus )
				{
					ChangeDisplaySettings( &g_FullScreenDevMode, CDS_FULLSCREEN );
					ShowWindow( g_hWndMain, SW_SHOWNORMAL );
				}
				else if( !g_bHasFocus && bHadFocus )
				{
					ChangeDisplaySettings( NULL, 0 );
				}
			}

			return 0;
		}
		case WM_KILLFOCUS:
			if( !g_bD3D && !g_CurrentParams.windowed && !g_bRecreatingVideoMode )
				ShowWindow( g_hWndMain, SW_SHOWMINNOACTIVE );
			break;

		/* Is there any reason we should care what size the user resizes
		 * the window to? (who? -aj)
		 * Short answer: yes. -aj */
	//	case WM_GETMINMAXINFO:

		case WM_SETCURSOR:
			if( !g_CurrentParams.windowed )
			{
				SetCursor( NULL );
				return 1;
			}
			break;

		case WM_SYSCOMMAND:
			switch( wParam&0xFFF0 )
			{
				case SC_MONITORPOWER:
				case SC_SCREENSAVE:
					return 0;
			}
			break;

		case WM_PAINT:
		{
			PAINTSTRUCT ps;
			BeginPaint( hWnd, &ps );
			EndPaint( hWnd, &ps );
			break;
		}

		case WM_KEYDOWN:
		case WM_KEYUP:
		case WM_SYSKEYDOWN:
		case WM_SYSKEYUP:
		case WM_MOUSEWHEEL: // might want to use this for GET_WHEEL_DELTA_WPARAM(wParam) -aj
			// We handle all input ourself, via DirectInput.
			return 0;

		case WM_CLOSE:
			LOG->Trace("WM_CLOSE: shutting down");
			ArchHooks::SetUserQuit();
			return 0;

		case WM_WINDOWPOSCHANGED:
		{
			/* If we're fullscreen and don't have focus, our window is hidden,
			 * so GetClientRect isn't meaningful. */
			if( !g_CurrentParams.windowed && !g_bHasFocus )
				break;

			RECT rect;
			GetClientRect( hWnd, &rect );

			int iWidth = rect.right - rect.left;
			int iHeight = rect.bottom - rect.top;
			if( g_CurrentParams.width != iWidth || g_CurrentParams.height != iHeight )
			{
				g_CurrentParams.width = iWidth;
				g_CurrentParams.height = iHeight;
				g_bResolutionChanged = true;
			}
			break;
		}
		case WM_COPYDATA:
		{
			PCOPYDATASTRUCT pMyCDS = (PCOPYDATASTRUCT) lParam;
			RString sCommandLine( (char*)pMyCDS->lpData, pMyCDS->cbData );
			CommandLineActions::CommandLineArgs args;
			split( sCommandLine, "|", args.argv, false );
			CommandLineActions::ToProcess.push_back( args );
			break;
		}
	}

	CHECKPOINT_M( ssprintf("%p, %u, %08x, %08x", hWnd, msg, wParam, lParam) );

	if( m_bWideWindowClass )
		return DefWindowProcW( hWnd, msg, wParam, lParam );
	else
		return DefWindowProcA( hWnd, msg, wParam, lParam );
}
Exemplo n.º 28
0
static void StartMusic( MusicToPlay &ToPlay )
{
CHECKPOINT;
	LockMutex L( *g_Mutex );
CHECKPOINT;
	if( g_Playing->m_Music->IsPlaying() && !g_Playing->m_Music->GetLoadedFilePath().CompareNoCase(ToPlay.file) )
		return;

CHECKPOINT;
	if( ToPlay.file.empty() )
	{
		/* StopPlaying() can take a while, so don't hold the lock while we stop the sound.
		 * Be sure to leave the rest of g_Playing in place. */
		RageSound *pOldSound = g_Playing->m_Music;
		g_Playing->m_Music = new RageSound;
		L.Unlock();

		/* We're not allowed to delete the sound in a separate thread, because
		 * RageSoundManager::FlushPosMapQueue might be running.  Stop the sound,
		 * and give it to RageSoundManager to delete. */
		SOUNDMAN->DeleteSound( pOldSound );
		return;
	}
CHECKPOINT;
	/* Unlock, load the sound here, and relock.  Loading may take a while if we're
	 * reading from CD and we have to seek far, which can throw off the timing below. */
	MusicPlaying *NewMusic;
	{
		g_Mutex->Unlock();
		RageSound *pSound = new RageSound;
		pSound->Load( ToPlay.file, false );
		g_Mutex->Lock();

		NewMusic = new MusicPlaying( pSound );
	}

	NewMusic->m_Timing = g_Playing->m_Timing;
CHECKPOINT;

	/* See if we can find timing data, if it's not already loaded. */
	if( !ToPlay.HasTiming && IsAFile(ToPlay.timing_file) )
	{
		LOG->Trace("Found '%s'", ToPlay.timing_file.c_str());
		if( SMLoader::LoadTimingFromFile( ToPlay.timing_file, ToPlay.timing_data ) )
			ToPlay.HasTiming = true;
	}
CHECKPOINT;
	if( ToPlay.HasTiming )
		NewMusic->m_NewTiming = ToPlay.timing_data;

	if( ToPlay.align_beat && ToPlay.HasTiming && ToPlay.force_loop && ToPlay.length_sec != -1 )
	{
		/* Extend the loop period so it always starts and ends on the same fractional
		 * beat.  That is, if it starts on beat 1.5, and ends on beat 10.2, extend it
		 * to end on beat 10.5.  This way, effects always loop cleanly. */
		float fStartBeat = NewMusic->m_NewTiming.GetBeatFromElapsedTime( ToPlay.start_sec );
		float fEndSec = ToPlay.start_sec + ToPlay.length_sec;
		float fEndBeat = NewMusic->m_NewTiming.GetBeatFromElapsedTime( fEndSec );
		
		const float fStartBeatFraction = fmodfp( fStartBeat, 1 );
		const float fEndBeatFraction = fmodfp( fEndBeat, 1 );

		float fBeatDifference = fStartBeatFraction - fEndBeatFraction;
		if( fBeatDifference < 0 )
			fBeatDifference += 1.0f; /* unwrap */

		fEndBeat += fBeatDifference;

		const float fRealEndSec = NewMusic->m_NewTiming.GetElapsedTimeFromBeat( fEndBeat );
		const float fNewLengthSec = fRealEndSec - ToPlay.start_sec;

		/* Extend the fade_len, so the added time is faded out. */
		ToPlay.fade_len += fNewLengthSec - ToPlay.length_sec;
		ToPlay.length_sec = fNewLengthSec;
	}

CHECKPOINT;
	bool StartImmediately = false;
	if( !ToPlay.HasTiming )
	{
		/* This song has no real timing data.  The offset is arbitrary.  Change it so
		 * the beat will line up to where we are now, so we don't have to delay. */
		float fDestBeat = fmodfp( GAMESTATE->m_fSongBeat, 1 );
CHECKPOINT_M(ssprintf("%f",GAMESTATE->m_fSongBeat));
CHECKPOINT_M(ssprintf("%p",NewMusic));
		float fTime = NewMusic->m_NewTiming.GetElapsedTimeFromBeat( fDestBeat );

		NewMusic->m_NewTiming.m_fBeat0OffsetInSeconds = fTime;

		StartImmediately = true;
	}

CHECKPOINT;
	/* If we have an active timer, try to start on the next update.  Otherwise,
	 * start now. */
	if( !g_Playing->m_HasTiming && !g_UpdatingTimer )
		StartImmediately = true;
	if( !ToPlay.align_beat )
		StartImmediately = true;

CHECKPOINT;
	RageTimer when; /* zero */
	if( !StartImmediately )
	{
		/* GetPlayLatency returns the minimum time until a sound starts.  That's
		 * common when starting a precached sound, but our sound isn't, so it'll
		 * probably take a little longer.  Nudge the latency up. */
		const float PresumedLatency = SOUND->GetPlayLatency() + 0.040f;
		const float fCurSecond = GAMESTATE->m_fMusicSeconds + PresumedLatency;
		const float fCurBeat = g_Playing->m_Timing.GetBeatFromElapsedTime( fCurSecond );
		const float fCurBeatFraction = fmodfp( fCurBeat,1 );

		/* The beat that the new sound will start on. */
		const float fStartBeat = NewMusic->m_NewTiming.GetBeatFromElapsedTime( ToPlay.start_sec );
		float fStartBeatFraction = fmodfp( fStartBeat, 1 );
		if( fStartBeatFraction < fCurBeatFraction )
			fStartBeatFraction += 1.0f; /* unwrap */

		const float fCurBeatToStartOn = truncf(fCurBeat) + fStartBeatFraction;
		const float fSecondToStartOn = g_Playing->m_Timing.GetElapsedTimeFromBeat( fCurBeatToStartOn );
		const float fMaximumDistance = 2;
		const float fDistance = min( fSecondToStartOn - fCurSecond, fMaximumDistance );

		when = GAMESTATE->m_LastBeatUpdate + PresumedLatency + fDistance;
	}
CHECKPOINT;

	/* Important: don't hold the mutex while we load and seek the actual sound. */
	L.Unlock();
	{
		NewMusic->m_HasTiming = ToPlay.HasTiming;
		if( ToPlay.HasTiming )
			NewMusic->m_NewTiming = ToPlay.timing_data;
		NewMusic->m_TimingDelayed = true;
//		NewMusic->m_Music->Load( ToPlay.file, false );

		RageSoundParams p;
		p.m_StartSecond = ToPlay.start_sec;
		p.m_LengthSeconds = ToPlay.length_sec;
		p.m_FadeLength = ToPlay.fade_len;
		p.StartTime = when;
		if( ToPlay.force_loop )
			p.StopMode = RageSoundParams::M_LOOP;
		NewMusic->m_Music->SetParams( p );

		NewMusic->m_Music->SetPositionSeconds( p.m_StartSecond );
		NewMusic->m_Music->StartPlaying();
	}

CHECKPOINT;
	LockMut( *g_Mutex );
	delete g_Playing;
	g_Playing = NewMusic;
CHECKPOINT;
}
Exemplo n.º 29
0
void GameSoundManager::Update( float fDeltaTime )
{
	LockMut( *g_Mutex );

	if( !g_UpdatingTimer )
		return;

	const float fAdjust = GetFrameTimingAdjustment( fDeltaTime );

	if( !g_Playing->m_Music->IsPlaying() )
	{
		/* There's no song playing.  Fake it. */
		CHECKPOINT_M( ssprintf("%f, delta %f", GAMESTATE->m_fMusicSeconds, fDeltaTime) );
		GAMESTATE->UpdateSongPosition( GAMESTATE->m_fMusicSeconds + fDeltaTime, g_Playing->m_Timing );
		return;
	}

	/* There's a delay between us calling Play() and the sound actually playing.
	 * During this time, approximate will be true.  Keep using the previous timing
	 * data until we get a non-approximate time, indicating that the sound has actually
	 * started playing. */
	bool approximate;
	RageTimer tm;
	const float fSeconds = g_Playing->m_Music->GetPositionSeconds( &approximate, &tm );

	if( g_Playing->m_TimingDelayed )
	{
		if( approximate )
		{
			/* We're still waiting for the new sound to start playing, so keep using the
			 * old timing data and fake the time. */
			CHECKPOINT_M( ssprintf("%f, delta %f", GAMESTATE->m_fMusicSeconds, fDeltaTime) );
			GAMESTATE->UpdateSongPosition( GAMESTATE->m_fMusicSeconds + fDeltaTime, g_Playing->m_Timing );
			return;
		}
		else
		{
			/* We've passed the start position of the new sound, so we should be OK.
			 * Load up the new timing data. */
			g_Playing->m_Timing = g_Playing->m_NewTiming;
			g_Playing->m_TimingDelayed = false;
		}
	}
	else if( PREFSMAN->m_bLogSkips )
	{
		const float fExpectedTimePassed = (tm - GAMESTATE->m_LastBeatUpdate) * g_Playing->m_Music->GetPlaybackRate();
		const float fSoundTimePassed = fSeconds - GAMESTATE->m_fMusicSeconds;
		const float fDiff = fExpectedTimePassed - fSoundTimePassed;

		static CString sLastFile = "";
		const CString ThisFile = g_Playing->m_Music->GetLoadedFilePath();

		/* If fSoundTimePassed < 0, the sound has probably looped. */
		if( sLastFile == ThisFile && fSoundTimePassed >= 0 && fabsf(fDiff) > 0.003f )
			LOG->Trace("Song position skip in %s: expected %.3f, got %.3f (cur %f, prev %f) (%.3f difference)",
				Basename(ThisFile).c_str(), fExpectedTimePassed, fSoundTimePassed, fSeconds, GAMESTATE->m_fMusicSeconds, fDiff );
		sLastFile = ThisFile;
	}

	CHECKPOINT_M( ssprintf("%f", fSeconds) );
	GAMESTATE->UpdateSongPosition( fSeconds+fAdjust, g_Playing->m_Timing, tm+fAdjust );
}
void DirectFilenameDB::PopulateFileSet( FileSet &fs, const RString &path )
{
	RString sPath = path;

#if defined(XBOX)
	/* Xbox doesn't handle path names which end with ".", which are used when using an
	 * alternative song directory */
	if( sPath.size() > 0 && sPath.Right(1) == "." )
		sPath.erase( sPath.size() - 1 );
#endif

	/* Resolve path cases (path/Path -> PATH/path). */
	ResolvePath( sPath );

	fs.age.GetDeltaTime(); /* reset */
	fs.files.clear();

#if defined(WIN32)
	WIN32_FIND_DATA fd;

	if ( sPath.size() > 0  && sPath.Right(1) == "/" )
		sPath.erase( sPath.size() - 1 );

	HANDLE hFind = DoFindFirstFile( root+sPath+"/*", &fd );
	CHECKPOINT_M( root+sPath+"/*" );

	if( hFind == INVALID_HANDLE_VALUE )
		return;

	do {
		if( !strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..") )
			continue;

		File f;
		f.SetName( fd.cFileName );
		f.dir = !!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
		f.size = fd.nFileSizeLow;
		f.hash = fd.ftLastWriteTime.dwLowDateTime;

		fs.files.insert( f );
	} while( FindNextFile( hFind, &fd ) );
	FindClose( hFind );
#else
	/* Ugly: POSIX threads are not guaranteed to have per-thread cwds, and only
	 * a few systems have openat() or equivalent; one or the other is needed
	 * to do efficient, thread-safe directory traversal.  Instead, we have to
	 * use absolute paths, which forces the system to re-parse the directory
	 * for each file.  This isn't a major issue, since most large directory
	 * scans are I/O-bound. */
	 
	DIR *pDir = opendir(root+sPath);
	if( pDir == NULL )
		return;

	while( struct dirent *pEnt = readdir(pDir) )
	{
		if( !strcmp(pEnt->d_name, ".") )
			continue;
		if( !strcmp(pEnt->d_name, "..") )
			continue;
		
		File f( pEnt->d_name );
		
		struct stat st;
		if( DoStat(root+sPath + "/" + pEnt->d_name, &st) == -1 )
		{
			int iError = errno;
			/* If it's a broken symlink, ignore it.  Otherwise, warn. */
			if( lstat(root+sPath + "/" + pEnt->d_name, &st) == 0 )
				continue;
			
			/* Huh? */
			WARN( ssprintf("Got file '%s' in '%s' from list, but can't stat? (%s)",
					pEnt->d_name, sPath.c_str(), strerror(iError)) );
			continue;
		}
		else
		{
			f.dir = (st.st_mode & S_IFDIR);
			f.size = (int)st.st_size;
			f.hash = st.st_mtime;
		}

		fs.files.insert(f);
	}
	       
	closedir( pDir );
#endif

	/*
	 * Check for any ".ignore" markers.  If a marker exists, hide the marker and its 
	 * corresponding file.
	 * For example, if "file.xml.ignore" exists, hide both it and "file.xml" by 
	 * removing them from the file set.
	 * Ignore markers are used for convenience during build staging and are not used in 
	 * performance-critical situations.  To avoid incurring some of the overheard 
	 * due to ignore markers, delete the file instead instead of using an ignore marker.
	 */
	static const RString IGNORE_MARKER_BEGINNING = "ignore-";

	vector<RString> vsFilesToRemove;
	for( set<File>::iterator iter = fs.files.lower_bound(IGNORE_MARKER_BEGINNING); 
		 iter != fs.files.end(); 
		 ++iter )
	{
		if( !BeginsWith( iter->lname, IGNORE_MARKER_BEGINNING ) )
			break;
		RString sFileLNameToIgnore = iter->lname.Right( iter->lname.length() - IGNORE_MARKER_BEGINNING.length() );
		vsFilesToRemove.push_back( iter->name );
		vsFilesToRemove.push_back( sFileLNameToIgnore );
	}
	
	FOREACH_CONST( RString, vsFilesToRemove, iter )
	{
		// Erase the file corresponding to the ignore marker
		File fileToDelete;
		fileToDelete.SetName( *iter );
		set<File>::iterator iter2 = fs.files.find( fileToDelete );
		if( iter2 != fs.files.end() )
			fs.files.erase( iter2 );
	}