The big NULL replacement party part 1.

This is meant to be a safer alternative since
NULL can often be 0. Let's not rely on that.

And yes, I know this is a lot of files. This is
a safer thing to do in big commits vs for loops.
This commit is contained in:
Jason Felds
2013-05-03 23:01:54 -04:00
parent b22a3bd3c4
commit 9f24627bf9
167 changed files with 31932 additions and 31932 deletions
+2 -2
View File
@@ -1249,7 +1249,7 @@ void Actor::AddCommand( const RString &sCmdName, apActorCommands apac )
bool Actor::HasCommand( const RString &sCmdName ) const
{
return GetCommand(sCmdName) != NULL;
return GetCommand(sCmdName) != nullptr;
}
const apActorCommands *Actor::GetCommand( const RString &sCommandName ) const
@@ -1268,7 +1268,7 @@ void Actor::HandleMessage( const Message &msg )
void Actor::PlayCommandNoRecurse( const Message &msg )
{
const apActorCommands *pCmd = GetCommand( msg.GetName() );
if( pCmd != NULL )
if( pCmd != nullptr )
RunCommands( *pCmd, &msg.GetParamTable() );
}
+3 -3
View File
@@ -145,7 +145,7 @@ void ActorFrame::AddChild( Actor *pActor )
Dialog::OK( ssprintf("Actor \"%s\" adds child \"%s\" more than once", GetLineage().c_str(), pActor->GetName().c_str()) );
#endif
ASSERT( pActor != NULL );
ASSERT( pActor != nullptr );
ASSERT( (void*)pActor != (void*)0xC0000005 );
m_SubActors.push_back( pActor );
@@ -285,14 +285,14 @@ void ActorFrame::PushChildrenTable( lua_State *L )
void ActorFrame::PlayCommandOnChildren( const RString &sCommandName, const LuaReference *pParamTable )
{
const apActorCommands *pCmd = GetCommand( sCommandName );
if( pCmd != NULL )
if( pCmd != nullptr )
RunCommandsOnChildren( *pCmd, pParamTable );
}
void ActorFrame::PlayCommandOnLeaves( const RString &sCommandName, const LuaReference *pParamTable )
{
const apActorCommands *pCmd = GetCommand( sCommandName );
if( pCmd != NULL )
if( pCmd != nullptr )
RunCommandsOnLeaves( **pCmd, pParamTable );
}
+1 -1
View File
@@ -65,7 +65,7 @@ void ActorMultiTexture::ClearTextures()
int ActorMultiTexture::AddTexture( RageTexture *pTexture )
{
ASSERT( pTexture != NULL );
ASSERT( pTexture != nullptr );
LOG->Trace( "ActorMultiTexture::AddTexture( %s )", pTexture->GetID().filename.c_str() );
m_aTextureUnits.push_back( TextureUnitState() );
+90 -90
View File
@@ -1,90 +1,90 @@
#include "global.h"
#include "ActorProxy.h"
#include "ActorUtil.h"
REGISTER_ACTOR_CLASS( ActorProxy );
ActorProxy::ActorProxy()
{
m_pActorTarget = NULL;
}
bool ActorProxy::EarlyAbortDraw() const
{
return m_pActorTarget == NULL || Actor::EarlyAbortDraw();
}
void ActorProxy::DrawPrimitives()
{
if( m_pActorTarget != NULL )
{
bool bVisible = m_pActorTarget->GetVisible();
m_pActorTarget->SetVisible( true );
m_pActorTarget->Draw();
m_pActorTarget->SetVisible( bVisible );
}
}
void ActorProxy::LoadFromNode( const XNode* pNode )
{
Actor::LoadFromNode( pNode );
}
// lua start
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the ActorProxy. */
class LunaActorProxy: public Luna<ActorProxy>
{
public:
static int SetTarget( T* p, lua_State *L )
{
Actor *pTarget = Luna<Actor>::check( L, 1 );
p->SetTarget( pTarget );
return 0;
}
static int GetTarget( T* p, lua_State *L )
{
Actor *pTarget = p->GetTarget();
if( pTarget != NULL )
pTarget->PushSelf( L );
else
lua_pushnil( L );
return 1;
}
LunaActorProxy()
{
ADD_METHOD( SetTarget );
ADD_METHOD( GetTarget );
}
};
LUA_REGISTER_DERIVED_CLASS( ActorProxy, Actor )
// lua end
/*
* (c) 2006 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "ActorProxy.h"
#include "ActorUtil.h"
REGISTER_ACTOR_CLASS( ActorProxy );
ActorProxy::ActorProxy()
{
m_pActorTarget = NULL;
}
bool ActorProxy::EarlyAbortDraw() const
{
return m_pActorTarget == NULL || Actor::EarlyAbortDraw();
}
void ActorProxy::DrawPrimitives()
{
if( m_pActorTarget != nullptr )
{
bool bVisible = m_pActorTarget->GetVisible();
m_pActorTarget->SetVisible( true );
m_pActorTarget->Draw();
m_pActorTarget->SetVisible( bVisible );
}
}
void ActorProxy::LoadFromNode( const XNode* pNode )
{
Actor::LoadFromNode( pNode );
}
// lua start
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the ActorProxy. */
class LunaActorProxy: public Luna<ActorProxy>
{
public:
static int SetTarget( T* p, lua_State *L )
{
Actor *pTarget = Luna<Actor>::check( L, 1 );
p->SetTarget( pTarget );
return 0;
}
static int GetTarget( T* p, lua_State *L )
{
Actor *pTarget = p->GetTarget();
if( pTarget != nullptr )
pTarget->PushSelf( L );
else
lua_pushnil( L );
return 1;
}
LunaActorProxy()
{
ADD_METHOD( SetTarget );
ADD_METHOD( GetTarget );
}
};
LUA_REGISTER_DERIVED_CLASS( ActorProxy, Actor )
// lua end
/*
* (c) 2006 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1 -1
View File
@@ -103,7 +103,7 @@ bool ActorUtil::ResolvePath( RString &sPath, const RString &sName )
Actor* ActorUtil::LoadFromNode( const XNode* pNode, Actor *pParentActor )
{
ASSERT( pNode != NULL );
ASSERT( pNode != nullptr );
// Remove this in favor of using conditionals in Lua. -Chris
// There are a number of themes out there that depend on this (including
+1 -1
View File
@@ -120,7 +120,7 @@ RString AnnouncerManager::GetPathTo( RString sAnnouncerName, RString sFolderName
/* Search for the announcer folder in the list of aliases. */
int i;
for(i = 0; aliases[i][0] != NULL; ++i)
for(i = 0; aliases[i][0] != nullptr; ++i)
{
if(!sFolderName.EqualsNoCase(aliases[i][0]))
continue; /* no match */
+3 -3
View File
@@ -9,7 +9,7 @@
void Attack::GetAttackBeats( const Song *pSong, float &fStartBeat, float &fEndBeat ) const
{
ASSERT( pSong != NULL );
ASSERT( pSong != nullptr );
ASSERT_M( fStartSecond >= 0, ssprintf("StartSecond: %f",fStartSecond) );
const TimingData &timing = pSong->m_SongTiming;
@@ -28,8 +28,8 @@ void Attack::GetRealtimeAttackBeats( const Song *pSong, const PlayerState* pPlay
return;
}
ASSERT( pPlayerState != NULL );
ASSERT( pSong != NULL );
ASSERT( pPlayerState != nullptr );
ASSERT( pSong != nullptr );
/* If reasonable, push the attack forward 8 beats so that notes on screen don't change suddenly. */
fStartBeat = min( GAMESTATE->m_Position.m_fSongBeat+8, pPlayerState->m_fLastDrawnBeat );
+138 -138
View File
@@ -1,138 +1,138 @@
#include "global.h"
#include "AttackDisplay.h"
#include "ThemeManager.h"
#include "GameState.h"
#include "ActorUtil.h"
#include "Character.h"
#include "RageLog.h"
#include <set>
#include "PlayerState.h"
RString GetAttackPieceName( const RString &sAttack )
{
RString ret = ssprintf( "attack %s", sAttack.c_str() );
/* 1.5x -> 1_5x. If we pass a period to THEME->GetPathTo, it'll think
* we're looking for a specific file and not search. */
ret.Replace( ".", "_" );
return ret;
}
AttackDisplay::AttackDisplay()
{
if( GAMESTATE->m_PlayMode != PLAY_MODE_BATTLE &&
GAMESTATE->m_PlayMode != PLAY_MODE_RAVE )
return;
m_sprAttack.SetDiffuseAlpha( 0 ); // invisible
this->AddChild( &m_sprAttack );
}
void AttackDisplay::Init( const PlayerState* pPlayerState )
{
m_pPlayerState = pPlayerState;
// TODO: Remove use of PlayerNumber.
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
m_sprAttack.SetName( ssprintf("TextP%d",pn+1) );
if( GAMESTATE->m_PlayMode != PLAY_MODE_BATTLE &&
GAMESTATE->m_PlayMode != PLAY_MODE_RAVE )
return;
set<RString> attacks;
for( int al=0; al<NUM_ATTACK_LEVELS; al++ )
{
const Character *ch = GAMESTATE->m_pCurCharacters[pn];
ASSERT( ch != NULL );
const RString* asAttacks = ch->m_sAttacks[al];
for( int att = 0; att < NUM_ATTACKS_PER_LEVEL; ++att )
attacks.insert( asAttacks[att] );
}
for( set<RString>::const_iterator it = attacks.begin(); it != attacks.end(); ++it )
{
const RString path = THEME->GetPathG( "AttackDisplay", GetAttackPieceName( *it ), true );
if( path == "" )
{
LOG->Trace( "Couldn't find \"%s\"", GetAttackPieceName( *it ).c_str() );
continue;
}
m_TexturePreload.Load( path );
}
}
void AttackDisplay::Update( float fDelta )
{
ActorFrame::Update( fDelta );
if( GAMESTATE->m_PlayMode != PLAY_MODE_BATTLE &&
GAMESTATE->m_PlayMode != PLAY_MODE_RAVE )
return;
if( !m_pPlayerState->m_bAttackBeganThisUpdate )
return;
// don't handle this again
for( unsigned s=0; s<m_pPlayerState->m_ActiveAttacks.size(); s++ )
{
const Attack& attack = m_pPlayerState->m_ActiveAttacks[s];
if( attack.fStartSecond >= 0 )
continue; /* hasn't started yet */
if( attack.fSecsRemaining <= 0 )
continue; /* ended already */
if( attack.IsBlank() )
continue;
SetAttack( attack.sModifiers );
break;
}
}
void AttackDisplay::SetAttack( const RString &sText )
{
const RString path = THEME->GetPathG( "AttackDisplay", GetAttackPieceName(sText), true );
if( path == "" )
return;
m_sprAttack.SetDiffuseAlpha( 1 );
m_sprAttack.Load( path );
// TODO: Remove use of PlayerNumber.
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
const RString sName = ssprintf( "%sP%i", sText.c_str(), pn+1 );
m_sprAttack.RunCommands( THEME->GetMetricA("AttackDisplay", sName + "OnCommand") );
}
/*
* (c) 2003 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "AttackDisplay.h"
#include "ThemeManager.h"
#include "GameState.h"
#include "ActorUtil.h"
#include "Character.h"
#include "RageLog.h"
#include <set>
#include "PlayerState.h"
RString GetAttackPieceName( const RString &sAttack )
{
RString ret = ssprintf( "attack %s", sAttack.c_str() );
/* 1.5x -> 1_5x. If we pass a period to THEME->GetPathTo, it'll think
* we're looking for a specific file and not search. */
ret.Replace( ".", "_" );
return ret;
}
AttackDisplay::AttackDisplay()
{
if( GAMESTATE->m_PlayMode != PLAY_MODE_BATTLE &&
GAMESTATE->m_PlayMode != PLAY_MODE_RAVE )
return;
m_sprAttack.SetDiffuseAlpha( 0 ); // invisible
this->AddChild( &m_sprAttack );
}
void AttackDisplay::Init( const PlayerState* pPlayerState )
{
m_pPlayerState = pPlayerState;
// TODO: Remove use of PlayerNumber.
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
m_sprAttack.SetName( ssprintf("TextP%d",pn+1) );
if( GAMESTATE->m_PlayMode != PLAY_MODE_BATTLE &&
GAMESTATE->m_PlayMode != PLAY_MODE_RAVE )
return;
set<RString> attacks;
for( int al=0; al<NUM_ATTACK_LEVELS; al++ )
{
const Character *ch = GAMESTATE->m_pCurCharacters[pn];
ASSERT( ch != nullptr );
const RString* asAttacks = ch->m_sAttacks[al];
for( int att = 0; att < NUM_ATTACKS_PER_LEVEL; ++att )
attacks.insert( asAttacks[att] );
}
for( set<RString>::const_iterator it = attacks.begin(); it != attacks.end(); ++it )
{
const RString path = THEME->GetPathG( "AttackDisplay", GetAttackPieceName( *it ), true );
if( path == "" )
{
LOG->Trace( "Couldn't find \"%s\"", GetAttackPieceName( *it ).c_str() );
continue;
}
m_TexturePreload.Load( path );
}
}
void AttackDisplay::Update( float fDelta )
{
ActorFrame::Update( fDelta );
if( GAMESTATE->m_PlayMode != PLAY_MODE_BATTLE &&
GAMESTATE->m_PlayMode != PLAY_MODE_RAVE )
return;
if( !m_pPlayerState->m_bAttackBeganThisUpdate )
return;
// don't handle this again
for( unsigned s=0; s<m_pPlayerState->m_ActiveAttacks.size(); s++ )
{
const Attack& attack = m_pPlayerState->m_ActiveAttacks[s];
if( attack.fStartSecond >= 0 )
continue; /* hasn't started yet */
if( attack.fSecsRemaining <= 0 )
continue; /* ended already */
if( attack.IsBlank() )
continue;
SetAttack( attack.sModifiers );
break;
}
}
void AttackDisplay::SetAttack( const RString &sText )
{
const RString path = THEME->GetPathG( "AttackDisplay", GetAttackPieceName(sText), true );
if( path == "" )
return;
m_sprAttack.SetDiffuseAlpha( 1 );
m_sprAttack.Load( path );
// TODO: Remove use of PlayerNumber.
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
const RString sName = ssprintf( "%sP%i", sText.c_str(), pn+1 );
m_sprAttack.RunCommands( THEME->GetMetricA("AttackDisplay", sName + "OnCommand") );
}
/*
* (c) 2003 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1 -1
View File
@@ -24,7 +24,7 @@ public:
/**
* @brief Determine if this actor is presently loaded.
* @return true if it is loaded, or false otherwise. */
bool IsLoaded() const { return m_pActor != NULL; }
bool IsLoaded() const { return m_pActor != nullptr; }
void Load( Actor *pActor ); // transfer pointer
void Load( const RString &sPath );
void LoadB( const RString &sMetricsGroup, const RString &sElement ); // load a background and set up LuaThreadVariables for recursive loading
+3 -3
View File
@@ -278,14 +278,14 @@ void AutoKeysounds::FinishLoading()
delete pChain;
}
}
ASSERT_M( m_pSharedSound != NULL, ssprintf("No keysounds were loaded for the song %s!", pSong->m_sMainTitle.c_str() ));
ASSERT_M( m_pSharedSound != nullptr, ssprintf("No keysounds were loaded for the song %s!", pSong->m_sMainTitle.c_str() ));
m_pSharedSound = new RageSoundReader_PitchChange( m_pSharedSound );
m_pSharedSound = new RageSoundReader_PostBuffering( m_pSharedSound );
m_pSharedSound = new RageSoundReader_Pan( m_pSharedSound );
apSounds.push_back( m_pSharedSound );
if( m_pPlayerSounds[0] != NULL )
if( m_pPlayerSounds[0] != nullptr )
{
m_pPlayerSounds[0] = new RageSoundReader_PitchChange( m_pPlayerSounds[0] );
m_pPlayerSounds[0] = new RageSoundReader_PostBuffering( m_pPlayerSounds[0] );
@@ -293,7 +293,7 @@ void AutoKeysounds::FinishLoading()
apSounds.push_back( m_pPlayerSounds[0] );
}
if( m_pPlayerSounds[1] != NULL )
if( m_pPlayerSounds[1] != nullptr )
{
m_pPlayerSounds[1] = new RageSoundReader_PitchChange( m_pPlayerSounds[1] );
m_pPlayerSounds[1] = new RageSoundReader_PostBuffering( m_pPlayerSounds[1] );
+1 -1
View File
@@ -49,7 +49,7 @@ void BGAnimation::AddLayersFromAniDir( const RString &_sAniDir, const XNode *pNo
for (RString const &sLayer : vsLayerNames)
{
const XNode* pKey = pNode->GetChild( sLayer );
ASSERT( pKey != NULL );
ASSERT( pKey != nullptr );
RString sImportDir;
if( pKey->GetAttrValue("Import", sImportDir) )
+378 -378
View File
@@ -1,378 +1,378 @@
#include "global.h"
#include "BPMDisplay.h"
#include "RageUtil.h"
#include "GameConstantsAndTypes.h"
#include "GameState.h"
#include "Course.h"
#include "Style.h"
#include "ActorUtil.h"
#include "CommonMetrics.h"
#include "LocalizedString.h"
#include "Song.h"
#include "Steps.h"
#include <limits.h>
REGISTER_ACTOR_CLASS( BPMDisplay );
BPMDisplay::BPMDisplay()
{
m_fBPMFrom = m_fBPMTo = 0;
m_iCurrentBPM = 0;
m_BPMS.push_back(0);
m_fPercentInState = 0;
m_fCycleTime = 1.0f;
}
void BPMDisplay::Load()
{
SET_NO_BPM_COMMAND.Load( m_sName, "SetNoBpmCommand");
SET_NORMAL_COMMAND.Load( m_sName, "SetNormalCommand");
SET_CHANGING_COMMAND.Load( m_sName, "SetChangeCommand" );
SET_RANDOM_COMMAND.Load( m_sName, "SetRandomCommand" );
SET_EXTRA_COMMAND.Load( m_sName, "SetExtraCommand" );
CYCLE.Load( m_sName, "Cycle" );
RANDOM_CYCLE_SPEED.Load( m_sName, "RandomCycleSpeed" );
COURSE_CYCLE_SPEED.Load( m_sName, "CourseCycleSpeed" );
SEPARATOR.Load( m_sName, "Separator" );
SHOW_QMARKS.Load( m_sName, "ShowQMarksInRandomCycle" );
NO_BPM_TEXT.Load( m_sName, "NoBpmText" );
QUESTIONMARKS_TEXT.Load( m_sName, "QuestionMarksText" );
RANDOM_TEXT.Load( m_sName, "RandomText" );
VARIOUS_TEXT.Load( m_sName, "VariousText" );
BPM_FORMAT_STRING.Load( m_sName, "FormatString" );
RunCommands( SET_NORMAL_COMMAND );
}
void BPMDisplay::LoadFromNode( const XNode *pNode )
{
BitmapText::LoadFromNode( pNode );
Load();
}
float BPMDisplay::GetActiveBPM() const
{
return m_fBPMTo + (m_fBPMFrom-m_fBPMTo)*m_fPercentInState;
}
void BPMDisplay::Update( float fDeltaTime )
{
BitmapText::Update( fDeltaTime );
if( !(bool)CYCLE )
return;
if( m_BPMS.size() == 0 )
return; // no bpm
m_fPercentInState -= fDeltaTime / m_fCycleTime;
if( m_fPercentInState < 0 )
{
// go to next state
m_fPercentInState = 1; // reset timer
m_iCurrentBPM = (m_iCurrentBPM + 1) % m_BPMS.size();
m_fBPMFrom = m_fBPMTo;
m_fBPMTo = m_BPMS[m_iCurrentBPM];
if(m_fBPMTo == -1)
{
m_fBPMFrom = -1;
if( (bool)SHOW_QMARKS )
SetText( (RandomFloat(0,1)>0.90f) ? (RString)QUESTIONMARKS_TEXT : ssprintf((RString)BPM_FORMAT_STRING,RandomFloat(0,999)) );
else
SetText( ssprintf((RString)BPM_FORMAT_STRING, RandomFloat(0,999)) );
}
else if(m_fBPMFrom == -1)
{
m_fBPMFrom = m_fBPMTo;
}
}
if( m_fBPMTo != -1)
{
const float fActualBPM = GetActiveBPM();
SetText( ssprintf((RString)BPM_FORMAT_STRING, fActualBPM) );
}
}
void BPMDisplay::SetBPMRange( const DisplayBpms &bpms )
{
ASSERT( !bpms.vfBpms.empty() );
m_BPMS.clear();
const vector<float> &BPMS = bpms.vfBpms;
bool AllIdentical = true;
for( unsigned i = 0; i < BPMS.size(); ++i )
{
if( i > 0 && BPMS[i] != BPMS[i-1] )
AllIdentical = false;
}
if( !(bool)CYCLE )
{
int MinBPM = INT_MAX;
int MaxBPM = INT_MIN;
for( unsigned i = 0; i < BPMS.size(); ++i )
{
MinBPM = min( MinBPM, (int)lrintf(BPMS[i]) );
MaxBPM = max( MaxBPM, (int)lrintf(BPMS[i]) );
}
if( MinBPM == MaxBPM )
{
if( MinBPM == -1 )
SetText( RANDOM_TEXT ); // random (was "...") -aj
else
SetText( ssprintf("%i", MinBPM) );
}
else
{
SetText( ssprintf("%i%s%i", MinBPM, SEPARATOR.GetValue().c_str(), MaxBPM) );
}
}
else
{
for( unsigned i = 0; i < BPMS.size(); ++i )
{
m_BPMS.push_back(BPMS[i]);
if( BPMS[i] != -1 )
m_BPMS.push_back(BPMS[i]); // hold
}
m_iCurrentBPM = min(1u, m_BPMS.size()); // start on the first hold
m_fBPMFrom = BPMS[0];
m_fBPMTo = BPMS[0];
m_fPercentInState = 1;
}
if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
RunCommands( SET_EXTRA_COMMAND );
else if( !AllIdentical )
RunCommands( SET_CHANGING_COMMAND );
else
RunCommands( SET_NORMAL_COMMAND );
}
void BPMDisplay::CycleRandomly()
{
DisplayBpms bpms;
bpms.Add(-1);
SetBPMRange( bpms );
RunCommands( SET_RANDOM_COMMAND );
m_fCycleTime = (float)RANDOM_CYCLE_SPEED;
// Go to default value in event of a negative value in the metrics
if( m_fCycleTime < 0 )
m_fCycleTime = 0.2f;
}
void BPMDisplay::NoBPM()
{
m_BPMS.clear();
SetText( NO_BPM_TEXT );
RunCommands( SET_NO_BPM_COMMAND );
}
void BPMDisplay::SetBpmFromSong( const Song* pSong )
{
ASSERT( pSong != NULL );
switch( pSong->m_DisplayBPMType )
{
case DISPLAY_BPM_ACTUAL:
case DISPLAY_BPM_SPECIFIED:
{
DisplayBpms bpms;
pSong->GetDisplayBpms( bpms );
SetBPMRange( bpms );
m_fCycleTime = 1.0f;
}
break;
case DISPLAY_BPM_RANDOM:
CycleRandomly();
break;
default:
FAIL_M(ssprintf("Invalid display BPM type: %i", pSong->m_DisplayBPMType));
}
}
void BPMDisplay::SetBpmFromSteps( const Steps* pSteps )
{
ASSERT( pSteps != NULL );
DisplayBpms bpms;
float fMinBPM, fMaxBPM;
pSteps->GetTimingData()->GetActualBPM( fMinBPM, fMaxBPM );
bpms.Add( fMinBPM );
bpms.Add( fMaxBPM );
m_fCycleTime = 1.0f;
}
void BPMDisplay::SetBpmFromCourse( const Course* pCourse )
{
ASSERT( pCourse != NULL );
ASSERT( GAMESTATE->GetCurrentStyle() != NULL );
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
Trail *pTrail = pCourse->GetTrail( st );
// GetTranslitFullTitle because "Crashinfo.txt is garbled because of the ANSI output as usual." -f
ASSERT_M( pTrail != NULL, ssprintf("Course '%s' has no trail for StepsType '%s'", pCourse->GetTranslitFullTitle().c_str(), StringConversion::ToString(st).c_str() ) );
m_fCycleTime = (float)COURSE_CYCLE_SPEED;
if( (int)pTrail->m_vEntries.size() > CommonMetrics::MAX_COURSE_ENTRIES_BEFORE_VARIOUS )
{
SetVarious();
return;
}
DisplayBpms bpms;
pTrail->GetDisplayBpms( bpms );
SetBPMRange( bpms );
}
void BPMDisplay::SetConstantBpm( float fBPM )
{
DisplayBpms bpms;
bpms.Add( fBPM );
SetBPMRange( bpms );
}
void BPMDisplay::SetVarious()
{
m_BPMS.clear();
m_BPMS.push_back( -1 );
SetText( VARIOUS_TEXT );
}
void BPMDisplay::SetFromGameState()
{
if( GAMESTATE->m_pCurSong.Get() )
{
if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
CycleRandomly();
else
SetBpmFromSong( GAMESTATE->m_pCurSong );
return;
}
if( GAMESTATE->m_pCurCourse.Get() )
{
if( GAMESTATE->GetCurrentStyle() == NULL )
; // This is true when backing out from ScreenSelectCourse to ScreenTitleMenu. So, don't call SetBpmFromCourse where an assert will fire.
else
SetBpmFromCourse( GAMESTATE->m_pCurCourse );
return;
}
NoBPM();
}
// SongBPMDisplay (in-game BPM display)
class SongBPMDisplay: public BPMDisplay
{
public:
SongBPMDisplay();
virtual SongBPMDisplay *Copy() const;
virtual void Update( float fDeltaTime );
private:
float m_fLastGameStateBPM;
};
SongBPMDisplay::SongBPMDisplay()
{
m_fLastGameStateBPM = 0;
}
void SongBPMDisplay::Update( float fDeltaTime )
{
float fGameStateBPM = GAMESTATE->m_Position.m_fCurBPS * 60.0f;
if( m_fLastGameStateBPM != fGameStateBPM )
{
m_fLastGameStateBPM = fGameStateBPM;
SetConstantBpm( fGameStateBPM );
}
BPMDisplay::Update( fDeltaTime );
}
REGISTER_ACTOR_CLASS( SongBPMDisplay );
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the BPMDisplay. */
class LunaBPMDisplay: public Luna<BPMDisplay>
{
public:
static int SetFromGameState( T* p, lua_State *L ) { p->SetFromGameState(); return 0; }
static int SetFromSong( T* p, lua_State *L )
{
if( lua_isnil(L,1) ) { p->NoBPM(); }
else
{
const Song* pSong = Luna<Song>::check( L, 1, true );
p->SetBpmFromSong(pSong);
}
return 0;
}
static int SetFromSteps( T* p, lua_State *L )
{
if( lua_isnil(L,1) ) { p->NoBPM(); }
else
{
const Steps* pSteps = Luna<Steps>::check( L, 1, true );
p->SetBpmFromSteps(pSteps);
}
return 0;
}
static int SetFromCourse( T* p, lua_State *L )
{
if( lua_isnil(L,1) ) { p->NoBPM(); }
else
{
const Course* pCourse = Luna<Course>::check( L, 1, true );
p->SetBpmFromCourse(pCourse);
}
return 0;
}
static int GetText( T* p, lua_State *L ) { lua_pushstring( L, p->GetText() ); return 1; }
LunaBPMDisplay()
{
ADD_METHOD( SetFromGameState );
ADD_METHOD( SetFromSong );
ADD_METHOD( SetFromSteps );
ADD_METHOD( SetFromCourse );
ADD_METHOD( GetText );
}
};
LUA_REGISTER_DERIVED_CLASS( BPMDisplay, BitmapText )
/*
* (c) 2001-2002 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "BPMDisplay.h"
#include "RageUtil.h"
#include "GameConstantsAndTypes.h"
#include "GameState.h"
#include "Course.h"
#include "Style.h"
#include "ActorUtil.h"
#include "CommonMetrics.h"
#include "LocalizedString.h"
#include "Song.h"
#include "Steps.h"
#include <limits.h>
REGISTER_ACTOR_CLASS( BPMDisplay );
BPMDisplay::BPMDisplay()
{
m_fBPMFrom = m_fBPMTo = 0;
m_iCurrentBPM = 0;
m_BPMS.push_back(0);
m_fPercentInState = 0;
m_fCycleTime = 1.0f;
}
void BPMDisplay::Load()
{
SET_NO_BPM_COMMAND.Load( m_sName, "SetNoBpmCommand");
SET_NORMAL_COMMAND.Load( m_sName, "SetNormalCommand");
SET_CHANGING_COMMAND.Load( m_sName, "SetChangeCommand" );
SET_RANDOM_COMMAND.Load( m_sName, "SetRandomCommand" );
SET_EXTRA_COMMAND.Load( m_sName, "SetExtraCommand" );
CYCLE.Load( m_sName, "Cycle" );
RANDOM_CYCLE_SPEED.Load( m_sName, "RandomCycleSpeed" );
COURSE_CYCLE_SPEED.Load( m_sName, "CourseCycleSpeed" );
SEPARATOR.Load( m_sName, "Separator" );
SHOW_QMARKS.Load( m_sName, "ShowQMarksInRandomCycle" );
NO_BPM_TEXT.Load( m_sName, "NoBpmText" );
QUESTIONMARKS_TEXT.Load( m_sName, "QuestionMarksText" );
RANDOM_TEXT.Load( m_sName, "RandomText" );
VARIOUS_TEXT.Load( m_sName, "VariousText" );
BPM_FORMAT_STRING.Load( m_sName, "FormatString" );
RunCommands( SET_NORMAL_COMMAND );
}
void BPMDisplay::LoadFromNode( const XNode *pNode )
{
BitmapText::LoadFromNode( pNode );
Load();
}
float BPMDisplay::GetActiveBPM() const
{
return m_fBPMTo + (m_fBPMFrom-m_fBPMTo)*m_fPercentInState;
}
void BPMDisplay::Update( float fDeltaTime )
{
BitmapText::Update( fDeltaTime );
if( !(bool)CYCLE )
return;
if( m_BPMS.size() == 0 )
return; // no bpm
m_fPercentInState -= fDeltaTime / m_fCycleTime;
if( m_fPercentInState < 0 )
{
// go to next state
m_fPercentInState = 1; // reset timer
m_iCurrentBPM = (m_iCurrentBPM + 1) % m_BPMS.size();
m_fBPMFrom = m_fBPMTo;
m_fBPMTo = m_BPMS[m_iCurrentBPM];
if(m_fBPMTo == -1)
{
m_fBPMFrom = -1;
if( (bool)SHOW_QMARKS )
SetText( (RandomFloat(0,1)>0.90f) ? (RString)QUESTIONMARKS_TEXT : ssprintf((RString)BPM_FORMAT_STRING,RandomFloat(0,999)) );
else
SetText( ssprintf((RString)BPM_FORMAT_STRING, RandomFloat(0,999)) );
}
else if(m_fBPMFrom == -1)
{
m_fBPMFrom = m_fBPMTo;
}
}
if( m_fBPMTo != -1)
{
const float fActualBPM = GetActiveBPM();
SetText( ssprintf((RString)BPM_FORMAT_STRING, fActualBPM) );
}
}
void BPMDisplay::SetBPMRange( const DisplayBpms &bpms )
{
ASSERT( !bpms.vfBpms.empty() );
m_BPMS.clear();
const vector<float> &BPMS = bpms.vfBpms;
bool AllIdentical = true;
for( unsigned i = 0; i < BPMS.size(); ++i )
{
if( i > 0 && BPMS[i] != BPMS[i-1] )
AllIdentical = false;
}
if( !(bool)CYCLE )
{
int MinBPM = INT_MAX;
int MaxBPM = INT_MIN;
for( unsigned i = 0; i < BPMS.size(); ++i )
{
MinBPM = min( MinBPM, (int)lrintf(BPMS[i]) );
MaxBPM = max( MaxBPM, (int)lrintf(BPMS[i]) );
}
if( MinBPM == MaxBPM )
{
if( MinBPM == -1 )
SetText( RANDOM_TEXT ); // random (was "...") -aj
else
SetText( ssprintf("%i", MinBPM) );
}
else
{
SetText( ssprintf("%i%s%i", MinBPM, SEPARATOR.GetValue().c_str(), MaxBPM) );
}
}
else
{
for( unsigned i = 0; i < BPMS.size(); ++i )
{
m_BPMS.push_back(BPMS[i]);
if( BPMS[i] != -1 )
m_BPMS.push_back(BPMS[i]); // hold
}
m_iCurrentBPM = min(1u, m_BPMS.size()); // start on the first hold
m_fBPMFrom = BPMS[0];
m_fBPMTo = BPMS[0];
m_fPercentInState = 1;
}
if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
RunCommands( SET_EXTRA_COMMAND );
else if( !AllIdentical )
RunCommands( SET_CHANGING_COMMAND );
else
RunCommands( SET_NORMAL_COMMAND );
}
void BPMDisplay::CycleRandomly()
{
DisplayBpms bpms;
bpms.Add(-1);
SetBPMRange( bpms );
RunCommands( SET_RANDOM_COMMAND );
m_fCycleTime = (float)RANDOM_CYCLE_SPEED;
// Go to default value in event of a negative value in the metrics
if( m_fCycleTime < 0 )
m_fCycleTime = 0.2f;
}
void BPMDisplay::NoBPM()
{
m_BPMS.clear();
SetText( NO_BPM_TEXT );
RunCommands( SET_NO_BPM_COMMAND );
}
void BPMDisplay::SetBpmFromSong( const Song* pSong )
{
ASSERT( pSong != nullptr );
switch( pSong->m_DisplayBPMType )
{
case DISPLAY_BPM_ACTUAL:
case DISPLAY_BPM_SPECIFIED:
{
DisplayBpms bpms;
pSong->GetDisplayBpms( bpms );
SetBPMRange( bpms );
m_fCycleTime = 1.0f;
}
break;
case DISPLAY_BPM_RANDOM:
CycleRandomly();
break;
default:
FAIL_M(ssprintf("Invalid display BPM type: %i", pSong->m_DisplayBPMType));
}
}
void BPMDisplay::SetBpmFromSteps( const Steps* pSteps )
{
ASSERT( pSteps != nullptr );
DisplayBpms bpms;
float fMinBPM, fMaxBPM;
pSteps->GetTimingData()->GetActualBPM( fMinBPM, fMaxBPM );
bpms.Add( fMinBPM );
bpms.Add( fMaxBPM );
m_fCycleTime = 1.0f;
}
void BPMDisplay::SetBpmFromCourse( const Course* pCourse )
{
ASSERT( pCourse != nullptr );
ASSERT( GAMESTATE->GetCurrentStyle() != nullptr );
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
Trail *pTrail = pCourse->GetTrail( st );
// GetTranslitFullTitle because "Crashinfo.txt is garbled because of the ANSI output as usual." -f
ASSERT_M( pTrail != nullptr, ssprintf("Course '%s' has no trail for StepsType '%s'", pCourse->GetTranslitFullTitle().c_str(), StringConversion::ToString(st).c_str() ) );
m_fCycleTime = (float)COURSE_CYCLE_SPEED;
if( (int)pTrail->m_vEntries.size() > CommonMetrics::MAX_COURSE_ENTRIES_BEFORE_VARIOUS )
{
SetVarious();
return;
}
DisplayBpms bpms;
pTrail->GetDisplayBpms( bpms );
SetBPMRange( bpms );
}
void BPMDisplay::SetConstantBpm( float fBPM )
{
DisplayBpms bpms;
bpms.Add( fBPM );
SetBPMRange( bpms );
}
void BPMDisplay::SetVarious()
{
m_BPMS.clear();
m_BPMS.push_back( -1 );
SetText( VARIOUS_TEXT );
}
void BPMDisplay::SetFromGameState()
{
if( GAMESTATE->m_pCurSong.Get() )
{
if( GAMESTATE->IsAnExtraStageAndSelectionLocked() )
CycleRandomly();
else
SetBpmFromSong( GAMESTATE->m_pCurSong );
return;
}
if( GAMESTATE->m_pCurCourse.Get() )
{
if( GAMESTATE->GetCurrentStyle() == NULL )
; // This is true when backing out from ScreenSelectCourse to ScreenTitleMenu. So, don't call SetBpmFromCourse where an assert will fire.
else
SetBpmFromCourse( GAMESTATE->m_pCurCourse );
return;
}
NoBPM();
}
// SongBPMDisplay (in-game BPM display)
class SongBPMDisplay: public BPMDisplay
{
public:
SongBPMDisplay();
virtual SongBPMDisplay *Copy() const;
virtual void Update( float fDeltaTime );
private:
float m_fLastGameStateBPM;
};
SongBPMDisplay::SongBPMDisplay()
{
m_fLastGameStateBPM = 0;
}
void SongBPMDisplay::Update( float fDeltaTime )
{
float fGameStateBPM = GAMESTATE->m_Position.m_fCurBPS * 60.0f;
if( m_fLastGameStateBPM != fGameStateBPM )
{
m_fLastGameStateBPM = fGameStateBPM;
SetConstantBpm( fGameStateBPM );
}
BPMDisplay::Update( fDeltaTime );
}
REGISTER_ACTOR_CLASS( SongBPMDisplay );
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the BPMDisplay. */
class LunaBPMDisplay: public Luna<BPMDisplay>
{
public:
static int SetFromGameState( T* p, lua_State *L ) { p->SetFromGameState(); return 0; }
static int SetFromSong( T* p, lua_State *L )
{
if( lua_isnil(L,1) ) { p->NoBPM(); }
else
{
const Song* pSong = Luna<Song>::check( L, 1, true );
p->SetBpmFromSong(pSong);
}
return 0;
}
static int SetFromSteps( T* p, lua_State *L )
{
if( lua_isnil(L,1) ) { p->NoBPM(); }
else
{
const Steps* pSteps = Luna<Steps>::check( L, 1, true );
p->SetBpmFromSteps(pSteps);
}
return 0;
}
static int SetFromCourse( T* p, lua_State *L )
{
if( lua_isnil(L,1) ) { p->NoBPM(); }
else
{
const Course* pCourse = Luna<Course>::check( L, 1, true );
p->SetBpmFromCourse(pCourse);
}
return 0;
}
static int GetText( T* p, lua_State *L ) { lua_pushstring( L, p->GetText() ); return 1; }
LunaBPMDisplay()
{
ADD_METHOD( SetFromGameState );
ADD_METHOD( SetFromSong );
ADD_METHOD( SetFromSteps );
ADD_METHOD( SetFromCourse );
ADD_METHOD( GetText );
}
};
LUA_REGISTER_DERIVED_CLASS( BPMDisplay, BitmapText )
/*
* (c) 2001-2002 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1 -1
View File
@@ -373,7 +373,7 @@ bool BackgroundImpl::Layer::CreateBackground( const Song *pSong, const Backgroun
Actor *pActor = ActorUtil::MakeActor( sEffectFile );
ASSERT( pActor != NULL );
ASSERT( pActor != nullptr );
m_BGAnimations[bd] = pActor;
for( unsigned i=0; i<vsResolvedRef.size(); i++ )
+3 -3
View File
@@ -203,7 +203,7 @@ struct BannerTexture: public RageTexture
void Create()
{
ASSERT( m_pImage != NULL );
ASSERT( m_pImage != nullptr );
/* The image is preprocessed; do as little work as possible. */
@@ -239,7 +239,7 @@ struct BannerTexture: public RageTexture
ASSERT( DISPLAY->SupportsTextureFormat(pf) );
ASSERT(m_pImage != NULL);
ASSERT(m_pImage != nullptr);
m_uTexHandle = DISPLAY->CreateTexture( pf, m_pImage, false );
CreateFrameRects();
@@ -290,7 +290,7 @@ RageTextureID BannerCache::LoadCachedBanner( RString sBannerPath )
* when converting; this way, the conversion will end up in the map so we
* only have to convert once. */
RageSurface *&pImage = g_BannerPathToImage[sBannerPath];
ASSERT( pImage != NULL );
ASSERT( pImage != nullptr );
int iSourceWidth = 0, iSourceHeight = 0;
BannerData.GetValue( sBannerPath, "Width", iSourceWidth );
+406 -406
View File
@@ -1,406 +1,406 @@
#include "global.h"
#include "ActorUtil.h"
#include "BeginnerHelper.h"
#include "GameState.h"
#include "PrefsManager.h"
#include "RageLog.h"
#include "RageDisplay.h"
#include "Steps.h"
#include "Style.h"
#include "Model.h"
#include "ScreenDimensions.h"
#include "ThemeManager.h"
// "PLAYER_X" offsets are relative to the pad.
// ex: Setting this to 10, and the HELPER to 300, will put the dancer at 310.
#define PLAYER_X( px ) THEME->GetMetricF("BeginnerHelper",ssprintf("Player%dX",px+1))
// "HELPER" offsets effect the pad/dancer as a whole.
// Their relative Y cooridinates are hard-coded for each other.
#define HELPER_X THEME->GetMetricF("BeginnerHelper","HelperX")
#define HELPER_Y THEME->GetMetricF("BeginnerHelper","HelperY")
#define ST_LEFT 0x01
#define ST_DOWN 0x02
#define ST_UP 0x04
#define ST_RIGHT 0x08
#define ST_JUMPLR (ST_LEFT | ST_RIGHT)
#define ST_JUMPUD (ST_UP | ST_DOWN)
enum Animation
{
ANIM_DANCE_PAD,
ANIM_DANCE_PADS,
ANIM_UP,
ANIM_DOWN,
ANIM_LEFT,
ANIM_RIGHT,
ANIM_JUMPLR,
NUM_ANIMATIONS
};
static const char *anims[NUM_ANIMATIONS] =
{
"DancePad.txt",
"DancePads.txt",
"BeginnerHelper_step-up.bones.txt",
"BeginnerHelper_step-down.bones.txt",
"BeginnerHelper_step-left.bones.txt",
"BeginnerHelper_step-right.bones.txt",
"BeginnerHelper_step-jumplr.bones.txt"
};
static RString GetAnimPath( Animation a )
{
return RString( "Characters/" ) + anims[a];
}
BeginnerHelper::BeginnerHelper()
{
m_bShowBackground = true;
m_bInitialized = false;
m_iLastRowChecked = m_iLastRowFlashed = 0;
FOREACH_PlayerNumber( pn )
m_bPlayerEnabled[pn] = false;
FOREACH_PlayerNumber( pn )
m_pDancer[pn] = new Model;
m_pDancePad = new Model;
}
BeginnerHelper::~BeginnerHelper()
{
FOREACH_PlayerNumber( pn )
delete m_pDancer[pn];
delete m_pDancePad;
}
bool BeginnerHelper::Init( int iDancePadType )
{
ASSERT( !m_bInitialized );
if( !CanUse() )
return false;
// If no players were successfully added, bail.
{
bool bAnyLoaded = false;
for( int pn=0; pn<NUM_PLAYERS; pn++ )
if( m_bPlayerEnabled[pn] )
bAnyLoaded = true;
if( !bAnyLoaded )
return false;
}
// Load the Background and flash. Flash only shows if the BG does.
if( m_bShowBackground )
{
m_sBackground.Load( THEME->GetPathG("BeginnerHelper","background") );
this->AddChild( m_sBackground );
//m_sBackground.SetXY( 1, 1 );
m_sFlash.Load( THEME->GetPathG("BeginnerHelper","flash") );
m_sFlash.SetXY( 0, 0 );
m_sFlash.SetDiffuseAlpha( 0 );
}
// Load StepCircle graphics
for( int lsc=0; lsc<NUM_PLAYERS; lsc++ )
{
for( int lsce=0; lsce<4; lsce++ )
{
m_sStepCircle[lsc][lsce].Load( THEME->GetPathG("BeginnerHelper","stepcircle") );
m_sStepCircle[lsc][lsce].SetZoom( 0 ); // Hide until needed.
this->AddChild(&m_sStepCircle[lsc][lsce]);
// Set StepCircle coordinates
switch( lsce )
{
case 0: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)-80),HELPER_Y); break; // Left
case 1: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)+80),HELPER_Y); break; // Right
case 2: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)),(HELPER_Y-60)); break; // Up
case 3: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)),(HELPER_Y+60)); break; // Down
}
}
}
SHOW_DANCE_PAD.Load( "BeginnerHelper","ShowDancePad" );
// Load the DancePad
if( SHOW_DANCE_PAD )
{
switch( iDancePadType )
{
case 0: break; // No pad
case 1: m_pDancePad->LoadMilkshapeAscii(GetAnimPath(ANIM_DANCE_PAD)); break;
case 2: m_pDancePad->LoadMilkshapeAscii(GetAnimPath(ANIM_DANCE_PADS)); break;
}
m_pDancePad->SetName("DancePad");
m_pDancePad->SetX( HELPER_X );
m_pDancePad->SetY( HELPER_Y );
ActorUtil::LoadAllCommands( m_pDancePad, "BeginnerHelper" );
}
for( int pl=0; pl<NUM_PLAYERS; pl++ ) // Load players
{
// Skip if not enabled
if( !m_bPlayerEnabled[pl] )
continue;
// Load character data
const Character *Character = GAMESTATE->m_pCurCharacters[pl];
ASSERT( Character != NULL );
m_pDancer[pl]->SetName( ssprintf("PlayerP%d",pl+1) );
// Load textures
m_pDancer[pl]->LoadMilkshapeAscii( Character->GetModelPath() );
// Load needed animations
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-LEFT", GetAnimPath(ANIM_LEFT) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-DOWN", GetAnimPath(ANIM_DOWN) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-UP", GetAnimPath(ANIM_UP) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-RIGHT", GetAnimPath(ANIM_RIGHT) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-JUMPLR", GetAnimPath(ANIM_JUMPLR) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "rest", Character->GetRestAnimationPath() );
m_pDancer[pl]->SetDefaultAnimation( "rest" ); // Stay bouncing after a step has finished animating
m_pDancer[pl]->PlayAnimation( "rest" );
m_pDancer[pl]->SetX( HELPER_X+PLAYER_X(pl) );
m_pDancer[pl]->SetY( HELPER_Y+10 );
ActorUtil::LoadAllCommandsAndOnCommand( m_pDancer[pl], "BeginnerHelper" );
// many of the models floating around have the vertex order flipped, so force this.
m_pDancer[pl]->SetCullMode( CULL_NONE );
}
m_bInitialized = true;
return true;
}
void BeginnerHelper::ShowStepCircle( PlayerNumber pn, int CSTEP )
{
int isc=0; // Save OR issues within array boundries.. it's worth the extra few bytes of memory.
switch(CSTEP)
{
case ST_LEFT: isc=0; break;
case ST_RIGHT: isc=1; break;
case ST_UP: isc=2; break;
case ST_DOWN: isc=3; break;
}
m_sStepCircle[pn][isc].StopEffect();
m_sStepCircle[pn][isc].SetZoom( 2 );
m_sStepCircle[pn][isc].StopTweening();
m_sStepCircle[pn][isc].BeginTweening( GAMESTATE->m_Position.m_fCurBPS/3, TWEEN_LINEAR );
m_sStepCircle[pn][isc].SetZoom( 0 );
}
void BeginnerHelper::AddPlayer( PlayerNumber pn, const NoteData &ns )
{
ASSERT( !m_bInitialized );
ASSERT( pn >= 0 && pn < NUM_PLAYERS );
ASSERT( GAMESTATE->IsHumanPlayer(pn) );
if( !CanUse() )
return;
const Character *Character = GAMESTATE->m_pCurCharacters[pn];
ASSERT( Character != NULL );
if( !DoesFileExist(Character->GetModelPath()) )
return;
m_NoteData[pn].CopyAll( ns );
m_bPlayerEnabled[pn] = true;
}
bool BeginnerHelper::CanUse()
{
for (int i=0; i<NUM_ANIMATIONS; ++i )
if( !DoesFileExist(GetAnimPath((Animation)i)) )
return false;
return GAMESTATE->GetCurrentStyle()->m_bCanUseBeginnerHelper;
}
void BeginnerHelper::DrawPrimitives()
{
// If not initialized, don't bother with this
if( !m_bInitialized )
return;
ActorFrame::DrawPrimitives();
m_sFlash.Draw();
bool DrawCelShaded = PREFSMAN->m_bCelShadeModels;
// Draw Pad
if( SHOW_DANCE_PAD )
{
if( DrawCelShaded )
m_pDancePad->DrawCelShaded();
else
{
DISPLAY->SetLighting( true );
DISPLAY->SetLightDirectional(
0,
RageColor(0.5f,0.5f,0.5f,1),
RageColor(1,1,1,1),
RageColor(0,0,0,1),
RageVector3(0, 0, 1) );
m_pDancePad->Draw();
DISPLAY->ClearZBuffer(); // So character doesn't step "into" the dance pad.
DISPLAY->SetLightOff( 0 );
DISPLAY->SetLighting( false );
}
}
// Draw StepCircles
for(int scd=0; scd<NUM_PLAYERS; scd++)
for(int scde=0; scde<4; scde++)
m_sStepCircle[scd][scde].Draw();
// Draw Dancers
if( DrawCelShaded )
{
FOREACH_PlayerNumber( pn )
if( GAMESTATE->IsHumanPlayer(pn) )
m_pDancer[pn]->DrawCelShaded();
}
else
{
DISPLAY->SetLighting( true );
DISPLAY->SetLightDirectional(
0,
RageColor(0.5f,0.5f,0.5f,1),
RageColor(1,1,1,1),
RageColor(0,0,0,1),
RageVector3(0, 0, 1) );
FOREACH_PlayerNumber( pn )
if( GAMESTATE->IsHumanPlayer(pn) )
m_pDancer[pn]->Draw();
DISPLAY->SetLightOff( 0 );
DISPLAY->SetLighting( false );
}
}
void BeginnerHelper::Step( PlayerNumber pn, int CSTEP )
{
m_pDancer[pn]->StopTweening();
m_pDancer[pn]->SetRotationY( 0 ); // Make sure we're not still inside of a JUMPUD tween.
switch(CSTEP)
{
case ST_LEFT:
ShowStepCircle( pn, ST_LEFT );
m_pDancer[pn]->PlayAnimation( "Step-LEFT", 1.5f );
break;
case ST_RIGHT:
ShowStepCircle( pn, ST_RIGHT );
m_pDancer[pn]->PlayAnimation( "Step-RIGHT", 1.5f );
break;
case ST_UP:
ShowStepCircle( pn, ST_UP );
m_pDancer[pn]->PlayAnimation( "Step-UP", 1.5f );
break;
case ST_DOWN:
ShowStepCircle( pn, ST_DOWN );
m_pDancer[pn]->PlayAnimation( "Step-DOWN", 1.5f );
break;
case ST_JUMPLR:
ShowStepCircle( pn, ST_LEFT );
ShowStepCircle( pn, ST_RIGHT );
m_pDancer[pn]->PlayAnimation( "Step-JUMPLR", 1.5f );
break;
case ST_JUMPUD:
ShowStepCircle( pn, ST_UP );
ShowStepCircle( pn, ST_DOWN );
m_pDancer[pn]->StopTweening();
m_pDancer[pn]->PlayAnimation( "Step-JUMPLR", 1.5f );
m_pDancer[pn]->BeginTweening( GAMESTATE->m_Position.m_fCurBPS/8, TWEEN_LINEAR );
m_pDancer[pn]->SetRotationY( 90 );
m_pDancer[pn]->BeginTweening( 1/(GAMESTATE->m_Position.m_fCurBPS * 2) ); //sleep between jump-frames
m_pDancer[pn]->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /6, TWEEN_LINEAR );
m_pDancer[pn]->SetRotationY( 0 );
break;
}
m_sFlash.StopEffect();
m_sFlash.StopTweening();
m_sFlash.Sleep( GAMESTATE->m_Position.m_fCurBPS/16 );
m_sFlash.SetDiffuseAlpha( 1 );
m_sFlash.BeginTweening( 1/GAMESTATE->m_Position.m_fCurBPS * 0.5f );
m_sFlash.SetDiffuseAlpha( 0 );
}
void BeginnerHelper::Update( float fDeltaTime )
{
if( !m_bInitialized )
return;
// the row we want to check on this update
int iCurRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat + 0.4f );
FOREACH_EnabledPlayer( pn )
{
for( int iRow=m_iLastRowChecked; iRow<iCurRow; iRow++ )
{
// Check if there are any notes at all on this row.. If not, save scanning.
if( !m_NoteData[pn].IsThereATapAtRow(iRow) )
continue;
// Find all steps on this row, in order to show the correct animations
int iStep = 0;
const int iNumTracks = m_NoteData[pn].GetNumTracks();
for( int t=0; t<iNumTracks; t++ )
if( m_NoteData[pn].GetTapNote(t,iRow).type == TapNote::tap )
iStep |= 1 << t;
// Assign new data
this->Step( pn, iStep );
}
}
// Make sure we don't accidentally scan a row 2x
m_iLastRowChecked = iCurRow;
// Update animations
ActorFrame::Update( fDeltaTime );
m_pDancePad->Update( fDeltaTime );
m_sFlash.Update( fDeltaTime );
float beat = fDeltaTime*GAMESTATE->m_Position.m_fCurBPS;
// If this is not a human player, the dancer is not shown
FOREACH_HumanPlayer( pu )
{
// Update dancer's animation and StepCircles
m_pDancer[pu]->Update( beat );
for( int scu=0; scu<NUM_PLAYERS; scu++ )
for( int scue=0; scue<4; scue++ )
m_sStepCircle[scu][scue].Update( beat );
}
}
/*
* (c) 2003 Kevin Slaughter, Thad Ward
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "ActorUtil.h"
#include "BeginnerHelper.h"
#include "GameState.h"
#include "PrefsManager.h"
#include "RageLog.h"
#include "RageDisplay.h"
#include "Steps.h"
#include "Style.h"
#include "Model.h"
#include "ScreenDimensions.h"
#include "ThemeManager.h"
// "PLAYER_X" offsets are relative to the pad.
// ex: Setting this to 10, and the HELPER to 300, will put the dancer at 310.
#define PLAYER_X( px ) THEME->GetMetricF("BeginnerHelper",ssprintf("Player%dX",px+1))
// "HELPER" offsets effect the pad/dancer as a whole.
// Their relative Y cooridinates are hard-coded for each other.
#define HELPER_X THEME->GetMetricF("BeginnerHelper","HelperX")
#define HELPER_Y THEME->GetMetricF("BeginnerHelper","HelperY")
#define ST_LEFT 0x01
#define ST_DOWN 0x02
#define ST_UP 0x04
#define ST_RIGHT 0x08
#define ST_JUMPLR (ST_LEFT | ST_RIGHT)
#define ST_JUMPUD (ST_UP | ST_DOWN)
enum Animation
{
ANIM_DANCE_PAD,
ANIM_DANCE_PADS,
ANIM_UP,
ANIM_DOWN,
ANIM_LEFT,
ANIM_RIGHT,
ANIM_JUMPLR,
NUM_ANIMATIONS
};
static const char *anims[NUM_ANIMATIONS] =
{
"DancePad.txt",
"DancePads.txt",
"BeginnerHelper_step-up.bones.txt",
"BeginnerHelper_step-down.bones.txt",
"BeginnerHelper_step-left.bones.txt",
"BeginnerHelper_step-right.bones.txt",
"BeginnerHelper_step-jumplr.bones.txt"
};
static RString GetAnimPath( Animation a )
{
return RString( "Characters/" ) + anims[a];
}
BeginnerHelper::BeginnerHelper()
{
m_bShowBackground = true;
m_bInitialized = false;
m_iLastRowChecked = m_iLastRowFlashed = 0;
FOREACH_PlayerNumber( pn )
m_bPlayerEnabled[pn] = false;
FOREACH_PlayerNumber( pn )
m_pDancer[pn] = new Model;
m_pDancePad = new Model;
}
BeginnerHelper::~BeginnerHelper()
{
FOREACH_PlayerNumber( pn )
delete m_pDancer[pn];
delete m_pDancePad;
}
bool BeginnerHelper::Init( int iDancePadType )
{
ASSERT( !m_bInitialized );
if( !CanUse() )
return false;
// If no players were successfully added, bail.
{
bool bAnyLoaded = false;
for( int pn=0; pn<NUM_PLAYERS; pn++ )
if( m_bPlayerEnabled[pn] )
bAnyLoaded = true;
if( !bAnyLoaded )
return false;
}
// Load the Background and flash. Flash only shows if the BG does.
if( m_bShowBackground )
{
m_sBackground.Load( THEME->GetPathG("BeginnerHelper","background") );
this->AddChild( m_sBackground );
//m_sBackground.SetXY( 1, 1 );
m_sFlash.Load( THEME->GetPathG("BeginnerHelper","flash") );
m_sFlash.SetXY( 0, 0 );
m_sFlash.SetDiffuseAlpha( 0 );
}
// Load StepCircle graphics
for( int lsc=0; lsc<NUM_PLAYERS; lsc++ )
{
for( int lsce=0; lsce<4; lsce++ )
{
m_sStepCircle[lsc][lsce].Load( THEME->GetPathG("BeginnerHelper","stepcircle") );
m_sStepCircle[lsc][lsce].SetZoom( 0 ); // Hide until needed.
this->AddChild(&m_sStepCircle[lsc][lsce]);
// Set StepCircle coordinates
switch( lsce )
{
case 0: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)-80),HELPER_Y); break; // Left
case 1: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)+80),HELPER_Y); break; // Right
case 2: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)),(HELPER_Y-60)); break; // Up
case 3: m_sStepCircle[lsc][lsce].SetXY((HELPER_X+PLAYER_X(lsc)),(HELPER_Y+60)); break; // Down
}
}
}
SHOW_DANCE_PAD.Load( "BeginnerHelper","ShowDancePad" );
// Load the DancePad
if( SHOW_DANCE_PAD )
{
switch( iDancePadType )
{
case 0: break; // No pad
case 1: m_pDancePad->LoadMilkshapeAscii(GetAnimPath(ANIM_DANCE_PAD)); break;
case 2: m_pDancePad->LoadMilkshapeAscii(GetAnimPath(ANIM_DANCE_PADS)); break;
}
m_pDancePad->SetName("DancePad");
m_pDancePad->SetX( HELPER_X );
m_pDancePad->SetY( HELPER_Y );
ActorUtil::LoadAllCommands( m_pDancePad, "BeginnerHelper" );
}
for( int pl=0; pl<NUM_PLAYERS; pl++ ) // Load players
{
// Skip if not enabled
if( !m_bPlayerEnabled[pl] )
continue;
// Load character data
const Character *Character = GAMESTATE->m_pCurCharacters[pl];
ASSERT( Character != nullptr );
m_pDancer[pl]->SetName( ssprintf("PlayerP%d",pl+1) );
// Load textures
m_pDancer[pl]->LoadMilkshapeAscii( Character->GetModelPath() );
// Load needed animations
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-LEFT", GetAnimPath(ANIM_LEFT) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-DOWN", GetAnimPath(ANIM_DOWN) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-UP", GetAnimPath(ANIM_UP) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-RIGHT", GetAnimPath(ANIM_RIGHT) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "Step-JUMPLR", GetAnimPath(ANIM_JUMPLR) );
m_pDancer[pl]->LoadMilkshapeAsciiBones( "rest", Character->GetRestAnimationPath() );
m_pDancer[pl]->SetDefaultAnimation( "rest" ); // Stay bouncing after a step has finished animating
m_pDancer[pl]->PlayAnimation( "rest" );
m_pDancer[pl]->SetX( HELPER_X+PLAYER_X(pl) );
m_pDancer[pl]->SetY( HELPER_Y+10 );
ActorUtil::LoadAllCommandsAndOnCommand( m_pDancer[pl], "BeginnerHelper" );
// many of the models floating around have the vertex order flipped, so force this.
m_pDancer[pl]->SetCullMode( CULL_NONE );
}
m_bInitialized = true;
return true;
}
void BeginnerHelper::ShowStepCircle( PlayerNumber pn, int CSTEP )
{
int isc=0; // Save OR issues within array boundries.. it's worth the extra few bytes of memory.
switch(CSTEP)
{
case ST_LEFT: isc=0; break;
case ST_RIGHT: isc=1; break;
case ST_UP: isc=2; break;
case ST_DOWN: isc=3; break;
}
m_sStepCircle[pn][isc].StopEffect();
m_sStepCircle[pn][isc].SetZoom( 2 );
m_sStepCircle[pn][isc].StopTweening();
m_sStepCircle[pn][isc].BeginTweening( GAMESTATE->m_Position.m_fCurBPS/3, TWEEN_LINEAR );
m_sStepCircle[pn][isc].SetZoom( 0 );
}
void BeginnerHelper::AddPlayer( PlayerNumber pn, const NoteData &ns )
{
ASSERT( !m_bInitialized );
ASSERT( pn >= 0 && pn < NUM_PLAYERS );
ASSERT( GAMESTATE->IsHumanPlayer(pn) );
if( !CanUse() )
return;
const Character *Character = GAMESTATE->m_pCurCharacters[pn];
ASSERT( Character != nullptr );
if( !DoesFileExist(Character->GetModelPath()) )
return;
m_NoteData[pn].CopyAll( ns );
m_bPlayerEnabled[pn] = true;
}
bool BeginnerHelper::CanUse()
{
for (int i=0; i<NUM_ANIMATIONS; ++i )
if( !DoesFileExist(GetAnimPath((Animation)i)) )
return false;
return GAMESTATE->GetCurrentStyle()->m_bCanUseBeginnerHelper;
}
void BeginnerHelper::DrawPrimitives()
{
// If not initialized, don't bother with this
if( !m_bInitialized )
return;
ActorFrame::DrawPrimitives();
m_sFlash.Draw();
bool DrawCelShaded = PREFSMAN->m_bCelShadeModels;
// Draw Pad
if( SHOW_DANCE_PAD )
{
if( DrawCelShaded )
m_pDancePad->DrawCelShaded();
else
{
DISPLAY->SetLighting( true );
DISPLAY->SetLightDirectional(
0,
RageColor(0.5f,0.5f,0.5f,1),
RageColor(1,1,1,1),
RageColor(0,0,0,1),
RageVector3(0, 0, 1) );
m_pDancePad->Draw();
DISPLAY->ClearZBuffer(); // So character doesn't step "into" the dance pad.
DISPLAY->SetLightOff( 0 );
DISPLAY->SetLighting( false );
}
}
// Draw StepCircles
for(int scd=0; scd<NUM_PLAYERS; scd++)
for(int scde=0; scde<4; scde++)
m_sStepCircle[scd][scde].Draw();
// Draw Dancers
if( DrawCelShaded )
{
FOREACH_PlayerNumber( pn )
if( GAMESTATE->IsHumanPlayer(pn) )
m_pDancer[pn]->DrawCelShaded();
}
else
{
DISPLAY->SetLighting( true );
DISPLAY->SetLightDirectional(
0,
RageColor(0.5f,0.5f,0.5f,1),
RageColor(1,1,1,1),
RageColor(0,0,0,1),
RageVector3(0, 0, 1) );
FOREACH_PlayerNumber( pn )
if( GAMESTATE->IsHumanPlayer(pn) )
m_pDancer[pn]->Draw();
DISPLAY->SetLightOff( 0 );
DISPLAY->SetLighting( false );
}
}
void BeginnerHelper::Step( PlayerNumber pn, int CSTEP )
{
m_pDancer[pn]->StopTweening();
m_pDancer[pn]->SetRotationY( 0 ); // Make sure we're not still inside of a JUMPUD tween.
switch(CSTEP)
{
case ST_LEFT:
ShowStepCircle( pn, ST_LEFT );
m_pDancer[pn]->PlayAnimation( "Step-LEFT", 1.5f );
break;
case ST_RIGHT:
ShowStepCircle( pn, ST_RIGHT );
m_pDancer[pn]->PlayAnimation( "Step-RIGHT", 1.5f );
break;
case ST_UP:
ShowStepCircle( pn, ST_UP );
m_pDancer[pn]->PlayAnimation( "Step-UP", 1.5f );
break;
case ST_DOWN:
ShowStepCircle( pn, ST_DOWN );
m_pDancer[pn]->PlayAnimation( "Step-DOWN", 1.5f );
break;
case ST_JUMPLR:
ShowStepCircle( pn, ST_LEFT );
ShowStepCircle( pn, ST_RIGHT );
m_pDancer[pn]->PlayAnimation( "Step-JUMPLR", 1.5f );
break;
case ST_JUMPUD:
ShowStepCircle( pn, ST_UP );
ShowStepCircle( pn, ST_DOWN );
m_pDancer[pn]->StopTweening();
m_pDancer[pn]->PlayAnimation( "Step-JUMPLR", 1.5f );
m_pDancer[pn]->BeginTweening( GAMESTATE->m_Position.m_fCurBPS/8, TWEEN_LINEAR );
m_pDancer[pn]->SetRotationY( 90 );
m_pDancer[pn]->BeginTweening( 1/(GAMESTATE->m_Position.m_fCurBPS * 2) ); //sleep between jump-frames
m_pDancer[pn]->BeginTweening( GAMESTATE->m_Position.m_fCurBPS /6, TWEEN_LINEAR );
m_pDancer[pn]->SetRotationY( 0 );
break;
}
m_sFlash.StopEffect();
m_sFlash.StopTweening();
m_sFlash.Sleep( GAMESTATE->m_Position.m_fCurBPS/16 );
m_sFlash.SetDiffuseAlpha( 1 );
m_sFlash.BeginTweening( 1/GAMESTATE->m_Position.m_fCurBPS * 0.5f );
m_sFlash.SetDiffuseAlpha( 0 );
}
void BeginnerHelper::Update( float fDeltaTime )
{
if( !m_bInitialized )
return;
// the row we want to check on this update
int iCurRow = BeatToNoteRowNotRounded( GAMESTATE->m_Position.m_fSongBeat + 0.4f );
FOREACH_EnabledPlayer( pn )
{
for( int iRow=m_iLastRowChecked; iRow<iCurRow; iRow++ )
{
// Check if there are any notes at all on this row.. If not, save scanning.
if( !m_NoteData[pn].IsThereATapAtRow(iRow) )
continue;
// Find all steps on this row, in order to show the correct animations
int iStep = 0;
const int iNumTracks = m_NoteData[pn].GetNumTracks();
for( int t=0; t<iNumTracks; t++ )
if( m_NoteData[pn].GetTapNote(t,iRow).type == TapNote::tap )
iStep |= 1 << t;
// Assign new data
this->Step( pn, iStep );
}
}
// Make sure we don't accidentally scan a row 2x
m_iLastRowChecked = iCurRow;
// Update animations
ActorFrame::Update( fDeltaTime );
m_pDancePad->Update( fDeltaTime );
m_sFlash.Update( fDeltaTime );
float beat = fDeltaTime*GAMESTATE->m_Position.m_fCurBPS;
// If this is not a human player, the dancer is not shown
FOREACH_HumanPlayer( pu )
{
// Update dancer's animation and StepCircles
m_pDancer[pu]->Update( beat );
for( int scu=0; scu<NUM_PLAYERS; scu++ )
for( int scue=0; scue<4; scue++ )
m_sStepCircle[scu][scue].Update( beat );
}
}
/*
* (c) 2003 Kevin Slaughter, Thad Ward
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+4 -4
View File
@@ -95,7 +95,7 @@ BitmapText & BitmapText::operator=(const BitmapText &cpy)
if( m_pFont )
FONT->UnloadFont( m_pFont );
if( cpy.m_pFont != NULL )
if( cpy.m_pFont != nullptr )
m_pFont = FONT->CopyFont( cpy.m_pFont );
else
m_pFont = NULL;
@@ -363,7 +363,7 @@ void BitmapText::DrawChars( bool bUseStrokeTexture )
* in sAlternateText, too, just use sText. */
void BitmapText::SetText( const RString& _sText, const RString& _sAlternateText, int iWrapWidthPixels )
{
ASSERT( m_pFont != NULL );
ASSERT( m_pFont != nullptr );
RString sNewText = StringWillUseAlternate(_sText,_sAlternateText) ? _sAlternateText : _sText;
@@ -505,7 +505,7 @@ void BitmapText::UpdateBaseZoom()
bool BitmapText::StringWillUseAlternate( const RString& sText, const RString& sAlternateText ) const
{
ASSERT( m_pFont != NULL );
ASSERT( m_pFont != nullptr );
// Can't use the alternate if there isn't one.
if( !sAlternateText.size() )
@@ -711,7 +711,7 @@ void BitmapText::SetHorizAlign( float f )
void BitmapText::SetWrapWidthPixels( int iWrapWidthPixels )
{
ASSERT( m_pFont != NULL ); // always load a font first
ASSERT( m_pFont != nullptr ); // always load a font first
if( m_iWrapWidthPixels == iWrapWidthPixels )
return;
m_iWrapWidthPixels = iWrapWidthPixels;
+2 -2
View File
@@ -127,7 +127,7 @@ public:
static int GetCharacter( T* p, lua_State *L )
{
Character *pCharacter = p->GetCharacterFromID(SArg(1));
if( pCharacter != NULL )
if( pCharacter != nullptr )
pCharacter->PushSelf( L );
else
lua_pushnil( L );
@@ -137,7 +137,7 @@ public:
static int GetRandomCharacter( T* p, lua_State *L )
{
Character *pCharacter = p->GetRandomCharacter();
if( pCharacter != NULL )
if( pCharacter != nullptr )
pCharacter->PushSelf( L );
else
lua_pushnil( L );
+3 -3
View File
@@ -690,7 +690,7 @@ int Course::GetMeter( StepsType st, CourseDifficulty cd ) const
if( m_iCustomMeter[cd] != -1 )
return m_iCustomMeter[cd];
const Trail* pTrail = GetTrail( st );
if( pTrail != NULL )
if( pTrail != nullptr )
return pTrail->GetMeter();
return 0;
}
@@ -893,7 +893,7 @@ void Course::UpdateCourseStats( StepsType st )
for(unsigned i = 0; i < m_vEntries.size(); i++)
{
Song *pSong = m_vEntries[i].songID.ToSong();
if( pSong != NULL )
if( pSong != nullptr )
continue;
if ( m_SortOrder_Ranking == 2 )
@@ -904,7 +904,7 @@ void Course::UpdateCourseStats( StepsType st )
const Trail* pTrail = GetTrail( st, Difficulty_Medium );
m_SortOrder_TotalDifficulty += pTrail != NULL? pTrail->GetTotalMeter():0;
m_SortOrder_TotalDifficulty += pTrail != nullptr? pTrail->GetTotalMeter():0;
// OPTIMIZATION: Ranking info isn't dependent on style, so call it
// sparingly. It's handled on startup and when themes change.
+3 -3
View File
@@ -195,7 +195,7 @@ void CourseUtil::SortCoursePointerArrayByNumPlays( vector<Course*> &vpCoursesInO
void CourseUtil::SortCoursePointerArrayByNumPlays( vector<Course*> &vpCoursesInOut, const Profile* pProfile, bool bDescending )
{
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
for(unsigned i = 0; i < vpCoursesInOut.size(); ++i)
course_sort_val[vpCoursesInOut[i]] = ssprintf( "%09i", pProfile->GetCourseNumTimesPlayed(vpCoursesInOut[i]) );
stable_sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), bDescending ? CompareCoursePointersBySortValueDescending : CompareCoursePointersBySortValueAscending );
@@ -422,7 +422,7 @@ bool EditCourseUtil::ValidateEditCourseName( const RString &sAnswer, RString &sE
}
static const RString sInvalidChars = "\\/:*?\"<>|";
if( strpbrk(sAnswer, sInvalidChars) != NULL )
if( strpbrk(sAnswer, sInvalidChars) != nullptr )
{
sErrorOut = ssprintf( EDIT_NAME_CANNOT_CONTAIN.GetValue(), sInvalidChars.c_str() );
return false;
@@ -448,7 +448,7 @@ bool EditCourseUtil::ValidateEditCourseName( const RString &sAnswer, RString &sE
void EditCourseUtil::UpdateAndSetTrail()
{
ASSERT( GAMESTATE->m_pCurStyle != NULL );
ASSERT( GAMESTATE->m_pCurStyle != nullptr );
StepsType st = GAMESTATE->m_pCurStyle->m_StepsType;
Trail *pTrail = NULL;
if( GAMESTATE->m_pCurCourse )
+1 -1
View File
@@ -631,7 +631,7 @@ unsigned TZip::swrite(void *param,const char *buf, unsigned size)
unsigned int TZip::write(const char *buf,unsigned int size)
{
const char *srcbuf=buf;
if (pfout != NULL)
if (pfout != nullptr)
{
unsigned long writ = pfout->Write( srcbuf, size );
return writ;
+417 -417
View File
@@ -1,417 +1,417 @@
#include "global.h"
#include "DancingCharacters.h"
#include "GameConstantsAndTypes.h"
#include "RageDisplay.h"
#include "RageUtil.h"
#include "RageMath.h"
#include "GameState.h"
#include "Song.h"
#include "Character.h"
#include "StatsManager.h"
#include "PrefsManager.h"
#include "Model.h"
int Neg1OrPos1();
#define DC_X( choice ) THEME->GetMetricF("DancingCharacters",ssprintf("2DCharacterXP%d",choice+1))
#define DC_Y( choice ) THEME->GetMetricF("DancingCharacters",ssprintf("2DCharacterYP%d",choice+1))
/*
* TODO:
* - Metrics/Lua for lighting and camera sweeping.
* - Ability to load secondary elements i.e. stages.
* - Remove support for 2D characters (Lua can do it).
* - Cleanup!
*
* -- Colby
*/
const float CAMERA_REST_DISTANCE = 32.f;
const float CAMERA_REST_LOOK_AT_HEIGHT = -11.f;
const float CAMERA_SWEEP_DISTANCE = 28.f;
const float CAMERA_SWEEP_DISTANCE_VARIANCE = 4.f;
const float CAMERA_SWEEP_HEIGHT_VARIANCE = 7.f;
const float CAMERA_SWEEP_PAN_Y_RANGE_DEGREES = 45.f;
const float CAMERA_SWEEP_PAN_Y_VARIANCE_DEGREES = 60.f;
const float CAMERA_SWEEP_LOOK_AT_HEIGHT = -11.f;
const float CAMERA_STILL_DISTANCE = 26.f;
const float CAMERA_STILL_DISTANCE_VARIANCE = 3.f;
const float CAMERA_STILL_PAN_Y_RANGE_DEGREES = 120.f;
const float CAMERA_STILL_HEIGHT_VARIANCE = 5.f;
const float CAMERA_STILL_LOOK_AT_HEIGHT = -10.f;
const float MODEL_X_ONE_PLAYER = 0;
const float MODEL_X_TWO_PLAYERS[NUM_PLAYERS] = { +8, -8 };
const float MODEL_ROTATIONY_TWO_PLAYERS[NUM_PLAYERS] = { -90, 90 };
DancingCharacters::DancingCharacters(): m_bDrawDangerLight(false),
m_CameraDistance(0), m_CameraPanYStart(0), m_CameraPanYEnd(0),
m_fLookAtHeight(0), m_fCameraHeightStart(0), m_fCameraHeightEnd(0),
m_fThisCameraStartBeat(0), m_fThisCameraEndBeat(0)
{
FOREACH_PlayerNumber( p )
{
m_pCharacter[p] = new Model;
m_2DIdleTimer[p].SetZero();
m_i2DAnimState[p] = AS2D_IDLE; // start on idle state
if( !GAMESTATE->IsPlayerEnabled(p) )
continue;
Character* pChar = GAMESTATE->m_pCurCharacters[p];
if( !pChar )
continue;
// load in any potential 2D stuff
RString sCharacterDirectory = pChar->m_sCharDir;
RString sCurrentAnim;
sCurrentAnim = sCharacterDirectory + "2DIdle";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgIdle[p].Load( sCurrentAnim );
m_bgIdle[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DMiss";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgMiss[p].Load( sCurrentAnim );
m_bgMiss[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DGood";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgGood[p].Load( sCurrentAnim );
m_bgGood[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DGreat";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgGreat[p].Load( sCurrentAnim );
m_bgGreat[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DFever";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgFever[p].Load( sCurrentAnim );
m_bgFever[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DFail";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgFail[p].Load( sCurrentAnim );
m_bgFail[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DWin";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgWin[p].Load( sCurrentAnim );
m_bgWin[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DWinFever";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgWinFever[p].Load( sCurrentAnim );
m_bgWinFever[p]->SetXY(DC_X(p),DC_Y(p));
}
if( pChar->GetModelPath().empty() )
continue;
if( GAMESTATE->GetNumPlayersEnabled()==2 )
m_pCharacter[p]->SetX( MODEL_X_TWO_PLAYERS[p] );
else
m_pCharacter[p]->SetX( MODEL_X_ONE_PLAYER );
switch( GAMESTATE->m_PlayMode )
{
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
m_pCharacter[p]->SetRotationY( MODEL_ROTATIONY_TWO_PLAYERS[p] );
default:
break;
}
m_pCharacter[p]->LoadMilkshapeAscii( pChar->GetModelPath() );
m_pCharacter[p]->LoadMilkshapeAsciiBones( "rest", pChar->GetRestAnimationPath() );
m_pCharacter[p]->LoadMilkshapeAsciiBones( "warmup", pChar->GetWarmUpAnimationPath() );
m_pCharacter[p]->LoadMilkshapeAsciiBones( "dance", pChar->GetDanceAnimationPath() );
m_pCharacter[p]->SetCullMode( CULL_NONE ); // many of the models floating around have the vertex order flipped
m_pCharacter[p]->RunCommands( pChar->m_cmdInit );
}
}
DancingCharacters::~DancingCharacters()
{
FOREACH_PlayerNumber( p )
delete m_pCharacter[p];
}
void DancingCharacters::LoadNextSong()
{
// initial camera sweep is still
m_CameraDistance = CAMERA_REST_DISTANCE;
m_CameraPanYStart = 0;
m_CameraPanYEnd = 0;
m_fCameraHeightStart = CAMERA_REST_LOOK_AT_HEIGHT;
m_fCameraHeightEnd = CAMERA_REST_LOOK_AT_HEIGHT;
m_fLookAtHeight = CAMERA_REST_LOOK_AT_HEIGHT;
m_fThisCameraStartBeat = 0;
m_fThisCameraEndBeat = 0;
ASSERT( GAMESTATE->m_pCurSong != NULL );
m_fThisCameraEndBeat = GAMESTATE->m_pCurSong->GetFirstBeat();
FOREACH_PlayerNumber( p )
if( GAMESTATE->IsPlayerEnabled(p) )
m_pCharacter[p]->PlayAnimation( "rest" );
}
int Neg1OrPos1() { return RandomInt( 2 ) ? -1 : +1; }
void DancingCharacters::Update( float fDelta )
{
if( GAMESTATE->m_Position.m_bFreeze || GAMESTATE->m_Position.m_bDelay )
{
// spin the camera Matrix-style
m_CameraPanYStart += fDelta*40;
m_CameraPanYEnd += fDelta*40;
}
else
{
// make the characters move
float fBPM = GAMESTATE->m_Position.m_fCurBPS*60;
float fUpdateScale = SCALE( fBPM, 60.f, 300.f, 0.75f, 1.5f );
CLAMP( fUpdateScale, 0.75f, 1.5f );
/* It's OK for the animation to go slower than natural when we're
* at a very low music rate. */
fUpdateScale *= GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
FOREACH_PlayerNumber( p )
{
if( GAMESTATE->IsPlayerEnabled(p) )
m_pCharacter[p]->Update( fDelta*fUpdateScale );
}
}
static bool bWasGameplayStarting = false;
bool bGameplayStarting = GAMESTATE->m_bGameplayLeadIn;
if( !bWasGameplayStarting && bGameplayStarting )
{
FOREACH_PlayerNumber( p )
if( GAMESTATE->IsPlayerEnabled(p) )
m_pCharacter[p]->PlayAnimation( "warmup" );
}
bWasGameplayStarting = bGameplayStarting;
static float fLastBeat = GAMESTATE->m_Position.m_fSongBeat;
float firstBeat = GAMESTATE->m_pCurSong->GetFirstBeat();
float fThisBeat = GAMESTATE->m_Position.m_fSongBeat;
if( fLastBeat < firstBeat && fThisBeat >= firstBeat )
{
FOREACH_PlayerNumber( p )
m_pCharacter[p]->PlayAnimation( "dance" );
}
fLastBeat = fThisBeat;
// time for a new sweep?
if( GAMESTATE->m_Position.m_fSongBeat > m_fThisCameraEndBeat )
{
if( RandomInt(6) >= 4 )
{
// sweeping camera
m_CameraDistance = CAMERA_SWEEP_DISTANCE + RandomInt(-1,1) * CAMERA_SWEEP_DISTANCE_VARIANCE;
m_CameraPanYStart = m_CameraPanYEnd = RandomInt(-1,1) * CAMERA_SWEEP_PAN_Y_RANGE_DEGREES;
m_fCameraHeightStart = m_fCameraHeightEnd = CAMERA_STILL_LOOK_AT_HEIGHT;
m_CameraPanYEnd += RandomInt(-1,1) * CAMERA_SWEEP_PAN_Y_VARIANCE_DEGREES;
m_fCameraHeightStart = m_fCameraHeightEnd = m_fCameraHeightStart + RandomInt(-1,1) * CAMERA_SWEEP_HEIGHT_VARIANCE;
float fCameraHeightVariance = RandomInt(-1,1) * CAMERA_SWEEP_HEIGHT_VARIANCE;
m_fCameraHeightStart -= fCameraHeightVariance;
m_fCameraHeightEnd += fCameraHeightVariance;
m_fLookAtHeight = CAMERA_SWEEP_LOOK_AT_HEIGHT;
}
else
{
// still camera
m_CameraDistance = CAMERA_STILL_DISTANCE + RandomInt(-1,1) * CAMERA_STILL_DISTANCE_VARIANCE;
m_CameraPanYStart = m_CameraPanYEnd = Neg1OrPos1() * CAMERA_STILL_PAN_Y_RANGE_DEGREES;
m_fCameraHeightStart = m_fCameraHeightEnd = CAMERA_SWEEP_LOOK_AT_HEIGHT + Neg1OrPos1() * CAMERA_STILL_HEIGHT_VARIANCE;
m_fLookAtHeight = CAMERA_STILL_LOOK_AT_HEIGHT;
}
int iCurBeat = (int)GAMESTATE->m_Position.m_fSongBeat;
iCurBeat -= iCurBeat%8;
m_fThisCameraStartBeat = (float) iCurBeat;
m_fThisCameraEndBeat = float(iCurBeat + 8);
}
/*
// is there any of this still around? This block of code is _ugly_. -Colby
// update any 2D stuff
FOREACH_PlayerNumber( p )
{
if( m_bgIdle[p].IsLoaded() )
{
if( m_bgIdle[p].IsLoaded() && m_i2DAnimState[p] == AS2D_IDLE )
m_bgIdle[p]->Update( fDelta );
if( m_bgMiss[p].IsLoaded() && m_i2DAnimState[p] == AS2D_MISS )
m_bgMiss[p]->Update( fDelta );
if( m_bgGood[p].IsLoaded() && m_i2DAnimState[p] == AS2D_GOOD )
m_bgGood[p]->Update( fDelta );
if( m_bgGreat[p].IsLoaded() && m_i2DAnimState[p] == AS2D_GREAT )
m_bgGreat[p]->Update( fDelta );
if( m_bgFever[p].IsLoaded() && m_i2DAnimState[p] == AS2D_FEVER )
m_bgFever[p]->Update( fDelta );
if( m_bgFail[p].IsLoaded() && m_i2DAnimState[p] == AS2D_FAIL )
m_bgFail[p]->Update( fDelta );
if( m_bgWin[p].IsLoaded() && m_i2DAnimState[p] == AS2D_WIN )
m_bgWin[p]->Update( fDelta );
if( m_bgWinFever[p].IsLoaded() && m_i2DAnimState[p] == AS2D_WINFEVER )
m_bgWinFever[p]->Update(fDelta);
if(m_i2DAnimState[p] != AS2D_IDLE) // if we're not in idle state, start a timer to return us to idle
{
// never return to idle state if we have failed / passed (i.e. completed) the song
if(m_i2DAnimState[p] != AS2D_WINFEVER && m_i2DAnimState[p] != AS2D_FAIL && m_i2DAnimState[p] != AS2D_WIN)
{
if(m_2DIdleTimer[p].IsZero())
m_2DIdleTimer[p].Touch();
if(!m_2DIdleTimer[p].IsZero() && m_2DIdleTimer[p].Ago() > 1.0f)
{
m_2DIdleTimer[p].SetZero();
m_i2DAnimState[p] = AS2D_IDLE;
}
}
}
}
}
*/
}
void DancingCharacters::Change2DAnimState( PlayerNumber pn, int iState )
{
ASSERT( pn < NUM_PLAYERS );
ASSERT( iState < AS2D_MAXSTATES );
m_i2DAnimState[pn] = iState;
}
void DancingCharacters::DrawPrimitives()
{
DISPLAY->CameraPushMatrix();
float fPercentIntoSweep;
if(m_fThisCameraStartBeat == m_fThisCameraEndBeat)
fPercentIntoSweep = 0;
else
fPercentIntoSweep = SCALE(GAMESTATE->m_Position.m_fSongBeat, m_fThisCameraStartBeat, m_fThisCameraEndBeat, 0.f, 1.f );
float fCameraPanY = SCALE( fPercentIntoSweep, 0.f, 1.f, m_CameraPanYStart, m_CameraPanYEnd );
float fCameraHeight = SCALE( fPercentIntoSweep, 0.f, 1.f, m_fCameraHeightStart, m_fCameraHeightEnd );
RageVector3 m_CameraPoint( 0, fCameraHeight, -m_CameraDistance );
RageMatrix CameraRot;
RageMatrixRotationY( &CameraRot, fCameraPanY );
RageVec3TransformCoord( &m_CameraPoint, &m_CameraPoint, &CameraRot );
RageVector3 m_LookAt( 0, m_fLookAtHeight, 0 );
DISPLAY->LoadLookAt( 45,
m_CameraPoint,
m_LookAt,
RageVector3(0,1,0) );
FOREACH_EnabledPlayer( p )
{
bool bFailed = STATSMAN->m_CurStageStats.m_player[p].m_bFailed;
bool bDanger = m_bDrawDangerLight;
DISPLAY->SetLighting( true );
RageColor ambient = bFailed ? RageColor(0.2f,0.1f,0.1f,1) : (bDanger ? RageColor(0.4f,0.1f,0.1f,1) : RageColor(0.4f,0.4f,0.4f,1));
RageColor diffuse = bFailed ? RageColor(0.4f,0.1f,0.1f,1) : (bDanger ? RageColor(0.8f,0.1f,0.1f,1) : RageColor(1,0.95f,0.925f,1));
RageColor specular = RageColor(0.8f,0.8f,0.8f,1);
DISPLAY->SetLightDirectional(
0,
ambient,
diffuse,
specular,
RageVector3(-3, -7.5f, +9) );
if( PREFSMAN->m_bCelShadeModels )
{
m_pCharacter[p]->DrawCelShaded();
DISPLAY->SetLightOff( 0 );
DISPLAY->SetLighting( false );
continue;
}
m_pCharacter[p]->Draw();
DISPLAY->SetLightOff( 0 );
DISPLAY->SetLighting( false );
}
DISPLAY->CameraPopMatrix();
/*
// Ugly! -Colby
// now draw any potential 2D stuff
FOREACH_PlayerNumber( p )
{
if(m_bgIdle[p].IsLoaded() && m_i2DAnimState[p] == AS2D_IDLE)
m_bgIdle[p]->Draw();
if(m_bgMiss[p].IsLoaded() && m_i2DAnimState[p] == AS2D_MISS)
m_bgMiss[p]->Draw();
if(m_bgGood[p].IsLoaded() && m_i2DAnimState[p] == AS2D_GOOD)
m_bgGood[p]->Draw();
if(m_bgGreat[p].IsLoaded() && m_i2DAnimState[p] == AS2D_GREAT)
m_bgGreat[p]->Draw();
if(m_bgFever[p].IsLoaded() && m_i2DAnimState[p] == AS2D_FEVER)
m_bgFever[p]->Draw();
if(m_bgWinFever[p].IsLoaded() && m_i2DAnimState[p] == AS2D_WINFEVER)
m_bgWinFever[p]->Draw();
if(m_bgWin[p].IsLoaded() && m_i2DAnimState[p] == AS2D_WIN)
m_bgWin[p]->Draw();
if(m_bgFail[p].IsLoaded() && m_i2DAnimState[p] == AS2D_FAIL)
m_bgFail[p]->Draw();
}
*/
}
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "DancingCharacters.h"
#include "GameConstantsAndTypes.h"
#include "RageDisplay.h"
#include "RageUtil.h"
#include "RageMath.h"
#include "GameState.h"
#include "Song.h"
#include "Character.h"
#include "StatsManager.h"
#include "PrefsManager.h"
#include "Model.h"
int Neg1OrPos1();
#define DC_X( choice ) THEME->GetMetricF("DancingCharacters",ssprintf("2DCharacterXP%d",choice+1))
#define DC_Y( choice ) THEME->GetMetricF("DancingCharacters",ssprintf("2DCharacterYP%d",choice+1))
/*
* TODO:
* - Metrics/Lua for lighting and camera sweeping.
* - Ability to load secondary elements i.e. stages.
* - Remove support for 2D characters (Lua can do it).
* - Cleanup!
*
* -- Colby
*/
const float CAMERA_REST_DISTANCE = 32.f;
const float CAMERA_REST_LOOK_AT_HEIGHT = -11.f;
const float CAMERA_SWEEP_DISTANCE = 28.f;
const float CAMERA_SWEEP_DISTANCE_VARIANCE = 4.f;
const float CAMERA_SWEEP_HEIGHT_VARIANCE = 7.f;
const float CAMERA_SWEEP_PAN_Y_RANGE_DEGREES = 45.f;
const float CAMERA_SWEEP_PAN_Y_VARIANCE_DEGREES = 60.f;
const float CAMERA_SWEEP_LOOK_AT_HEIGHT = -11.f;
const float CAMERA_STILL_DISTANCE = 26.f;
const float CAMERA_STILL_DISTANCE_VARIANCE = 3.f;
const float CAMERA_STILL_PAN_Y_RANGE_DEGREES = 120.f;
const float CAMERA_STILL_HEIGHT_VARIANCE = 5.f;
const float CAMERA_STILL_LOOK_AT_HEIGHT = -10.f;
const float MODEL_X_ONE_PLAYER = 0;
const float MODEL_X_TWO_PLAYERS[NUM_PLAYERS] = { +8, -8 };
const float MODEL_ROTATIONY_TWO_PLAYERS[NUM_PLAYERS] = { -90, 90 };
DancingCharacters::DancingCharacters(): m_bDrawDangerLight(false),
m_CameraDistance(0), m_CameraPanYStart(0), m_CameraPanYEnd(0),
m_fLookAtHeight(0), m_fCameraHeightStart(0), m_fCameraHeightEnd(0),
m_fThisCameraStartBeat(0), m_fThisCameraEndBeat(0)
{
FOREACH_PlayerNumber( p )
{
m_pCharacter[p] = new Model;
m_2DIdleTimer[p].SetZero();
m_i2DAnimState[p] = AS2D_IDLE; // start on idle state
if( !GAMESTATE->IsPlayerEnabled(p) )
continue;
Character* pChar = GAMESTATE->m_pCurCharacters[p];
if( !pChar )
continue;
// load in any potential 2D stuff
RString sCharacterDirectory = pChar->m_sCharDir;
RString sCurrentAnim;
sCurrentAnim = sCharacterDirectory + "2DIdle";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgIdle[p].Load( sCurrentAnim );
m_bgIdle[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DMiss";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgMiss[p].Load( sCurrentAnim );
m_bgMiss[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DGood";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgGood[p].Load( sCurrentAnim );
m_bgGood[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DGreat";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgGreat[p].Load( sCurrentAnim );
m_bgGreat[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DFever";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgFever[p].Load( sCurrentAnim );
m_bgFever[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DFail";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgFail[p].Load( sCurrentAnim );
m_bgFail[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DWin";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgWin[p].Load( sCurrentAnim );
m_bgWin[p]->SetXY(DC_X(p),DC_Y(p));
}
sCurrentAnim = sCharacterDirectory + "2DWinFever";
if( DoesFileExist(sCurrentAnim + "/BGAnimation.ini") ) // check 2D Idle BGAnim exists
{
m_bgWinFever[p].Load( sCurrentAnim );
m_bgWinFever[p]->SetXY(DC_X(p),DC_Y(p));
}
if( pChar->GetModelPath().empty() )
continue;
if( GAMESTATE->GetNumPlayersEnabled()==2 )
m_pCharacter[p]->SetX( MODEL_X_TWO_PLAYERS[p] );
else
m_pCharacter[p]->SetX( MODEL_X_ONE_PLAYER );
switch( GAMESTATE->m_PlayMode )
{
case PLAY_MODE_BATTLE:
case PLAY_MODE_RAVE:
m_pCharacter[p]->SetRotationY( MODEL_ROTATIONY_TWO_PLAYERS[p] );
default:
break;
}
m_pCharacter[p]->LoadMilkshapeAscii( pChar->GetModelPath() );
m_pCharacter[p]->LoadMilkshapeAsciiBones( "rest", pChar->GetRestAnimationPath() );
m_pCharacter[p]->LoadMilkshapeAsciiBones( "warmup", pChar->GetWarmUpAnimationPath() );
m_pCharacter[p]->LoadMilkshapeAsciiBones( "dance", pChar->GetDanceAnimationPath() );
m_pCharacter[p]->SetCullMode( CULL_NONE ); // many of the models floating around have the vertex order flipped
m_pCharacter[p]->RunCommands( pChar->m_cmdInit );
}
}
DancingCharacters::~DancingCharacters()
{
FOREACH_PlayerNumber( p )
delete m_pCharacter[p];
}
void DancingCharacters::LoadNextSong()
{
// initial camera sweep is still
m_CameraDistance = CAMERA_REST_DISTANCE;
m_CameraPanYStart = 0;
m_CameraPanYEnd = 0;
m_fCameraHeightStart = CAMERA_REST_LOOK_AT_HEIGHT;
m_fCameraHeightEnd = CAMERA_REST_LOOK_AT_HEIGHT;
m_fLookAtHeight = CAMERA_REST_LOOK_AT_HEIGHT;
m_fThisCameraStartBeat = 0;
m_fThisCameraEndBeat = 0;
ASSERT( GAMESTATE->m_pCurSong != nullptr );
m_fThisCameraEndBeat = GAMESTATE->m_pCurSong->GetFirstBeat();
FOREACH_PlayerNumber( p )
if( GAMESTATE->IsPlayerEnabled(p) )
m_pCharacter[p]->PlayAnimation( "rest" );
}
int Neg1OrPos1() { return RandomInt( 2 ) ? -1 : +1; }
void DancingCharacters::Update( float fDelta )
{
if( GAMESTATE->m_Position.m_bFreeze || GAMESTATE->m_Position.m_bDelay )
{
// spin the camera Matrix-style
m_CameraPanYStart += fDelta*40;
m_CameraPanYEnd += fDelta*40;
}
else
{
// make the characters move
float fBPM = GAMESTATE->m_Position.m_fCurBPS*60;
float fUpdateScale = SCALE( fBPM, 60.f, 300.f, 0.75f, 1.5f );
CLAMP( fUpdateScale, 0.75f, 1.5f );
/* It's OK for the animation to go slower than natural when we're
* at a very low music rate. */
fUpdateScale *= GAMESTATE->m_SongOptions.GetCurrent().m_fMusicRate;
FOREACH_PlayerNumber( p )
{
if( GAMESTATE->IsPlayerEnabled(p) )
m_pCharacter[p]->Update( fDelta*fUpdateScale );
}
}
static bool bWasGameplayStarting = false;
bool bGameplayStarting = GAMESTATE->m_bGameplayLeadIn;
if( !bWasGameplayStarting && bGameplayStarting )
{
FOREACH_PlayerNumber( p )
if( GAMESTATE->IsPlayerEnabled(p) )
m_pCharacter[p]->PlayAnimation( "warmup" );
}
bWasGameplayStarting = bGameplayStarting;
static float fLastBeat = GAMESTATE->m_Position.m_fSongBeat;
float firstBeat = GAMESTATE->m_pCurSong->GetFirstBeat();
float fThisBeat = GAMESTATE->m_Position.m_fSongBeat;
if( fLastBeat < firstBeat && fThisBeat >= firstBeat )
{
FOREACH_PlayerNumber( p )
m_pCharacter[p]->PlayAnimation( "dance" );
}
fLastBeat = fThisBeat;
// time for a new sweep?
if( GAMESTATE->m_Position.m_fSongBeat > m_fThisCameraEndBeat )
{
if( RandomInt(6) >= 4 )
{
// sweeping camera
m_CameraDistance = CAMERA_SWEEP_DISTANCE + RandomInt(-1,1) * CAMERA_SWEEP_DISTANCE_VARIANCE;
m_CameraPanYStart = m_CameraPanYEnd = RandomInt(-1,1) * CAMERA_SWEEP_PAN_Y_RANGE_DEGREES;
m_fCameraHeightStart = m_fCameraHeightEnd = CAMERA_STILL_LOOK_AT_HEIGHT;
m_CameraPanYEnd += RandomInt(-1,1) * CAMERA_SWEEP_PAN_Y_VARIANCE_DEGREES;
m_fCameraHeightStart = m_fCameraHeightEnd = m_fCameraHeightStart + RandomInt(-1,1) * CAMERA_SWEEP_HEIGHT_VARIANCE;
float fCameraHeightVariance = RandomInt(-1,1) * CAMERA_SWEEP_HEIGHT_VARIANCE;
m_fCameraHeightStart -= fCameraHeightVariance;
m_fCameraHeightEnd += fCameraHeightVariance;
m_fLookAtHeight = CAMERA_SWEEP_LOOK_AT_HEIGHT;
}
else
{
// still camera
m_CameraDistance = CAMERA_STILL_DISTANCE + RandomInt(-1,1) * CAMERA_STILL_DISTANCE_VARIANCE;
m_CameraPanYStart = m_CameraPanYEnd = Neg1OrPos1() * CAMERA_STILL_PAN_Y_RANGE_DEGREES;
m_fCameraHeightStart = m_fCameraHeightEnd = CAMERA_SWEEP_LOOK_AT_HEIGHT + Neg1OrPos1() * CAMERA_STILL_HEIGHT_VARIANCE;
m_fLookAtHeight = CAMERA_STILL_LOOK_AT_HEIGHT;
}
int iCurBeat = (int)GAMESTATE->m_Position.m_fSongBeat;
iCurBeat -= iCurBeat%8;
m_fThisCameraStartBeat = (float) iCurBeat;
m_fThisCameraEndBeat = float(iCurBeat + 8);
}
/*
// is there any of this still around? This block of code is _ugly_. -Colby
// update any 2D stuff
FOREACH_PlayerNumber( p )
{
if( m_bgIdle[p].IsLoaded() )
{
if( m_bgIdle[p].IsLoaded() && m_i2DAnimState[p] == AS2D_IDLE )
m_bgIdle[p]->Update( fDelta );
if( m_bgMiss[p].IsLoaded() && m_i2DAnimState[p] == AS2D_MISS )
m_bgMiss[p]->Update( fDelta );
if( m_bgGood[p].IsLoaded() && m_i2DAnimState[p] == AS2D_GOOD )
m_bgGood[p]->Update( fDelta );
if( m_bgGreat[p].IsLoaded() && m_i2DAnimState[p] == AS2D_GREAT )
m_bgGreat[p]->Update( fDelta );
if( m_bgFever[p].IsLoaded() && m_i2DAnimState[p] == AS2D_FEVER )
m_bgFever[p]->Update( fDelta );
if( m_bgFail[p].IsLoaded() && m_i2DAnimState[p] == AS2D_FAIL )
m_bgFail[p]->Update( fDelta );
if( m_bgWin[p].IsLoaded() && m_i2DAnimState[p] == AS2D_WIN )
m_bgWin[p]->Update( fDelta );
if( m_bgWinFever[p].IsLoaded() && m_i2DAnimState[p] == AS2D_WINFEVER )
m_bgWinFever[p]->Update(fDelta);
if(m_i2DAnimState[p] != AS2D_IDLE) // if we're not in idle state, start a timer to return us to idle
{
// never return to idle state if we have failed / passed (i.e. completed) the song
if(m_i2DAnimState[p] != AS2D_WINFEVER && m_i2DAnimState[p] != AS2D_FAIL && m_i2DAnimState[p] != AS2D_WIN)
{
if(m_2DIdleTimer[p].IsZero())
m_2DIdleTimer[p].Touch();
if(!m_2DIdleTimer[p].IsZero() && m_2DIdleTimer[p].Ago() > 1.0f)
{
m_2DIdleTimer[p].SetZero();
m_i2DAnimState[p] = AS2D_IDLE;
}
}
}
}
}
*/
}
void DancingCharacters::Change2DAnimState( PlayerNumber pn, int iState )
{
ASSERT( pn < NUM_PLAYERS );
ASSERT( iState < AS2D_MAXSTATES );
m_i2DAnimState[pn] = iState;
}
void DancingCharacters::DrawPrimitives()
{
DISPLAY->CameraPushMatrix();
float fPercentIntoSweep;
if(m_fThisCameraStartBeat == m_fThisCameraEndBeat)
fPercentIntoSweep = 0;
else
fPercentIntoSweep = SCALE(GAMESTATE->m_Position.m_fSongBeat, m_fThisCameraStartBeat, m_fThisCameraEndBeat, 0.f, 1.f );
float fCameraPanY = SCALE( fPercentIntoSweep, 0.f, 1.f, m_CameraPanYStart, m_CameraPanYEnd );
float fCameraHeight = SCALE( fPercentIntoSweep, 0.f, 1.f, m_fCameraHeightStart, m_fCameraHeightEnd );
RageVector3 m_CameraPoint( 0, fCameraHeight, -m_CameraDistance );
RageMatrix CameraRot;
RageMatrixRotationY( &CameraRot, fCameraPanY );
RageVec3TransformCoord( &m_CameraPoint, &m_CameraPoint, &CameraRot );
RageVector3 m_LookAt( 0, m_fLookAtHeight, 0 );
DISPLAY->LoadLookAt( 45,
m_CameraPoint,
m_LookAt,
RageVector3(0,1,0) );
FOREACH_EnabledPlayer( p )
{
bool bFailed = STATSMAN->m_CurStageStats.m_player[p].m_bFailed;
bool bDanger = m_bDrawDangerLight;
DISPLAY->SetLighting( true );
RageColor ambient = bFailed ? RageColor(0.2f,0.1f,0.1f,1) : (bDanger ? RageColor(0.4f,0.1f,0.1f,1) : RageColor(0.4f,0.4f,0.4f,1));
RageColor diffuse = bFailed ? RageColor(0.4f,0.1f,0.1f,1) : (bDanger ? RageColor(0.8f,0.1f,0.1f,1) : RageColor(1,0.95f,0.925f,1));
RageColor specular = RageColor(0.8f,0.8f,0.8f,1);
DISPLAY->SetLightDirectional(
0,
ambient,
diffuse,
specular,
RageVector3(-3, -7.5f, +9) );
if( PREFSMAN->m_bCelShadeModels )
{
m_pCharacter[p]->DrawCelShaded();
DISPLAY->SetLightOff( 0 );
DISPLAY->SetLighting( false );
continue;
}
m_pCharacter[p]->Draw();
DISPLAY->SetLightOff( 0 );
DISPLAY->SetLighting( false );
}
DISPLAY->CameraPopMatrix();
/*
// Ugly! -Colby
// now draw any potential 2D stuff
FOREACH_PlayerNumber( p )
{
if(m_bgIdle[p].IsLoaded() && m_i2DAnimState[p] == AS2D_IDLE)
m_bgIdle[p]->Draw();
if(m_bgMiss[p].IsLoaded() && m_i2DAnimState[p] == AS2D_MISS)
m_bgMiss[p]->Draw();
if(m_bgGood[p].IsLoaded() && m_i2DAnimState[p] == AS2D_GOOD)
m_bgGood[p]->Draw();
if(m_bgGreat[p].IsLoaded() && m_i2DAnimState[p] == AS2D_GREAT)
m_bgGreat[p]->Draw();
if(m_bgFever[p].IsLoaded() && m_i2DAnimState[p] == AS2D_FEVER)
m_bgFever[p]->Draw();
if(m_bgWinFever[p].IsLoaded() && m_i2DAnimState[p] == AS2D_WINFEVER)
m_bgWinFever[p]->Draw();
if(m_bgWin[p].IsLoaded() && m_i2DAnimState[p] == AS2D_WIN)
m_bgWin[p]->Draw();
if(m_bgFail[p].IsLoaded() && m_i2DAnimState[p] == AS2D_FAIL)
m_bgFail[p]->Draw();
}
*/
}
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1 -1
View File
@@ -493,7 +493,7 @@ void EditMenu::OnRowValueChanged( EditMenuRow row )
if( dc != Difficulty_Edit )
{
Steps *pSteps = SongUtil::GetStepsByDifficulty( GetSelectedSong(), GetSelectedSourceStepsType(), dc );
if( pSteps != NULL )
if( pSteps != nullptr )
m_vpSourceSteps.push_back( StepsAndDifficulty(pSteps,dc) );
}
else
+5 -5
View File
@@ -26,7 +26,7 @@ void FontPage::Load( const FontPageSettings &cfg )
ID1.AdditionalTextureHints = cfg.m_sTextureHints;
m_FontPageTextures.m_pTextureMain = TEXTUREMAN->LoadTexture( ID1 );
ASSERT( m_FontPageTextures.m_pTextureMain != NULL );
ASSERT( m_FontPageTextures.m_pTextureMain != nullptr );
RageTextureID ID2 = ID1;
// "arial 20 16x16 [main].png" => "arial 20 16x16 [main-stroke].png"
@@ -36,7 +36,7 @@ void FontPage::Load( const FontPageSettings &cfg )
if( IsAFile(ID2.filename) )
{
m_FontPageTextures.m_pTextureStroke = TEXTUREMAN->LoadTexture( ID2 );
ASSERT( m_FontPageTextures.m_pTextureStroke != NULL );
ASSERT( m_FontPageTextures.m_pTextureStroke != nullptr );
ASSERT_M( m_FontPageTextures.m_pTextureMain->GetSourceFrameWidth() == m_FontPageTextures.m_pTextureStroke->GetSourceFrameWidth(), ssprintf("'%s' and '%s' must have the same frame widths", ID1.filename.c_str(), ID2.filename.c_str()) );
ASSERT_M( m_FontPageTextures.m_pTextureMain->GetNumFrames() == m_FontPageTextures.m_pTextureStroke->GetNumFrames(), ssprintf("'%s' and '%s' must have the same frame dimensions", ID1.filename.c_str(), ID2.filename.c_str()) );
}
@@ -187,12 +187,12 @@ void FontPage::SetExtraPixels( int iDrawExtraPixelsLeft, int iDrawExtraPixelsRig
FontPage::~FontPage()
{
if( m_FontPageTextures.m_pTextureMain != NULL )
if( m_FontPageTextures.m_pTextureMain != nullptr )
{
TEXTUREMAN->UnloadTexture( m_FontPageTextures.m_pTextureMain );
m_FontPageTextures.m_pTextureMain = NULL;
}
if( m_FontPageTextures.m_pTextureStroke != NULL )
if( m_FontPageTextures.m_pTextureStroke != nullptr )
{
TEXTUREMAN->UnloadTexture( m_FontPageTextures.m_pTextureStroke );
m_FontPageTextures.m_pTextureStroke = NULL;
@@ -346,7 +346,7 @@ void Font::CapsOnly()
void Font::SetDefaultGlyph( FontPage *pPage )
{
ASSERT( pPage != NULL );
ASSERT( pPage != nullptr );
ASSERT( !pPage->m_aGlyphs.empty() );
m_pDefault = pPage;
}
+11 -11
View File
@@ -258,7 +258,7 @@ void GameCommand::LoadOne( const Command& cmd )
// This must be processed after "song" and "style" commands.
if( !m_bInvalid )
{
Song *pSong = (m_pSong != NULL)? m_pSong:GAMESTATE->m_pCurSong;
Song *pSong = (m_pSong != nullptr)? m_pSong:GAMESTATE->m_pCurSong;
const Style *pStyle = m_pStyle ? m_pStyle : GAMESTATE->GetCurrentStyle();
if( pSong == NULL || pStyle == NULL )
RageException::Throw( "Must set Song and Style to set Steps." );
@@ -293,7 +293,7 @@ void GameCommand::LoadOne( const Command& cmd )
// This must be processed after "course" and "style" commands.
if( !m_bInvalid )
{
Course *pCourse = (m_pCourse != NULL)? m_pCourse:GAMESTATE->m_pCurCourse;
Course *pCourse = (m_pCourse != nullptr)? m_pCourse:GAMESTATE->m_pCurCourse;
const Style *pStyle = m_pStyle ? m_pStyle : GAMESTATE->GetCurrentStyle();
if( pCourse == NULL || pStyle == NULL )
RageException::Throw( "Must set Course and Style to set Steps." );
@@ -464,10 +464,10 @@ bool GameCommand::IsPlayable( RString *why ) const
/* Don't allow a PlayMode that's incompatible with our current Style (if set),
* and vice versa. */
if( m_pm != PlayMode_Invalid || m_pStyle != NULL )
if( m_pm != PlayMode_Invalid || m_pStyle != nullptr )
{
const PlayMode pm = (m_pm != PlayMode_Invalid) ? m_pm : GAMESTATE->m_PlayMode;
const Style *style = (m_pStyle != NULL)? m_pStyle: GAMESTATE->GetCurrentStyle();
const Style *style = (m_pStyle != nullptr)? m_pStyle: GAMESTATE->GetCurrentStyle();
if( !AreStyleAndPlayModeCompatible( style, pm ) )
{
if( why )
@@ -572,7 +572,7 @@ void GameCommand::ApplySelf( const vector<PlayerNumber> &vpns ) const
if( m_pm != PlayMode_Invalid )
GAMESTATE->m_PlayMode.Set( m_pm );
if( m_pStyle != NULL )
if( m_pStyle != nullptr )
{
GAMESTATE->SetCurrentStyle( m_pStyle );
@@ -718,16 +718,16 @@ void GameCommand::ApplySelf( const vector<PlayerNumber> &vpns ) const
bool GameCommand::IsZero() const
{
if( m_pm != PlayMode_Invalid ||
m_pStyle != NULL ||
m_pStyle != nullptr ||
m_dc != Difficulty_Invalid ||
m_sAnnouncer != "" ||
m_sPreferredModifiers != "" ||
m_sStageModifiers != "" ||
m_pSong != NULL ||
m_pSteps != NULL ||
m_pCourse != NULL ||
m_pTrail != NULL ||
m_pCharacter != NULL ||
m_pSong != nullptr ||
m_pSteps != nullptr ||
m_pCourse != nullptr ||
m_pTrail != nullptr ||
m_pCharacter != nullptr ||
m_CourseDifficulty != Difficulty_Invalid ||
!m_sSongGroup.empty() ||
m_SortOrder != SortOrder_Invalid ||
+1 -1
View File
@@ -281,7 +281,7 @@ void ConcurrentRenderer::Stop()
void ConcurrentRenderer::RenderThread()
{
ASSERT( SCREENMAN != NULL );
ASSERT( SCREENMAN != nullptr );
while( !m_bShutdown )
{
+884 -884
View File
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -275,7 +275,7 @@ void GameState::Reset()
FOREACH_PlayerNumber( pn )
UnjoinPlayer( pn );
ASSERT( THEME != NULL );
ASSERT( THEME != nullptr );
m_timeGameStarted.SetZero();
SetCurrentStyle( NULL );
@@ -335,7 +335,7 @@ void GameState::Reset()
m_pCurCharacters[p] = CHARMAN->GetRandomCharacter();
else
m_pCurCharacters[p] = CHARMAN->GetDefaultCharacter();
ASSERT( m_pCurCharacters[p] != NULL );
ASSERT( m_pCurCharacters[p] != nullptr );
}
m_bTemporaryEventMode = false;
@@ -375,7 +375,7 @@ void GameState::JoinPlayer( PlayerNumber pn )
}
// Set the current style to something appropriate for the new number of joined players.
if( ALLOW_LATE_JOIN && m_pCurStyle != NULL )
if( ALLOW_LATE_JOIN && m_pCurStyle != nullptr )
{
const Style *pStyle;
// Only use one player for StyleType_OnePlayerTwoSides and StepsTypes
@@ -592,7 +592,7 @@ int GameState::GetNumStagesMultiplierForSong( const Song* pSong )
{
int iNumStages = 1;
ASSERT( pSong != NULL );
ASSERT( pSong != nullptr );
if( pSong->IsMarathon() )
iNumStages *= 3;
if( pSong->IsLong() )
@@ -1115,7 +1115,7 @@ int GameState::GetNumSidesJoined() const
const Game* GameState::GetCurrentGame()
{
ASSERT( m_pCurGame != NULL ); // the game must be set before calling this
ASSERT( m_pCurGame != nullptr ); // the game must be set before calling this
return m_pCurGame;
}
@@ -1424,7 +1424,7 @@ void GameState::GetAllUsedNoteSkins( vector<RString> &out ) const
if( IsCourseMode() )
{
const Trail *pTrail = m_pCurTrail[pn];
ASSERT( pTrail != NULL );
ASSERT( pTrail != nullptr );
for (TrailEntry const &e : pTrail->m_vEntries)
{
@@ -1555,11 +1555,11 @@ void GameState::GetRankingFeats( PlayerNumber pn, vector<RankingFeat> &asFeatsOu
SongAndSteps sas;
ASSERT( !STATSMAN->m_vPlayedStageStats[i].m_vpPlayedSongs.empty() );
sas.pSong = STATSMAN->m_vPlayedStageStats[i].m_vpPlayedSongs[0];
ASSERT( sas.pSong != NULL );
ASSERT( sas.pSong != nullptr );
if( STATSMAN->m_vPlayedStageStats[i].m_player[pn].m_vpPossibleSteps.empty() )
continue;
sas.pSteps = STATSMAN->m_vPlayedStageStats[i].m_player[pn].m_vpPossibleSteps[0];
ASSERT( sas.pSteps != NULL );
ASSERT( sas.pSteps != nullptr );
vSongAndSteps.push_back( sas );
}
CHECKPOINT;
@@ -1697,9 +1697,9 @@ void GameState::GetRankingFeats( PlayerNumber pn, vector<RankingFeat> &asFeatsOu
{
CHECKPOINT;
Course* pCourse = m_pCurCourse;
ASSERT( pCourse != NULL );
ASSERT( pCourse != nullptr );
Trail *pTrail = m_pCurTrail[pn];
ASSERT( pTrail != NULL );
ASSERT( pTrail != nullptr );
CourseDifficulty cd = pTrail->m_CourseDifficulty;
// Find Machine Records
+1 -1
View File
@@ -165,7 +165,7 @@ bool IniFile::DeleteKey(const RString &keyname)
bool IniFile::RenameKey(const RString &from, const RString &to)
{
// If to already exists, do nothing.
if( GetChild(to) != NULL )
if( GetChild(to) != nullptr )
return false;
XNode* pNode = GetChild( from );
+1 -1
View File
@@ -347,7 +347,7 @@ bool InputFilter::IsBeingPressed( const DeviceInput &di, const DeviceInputList *
if( pButtonState == NULL )
pButtonState = &g_CurrentState;
const DeviceInput *pDI = FindItemBinarySearch( pButtonState->begin(), pButtonState->end(), di );
return pDI != NULL && pDI->bDown;
return pDI != nullptr && pDI->bDown;
}
float InputFilter::GetSecsHeld( const DeviceInput &di, const DeviceInputList *pButtonState ) const
+1 -1
View File
@@ -1111,7 +1111,7 @@ void InputMappings::WriteMappings( const InputScheme *pInputScheme, RString sFil
ini.DeleteKey( pInputScheme->m_szName );
XNode *pKey = ini.GetChild( pInputScheme->m_szName );
if( pKey != NULL )
if( pKey != nullptr )
ini.RemoveChild( pKey );
pKey = ini.AppendChild( pInputScheme->m_szName );
+1 -1
View File
@@ -38,7 +38,7 @@ bool InputQueue::WasPressedRecently( GameController c, const GameButton button,
if( iep.GameI.button != button )
continue;
if( pIEP != NULL )
if( pIEP != nullptr )
*pIEP = iep;
return true;
+1 -1
View File
@@ -96,7 +96,7 @@ void LifeMeterTime::OnLoadSong()
return;
Course* pCourse = GAMESTATE->m_pCurCourse;
ASSERT( pCourse != NULL );
ASSERT( pCourse != nullptr );
float fOldLife = m_fLifeTotalLostSeconds;
float fGainSeconds = pCourse->m_vEntries[GAMESTATE->GetCourseSongIndex()].fGainSeconds;
+5 -5
View File
@@ -86,12 +86,12 @@ namespace LuaHelpers
{
size_t iLen;
const char *pStr = lua_tolstring( L, iOffset, &iLen );
if( pStr != NULL )
if( pStr != nullptr )
Object.assign( pStr, iLen );
else
Object.clear();
return pStr != NULL;
return pStr != nullptr;
}
}
@@ -174,7 +174,7 @@ static int GetLuaStack( lua_State *L )
if( !strcmp(ar.what, "C") )
{
for( int i = 1; i <= ar.nups && (name = lua_getupvalue(L, -1, i)) != NULL; ++i )
for( int i = 1; i <= ar.nups && (name = lua_getupvalue(L, -1, i)) != nullptr; ++i )
{
vArgs.push_back( ssprintf("%s = %s", name, lua_tostring(L, -1)) );
lua_pop( L, 1 ); // pop value
@@ -182,7 +182,7 @@ static int GetLuaStack( lua_State *L )
}
else
{
for( int i = 1; (name = lua_getlocal(L, &ar, i)) != NULL; ++i )
for( int i = 1; (name = lua_getlocal(L, &ar, i)) != nullptr; ++i )
{
vArgs.push_back( ssprintf("%s = %s", name, lua_tostring(L, -1)) );
lua_pop( L, 1 ); // pop value
@@ -243,7 +243,7 @@ LuaManager::LuaManager()
LUA = this; // so that LUA is available when we call the Register functions
lua_State *L = lua_open();
ASSERT( L != NULL );
ASSERT( L != nullptr );
lua_atpanic( L, LuaPanic );
m_pLuaMain = L;
+236 -236
View File
@@ -1,236 +1,236 @@
#include "global.h"
#include "LuaReference.h"
REGISTER_CLASS_TRAITS( LuaReference, new LuaReference(*pCopy) )
LuaReference::LuaReference()
{
m_iReference = LUA_NOREF;
}
LuaReference::~LuaReference()
{
Unregister();
}
LuaReference::LuaReference( const LuaReference &cpy )
{
if( cpy.m_iReference == LUA_NOREF || cpy.m_iReference == LUA_REFNIL )
{
m_iReference = cpy.m_iReference;
}
else
{
/* Make a new reference. */
Lua *L = LUA->Get();
lua_rawgeti( L, LUA_REGISTRYINDEX, cpy.m_iReference );
m_iReference = luaL_ref( L, LUA_REGISTRYINDEX );
LUA->Release( L );
}
}
LuaReference &LuaReference::operator=( const LuaReference &cpy )
{
if( this == &cpy )
return *this;
Unregister();
if( cpy.m_iReference == LUA_NOREF || cpy.m_iReference == LUA_REFNIL )
{
m_iReference = cpy.m_iReference;
}
else
{
/* Make a new reference. */
Lua *L = LUA->Get();
lua_rawgeti( L, LUA_REGISTRYINDEX, cpy.m_iReference );
m_iReference = luaL_ref( L, LUA_REGISTRYINDEX );
LUA->Release( L );
}
return *this;
}
void LuaReference::SetFromStack( Lua *L )
{
if( m_iReference != LUA_NOREF )
luaL_unref( L, LUA_REGISTRYINDEX, m_iReference );
m_iReference = luaL_ref( L, LUA_REGISTRYINDEX );
}
void LuaReference::SetFromNil()
{
Unregister();
m_iReference = LUA_REFNIL;
}
void LuaReference::DeepCopy()
{
/* Call DeepCopy(t, u), where t is our referenced object and u is the new table. */
Lua *L = LUA->Get();
/* Arg 1 (t): */
this->PushSelf( L );
/* Arg 2 (u): */
lua_newtable( L );
lua_pushvalue( L, -1 );
this->SetFromStack( L );
LuaHelpers::DeepCopy( L );
LUA->Release( L );
}
void LuaReference::PushSelf( lua_State *L ) const
{
lua_rawgeti( L, LUA_REGISTRYINDEX, m_iReference );
}
bool LuaReference::IsSet() const
{
return m_iReference != LUA_NOREF;
}
bool LuaReference::IsNil() const
{
return m_iReference == LUA_REFNIL;
}
int LuaReference::GetLuaType() const
{
Lua *L = LUA->Get();
this->PushSelf( L );
int iRet = lua_type( L, -1 );
lua_pop( L, 1 );
LUA->Release( L );
return iRet;
}
void LuaReference::Unregister()
{
if( LUA == NULL || m_iReference == LUA_NOREF )
return; // nothing to do
Lua *L = LUA->Get();
luaL_unref( L, LUA_REGISTRYINDEX, m_iReference );
LUA->Release( L );
m_iReference = LUA_NOREF;
}
bool LuaReference::SetFromExpression( const RString &sExpression )
{
Lua *L = LUA->Get();
bool bSuccess = LuaHelpers::RunExpression( L, sExpression );
this->SetFromStack( L );
LUA->Release( L );
return bSuccess;
}
RString LuaReference::Serialize() const
{
/* Call Serialize(t), where t is our referenced object. */
Lua *L = LUA->Get();
lua_getglobal( L, "Serialize" );
ASSERT_M( !lua_isnil(L, -1), "Serialize() missing" );
ASSERT_M( lua_isfunction(L, -1), "Serialize() not a function" );
/* Arg 1 (t): */
this->PushSelf( L );
lua_call( L, 1, 1 );
/* The return value is a string, which we store in m_sSerializedData. */
const char *pString = lua_tostring( L, -1 );
ASSERT_M( pString != NULL, "Serialize() didn't return a string" );
RString sRet = pString;
lua_pop( L, 1 );
LUA->Release( L );
return sRet;
}
/** @brief Utilities for working with Lua. */
namespace LuaHelpers
{
template<> bool FromStack<LuaReference>( lua_State *L, LuaReference &Object, int iOffset )
{
lua_pushvalue( L, iOffset );
Object.SetFromStack( L );
return true;
}
template<> bool FromStack<apActorCommands>( lua_State *L, apActorCommands &Object, int iOffset )
{
LuaReference *pRef = new LuaReference;
FromStack( L, *pRef, iOffset );
Object = apActorCommands( pRef );
return true;
}
}
LuaTable::LuaTable()
{
Lua *L = LUA->Get();
lua_newtable( L );
this->SetFromStack(L);
LUA->Release( L );
}
void LuaTable::Set( Lua *L, const RString &sKey )
{
int iTop = lua_gettop( L );
this->PushSelf( L );
lua_pushvalue( L, iTop ); // push the value
lua_setfield( L, -2, sKey );
lua_settop( L, iTop-1 ); // remove all of the above
}
void LuaTable::Get( Lua *L, const RString &sKey )
{
this->PushSelf( L );
lua_getfield( L, -1, sKey );
lua_remove( L, -2 ); // remove self
}
/** @brief Utilities for working with Lua. */
namespace LuaHelpers
{
template<> void Push<LuaReference>( lua_State *L, const LuaReference &Object )
{
Object.PushSelf( L );
}
}
/*
* (c) 2005 Glenn Maynard, Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "LuaReference.h"
REGISTER_CLASS_TRAITS( LuaReference, new LuaReference(*pCopy) )
LuaReference::LuaReference()
{
m_iReference = LUA_NOREF;
}
LuaReference::~LuaReference()
{
Unregister();
}
LuaReference::LuaReference( const LuaReference &cpy )
{
if( cpy.m_iReference == LUA_NOREF || cpy.m_iReference == LUA_REFNIL )
{
m_iReference = cpy.m_iReference;
}
else
{
/* Make a new reference. */
Lua *L = LUA->Get();
lua_rawgeti( L, LUA_REGISTRYINDEX, cpy.m_iReference );
m_iReference = luaL_ref( L, LUA_REGISTRYINDEX );
LUA->Release( L );
}
}
LuaReference &LuaReference::operator=( const LuaReference &cpy )
{
if( this == &cpy )
return *this;
Unregister();
if( cpy.m_iReference == LUA_NOREF || cpy.m_iReference == LUA_REFNIL )
{
m_iReference = cpy.m_iReference;
}
else
{
/* Make a new reference. */
Lua *L = LUA->Get();
lua_rawgeti( L, LUA_REGISTRYINDEX, cpy.m_iReference );
m_iReference = luaL_ref( L, LUA_REGISTRYINDEX );
LUA->Release( L );
}
return *this;
}
void LuaReference::SetFromStack( Lua *L )
{
if( m_iReference != LUA_NOREF )
luaL_unref( L, LUA_REGISTRYINDEX, m_iReference );
m_iReference = luaL_ref( L, LUA_REGISTRYINDEX );
}
void LuaReference::SetFromNil()
{
Unregister();
m_iReference = LUA_REFNIL;
}
void LuaReference::DeepCopy()
{
/* Call DeepCopy(t, u), where t is our referenced object and u is the new table. */
Lua *L = LUA->Get();
/* Arg 1 (t): */
this->PushSelf( L );
/* Arg 2 (u): */
lua_newtable( L );
lua_pushvalue( L, -1 );
this->SetFromStack( L );
LuaHelpers::DeepCopy( L );
LUA->Release( L );
}
void LuaReference::PushSelf( lua_State *L ) const
{
lua_rawgeti( L, LUA_REGISTRYINDEX, m_iReference );
}
bool LuaReference::IsSet() const
{
return m_iReference != LUA_NOREF;
}
bool LuaReference::IsNil() const
{
return m_iReference == LUA_REFNIL;
}
int LuaReference::GetLuaType() const
{
Lua *L = LUA->Get();
this->PushSelf( L );
int iRet = lua_type( L, -1 );
lua_pop( L, 1 );
LUA->Release( L );
return iRet;
}
void LuaReference::Unregister()
{
if( LUA == NULL || m_iReference == LUA_NOREF )
return; // nothing to do
Lua *L = LUA->Get();
luaL_unref( L, LUA_REGISTRYINDEX, m_iReference );
LUA->Release( L );
m_iReference = LUA_NOREF;
}
bool LuaReference::SetFromExpression( const RString &sExpression )
{
Lua *L = LUA->Get();
bool bSuccess = LuaHelpers::RunExpression( L, sExpression );
this->SetFromStack( L );
LUA->Release( L );
return bSuccess;
}
RString LuaReference::Serialize() const
{
/* Call Serialize(t), where t is our referenced object. */
Lua *L = LUA->Get();
lua_getglobal( L, "Serialize" );
ASSERT_M( !lua_isnil(L, -1), "Serialize() missing" );
ASSERT_M( lua_isfunction(L, -1), "Serialize() not a function" );
/* Arg 1 (t): */
this->PushSelf( L );
lua_call( L, 1, 1 );
/* The return value is a string, which we store in m_sSerializedData. */
const char *pString = lua_tostring( L, -1 );
ASSERT_M( pString != nullptr, "Serialize() didn't return a string" );
RString sRet = pString;
lua_pop( L, 1 );
LUA->Release( L );
return sRet;
}
/** @brief Utilities for working with Lua. */
namespace LuaHelpers
{
template<> bool FromStack<LuaReference>( lua_State *L, LuaReference &Object, int iOffset )
{
lua_pushvalue( L, iOffset );
Object.SetFromStack( L );
return true;
}
template<> bool FromStack<apActorCommands>( lua_State *L, apActorCommands &Object, int iOffset )
{
LuaReference *pRef = new LuaReference;
FromStack( L, *pRef, iOffset );
Object = apActorCommands( pRef );
return true;
}
}
LuaTable::LuaTable()
{
Lua *L = LUA->Get();
lua_newtable( L );
this->SetFromStack(L);
LUA->Release( L );
}
void LuaTable::Set( Lua *L, const RString &sKey )
{
int iTop = lua_gettop( L );
this->PushSelf( L );
lua_pushvalue( L, iTop ); // push the value
lua_setfield( L, -2, sKey );
lua_settop( L, iTop-1 ); // remove all of the above
}
void LuaTable::Get( Lua *L, const RString &sKey )
{
this->PushSelf( L );
lua_getfield( L, -1, sKey );
lua_remove( L, -2 ); // remove self
}
/** @brief Utilities for working with Lua. */
namespace LuaHelpers
{
template<> void Push<LuaReference>( lua_State *L, const LuaReference &Object )
{
Object.PushSelf( L );
}
}
/*
* (c) 2005 Glenn Maynard, Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1 -1
View File
@@ -298,7 +298,7 @@ MemoryCardManager::~MemoryCardManager()
// Unregister with Lua.
LUA->UnsetGlobal( "MEMCARDMAN" );
ASSERT( g_pWorker != NULL );
ASSERT( g_pWorker != nullptr );
SAFE_DELETE(g_pWorker);
FOREACH_PlayerNumber( pn )
+127 -127
View File
@@ -1,127 +1,127 @@
#include "global.h"
#include "MeterDisplay.h"
#include "RageUtil.h"
#include "GameState.h"
#include "Song.h"
#include "ActorUtil.h"
#include "XmlFile.h"
#include "RageLog.h"
#include "LuaManager.h"
REGISTER_ACTOR_CLASS(MeterDisplay);
REGISTER_ACTOR_CLASS(SongMeterDisplay);
MeterDisplay::MeterDisplay()
{
}
void MeterDisplay::Load( RString sStreamPath, float fStreamWidth, RString sTipPath )
{
m_sprStream.Load( sStreamPath );
this->AddChild( m_sprStream );
m_sprTip.Load( sTipPath );
this->AddChild( m_sprTip );
SetStreamWidth( fStreamWidth );
SetPercent( 0.5f );
}
void MeterDisplay::LoadFromNode( const XNode* pNode )
{
LOG->Trace( "MeterDisplay::LoadFromNode(%s)", ActorUtil::GetWhere(pNode).c_str() );
const XNode *pStream = pNode->GetChild( "Stream" );
if( pStream == NULL )
RageException::Throw( "%s: MeterDisplay: missing the \"Stream\" attribute", ActorUtil::GetWhere(pNode).c_str() );
m_sprStream.LoadActorFromNode( pStream, this );
this->AddChild( m_sprStream );
const XNode* pChild = pNode->GetChild( "Tip" );
if( pChild != NULL )
{
m_sprTip.LoadActorFromNode( pChild, this );
this->AddChild( m_sprTip );
}
float fStreamWidth = 0;
pNode->GetAttrValue( "StreamWidth", fStreamWidth );
SetStreamWidth( fStreamWidth );
SetPercent( 0.5f );
ActorFrame::LoadFromNode( pNode );
}
void MeterDisplay::SetPercent( float fPercent )
{
ASSERT( fPercent >= 0 && fPercent <= 1 );
m_sprStream->SetCropRight( 1-fPercent );
if( m_sprTip.IsLoaded() )
m_sprTip->SetX( SCALE(fPercent, 0.f, 1.f, -m_fStreamWidth/2, m_fStreamWidth/2) );
}
void MeterDisplay::SetStreamWidth( float fStreamWidth )
{
m_fStreamWidth = fStreamWidth;
m_sprStream->SetZoomX( m_fStreamWidth / m_sprStream->GetUnzoomedWidth() );
}
void SongMeterDisplay::Update( float fDeltaTime )
{
if( GAMESTATE->m_pCurSong )
{
float fSongStartSeconds = GAMESTATE->m_pCurSong->GetFirstSecond();
float fSongEndSeconds = GAMESTATE->m_pCurSong->GetLastSecond();
float fPercentPositionSong = SCALE( GAMESTATE->m_Position.m_fMusicSeconds, fSongStartSeconds, fSongEndSeconds, 0.0f, 1.0f );
CLAMP( fPercentPositionSong, 0, 1 );
SetPercent( fPercentPositionSong );
}
MeterDisplay::Update( fDeltaTime );
}
// lua start
#include "LuaBinding.h"
class LunaMeterDisplay: public Luna<MeterDisplay>
{
public:
static int SetStreamWidth( T* p, lua_State *L ) { p->SetStreamWidth(FArg(1)); return 0; }
LunaMeterDisplay()
{
ADD_METHOD( SetStreamWidth );
}
};
LUA_REGISTER_DERIVED_CLASS( MeterDisplay, ActorFrame )
// lua end
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "MeterDisplay.h"
#include "RageUtil.h"
#include "GameState.h"
#include "Song.h"
#include "ActorUtil.h"
#include "XmlFile.h"
#include "RageLog.h"
#include "LuaManager.h"
REGISTER_ACTOR_CLASS(MeterDisplay);
REGISTER_ACTOR_CLASS(SongMeterDisplay);
MeterDisplay::MeterDisplay()
{
}
void MeterDisplay::Load( RString sStreamPath, float fStreamWidth, RString sTipPath )
{
m_sprStream.Load( sStreamPath );
this->AddChild( m_sprStream );
m_sprTip.Load( sTipPath );
this->AddChild( m_sprTip );
SetStreamWidth( fStreamWidth );
SetPercent( 0.5f );
}
void MeterDisplay::LoadFromNode( const XNode* pNode )
{
LOG->Trace( "MeterDisplay::LoadFromNode(%s)", ActorUtil::GetWhere(pNode).c_str() );
const XNode *pStream = pNode->GetChild( "Stream" );
if( pStream == NULL )
RageException::Throw( "%s: MeterDisplay: missing the \"Stream\" attribute", ActorUtil::GetWhere(pNode).c_str() );
m_sprStream.LoadActorFromNode( pStream, this );
this->AddChild( m_sprStream );
const XNode* pChild = pNode->GetChild( "Tip" );
if( pChild != nullptr )
{
m_sprTip.LoadActorFromNode( pChild, this );
this->AddChild( m_sprTip );
}
float fStreamWidth = 0;
pNode->GetAttrValue( "StreamWidth", fStreamWidth );
SetStreamWidth( fStreamWidth );
SetPercent( 0.5f );
ActorFrame::LoadFromNode( pNode );
}
void MeterDisplay::SetPercent( float fPercent )
{
ASSERT( fPercent >= 0 && fPercent <= 1 );
m_sprStream->SetCropRight( 1-fPercent );
if( m_sprTip.IsLoaded() )
m_sprTip->SetX( SCALE(fPercent, 0.f, 1.f, -m_fStreamWidth/2, m_fStreamWidth/2) );
}
void MeterDisplay::SetStreamWidth( float fStreamWidth )
{
m_fStreamWidth = fStreamWidth;
m_sprStream->SetZoomX( m_fStreamWidth / m_sprStream->GetUnzoomedWidth() );
}
void SongMeterDisplay::Update( float fDeltaTime )
{
if( GAMESTATE->m_pCurSong )
{
float fSongStartSeconds = GAMESTATE->m_pCurSong->GetFirstSecond();
float fSongEndSeconds = GAMESTATE->m_pCurSong->GetLastSecond();
float fPercentPositionSong = SCALE( GAMESTATE->m_Position.m_fMusicSeconds, fSongStartSeconds, fSongEndSeconds, 0.0f, 1.0f );
CLAMP( fPercentPositionSong, 0, 1 );
SetPercent( fPercentPositionSong );
}
MeterDisplay::Update( fDeltaTime );
}
// lua start
#include "LuaBinding.h"
class LunaMeterDisplay: public Luna<MeterDisplay>
{
public:
static int SetStreamWidth( T* p, lua_State *L ) { p->SetStreamWidth(FArg(1)); return 0; }
LunaMeterDisplay()
{
ADD_METHOD( SetStreamWidth );
}
};
LUA_REGISTER_DERIVED_CLASS( MeterDisplay, ActorFrame )
// lua end
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+2 -2
View File
@@ -620,7 +620,7 @@ void Model::SetBones( const msAnimation* pAnimation, float fFrame, vector<myBone
}
RageVector3 vPos;
if( pLastPositionKey != NULL && pThisPositionKey != NULL )
if( pLastPositionKey != nullptr && pThisPositionKey != nullptr )
{
const float s = SCALE( fFrame, pLastPositionKey->fTime, pThisPositionKey->fTime, 0, 1 );
vPos = pLastPositionKey->Position + (pThisPositionKey->Position - pLastPositionKey->Position) * s;
@@ -644,7 +644,7 @@ void Model::SetBones( const msAnimation* pAnimation, float fFrame, vector<myBone
}
RageVector4 vRot;
if( pLastRotationKey != NULL && pThisRotationKey != NULL )
if( pLastRotationKey != nullptr && pThisRotationKey != nullptr )
{
const float s = SCALE( fFrame, pLastRotationKey->fTime, pThisRotationKey->fTime, 0, 1 );
RageQuatSlerp( &vRot, pLastRotationKey->Rotation, pThisRotationKey->Rotation, s );
+6 -6
View File
@@ -151,7 +151,7 @@ void MusicWheel::BeginScreen()
const vector<MusicWheelItemData *> &from = getWheelItemsData(SORT_MODE_MENU);
for( unsigned i=0; i<from.size(); i++ )
{
ASSERT( &*from[i]->m_pAction != NULL );
ASSERT( &*from[i]->m_pAction != nullptr );
if( from[i]->m_pAction->DescribesCurrentModeForAllPlayers() )
{
m_sLastModeMenuItem = from[i]->m_pAction->m_sName;
@@ -184,7 +184,7 @@ void MusicWheel::BeginScreen()
/* Invalidate current Song if it can't be played
* because there are not enough stages remaining. */
if( GAMESTATE->m_pCurSong != NULL &&
if( GAMESTATE->m_pCurSong != nullptr &&
GameState::GetNumStagesMultiplierForSong( GAMESTATE->m_pCurSong ) > GAMESTATE->GetSmallestNumStagesLeftForAnyHumanPlayer() )
{
GAMESTATE->m_pCurSong.Set( NULL );
@@ -194,10 +194,10 @@ void MusicWheel::BeginScreen()
* because there are not enough stages remaining. */
FOREACH_ENUM( PlayerNumber, p )
{
if( GAMESTATE->m_pCurSteps[p] != NULL )
if( GAMESTATE->m_pCurSteps[p] != nullptr )
{
vector<Steps*> vpPossibleSteps;
if( GAMESTATE->m_pCurSong != NULL )
if( GAMESTATE->m_pCurSong != nullptr )
SongUtil::GetPlayableSteps( GAMESTATE->m_pCurSong, vpPossibleSteps );
bool bStepsIsPossible = find( vpPossibleSteps.begin(), vpPossibleSteps.end(), GAMESTATE->m_pCurSteps[p] ) == vpPossibleSteps.end();
if( !bStepsIsPossible )
@@ -849,7 +849,7 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
// init music status icons
for (MusicWheelItemData *WID : arrayWheelItemDatas)
{
if( WID->m_pSong != NULL )
if( WID->m_pSong != nullptr )
{
WID->m_Flags.bHasBeginnerOr1Meter = WID->m_pSong->IsEasy( GAMESTATE->GetCurrentStyle()->m_StepsType ) && SHOW_EASY_FLAG;
WID->m_Flags.bEdits = false;
@@ -859,7 +859,7 @@ void MusicWheel::BuildWheelItemDatas( vector<MusicWheelItemData *> &arrayWheelIt
WID->m_Flags.bEdits |= WID->m_pSong->HasEdits( type );
WID->m_Flags.iStagesForSong = GameState::GetNumStagesMultiplierForSong( WID->m_pSong );
}
else if( WID->m_pCourse != NULL )
else if( WID->m_pCourse != nullptr )
{
WID->m_Flags.bHasBeginnerOr1Meter = false;
WID->m_Flags.bEdits = WID->m_pCourse->IsAnEdit();
+414 -414
View File
@@ -1,414 +1,414 @@
#include "global.h"
#include "MusicWheelItem.h"
#include "RageUtil.h"
#include "SongManager.h"
#include "GameManager.h"
#include "RageLog.h"
#include "GameConstantsAndTypes.h"
#include "GameState.h"
#include "ThemeManager.h"
#include "Steps.h"
#include "Song.h"
#include "Course.h"
#include "ProfileManager.h"
#include "Profile.h"
#include "Style.h"
#include "ActorUtil.h"
#include "ThemeMetric.h"
#include "HighScore.h"
#include "ScreenSelectMusic.h"
#include "ScreenManager.h"
static const char *MusicWheelItemTypeNames[] = {
"Song",
"SectionExpanded",
"SectionCollapsed",
"Roulette",
"Course",
"Sort",
"Mode",
"Random",
"Portal",
"Custom",
};
XToString( MusicWheelItemType );
MusicWheelItemData::MusicWheelItemData( WheelItemDataType type, Song* pSong,
RString sSectionName, Course* pCourse,
RageColor color, int iSectionCount ):
WheelItemBaseData(type, sSectionName, color),
m_pCourse(pCourse), m_pSong(pSong), m_Flags(WheelNotifyIcon::Flags()),
m_iSectionCount(iSectionCount), m_sLabel(""), m_pAction() {}
MusicWheelItem::MusicWheelItem( RString sType ):
WheelItemBase( sType )
{
GRADES_SHOW_MACHINE.Load( sType, "GradesShowMachine" );
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprColorPart[i].Load( THEME->GetPathG(sType,MusicWheelItemTypeToString(i)+" ColorPart") );
m_sprColorPart[i]->SetName( MusicWheelItemTypeToString(i)+"ColorPart" );
ActorUtil::LoadAllCommands(m_sprColorPart[i],"MusicWheelItem");
this->AddChild( m_sprColorPart[i] );
m_sprNormalPart[i].Load( THEME->GetPathG(sType,MusicWheelItemTypeToString(i)+" NormalPart") );
m_sprNormalPart[i]->SetName( MusicWheelItemTypeToString(i)+"NormalPart" );
ActorUtil::LoadAllCommands(m_sprNormalPart[i],"MusicWheelItem");
this->AddChild( m_sprNormalPart[i] );
}
m_TextBanner.SetName( "SongName" );
ActorUtil::LoadAllCommands( m_TextBanner, "MusicWheelItem" );
m_TextBanner.Load( "TextBanner" );
ActorUtil::SetXY( m_TextBanner, "MusicWheelItem" );
m_TextBanner.PlayCommand( "On" );
this->AddChild( &m_TextBanner );
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprOverPart[i].Load( THEME->GetPathG(sType,MusicWheelItemTypeToString(i)+" OverPart") );
m_sprOverPart[i]->SetName( MusicWheelItemTypeToString(i)+"OverPart" );
ActorUtil::LoadAllCommands(m_sprOverPart[i],"MusicWheelItem");
this->AddChild( m_sprOverPart[i] );
}
FOREACH_ENUM( MusicWheelItemType, i )
{
m_pText[i] = NULL;
// Don't init text for Type_Song. It uses a TextBanner.
if( i == MusicWheelItemType_Song )
continue;
m_pText[i] = new BitmapText;
m_pText[i]->SetName( MusicWheelItemTypeToString(i) );
ActorUtil::LoadAllCommands( m_pText[i], "MusicWheelItem" );
m_pText[i]->LoadFromFont( THEME->GetPathF(sType,MusicWheelItemTypeToString(i)) );
ActorUtil::SetXY( m_pText[i], "MusicWheelItem" );
m_pText[i]->PlayCommand( "On" );
this->AddChild( m_pText[i] );
}
m_pTextSectionCount = new BitmapText;
m_pTextSectionCount->SetName( "SectionCount" );
ActorUtil::LoadAllCommands( m_pTextSectionCount, "MusicWheelItem" );
m_pTextSectionCount->LoadFromFont( THEME->GetPathF(sType,"SectionCount") );
ActorUtil::SetXY( m_pTextSectionCount, "MusicWheelItem" );
m_pTextSectionCount->PlayCommand( "On" );
this->AddChild( m_pTextSectionCount );
m_WheelNotifyIcon.SetName( "WheelNotifyIcon" );
ActorUtil::LoadAllCommands( m_WheelNotifyIcon, "MusicWheelItem" );
ActorUtil::SetXY( m_WheelNotifyIcon, "MusicWheelItem" );
m_WheelNotifyIcon.PlayCommand( "On" );
this->AddChild( &m_WheelNotifyIcon );
FOREACH_PlayerNumber( p )
{
m_pGradeDisplay[p].Load( THEME->GetPathG(sType,"grades") );
m_pGradeDisplay[p]->SetName( ssprintf("GradeP%d",int(p+1)) );
this->AddChild( m_pGradeDisplay[p] );
LOAD_ALL_COMMANDS_AND_SET_XY( m_pGradeDisplay[p] );
}
this->SubscribeToMessage( Message_CurrentStepsP1Changed );
this->SubscribeToMessage( Message_CurrentStepsP2Changed );
this->SubscribeToMessage( Message_CurrentTrailP1Changed );
this->SubscribeToMessage( Message_CurrentTrailP2Changed );
this->SubscribeToMessage( Message_PreferredDifficultyP1Changed );
this->SubscribeToMessage( Message_PreferredDifficultyP2Changed );
}
MusicWheelItem::MusicWheelItem( const MusicWheelItem &cpy ):
WheelItemBase( cpy ),
GRADES_SHOW_MACHINE( cpy.GRADES_SHOW_MACHINE ),
m_TextBanner( cpy.m_TextBanner ),
m_WheelNotifyIcon( cpy.m_WheelNotifyIcon )
{
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprColorPart[i] = cpy.m_sprColorPart[i];
this->AddChild( m_sprColorPart[i] );
m_sprNormalPart[i] = cpy.m_sprNormalPart[i];
this->AddChild( m_sprNormalPart[i] );
}
this->AddChild( &m_TextBanner );
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprOverPart[i] = cpy.m_sprOverPart[i];
this->AddChild( m_sprOverPart[i] );
}
FOREACH_ENUM( MusicWheelItemType, i )
{
if( cpy.m_pText[i] == NULL )
{
m_pText[i] = NULL;
}
else
{
m_pText[i] = new BitmapText( *cpy.m_pText[i] );
this->AddChild( m_pText[i] );
}
}
m_pTextSectionCount = new BitmapText( *cpy.m_pTextSectionCount );
this->AddChild( m_pTextSectionCount );
this->AddChild( &m_WheelNotifyIcon );
FOREACH_PlayerNumber( p )
{
m_pGradeDisplay[p] = cpy.m_pGradeDisplay[p];
this->AddChild( m_pGradeDisplay[p] );
}
}
MusicWheelItem::~MusicWheelItem()
{
FOREACH_ENUM( MusicWheelItemType, i )
{
SAFE_DELETE(m_pText[i]);
}
delete m_pTextSectionCount;
}
void MusicWheelItem::LoadFromWheelItemData( const WheelItemBaseData *pData, int iIndex, bool bHasFocus, int iDrawIndex )
{
WheelItemBase::LoadFromWheelItemData( pData, iIndex, bHasFocus, iDrawIndex );
const MusicWheelItemData *pWID = dynamic_cast<const MusicWheelItemData*>( pData );
// hide all
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprColorPart[i]->SetVisible( false );
m_sprNormalPart[i]->SetVisible( false );
m_sprOverPart[i]->SetVisible( false );
}
m_TextBanner.SetVisible( false );
FOREACH_ENUM( MusicWheelItemType, i )
if( m_pText[i] )
m_pText[i]->SetVisible( false );
m_pTextSectionCount->SetVisible( false );
m_WheelNotifyIcon.SetVisible( false );
FOREACH_PlayerNumber( p )
m_pGradeDisplay[p]->SetVisible( false );
// Fill these in below
RString sDisplayName, sTranslitName;
MusicWheelItemType type = MusicWheelItemType_Invalid;
switch( pWID->m_Type )
{
DEFAULT_FAIL( pWID->m_Type );
case WheelItemDataType_Song:
type = MusicWheelItemType_Song;
m_TextBanner.SetFromSong( pWID->m_pSong );
// We can do this manually if we wanted... maybe have a metric for overrides? -aj
m_TextBanner.SetDiffuse( pWID->m_color );
m_TextBanner.SetVisible( true );
m_WheelNotifyIcon.SetFlags( pWID->m_Flags );
m_WheelNotifyIcon.SetVisible( true );
RefreshGrades();
break;
case WheelItemDataType_Section:
{
sDisplayName = SONGMAN->ShortenGroupName(pWID->m_sText);
if( GAMESTATE->sExpandedSectionName == pWID->m_sText )
type = MusicWheelItemType_SectionExpanded;
else
type = MusicWheelItemType_SectionCollapsed;
m_pTextSectionCount->SetText( ssprintf("%d",pWID->m_iSectionCount) );
m_pTextSectionCount->SetVisible( true );
}
break;
case WheelItemDataType_Course:
sDisplayName = pWID->m_pCourse->GetDisplayFullTitle();
sTranslitName = pWID->m_pCourse->GetTranslitFullTitle();
type = MusicWheelItemType_Course;
m_WheelNotifyIcon.SetFlags( pWID->m_Flags );
m_WheelNotifyIcon.SetVisible( true );
break;
case WheelItemDataType_Sort:
sDisplayName = pWID->m_sLabel;
// hack to get mode items working. -freem
if( pWID->m_pAction->m_pm != PlayMode_Invalid )
type = MusicWheelItemType_Mode;
else
type = MusicWheelItemType_Sort;
break;
case WheelItemDataType_Roulette:
sDisplayName = THEME->GetString("MusicWheel","Roulette");
type = MusicWheelItemType_Roulette;
break;
case WheelItemDataType_Random:
sDisplayName = THEME->GetString("MusicWheel","Random");
type = MusicWheelItemType_Random;
break;
case WheelItemDataType_Portal:
sDisplayName = THEME->GetString("MusicWheel","Portal");
type = MusicWheelItemType_Portal;
break;
case WheelItemDataType_Custom:
sDisplayName = pWID->m_sLabel;
type = MusicWheelItemType_Custom;
break;
}
m_sprColorPart[type]->SetVisible( true );
m_sprColorPart[type]->SetDiffuse( pWID->m_color );
m_sprNormalPart[type]->SetVisible( true );
m_sprOverPart[type]->SetVisible( true );
BitmapText *bt = m_pText[type];
if( bt )
{
bt->SetText( sDisplayName, sTranslitName );
bt->SetDiffuse( pWID->m_color );
bt->SetVisible( true );
}
FOREACH_ENUM( MusicWheelItemType, i )
{
if( m_sprColorPart[i]->GetVisible() )
{
SetGrayBar( m_sprColorPart[i] );
break;
}
}
// Call "Set" so that elements like TextBanner react to the change in song.
{
Message msg( "Set" );
msg.SetParam( "Song", pWID->m_pSong );
msg.SetParam( "Course", pWID->m_pCourse );
msg.SetParam( "Index", iIndex );
msg.SetParam( "HasFocus", bHasFocus );
msg.SetParam( "Text", pWID->m_sText );
msg.SetParam( "DrawIndex", iDrawIndex );
msg.SetParam( "Type", MusicWheelItemTypeToString(type) );
msg.SetParam( "Color", pWID->m_color );
msg.SetParam( "Label", pWID->m_sLabel );
this->HandleMessage( msg );
}
}
void MusicWheelItem::RefreshGrades()
{
const MusicWheelItemData *pWID = dynamic_cast<const MusicWheelItemData*>( m_pData );
if( pWID == NULL )
return; // LoadFromWheelItemData() hasn't been called yet.
FOREACH_HumanPlayer( p )
{
m_pGradeDisplay[p]->SetVisible( false );
if( pWID->m_pSong == NULL && pWID->m_pCourse == NULL )
continue;
Difficulty dc;
if( GAMESTATE->m_pCurSteps[p] )
dc = GAMESTATE->m_pCurSteps[p]->GetDifficulty();
else if( GAMESTATE->m_pCurTrail[p] )
dc = GAMESTATE->m_pCurTrail[p]->m_CourseDifficulty;
else
dc = GAMESTATE->m_PreferredDifficulty[p];
ProfileSlot ps;
if( PROFILEMAN->IsPersistentProfile(p) )
ps = (ProfileSlot)p;
else if( GRADES_SHOW_MACHINE )
ps = ProfileSlot_Machine;
else
continue;
StepsType st;
if( GAMESTATE->m_pCurSteps[p] )
st = GAMESTATE->m_pCurSteps[p]->m_StepsType;
else if( GAMESTATE->m_pCurTrail[p] )
st = GAMESTATE->m_pCurTrail[p]->m_StepsType;
else
st = GAMESTATE->m_pCurStyle->m_StepsType;
m_pGradeDisplay[p]->SetVisible( true );
Profile *pProfile = PROFILEMAN->GetProfile(ps);
HighScoreList *pHSL = NULL;
if( PROFILEMAN->IsPersistentProfile(ps) && dc != Difficulty_Invalid )
{
if( pWID->m_pSong )
{
const Steps* pSteps = SongUtil::GetStepsByDifficulty( pWID->m_pSong, st, dc );
if( pSteps != NULL )
pHSL = &pProfile->GetStepsHighScoreList(pWID->m_pSong, pSteps);
}
else if( pWID->m_pCourse )
{
const Trail *pTrail = pWID->m_pCourse->GetTrail( st, dc );
if( pTrail != NULL )
pHSL = &pProfile->GetCourseHighScoreList( pWID->m_pCourse, pTrail );
}
}
Message msg( "SetGrade" );
msg.SetParam( "PlayerNumber", p );
if( pHSL )
{
msg.SetParam( "Grade", pHSL->HighGrade );
msg.SetParam( "NumTimesPlayed", pHSL->GetNumTimesPlayed() );
}
m_pGradeDisplay[p]->HandleMessage( msg );
}
}
void MusicWheelItem::HandleMessage( const Message &msg )
{
if( msg == Message_CurrentStepsP1Changed ||
msg == Message_CurrentStepsP2Changed ||
msg == Message_CurrentTrailP1Changed ||
msg == Message_CurrentTrailP2Changed ||
msg == Message_PreferredDifficultyP1Changed ||
msg == Message_PreferredDifficultyP2Changed )
{
RefreshGrades();
}
WheelItemBase::HandleMessage( msg );
}
/*
* (c) 2001-2004 Chris Danford, Chris Gomez, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "MusicWheelItem.h"
#include "RageUtil.h"
#include "SongManager.h"
#include "GameManager.h"
#include "RageLog.h"
#include "GameConstantsAndTypes.h"
#include "GameState.h"
#include "ThemeManager.h"
#include "Steps.h"
#include "Song.h"
#include "Course.h"
#include "ProfileManager.h"
#include "Profile.h"
#include "Style.h"
#include "ActorUtil.h"
#include "ThemeMetric.h"
#include "HighScore.h"
#include "ScreenSelectMusic.h"
#include "ScreenManager.h"
static const char *MusicWheelItemTypeNames[] = {
"Song",
"SectionExpanded",
"SectionCollapsed",
"Roulette",
"Course",
"Sort",
"Mode",
"Random",
"Portal",
"Custom",
};
XToString( MusicWheelItemType );
MusicWheelItemData::MusicWheelItemData( WheelItemDataType type, Song* pSong,
RString sSectionName, Course* pCourse,
RageColor color, int iSectionCount ):
WheelItemBaseData(type, sSectionName, color),
m_pCourse(pCourse), m_pSong(pSong), m_Flags(WheelNotifyIcon::Flags()),
m_iSectionCount(iSectionCount), m_sLabel(""), m_pAction() {}
MusicWheelItem::MusicWheelItem( RString sType ):
WheelItemBase( sType )
{
GRADES_SHOW_MACHINE.Load( sType, "GradesShowMachine" );
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprColorPart[i].Load( THEME->GetPathG(sType,MusicWheelItemTypeToString(i)+" ColorPart") );
m_sprColorPart[i]->SetName( MusicWheelItemTypeToString(i)+"ColorPart" );
ActorUtil::LoadAllCommands(m_sprColorPart[i],"MusicWheelItem");
this->AddChild( m_sprColorPart[i] );
m_sprNormalPart[i].Load( THEME->GetPathG(sType,MusicWheelItemTypeToString(i)+" NormalPart") );
m_sprNormalPart[i]->SetName( MusicWheelItemTypeToString(i)+"NormalPart" );
ActorUtil::LoadAllCommands(m_sprNormalPart[i],"MusicWheelItem");
this->AddChild( m_sprNormalPart[i] );
}
m_TextBanner.SetName( "SongName" );
ActorUtil::LoadAllCommands( m_TextBanner, "MusicWheelItem" );
m_TextBanner.Load( "TextBanner" );
ActorUtil::SetXY( m_TextBanner, "MusicWheelItem" );
m_TextBanner.PlayCommand( "On" );
this->AddChild( &m_TextBanner );
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprOverPart[i].Load( THEME->GetPathG(sType,MusicWheelItemTypeToString(i)+" OverPart") );
m_sprOverPart[i]->SetName( MusicWheelItemTypeToString(i)+"OverPart" );
ActorUtil::LoadAllCommands(m_sprOverPart[i],"MusicWheelItem");
this->AddChild( m_sprOverPart[i] );
}
FOREACH_ENUM( MusicWheelItemType, i )
{
m_pText[i] = NULL;
// Don't init text for Type_Song. It uses a TextBanner.
if( i == MusicWheelItemType_Song )
continue;
m_pText[i] = new BitmapText;
m_pText[i]->SetName( MusicWheelItemTypeToString(i) );
ActorUtil::LoadAllCommands( m_pText[i], "MusicWheelItem" );
m_pText[i]->LoadFromFont( THEME->GetPathF(sType,MusicWheelItemTypeToString(i)) );
ActorUtil::SetXY( m_pText[i], "MusicWheelItem" );
m_pText[i]->PlayCommand( "On" );
this->AddChild( m_pText[i] );
}
m_pTextSectionCount = new BitmapText;
m_pTextSectionCount->SetName( "SectionCount" );
ActorUtil::LoadAllCommands( m_pTextSectionCount, "MusicWheelItem" );
m_pTextSectionCount->LoadFromFont( THEME->GetPathF(sType,"SectionCount") );
ActorUtil::SetXY( m_pTextSectionCount, "MusicWheelItem" );
m_pTextSectionCount->PlayCommand( "On" );
this->AddChild( m_pTextSectionCount );
m_WheelNotifyIcon.SetName( "WheelNotifyIcon" );
ActorUtil::LoadAllCommands( m_WheelNotifyIcon, "MusicWheelItem" );
ActorUtil::SetXY( m_WheelNotifyIcon, "MusicWheelItem" );
m_WheelNotifyIcon.PlayCommand( "On" );
this->AddChild( &m_WheelNotifyIcon );
FOREACH_PlayerNumber( p )
{
m_pGradeDisplay[p].Load( THEME->GetPathG(sType,"grades") );
m_pGradeDisplay[p]->SetName( ssprintf("GradeP%d",int(p+1)) );
this->AddChild( m_pGradeDisplay[p] );
LOAD_ALL_COMMANDS_AND_SET_XY( m_pGradeDisplay[p] );
}
this->SubscribeToMessage( Message_CurrentStepsP1Changed );
this->SubscribeToMessage( Message_CurrentStepsP2Changed );
this->SubscribeToMessage( Message_CurrentTrailP1Changed );
this->SubscribeToMessage( Message_CurrentTrailP2Changed );
this->SubscribeToMessage( Message_PreferredDifficultyP1Changed );
this->SubscribeToMessage( Message_PreferredDifficultyP2Changed );
}
MusicWheelItem::MusicWheelItem( const MusicWheelItem &cpy ):
WheelItemBase( cpy ),
GRADES_SHOW_MACHINE( cpy.GRADES_SHOW_MACHINE ),
m_TextBanner( cpy.m_TextBanner ),
m_WheelNotifyIcon( cpy.m_WheelNotifyIcon )
{
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprColorPart[i] = cpy.m_sprColorPart[i];
this->AddChild( m_sprColorPart[i] );
m_sprNormalPart[i] = cpy.m_sprNormalPart[i];
this->AddChild( m_sprNormalPart[i] );
}
this->AddChild( &m_TextBanner );
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprOverPart[i] = cpy.m_sprOverPart[i];
this->AddChild( m_sprOverPart[i] );
}
FOREACH_ENUM( MusicWheelItemType, i )
{
if( cpy.m_pText[i] == NULL )
{
m_pText[i] = NULL;
}
else
{
m_pText[i] = new BitmapText( *cpy.m_pText[i] );
this->AddChild( m_pText[i] );
}
}
m_pTextSectionCount = new BitmapText( *cpy.m_pTextSectionCount );
this->AddChild( m_pTextSectionCount );
this->AddChild( &m_WheelNotifyIcon );
FOREACH_PlayerNumber( p )
{
m_pGradeDisplay[p] = cpy.m_pGradeDisplay[p];
this->AddChild( m_pGradeDisplay[p] );
}
}
MusicWheelItem::~MusicWheelItem()
{
FOREACH_ENUM( MusicWheelItemType, i )
{
SAFE_DELETE(m_pText[i]);
}
delete m_pTextSectionCount;
}
void MusicWheelItem::LoadFromWheelItemData( const WheelItemBaseData *pData, int iIndex, bool bHasFocus, int iDrawIndex )
{
WheelItemBase::LoadFromWheelItemData( pData, iIndex, bHasFocus, iDrawIndex );
const MusicWheelItemData *pWID = dynamic_cast<const MusicWheelItemData*>( pData );
// hide all
FOREACH_ENUM( MusicWheelItemType, i )
{
m_sprColorPart[i]->SetVisible( false );
m_sprNormalPart[i]->SetVisible( false );
m_sprOverPart[i]->SetVisible( false );
}
m_TextBanner.SetVisible( false );
FOREACH_ENUM( MusicWheelItemType, i )
if( m_pText[i] )
m_pText[i]->SetVisible( false );
m_pTextSectionCount->SetVisible( false );
m_WheelNotifyIcon.SetVisible( false );
FOREACH_PlayerNumber( p )
m_pGradeDisplay[p]->SetVisible( false );
// Fill these in below
RString sDisplayName, sTranslitName;
MusicWheelItemType type = MusicWheelItemType_Invalid;
switch( pWID->m_Type )
{
DEFAULT_FAIL( pWID->m_Type );
case WheelItemDataType_Song:
type = MusicWheelItemType_Song;
m_TextBanner.SetFromSong( pWID->m_pSong );
// We can do this manually if we wanted... maybe have a metric for overrides? -aj
m_TextBanner.SetDiffuse( pWID->m_color );
m_TextBanner.SetVisible( true );
m_WheelNotifyIcon.SetFlags( pWID->m_Flags );
m_WheelNotifyIcon.SetVisible( true );
RefreshGrades();
break;
case WheelItemDataType_Section:
{
sDisplayName = SONGMAN->ShortenGroupName(pWID->m_sText);
if( GAMESTATE->sExpandedSectionName == pWID->m_sText )
type = MusicWheelItemType_SectionExpanded;
else
type = MusicWheelItemType_SectionCollapsed;
m_pTextSectionCount->SetText( ssprintf("%d",pWID->m_iSectionCount) );
m_pTextSectionCount->SetVisible( true );
}
break;
case WheelItemDataType_Course:
sDisplayName = pWID->m_pCourse->GetDisplayFullTitle();
sTranslitName = pWID->m_pCourse->GetTranslitFullTitle();
type = MusicWheelItemType_Course;
m_WheelNotifyIcon.SetFlags( pWID->m_Flags );
m_WheelNotifyIcon.SetVisible( true );
break;
case WheelItemDataType_Sort:
sDisplayName = pWID->m_sLabel;
// hack to get mode items working. -freem
if( pWID->m_pAction->m_pm != PlayMode_Invalid )
type = MusicWheelItemType_Mode;
else
type = MusicWheelItemType_Sort;
break;
case WheelItemDataType_Roulette:
sDisplayName = THEME->GetString("MusicWheel","Roulette");
type = MusicWheelItemType_Roulette;
break;
case WheelItemDataType_Random:
sDisplayName = THEME->GetString("MusicWheel","Random");
type = MusicWheelItemType_Random;
break;
case WheelItemDataType_Portal:
sDisplayName = THEME->GetString("MusicWheel","Portal");
type = MusicWheelItemType_Portal;
break;
case WheelItemDataType_Custom:
sDisplayName = pWID->m_sLabel;
type = MusicWheelItemType_Custom;
break;
}
m_sprColorPart[type]->SetVisible( true );
m_sprColorPart[type]->SetDiffuse( pWID->m_color );
m_sprNormalPart[type]->SetVisible( true );
m_sprOverPart[type]->SetVisible( true );
BitmapText *bt = m_pText[type];
if( bt )
{
bt->SetText( sDisplayName, sTranslitName );
bt->SetDiffuse( pWID->m_color );
bt->SetVisible( true );
}
FOREACH_ENUM( MusicWheelItemType, i )
{
if( m_sprColorPart[i]->GetVisible() )
{
SetGrayBar( m_sprColorPart[i] );
break;
}
}
// Call "Set" so that elements like TextBanner react to the change in song.
{
Message msg( "Set" );
msg.SetParam( "Song", pWID->m_pSong );
msg.SetParam( "Course", pWID->m_pCourse );
msg.SetParam( "Index", iIndex );
msg.SetParam( "HasFocus", bHasFocus );
msg.SetParam( "Text", pWID->m_sText );
msg.SetParam( "DrawIndex", iDrawIndex );
msg.SetParam( "Type", MusicWheelItemTypeToString(type) );
msg.SetParam( "Color", pWID->m_color );
msg.SetParam( "Label", pWID->m_sLabel );
this->HandleMessage( msg );
}
}
void MusicWheelItem::RefreshGrades()
{
const MusicWheelItemData *pWID = dynamic_cast<const MusicWheelItemData*>( m_pData );
if( pWID == NULL )
return; // LoadFromWheelItemData() hasn't been called yet.
FOREACH_HumanPlayer( p )
{
m_pGradeDisplay[p]->SetVisible( false );
if( pWID->m_pSong == NULL && pWID->m_pCourse == NULL )
continue;
Difficulty dc;
if( GAMESTATE->m_pCurSteps[p] )
dc = GAMESTATE->m_pCurSteps[p]->GetDifficulty();
else if( GAMESTATE->m_pCurTrail[p] )
dc = GAMESTATE->m_pCurTrail[p]->m_CourseDifficulty;
else
dc = GAMESTATE->m_PreferredDifficulty[p];
ProfileSlot ps;
if( PROFILEMAN->IsPersistentProfile(p) )
ps = (ProfileSlot)p;
else if( GRADES_SHOW_MACHINE )
ps = ProfileSlot_Machine;
else
continue;
StepsType st;
if( GAMESTATE->m_pCurSteps[p] )
st = GAMESTATE->m_pCurSteps[p]->m_StepsType;
else if( GAMESTATE->m_pCurTrail[p] )
st = GAMESTATE->m_pCurTrail[p]->m_StepsType;
else
st = GAMESTATE->m_pCurStyle->m_StepsType;
m_pGradeDisplay[p]->SetVisible( true );
Profile *pProfile = PROFILEMAN->GetProfile(ps);
HighScoreList *pHSL = NULL;
if( PROFILEMAN->IsPersistentProfile(ps) && dc != Difficulty_Invalid )
{
if( pWID->m_pSong )
{
const Steps* pSteps = SongUtil::GetStepsByDifficulty( pWID->m_pSong, st, dc );
if( pSteps != nullptr )
pHSL = &pProfile->GetStepsHighScoreList(pWID->m_pSong, pSteps);
}
else if( pWID->m_pCourse )
{
const Trail *pTrail = pWID->m_pCourse->GetTrail( st, dc );
if( pTrail != nullptr )
pHSL = &pProfile->GetCourseHighScoreList( pWID->m_pCourse, pTrail );
}
}
Message msg( "SetGrade" );
msg.SetParam( "PlayerNumber", p );
if( pHSL )
{
msg.SetParam( "Grade", pHSL->HighGrade );
msg.SetParam( "NumTimesPlayed", pHSL->GetNumTimesPlayed() );
}
m_pGradeDisplay[p]->HandleMessage( msg );
}
}
void MusicWheelItem::HandleMessage( const Message &msg )
{
if( msg == Message_CurrentStepsP1Changed ||
msg == Message_CurrentStepsP2Changed ||
msg == Message_CurrentTrailP1Changed ||
msg == Message_CurrentTrailP2Changed ||
msg == Message_PreferredDifficultyP1Changed ||
msg == Message_PreferredDifficultyP2Changed )
{
RefreshGrades();
}
WheelItemBase::HandleMessage( msg );
}
/*
* (c) 2001-2004 Chris Danford, Chris Gomez, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1017 -1017
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -351,7 +351,7 @@ bool NoteData::IsHoldHeadOrBodyAtRow( int iTrack, int iRow, int *pHeadRow ) cons
const TapNote &tn = GetTapNote( iTrack, iRow );
if( tn.type == TapNote::hold_head )
{
if( pHeadRow != NULL )
if( pHeadRow != nullptr )
*pHeadRow = iRow;
return true;
}
+2 -2
View File
@@ -145,7 +145,7 @@ static NoteResource *MakeNoteResource( const RString &sButton, const RString &sE
NoteResource *pRes = new NoteResource( nsap );
pRes->m_pActor = NOTESKIN->LoadActor( sButton, sElement, NULL, bSpriteOnly );
ASSERT( pRes->m_pActor != NULL );
ASSERT( pRes->m_pActor != nullptr );
g_NoteResource[nsap] = pRes;
it = g_NoteResource.find( nsap );
@@ -158,7 +158,7 @@ static NoteResource *MakeNoteResource( const RString &sButton, const RString &sE
static void DeleteNoteResource( NoteResource *pRes )
{
ASSERT( pRes != NULL );
ASSERT( pRes != nullptr );
ASSERT_M( pRes->m_iRefCount > 0, ssprintf("RefCount %i > 0", pRes->m_iRefCount) );
--pRes->m_iRefCount;
+5 -5
View File
@@ -175,7 +175,7 @@ void NoteField::Load(
int iDrawDistanceAfterTargetsPixels,
int iDrawDistanceBeforeTargetsPixels )
{
ASSERT( pNoteData != NULL );
ASSERT( pNoteData != nullptr );
m_pNoteData = pNoteData;
m_iDrawDistanceAfterTargetsPixels = iDrawDistanceAfterTargetsPixels;
m_iDrawDistanceBeforeTargetsPixels = iDrawDistanceBeforeTargetsPixels;
@@ -814,7 +814,7 @@ void NoteField::DrawPrimitives()
//LOG->Trace( "NoteField::DrawPrimitives()" );
// This should be filled in on the first update.
ASSERT( m_pCurDisplay != NULL );
ASSERT( m_pCurDisplay != nullptr );
ArrowEffects::Update();
@@ -873,7 +873,7 @@ void NoteField::DrawPrimitives()
unsigned i = 0;
// Draw beat bars
if( ( GAMESTATE->IsEditing() || SHOW_BEAT_BARS ) && pTiming != NULL )
if( ( GAMESTATE->IsEditing() || SHOW_BEAT_BARS ) && pTiming != nullptr )
{
const vector<TimingSegment *> &tSigs = *segs[SEGMENT_TIME_SIG];
int iMeasureIndex = 0;
@@ -913,9 +913,9 @@ void NoteField::DrawPrimitives()
}
}
if( GAMESTATE->IsEditing() && pTiming != NULL )
if( GAMESTATE->IsEditing() && pTiming != nullptr )
{
ASSERT(GAMESTATE->m_pCurSong != NULL);
ASSERT(GAMESTATE->m_pCurSong != nullptr);
const TimingData &timing = *pTiming;
+1307 -1307
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -61,7 +61,7 @@ void OptionRow::Clear()
FOREACH_PlayerNumber( p )
m_Underline[p].clear();
if( m_pHand != NULL )
if( m_pHand != nullptr )
{
for (RString const &m : m_pHand->m_vsReloadRowMessages)
MESSAGEMAN->Unsubscribe( this, m );
@@ -197,7 +197,7 @@ RString OptionRow::GetRowTitle() const
if( GAMESTATE->m_pCurCourse )
{
const Trail* pTrail = GAMESTATE->m_pCurTrail[GAMESTATE->GetMasterPlayerNumber()];
ASSERT( pTrail != NULL );
ASSERT( pTrail != nullptr );
const int iNumCourseEntries = pTrail->m_vEntries.size();
if( iNumCourseEntries > CommonMetrics::MAX_COURSE_ENTRIES_BEFORE_VARIOUS )
bShowBpmInSpeedTitle = false;
@@ -216,7 +216,7 @@ RString OptionRow::GetRowTitle() const
const Course *pCourse = GAMESTATE->m_pCurCourse;
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
const Trail* pTrail = pCourse->GetTrail( st );
ASSERT( pTrail != NULL );
ASSERT( pTrail != nullptr );
pTrail->GetDisplayBpms( bpms );
}
@@ -651,7 +651,7 @@ void OptionRow::SetModIcon( PlayerNumber pn, const RString &sText, GameCommand &
msg.SetParam( "GameCommand", &gc );
msg.SetParam( "Text", sText );
m_sprFrame->HandleMessage( msg );
if( m_ModIcons[pn] != NULL )
if( m_ModIcons[pn] != nullptr )
m_ModIcons[pn]->Set( sText );
}
+3 -3
View File
@@ -536,7 +536,7 @@ public:
m_ppStepsToFill = &GAMESTATE->m_pEditSourceSteps;
m_pst = &GAMESTATE->m_stEditSource;
m_vsReloadRowMessages.push_back( MessageIDToString(Message_EditSourceStepsTypeChanged) );
if( GAMESTATE->m_pCurSteps[0].Get() != NULL )
if( GAMESTATE->m_pCurSteps[0].Get() != nullptr )
m_Def.m_vEnabledForPlayers.clear(); // hide row
}
else
@@ -1120,7 +1120,7 @@ public:
{
LOG->Warn( "Invalid Conf type \"%s\"", sParam.c_str() );
pConfOption = ConfOption::Find( "Invalid" );
ASSERT_M( pConfOption != NULL, "ConfOption::Find(Invalid)" );
ASSERT_M( pConfOption != nullptr, "ConfOption::Find(Invalid)" );
}
pConfOption->UpdateAvailableOptions();
@@ -1201,7 +1201,7 @@ public:
m_pstToFill = &GAMESTATE->m_stEditSource;
m_vsReloadRowMessages.push_back( MessageIDToString(Message_CurrentStepsP1Changed) );
m_vsReloadRowMessages.push_back( MessageIDToString(Message_EditStepsTypeChanged) );
if( GAMESTATE->m_pCurSteps[0].Get() != NULL )
if( GAMESTATE->m_pCurSteps[0].Get() != nullptr )
m_Def.m_vEnabledForPlayers.clear(); // hide row
}
else
+2 -2
View File
@@ -101,7 +101,7 @@ void OptionListRow::SetFromHandler( const OptionRowHandler *pHandler )
void OptionListRow::SetTextFromHandler( const OptionRowHandler *pHandler )
{
ASSERT( pHandler != NULL );
ASSERT( pHandler != nullptr );
for( unsigned i = 0; i < pHandler->m_Def.m_vsChoices.size(); ++i )
{
// init text
@@ -632,7 +632,7 @@ void OptionsList::SelectionsChanged( const RString &sRowName )
const OptionRowHandler *pHandler = m_Rows[sRowName];
vector<bool> &bSelections = m_bSelections[sRowName];
if( pHandler->m_Def.m_bOneChoiceForAllPlayers && m_pLinked != NULL )
if( pHandler->m_Def.m_bOneChoiceForAllPlayers && m_pLinked != nullptr )
{
vector<bool> &bLinkedSelections = m_pLinked->m_bSelections[sRowName];
bLinkedSelections = bSelections;
+235 -235
View File
@@ -1,235 +1,235 @@
#include "global.h"
#include "PercentageDisplay.h"
#include "GameState.h"
#include "ThemeManager.h"
#include "PrefsManager.h"
#include "ActorUtil.h"
#include "RageLog.h"
#include "StageStats.h"
#include "PlayerState.h"
#include "XmlFile.h"
#include "Course.h"
REGISTER_ACTOR_CLASS( PercentageDisplay );
PercentageDisplay::PercentageDisplay()
{
m_pPlayerState = NULL;
m_pPlayerStageStats = NULL;
m_Last = -1;
m_LastMax = -1;
m_iDancePointsDigits = 0;
m_bUseRemainder = false;
m_bAutoRefresh = false;
m_FormatPercentScore.SetFromExpression( "FormatPercentScore" );
}
void PercentageDisplay::LoadFromNode( const XNode* pNode )
{
pNode->GetAttrValue( "DancePointsDigits", m_iDancePointsDigits );
pNode->GetAttrValue( "AutoRefresh", m_bAutoRefresh );
{
Lua *L = LUA->Get();
if( pNode->PushAttrValue(L, "FormatPercentScore") )
m_FormatPercentScore.SetFromStack( L );
else
lua_pop(L, 1);
LUA->Release(L);
}
const XNode *pChild = pNode->GetChild( "Percent" );
if( pChild == NULL )
RageException::Throw( "%s: PercentageDisplay: missing the node \"Percent\"", ActorUtil::GetWhere(pNode).c_str() );
m_textPercent.LoadFromNode( pChild );
this->AddChild( &m_textPercent );
pChild = pNode->GetChild( "PercentRemainder" );
if( !ShowDancePointsNotPercentage() && pChild != NULL )
{
m_bUseRemainder = true;
m_textPercentRemainder.LoadFromNode( pChild );
this->AddChild( &m_textPercentRemainder );
}
// only run the Init command after we load Fonts.
ActorFrame::LoadFromNode( pNode );
}
void PercentageDisplay::Load( const PlayerState *pPlayerState, const PlayerStageStats *pPlayerStageStats )
{
m_pPlayerState = pPlayerState;
m_pPlayerStageStats = pPlayerStageStats;
Refresh();
}
void PercentageDisplay::Load( const PlayerState *pPlayerState, const PlayerStageStats *pPlayerStageStats, const RString &sMetricsGroup, bool bAutoRefresh )
{
m_pPlayerState = pPlayerState;
m_pPlayerStageStats = pPlayerStageStats;
m_bAutoRefresh = bAutoRefresh;
m_iDancePointsDigits = THEME->GetMetricI( sMetricsGroup, "DancePointsDigits" );
m_bUseRemainder = THEME->GetMetricB( sMetricsGroup, "PercentUseRemainder" );
m_FormatPercentScore = THEME->GetMetricR( sMetricsGroup, "Format" );
m_sPercentFormat = THEME->GetMetric( sMetricsGroup, "PercentFormat" );
m_sRemainderFormat = THEME->GetMetric( sMetricsGroup, "RemainderFormat" );
if( m_FormatPercentScore.IsNil() )
{
LOG->Trace( "Format is nil in [%s]. Defaulting to 'FormatPercentScore'.", sMetricsGroup.c_str() );
m_FormatPercentScore.SetFromExpression( "FormatPercentScore" );
}
if( ShowDancePointsNotPercentage() )
m_textPercent.SetName( "DancePoints" + PlayerNumberToString(m_pPlayerState->m_PlayerNumber) );
else
m_textPercent.SetName( "Percent" + PlayerNumberToString(m_pPlayerState->m_PlayerNumber) );
m_textPercent.LoadFromFont( THEME->GetPathF(sMetricsGroup,"text") );
ActorUtil::SetXY( m_textPercent, sMetricsGroup );
ActorUtil::LoadAllCommands( m_textPercent, sMetricsGroup );
this->AddChild( &m_textPercent );
if( !ShowDancePointsNotPercentage() && m_bUseRemainder )
{
m_textPercentRemainder.SetName( "PercentRemainder" + PlayerNumberToString(m_pPlayerState->m_PlayerNumber) );
m_textPercentRemainder.LoadFromFont( THEME->GetPathF(sMetricsGroup,"remainder") );
ActorUtil::SetXY( m_textPercentRemainder, sMetricsGroup );
ActorUtil::LoadAllCommands( m_textPercentRemainder, sMetricsGroup );
ASSERT( m_textPercentRemainder.HasCommand("Off") );
m_textPercentRemainder.SetText( "456" );
this->AddChild( &m_textPercentRemainder );
}
Refresh();
}
void PercentageDisplay::Update( float fDeltaTime )
{
ActorFrame::Update( fDeltaTime );
if( m_bAutoRefresh )
Refresh();
}
void PercentageDisplay::Refresh()
{
const int iActualDancePoints = m_pPlayerStageStats->m_iActualDancePoints;
const int iCurPossibleDancePoints = m_pPlayerStageStats->m_iCurPossibleDancePoints;
if( iActualDancePoints == m_Last && iCurPossibleDancePoints == m_LastMax )
return;
m_Last = iActualDancePoints;
m_LastMax = iCurPossibleDancePoints;
RString sNumToDisplay;
if( ShowDancePointsNotPercentage() )
{
sNumToDisplay = ssprintf( "%*d", m_iDancePointsDigits, max( 0, iActualDancePoints ) );
}
else
{
float fPercentDancePoints = m_pPlayerStageStats->GetPercentDancePoints();
// clamp percentage - feedback is that negative numbers look weird here.
CLAMP( fPercentDancePoints, 0.f, 1.f );
if( m_bUseRemainder )
{
int iPercentWhole = int(fPercentDancePoints*100);
int iPercentRemainder = int( (fPercentDancePoints*100 - int(fPercentDancePoints*100)) * 10 );
sNumToDisplay = ssprintf( m_sPercentFormat, iPercentWhole );
m_textPercentRemainder.SetText( ssprintf(m_sRemainderFormat, iPercentRemainder) );
}
else
{
Lua *L = LUA->Get();
m_FormatPercentScore.PushSelf( L );
ASSERT( !lua_isnil(L, -1) );
LuaHelpers::Push( L, fPercentDancePoints );
RString sError;
if( !LuaHelpers::RunScriptOnStack(L, sError, 1, 1) ) // 1 arg, 1 result
LOG->Warn( "Error running FormatPercentScore: %s", sError.c_str() );
LuaHelpers::Pop( L, sNumToDisplay );
LUA->Release(L);
// HACK: Use the last frame in the numbers texture as '-'
sNumToDisplay.Replace('-','x');
}
}
m_textPercent.SetText( sNumToDisplay );
}
bool PercentageDisplay::ShowDancePointsNotPercentage() const
{
// Use staight dance points in workout because the percentage denominator isn't accurate - we don't know when the players are going to stop.
if( GAMESTATE->m_pCurCourse )
{
if( GAMESTATE->m_pCurCourse->m_fGoalSeconds > 0 )
return true;
}
if( PREFSMAN->m_bDancePointsForOni )
return true;
return false;
}
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the PercentageDisplay. */
class LunaPercentageDisplay: public Luna<PercentageDisplay>
{
public:
static int LoadFromStats( T* p, lua_State *L )
{
const PlayerState *pStageStats = Luna<PlayerState>::check( L, 1 );
const PlayerStageStats *pPlayerStageStats = Luna<PlayerStageStats>::check( L, 2 );
p->Load( pStageStats, pPlayerStageStats );
return 0;
}
LunaPercentageDisplay()
{
ADD_METHOD( LoadFromStats );
}
};
LUA_REGISTER_DERIVED_CLASS( PercentageDisplay, ActorFrame )
// lua end
/*
* (c) 2001-2003 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "PercentageDisplay.h"
#include "GameState.h"
#include "ThemeManager.h"
#include "PrefsManager.h"
#include "ActorUtil.h"
#include "RageLog.h"
#include "StageStats.h"
#include "PlayerState.h"
#include "XmlFile.h"
#include "Course.h"
REGISTER_ACTOR_CLASS( PercentageDisplay );
PercentageDisplay::PercentageDisplay()
{
m_pPlayerState = NULL;
m_pPlayerStageStats = NULL;
m_Last = -1;
m_LastMax = -1;
m_iDancePointsDigits = 0;
m_bUseRemainder = false;
m_bAutoRefresh = false;
m_FormatPercentScore.SetFromExpression( "FormatPercentScore" );
}
void PercentageDisplay::LoadFromNode( const XNode* pNode )
{
pNode->GetAttrValue( "DancePointsDigits", m_iDancePointsDigits );
pNode->GetAttrValue( "AutoRefresh", m_bAutoRefresh );
{
Lua *L = LUA->Get();
if( pNode->PushAttrValue(L, "FormatPercentScore") )
m_FormatPercentScore.SetFromStack( L );
else
lua_pop(L, 1);
LUA->Release(L);
}
const XNode *pChild = pNode->GetChild( "Percent" );
if( pChild == NULL )
RageException::Throw( "%s: PercentageDisplay: missing the node \"Percent\"", ActorUtil::GetWhere(pNode).c_str() );
m_textPercent.LoadFromNode( pChild );
this->AddChild( &m_textPercent );
pChild = pNode->GetChild( "PercentRemainder" );
if( !ShowDancePointsNotPercentage() && pChild != nullptr )
{
m_bUseRemainder = true;
m_textPercentRemainder.LoadFromNode( pChild );
this->AddChild( &m_textPercentRemainder );
}
// only run the Init command after we load Fonts.
ActorFrame::LoadFromNode( pNode );
}
void PercentageDisplay::Load( const PlayerState *pPlayerState, const PlayerStageStats *pPlayerStageStats )
{
m_pPlayerState = pPlayerState;
m_pPlayerStageStats = pPlayerStageStats;
Refresh();
}
void PercentageDisplay::Load( const PlayerState *pPlayerState, const PlayerStageStats *pPlayerStageStats, const RString &sMetricsGroup, bool bAutoRefresh )
{
m_pPlayerState = pPlayerState;
m_pPlayerStageStats = pPlayerStageStats;
m_bAutoRefresh = bAutoRefresh;
m_iDancePointsDigits = THEME->GetMetricI( sMetricsGroup, "DancePointsDigits" );
m_bUseRemainder = THEME->GetMetricB( sMetricsGroup, "PercentUseRemainder" );
m_FormatPercentScore = THEME->GetMetricR( sMetricsGroup, "Format" );
m_sPercentFormat = THEME->GetMetric( sMetricsGroup, "PercentFormat" );
m_sRemainderFormat = THEME->GetMetric( sMetricsGroup, "RemainderFormat" );
if( m_FormatPercentScore.IsNil() )
{
LOG->Trace( "Format is nil in [%s]. Defaulting to 'FormatPercentScore'.", sMetricsGroup.c_str() );
m_FormatPercentScore.SetFromExpression( "FormatPercentScore" );
}
if( ShowDancePointsNotPercentage() )
m_textPercent.SetName( "DancePoints" + PlayerNumberToString(m_pPlayerState->m_PlayerNumber) );
else
m_textPercent.SetName( "Percent" + PlayerNumberToString(m_pPlayerState->m_PlayerNumber) );
m_textPercent.LoadFromFont( THEME->GetPathF(sMetricsGroup,"text") );
ActorUtil::SetXY( m_textPercent, sMetricsGroup );
ActorUtil::LoadAllCommands( m_textPercent, sMetricsGroup );
this->AddChild( &m_textPercent );
if( !ShowDancePointsNotPercentage() && m_bUseRemainder )
{
m_textPercentRemainder.SetName( "PercentRemainder" + PlayerNumberToString(m_pPlayerState->m_PlayerNumber) );
m_textPercentRemainder.LoadFromFont( THEME->GetPathF(sMetricsGroup,"remainder") );
ActorUtil::SetXY( m_textPercentRemainder, sMetricsGroup );
ActorUtil::LoadAllCommands( m_textPercentRemainder, sMetricsGroup );
ASSERT( m_textPercentRemainder.HasCommand("Off") );
m_textPercentRemainder.SetText( "456" );
this->AddChild( &m_textPercentRemainder );
}
Refresh();
}
void PercentageDisplay::Update( float fDeltaTime )
{
ActorFrame::Update( fDeltaTime );
if( m_bAutoRefresh )
Refresh();
}
void PercentageDisplay::Refresh()
{
const int iActualDancePoints = m_pPlayerStageStats->m_iActualDancePoints;
const int iCurPossibleDancePoints = m_pPlayerStageStats->m_iCurPossibleDancePoints;
if( iActualDancePoints == m_Last && iCurPossibleDancePoints == m_LastMax )
return;
m_Last = iActualDancePoints;
m_LastMax = iCurPossibleDancePoints;
RString sNumToDisplay;
if( ShowDancePointsNotPercentage() )
{
sNumToDisplay = ssprintf( "%*d", m_iDancePointsDigits, max( 0, iActualDancePoints ) );
}
else
{
float fPercentDancePoints = m_pPlayerStageStats->GetPercentDancePoints();
// clamp percentage - feedback is that negative numbers look weird here.
CLAMP( fPercentDancePoints, 0.f, 1.f );
if( m_bUseRemainder )
{
int iPercentWhole = int(fPercentDancePoints*100);
int iPercentRemainder = int( (fPercentDancePoints*100 - int(fPercentDancePoints*100)) * 10 );
sNumToDisplay = ssprintf( m_sPercentFormat, iPercentWhole );
m_textPercentRemainder.SetText( ssprintf(m_sRemainderFormat, iPercentRemainder) );
}
else
{
Lua *L = LUA->Get();
m_FormatPercentScore.PushSelf( L );
ASSERT( !lua_isnil(L, -1) );
LuaHelpers::Push( L, fPercentDancePoints );
RString sError;
if( !LuaHelpers::RunScriptOnStack(L, sError, 1, 1) ) // 1 arg, 1 result
LOG->Warn( "Error running FormatPercentScore: %s", sError.c_str() );
LuaHelpers::Pop( L, sNumToDisplay );
LUA->Release(L);
// HACK: Use the last frame in the numbers texture as '-'
sNumToDisplay.Replace('-','x');
}
}
m_textPercent.SetText( sNumToDisplay );
}
bool PercentageDisplay::ShowDancePointsNotPercentage() const
{
// Use staight dance points in workout because the percentage denominator isn't accurate - we don't know when the players are going to stop.
if( GAMESTATE->m_pCurCourse )
{
if( GAMESTATE->m_pCurCourse->m_fGoalSeconds > 0 )
return true;
}
if( PREFSMAN->m_bDancePointsForOni )
return true;
return false;
}
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the PercentageDisplay. */
class LunaPercentageDisplay: public Luna<PercentageDisplay>
{
public:
static int LoadFromStats( T* p, lua_State *L )
{
const PlayerState *pStageStats = Luna<PlayerState>::check( L, 1 );
const PlayerStageStats *pPlayerStageStats = Luna<PlayerStageStats>::check( L, 2 );
p->Load( pStageStats, pPlayerStageStats );
return 0;
}
LunaPercentageDisplay()
{
ADD_METHOD( LoadFromStats );
}
};
LUA_REGISTER_DERIVED_CLASS( PercentageDisplay, ActorFrame )
// lua end
/*
* (c) 2001-2003 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+10 -10
View File
@@ -416,12 +416,12 @@ void Player::Init(
if( GAMESTATE->IsCourseMode() )
{
ASSERT( GAMESTATE->m_pCurTrail[pn] != NULL );
ASSERT( GAMESTATE->m_pCurTrail[pn] != nullptr );
GAMESTATE->m_pCurTrail[pn]->GetDisplayBpms( bpms );
}
else
{
ASSERT( GAMESTATE->m_pCurSong != NULL );
ASSERT( GAMESTATE->m_pCurSong != nullptr );
GAMESTATE->m_pCurSong->GetDisplayBpms( bpms );
}
@@ -891,14 +891,14 @@ void Player::Update( float fDeltaTime )
const bool bReverse = m_pPlayerState->m_PlayerOptions.GetCurrent().GetReversePercentForColumn(0) == 1;
float fPercentCentered = m_pPlayerState->m_PlayerOptions.GetCurrent().m_fScrolls[PlayerOptions::SCROLL_CENTERED];
if( m_pActorWithJudgmentPosition != NULL )
if( m_pActorWithJudgmentPosition != nullptr )
{
const Actor::TweenState &ts1 = m_tsJudgment[bReverse?1:0][0];
const Actor::TweenState &ts2 = m_tsJudgment[bReverse?1:0][1];
Actor::TweenState::MakeWeightedAverage( m_pActorWithJudgmentPosition->DestTweenState(), ts1, ts2, fPercentCentered );
}
if( m_pActorWithComboPosition != NULL )
if( m_pActorWithComboPosition != nullptr )
{
const Actor::TweenState &ts1 = m_tsCombo[bReverse?1:0][0];
const Actor::TweenState &ts2 = m_tsCombo[bReverse?1:0][1];
@@ -908,9 +908,9 @@ void Player::Update( float fDeltaTime )
float fNoteFieldZoom = 1 - fMiniPercent*0.5f;
if( m_pNoteField )
m_pNoteField->SetZoom( fNoteFieldZoom );
if( m_pActorWithJudgmentPosition != NULL )
if( m_pActorWithJudgmentPosition != nullptr )
m_pActorWithJudgmentPosition->SetZoom( m_pActorWithJudgmentPosition->GetZoom() * fJudgmentZoom );
if( m_pActorWithComboPosition != NULL )
if( m_pActorWithComboPosition != nullptr )
m_pActorWithComboPosition->SetZoom( m_pActorWithComboPosition->GetZoom() * fJudgmentZoom );
}
@@ -931,7 +931,7 @@ void Player::Update( float fDeltaTime )
ASSERT_M( iNumCols <= MAX_COLS_PER_PLAYER, ssprintf("%i > %i", iNumCols, MAX_COLS_PER_PLAYER) );
for( int col=0; col < iNumCols; ++col )
{
ASSERT( m_pPlayerState != NULL );
ASSERT( m_pPlayerState != nullptr );
// TODO: Remove use of PlayerNumber.
GameInput GameI = GAMESTATE->GetCurrentStyle()->StyleInputToGameInput( col, m_pPlayerState->m_PlayerNumber );
@@ -1216,7 +1216,7 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTap
if( m_pPlayerState->m_PlayerController == PC_AUTOPLAY )
{
STATSMAN->m_CurStageStats.m_bUsedAutoplay = true;
if( m_pPlayerStageStats != NULL )
if( m_pPlayerStageStats != nullptr )
m_pPlayerStageStats->m_bDisqualified = true;
}
}
@@ -3162,9 +3162,9 @@ void Player::HandleTapRowScore( unsigned row )
m_pSecondaryScoreKeeper->HandleTapScore( tn );
}
if( m_pPrimaryScoreKeeper != NULL )
if( m_pPrimaryScoreKeeper != nullptr )
m_pPrimaryScoreKeeper->HandleTapRowScore( m_NoteData, row );
if( m_pSecondaryScoreKeeper != NULL )
if( m_pSecondaryScoreKeeper != nullptr )
m_pSecondaryScoreKeeper->HandleTapRowScore( m_NoteData, row );
const int iCurCombo = m_pPlayerStageStats ? m_pPlayerStageStats->m_iCurCombo : 0;
+271 -271
View File
@@ -1,271 +1,271 @@
#ifndef PLAYER_H
#define PLAYER_H
#include "ActorFrame.h"
#include "HoldJudgment.h"
#include "NoteDataWithScoring.h"
#include "RageSound.h"
#include "AttackDisplay.h"
#include "NoteData.h"
#include "ScreenMessage.h"
#include "ThemeMetric.h"
#include "InputEventPlus.h"
#include "TimingData.h"
class ScoreDisplay;
class LifeMeter;
class CombinedLifeMeter;
class ScoreKeeper;
class Inventory;
class RageTimer;
class NoteField;
class PlayerStageStats;
class JudgedRows;
// todo: replace these with a Message and MESSAGEMAN? -aj
AutoScreenMessage( SM_100Combo );
AutoScreenMessage( SM_200Combo );
AutoScreenMessage( SM_300Combo );
AutoScreenMessage( SM_400Combo );
AutoScreenMessage( SM_500Combo );
AutoScreenMessage( SM_600Combo );
AutoScreenMessage( SM_700Combo );
AutoScreenMessage( SM_800Combo );
AutoScreenMessage( SM_900Combo );
AutoScreenMessage( SM_1000Combo );
AutoScreenMessage( SM_ComboStopped );
AutoScreenMessage( SM_ComboContinuing );
/** @brief Accepts input, knocks down TapNotes that were stepped on, and keeps score for the player. */
class Player: public ActorFrame
{
public:
// The passed in NoteData isn't touched until Load() is called.
Player( NoteData &nd, bool bVisibleParts = true );
~Player();
virtual void Update( float fDeltaTime );
virtual void DrawPrimitives();
struct TrackRowTapNote
{
int iTrack;
int iRow;
TapNote *pTN;
};
void UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTapNote> &vTN );
void Init(
const RString &sType,
PlayerState* pPlayerState,
PlayerStageStats* pPlayerStageStats,
LifeMeter* pLM,
CombinedLifeMeter* pCombinedLM,
ScoreDisplay* pScoreDisplay,
ScoreDisplay* pSecondaryScoreDisplay,
Inventory* pInventory,
ScoreKeeper* pPrimaryScoreKeeper,
ScoreKeeper* pSecondaryScoreKeeper );
void Load();
void CrossedRows( int iLastRowCrossed, const RageTimer &now );
bool IsOniDead() const;
/**
* @brief Retrieve the Player's TimingData.
*
* This is primarily for a lua hook.
* @return the TimingData in question. */
TimingData GetPlayerTimingData() const
{
return *(this->m_Timing);
}
// Called when a fret, step, or strum type button changes
void Fret( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease );
// Called when the strum bar is pressed down
void Strum( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease );
// Called when the strum window passes without a row being hit
void DoStrumMiss();
void ScoreAllActiveHoldsLetGo();
void DoTapScoreNone();
enum ButtonType { ButtonType_Step, ButtonType_StrumFretsChanged, ButtonType_Hopo };
void StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease, ButtonType gbt );
void Step( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease ) { StepStrumHopo(col, row, tm, bHeld, bRelease, ButtonType_Step); }
// called by Fret for Hammer-ons and Pull-offs
void Hopo( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease ) { StepStrumHopo(col, row, tm, bHeld, bRelease, ButtonType_Hopo); }
void RandomizeNotes( int iNoteRow );
void FadeToFail();
void CacheAllUsedNoteSkins();
TapNoteScore GetLastTapNoteScore() const { return m_LastTapNoteScore; }
void ApplyWaitingTransforms();
void SetPaused( bool bPaused ) { m_bPaused = bPaused; }
static float GetMaxStepDistanceSeconds();
static float GetWindowSeconds( TimingWindow tw );
const NoteData &GetNoteData() const { return m_NoteData; }
bool HasVisibleParts() const { return m_pNoteField != NULL; }
void SetActorWithJudgmentPosition( Actor *pActor ) { m_pActorWithJudgmentPosition = pActor; }
void SetActorWithComboPosition( Actor *pActor ) { m_pActorWithComboPosition = pActor; }
void SetSendJudgmentAndComboMessages( bool b ) { m_bSendJudgmentAndComboMessages = b; }
// Lua
virtual void PushSelf( lua_State *L );
PlayerState * GetPlayerState() { return this->m_pPlayerState; }
protected:
void UpdateTapNotesMissedOlderThan( float fMissIfOlderThanThisBeat );
void UpdateJudgedRows();
void FlashGhostRow( int iRow );
void HandleTapRowScore( unsigned row );
void HandleHoldScore( const TapNote &tn );
void HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumHoldsMissedThisRow, const vector<int> &viColsWithHold );
void DrawTapJudgments();
void DrawHoldJudgments();
void SendComboMessages( int iOldCombo, int iOldMissCombo );
void PlayKeysound( const TapNote &tn, TapNoteScore score );
void SetMineJudgment( TapNoteScore tns );
void SetJudgment( TapNoteScore tns, int iFirstTrack, float fTapNoteOffset ); // -1 if no track as in TNS_Miss
void SetHoldJudgment( TapNoteScore tns, HoldNoteScore hns, int iTrack );
void SetCombo( int iCombo, int iMisses );
void ChangeLife( TapNoteScore tns );
void ChangeLife( HoldNoteScore hns, TapNoteScore tns );
void ChangeLifeRecord();
int GetClosestNoteDirectional( int col, int iStartRow, int iMaxRowsAhead, bool bAllowGraded, bool bForward ) const;
int GetClosestNote( int col, int iNoteRow, int iMaxRowsAhead, int iMaxRowsBehind, bool bAllowGraded ) const;
int GetClosestNonEmptyRowDirectional( int iStartRow, int iMaxRowsAhead, bool bAllowGraded, bool bForward ) const;
int GetClosestNonEmptyRow( int iNoteRow, int iMaxRowsAhead, int iMaxRowsBehind, bool bAllowGraded ) const;
RString ApplyRandomAttack();
inline void HideNote( int col, int row )
{
NoteData::iterator iter = m_NoteData.FindTapNote( col, row );
if( iter != m_NoteData.end(col) )
iter->second.result.bHidden = true;
}
bool m_bLoaded;
/** @brief The player's present state. */
PlayerState *m_pPlayerState;
/** @brief The player's present stage stats. */
PlayerStageStats *m_pPlayerStageStats;
TimingData *m_Timing;
float m_fNoteFieldHeight;
bool m_bPaused;
bool m_bDelay;
NoteData &m_NoteData;
NoteField *m_pNoteField;
vector<HoldJudgment*> m_vpHoldJudgment;
AutoActor m_sprJudgment;
AutoActor m_sprCombo;
Actor *m_pActorWithJudgmentPosition;
Actor *m_pActorWithComboPosition;
AttackDisplay *m_pAttackDisplay;
TapNoteScore m_LastTapNoteScore;
LifeMeter *m_pLifeMeter;
CombinedLifeMeter *m_pCombinedLifeMeter;
ScoreDisplay *m_pScoreDisplay;
ScoreDisplay *m_pSecondaryScoreDisplay;
ScoreKeeper *m_pPrimaryScoreKeeper;
ScoreKeeper *m_pSecondaryScoreKeeper;
Inventory *m_pInventory;
int m_iFirstUncrossedRow; // used by hold checkpoints logic
NoteData::all_tracks_iterator *m_pIterNeedsTapJudging;
NoteData::all_tracks_iterator *m_pIterNeedsHoldJudging;
NoteData::all_tracks_iterator *m_pIterUncrossedRows;
NoteData::all_tracks_iterator *m_pIterUnjudgedRows;
NoteData::all_tracks_iterator *m_pIterUnjudgedMineRows;
int m_iLastSeenCombo;
JudgedRows *m_pJudgedRows;
RageSound m_soundMine;
RageSound m_soundAttackLaunch;
RageSound m_soundAttackEnding;
float m_fActiveRandomAttackStart;
vector<bool> m_vbFretIsDown;
vector<RageSound> m_vKeysounds;
ThemeMetric<float> GRAY_ARROWS_Y_STANDARD;
ThemeMetric<float> GRAY_ARROWS_Y_REVERSE;
ThemeMetric2D<float> ATTACK_DISPLAY_X;
ThemeMetric<float> ATTACK_DISPLAY_Y;
ThemeMetric<float> ATTACK_DISPLAY_Y_REVERSE;
ThemeMetric<float> HOLD_JUDGMENT_Y_STANDARD;
ThemeMetric<float> HOLD_JUDGMENT_Y_REVERSE;
ThemeMetric<int> BRIGHT_GHOST_COMBO_THRESHOLD;
ThemeMetric<bool> TAP_JUDGMENTS_UNDER_FIELD;
ThemeMetric<bool> HOLD_JUDGMENTS_UNDER_FIELD;
ThemeMetric<bool> COMBO_UNDER_FIELD;
ThemeMetric<int> DRAW_DISTANCE_AFTER_TARGET_PIXELS;
ThemeMetric<int> DRAW_DISTANCE_BEFORE_TARGET_PIXELS;
#define NUM_REVERSE 2
#define NUM_CENTERED 2
TweenState m_tsJudgment[NUM_REVERSE][NUM_CENTERED];
TweenState m_tsCombo[NUM_REVERSE][NUM_CENTERED];
bool m_bSendJudgmentAndComboMessages;
};
class PlayerPlus
{
Player *m_pPlayer;
NoteData m_NoteData;
public:
PlayerPlus() { m_pPlayer = new Player(m_NoteData); }
~PlayerPlus() { delete m_pPlayer; }
void Load( const NoteData &nd ) { m_NoteData = nd; m_pPlayer->Load(); }
Player *operator->() { return m_pPlayer; }
const Player *operator->() const { return m_pPlayer; }
operator Player*() { return m_pPlayer; }
operator const Player*() const { return m_pPlayer; }
};
#endif
/*
* (c) 2001-2006 Chris Danford, Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef PLAYER_H
#define PLAYER_H
#include "ActorFrame.h"
#include "HoldJudgment.h"
#include "NoteDataWithScoring.h"
#include "RageSound.h"
#include "AttackDisplay.h"
#include "NoteData.h"
#include "ScreenMessage.h"
#include "ThemeMetric.h"
#include "InputEventPlus.h"
#include "TimingData.h"
class ScoreDisplay;
class LifeMeter;
class CombinedLifeMeter;
class ScoreKeeper;
class Inventory;
class RageTimer;
class NoteField;
class PlayerStageStats;
class JudgedRows;
// todo: replace these with a Message and MESSAGEMAN? -aj
AutoScreenMessage( SM_100Combo );
AutoScreenMessage( SM_200Combo );
AutoScreenMessage( SM_300Combo );
AutoScreenMessage( SM_400Combo );
AutoScreenMessage( SM_500Combo );
AutoScreenMessage( SM_600Combo );
AutoScreenMessage( SM_700Combo );
AutoScreenMessage( SM_800Combo );
AutoScreenMessage( SM_900Combo );
AutoScreenMessage( SM_1000Combo );
AutoScreenMessage( SM_ComboStopped );
AutoScreenMessage( SM_ComboContinuing );
/** @brief Accepts input, knocks down TapNotes that were stepped on, and keeps score for the player. */
class Player: public ActorFrame
{
public:
// The passed in NoteData isn't touched until Load() is called.
Player( NoteData &nd, bool bVisibleParts = true );
~Player();
virtual void Update( float fDeltaTime );
virtual void DrawPrimitives();
struct TrackRowTapNote
{
int iTrack;
int iRow;
TapNote *pTN;
};
void UpdateHoldNotes( int iSongRow, float fDeltaTime, vector<TrackRowTapNote> &vTN );
void Init(
const RString &sType,
PlayerState* pPlayerState,
PlayerStageStats* pPlayerStageStats,
LifeMeter* pLM,
CombinedLifeMeter* pCombinedLM,
ScoreDisplay* pScoreDisplay,
ScoreDisplay* pSecondaryScoreDisplay,
Inventory* pInventory,
ScoreKeeper* pPrimaryScoreKeeper,
ScoreKeeper* pSecondaryScoreKeeper );
void Load();
void CrossedRows( int iLastRowCrossed, const RageTimer &now );
bool IsOniDead() const;
/**
* @brief Retrieve the Player's TimingData.
*
* This is primarily for a lua hook.
* @return the TimingData in question. */
TimingData GetPlayerTimingData() const
{
return *(this->m_Timing);
}
// Called when a fret, step, or strum type button changes
void Fret( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease );
// Called when the strum bar is pressed down
void Strum( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease );
// Called when the strum window passes without a row being hit
void DoStrumMiss();
void ScoreAllActiveHoldsLetGo();
void DoTapScoreNone();
enum ButtonType { ButtonType_Step, ButtonType_StrumFretsChanged, ButtonType_Hopo };
void StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease, ButtonType gbt );
void Step( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease ) { StepStrumHopo(col, row, tm, bHeld, bRelease, ButtonType_Step); }
// called by Fret for Hammer-ons and Pull-offs
void Hopo( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease ) { StepStrumHopo(col, row, tm, bHeld, bRelease, ButtonType_Hopo); }
void RandomizeNotes( int iNoteRow );
void FadeToFail();
void CacheAllUsedNoteSkins();
TapNoteScore GetLastTapNoteScore() const { return m_LastTapNoteScore; }
void ApplyWaitingTransforms();
void SetPaused( bool bPaused ) { m_bPaused = bPaused; }
static float GetMaxStepDistanceSeconds();
static float GetWindowSeconds( TimingWindow tw );
const NoteData &GetNoteData() const { return m_NoteData; }
bool HasVisibleParts() const { return m_pNoteField != nullptr; }
void SetActorWithJudgmentPosition( Actor *pActor ) { m_pActorWithJudgmentPosition = pActor; }
void SetActorWithComboPosition( Actor *pActor ) { m_pActorWithComboPosition = pActor; }
void SetSendJudgmentAndComboMessages( bool b ) { m_bSendJudgmentAndComboMessages = b; }
// Lua
virtual void PushSelf( lua_State *L );
PlayerState * GetPlayerState() { return this->m_pPlayerState; }
protected:
void UpdateTapNotesMissedOlderThan( float fMissIfOlderThanThisBeat );
void UpdateJudgedRows();
void FlashGhostRow( int iRow );
void HandleTapRowScore( unsigned row );
void HandleHoldScore( const TapNote &tn );
void HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumHoldsMissedThisRow, const vector<int> &viColsWithHold );
void DrawTapJudgments();
void DrawHoldJudgments();
void SendComboMessages( int iOldCombo, int iOldMissCombo );
void PlayKeysound( const TapNote &tn, TapNoteScore score );
void SetMineJudgment( TapNoteScore tns );
void SetJudgment( TapNoteScore tns, int iFirstTrack, float fTapNoteOffset ); // -1 if no track as in TNS_Miss
void SetHoldJudgment( TapNoteScore tns, HoldNoteScore hns, int iTrack );
void SetCombo( int iCombo, int iMisses );
void ChangeLife( TapNoteScore tns );
void ChangeLife( HoldNoteScore hns, TapNoteScore tns );
void ChangeLifeRecord();
int GetClosestNoteDirectional( int col, int iStartRow, int iMaxRowsAhead, bool bAllowGraded, bool bForward ) const;
int GetClosestNote( int col, int iNoteRow, int iMaxRowsAhead, int iMaxRowsBehind, bool bAllowGraded ) const;
int GetClosestNonEmptyRowDirectional( int iStartRow, int iMaxRowsAhead, bool bAllowGraded, bool bForward ) const;
int GetClosestNonEmptyRow( int iNoteRow, int iMaxRowsAhead, int iMaxRowsBehind, bool bAllowGraded ) const;
RString ApplyRandomAttack();
inline void HideNote( int col, int row )
{
NoteData::iterator iter = m_NoteData.FindTapNote( col, row );
if( iter != m_NoteData.end(col) )
iter->second.result.bHidden = true;
}
bool m_bLoaded;
/** @brief The player's present state. */
PlayerState *m_pPlayerState;
/** @brief The player's present stage stats. */
PlayerStageStats *m_pPlayerStageStats;
TimingData *m_Timing;
float m_fNoteFieldHeight;
bool m_bPaused;
bool m_bDelay;
NoteData &m_NoteData;
NoteField *m_pNoteField;
vector<HoldJudgment*> m_vpHoldJudgment;
AutoActor m_sprJudgment;
AutoActor m_sprCombo;
Actor *m_pActorWithJudgmentPosition;
Actor *m_pActorWithComboPosition;
AttackDisplay *m_pAttackDisplay;
TapNoteScore m_LastTapNoteScore;
LifeMeter *m_pLifeMeter;
CombinedLifeMeter *m_pCombinedLifeMeter;
ScoreDisplay *m_pScoreDisplay;
ScoreDisplay *m_pSecondaryScoreDisplay;
ScoreKeeper *m_pPrimaryScoreKeeper;
ScoreKeeper *m_pSecondaryScoreKeeper;
Inventory *m_pInventory;
int m_iFirstUncrossedRow; // used by hold checkpoints logic
NoteData::all_tracks_iterator *m_pIterNeedsTapJudging;
NoteData::all_tracks_iterator *m_pIterNeedsHoldJudging;
NoteData::all_tracks_iterator *m_pIterUncrossedRows;
NoteData::all_tracks_iterator *m_pIterUnjudgedRows;
NoteData::all_tracks_iterator *m_pIterUnjudgedMineRows;
int m_iLastSeenCombo;
JudgedRows *m_pJudgedRows;
RageSound m_soundMine;
RageSound m_soundAttackLaunch;
RageSound m_soundAttackEnding;
float m_fActiveRandomAttackStart;
vector<bool> m_vbFretIsDown;
vector<RageSound> m_vKeysounds;
ThemeMetric<float> GRAY_ARROWS_Y_STANDARD;
ThemeMetric<float> GRAY_ARROWS_Y_REVERSE;
ThemeMetric2D<float> ATTACK_DISPLAY_X;
ThemeMetric<float> ATTACK_DISPLAY_Y;
ThemeMetric<float> ATTACK_DISPLAY_Y_REVERSE;
ThemeMetric<float> HOLD_JUDGMENT_Y_STANDARD;
ThemeMetric<float> HOLD_JUDGMENT_Y_REVERSE;
ThemeMetric<int> BRIGHT_GHOST_COMBO_THRESHOLD;
ThemeMetric<bool> TAP_JUDGMENTS_UNDER_FIELD;
ThemeMetric<bool> HOLD_JUDGMENTS_UNDER_FIELD;
ThemeMetric<bool> COMBO_UNDER_FIELD;
ThemeMetric<int> DRAW_DISTANCE_AFTER_TARGET_PIXELS;
ThemeMetric<int> DRAW_DISTANCE_BEFORE_TARGET_PIXELS;
#define NUM_REVERSE 2
#define NUM_CENTERED 2
TweenState m_tsJudgment[NUM_REVERSE][NUM_CENTERED];
TweenState m_tsCombo[NUM_REVERSE][NUM_CENTERED];
bool m_bSendJudgmentAndComboMessages;
};
class PlayerPlus
{
Player *m_pPlayer;
NoteData m_NoteData;
public:
PlayerPlus() { m_pPlayer = new Player(m_NoteData); }
~PlayerPlus() { delete m_pPlayer; }
void Load( const NoteData &nd ) { m_NoteData = nd; m_pPlayer->Load(); }
Player *operator->() { return m_pPlayer; }
const Player *operator->() const { return m_pPlayer; }
operator Player*() { return m_pPlayer; }
operator const Player*() const { return m_pPlayer; }
};
#endif
/*
* (c) 2001-2006 Chris Danford, Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+3 -3
View File
@@ -282,7 +282,7 @@ void PlayerOptions::FromString( const RString &sMultipleMods )
bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut )
{
ASSERT_M( NOTESKIN != NULL, "The Noteskin Manager must be loaded in order to process mods." );
ASSERT_M( NOTESKIN != nullptr, "The Noteskin Manager must be loaded in order to process mods." );
RString sBit = sOneMod;
sBit.MakeLower();
@@ -764,8 +764,8 @@ bool PlayerOptions::IsEasierForSongAndSteps( Song* pSong, Steps* pSteps, PlayerN
bool PlayerOptions::IsEasierForCourseAndTrail( Course* pCourse, Trail* pTrail ) const
{
ASSERT( pCourse != NULL );
ASSERT( pTrail != NULL );
ASSERT( pCourse != nullptr );
ASSERT( pTrail != nullptr );
return std::any_of(pTrail->m_vEntries.begin(), pTrail->m_vEntries.end(), [&](TrailEntry const &e) {
return e.pSong && IsEasierForSongAndSteps(e.pSong, e.pSteps, PLAYER_1);
+1 -1
View File
@@ -40,7 +40,7 @@ void IPreference::LoadAllDefaults()
void IPreference::ReadAllPrefsFromNode( const XNode* pNode, bool bIsStatic )
{
ASSERT( pNode != NULL );
ASSERT( pNode != nullptr );
for (IPreference *p : *m_Subscribers.m_pSubscribers)
p->ReadFrom( pNode, bIsStatic );
}
+6 -6
View File
@@ -1367,7 +1367,7 @@ XNode* Profile::SaveSongScoresCreateNode() const
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
XNode* pNode = new XNode( "SongScores" );
@@ -1448,7 +1448,7 @@ XNode* Profile::SaveCourseScoresCreateNode() const
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
XNode* pNode = new XNode( "CourseScores" );
@@ -1556,7 +1556,7 @@ XNode* Profile::SaveCategoryScoresCreateNode() const
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
XNode* pNode = new XNode( "CategoryScores" );
@@ -1628,7 +1628,7 @@ void Profile::LoadCategoryScoresFromNode( const XNode* pCategoryScores )
void Profile::SaveStatsWebPageToDir( RString sDir ) const
{
ASSERT( PROFILEMAN != NULL );
ASSERT( PROFILEMAN != nullptr );
}
void Profile::SaveMachinePublicKeyToDir( RString sDir ) const
@@ -1664,7 +1664,7 @@ XNode* Profile::SaveScreenshotDataCreateNode() const
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
XNode* pNode = new XNode( "ScreenshotData" );
@@ -1706,7 +1706,7 @@ XNode* Profile::SaveCalorieDataCreateNode() const
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
XNode* pNode = new XNode( "CalorieData" );
+7 -7
View File
@@ -114,12 +114,12 @@ void ProfileManager::Init()
{
RString sCharacterID = FIXED_PROFILE_CHARACTER_ID( i );
Character *pCharacter = CHARMAN->GetCharacterFromID( sCharacterID );
ASSERT_M( pCharacter != NULL, sCharacterID );
ASSERT_M( pCharacter != nullptr, sCharacterID );
RString sProfileID;
bool b = CreateLocalProfile( pCharacter->GetDisplayName(), sProfileID );
ASSERT( b );
Profile* pProfile = GetLocalProfile( sProfileID );
ASSERT_M( pProfile != NULL, sProfileID );
ASSERT_M( pProfile != nullptr, sProfileID );
pProfile->m_sCharacterID = sCharacterID;
SaveLocalProfile( sProfileID );
}
@@ -341,7 +341,7 @@ bool ProfileManager::SaveProfile( PlayerNumber pn ) const
bool ProfileManager::SaveLocalProfile( RString sProfileID )
{
const Profile *pProfile = GetLocalProfile( sProfileID );
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
RString sDir = LocalProfileIDToDir( sProfileID );
bool b = pProfile->SaveAllToDir( sDir, PREFSMAN->m_bSignProfileData );
return b;
@@ -473,7 +473,7 @@ bool ProfileManager::RenameLocalProfile( RString sProfileID, RString sNewName )
ASSERT( !sProfileID.empty() );
Profile *pProfile = ProfileManager::GetLocalProfile( sProfileID );
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
pProfile->m_sDisplayName = sNewName;
RString sProfileDir = LocalProfileIDToDir( sProfileID );
@@ -483,7 +483,7 @@ bool ProfileManager::RenameLocalProfile( RString sProfileID, RString sNewName )
bool ProfileManager::DeleteLocalProfile( RString sProfileID )
{
Profile *pProfile = ProfileManager::GetLocalProfile( sProfileID );
ASSERT( pProfile != NULL );
ASSERT( pProfile != nullptr );
RString sProfileDir = LocalProfileIDToDir( sProfileID );
// flush directory cache in an attempt to get this working
@@ -821,7 +821,7 @@ class LunaProfileManager: public Luna<ProfileManager>
{
public:
static int IsPersistentProfile( T* p, lua_State *L ) { lua_pushboolean(L, p->IsPersistentProfile(Enum::Check<PlayerNumber>(L, 1)) ); return 1; }
static int GetProfile( T* p, lua_State *L ) { PlayerNumber pn = Enum::Check<PlayerNumber>(L, 1); Profile* pP = p->GetProfile(pn); ASSERT(pP != NULL); pP->PushSelf(L); return 1; }
static int GetProfile( T* p, lua_State *L ) { PlayerNumber pn = Enum::Check<PlayerNumber>(L, 1); Profile* pP = p->GetProfile(pn); ASSERT(pP != nullptr); pP->PushSelf(L); return 1; }
static int GetMachineProfile( T* p, lua_State *L ) { p->GetMachineProfile()->PushSelf(L); return 1; }
static int SaveMachineProfile( T* p, lua_State * ) { p->SaveMachineProfile(); return 0; }
static int GetLocalProfile( T* p, lua_State *L )
@@ -833,7 +833,7 @@ public:
lua_pushnil(L);
return 1;
}
static int GetLocalProfileFromIndex( T* p, lua_State *L ) { Profile *pProfile = p->GetLocalProfileFromIndex(IArg(1)); ASSERT(pProfile != NULL); pProfile->PushSelf(L); return 1; }
static int GetLocalProfileFromIndex( T* p, lua_State *L ) { Profile *pProfile = p->GetLocalProfileFromIndex(IArg(1)); ASSERT(pProfile != nullptr); pProfile->PushSelf(L); return 1; }
static int GetLocalProfileIDFromIndex( T* p, lua_State *L ) { lua_pushstring(L, p->GetLocalProfileIDFromIndex(IArg(1)) ); return 1; }
static int GetLocalProfileIndexFromID( T* p, lua_State *L ) { lua_pushnumber(L, p->GetLocalProfileIndexFromID(SArg(1)) ); return 1; }
static int GetNumLocalProfiles( T* p, lua_State *L ) { lua_pushnumber(L, p->GetNumLocalProfiles() ); return 1; }
+361 -361
View File
@@ -1,361 +1,361 @@
#include "global.h"
#include "RageBitmapTexture.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageTextureManager.h"
#include "RageDisplay.h"
#include "RageTypes.h"
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "RageSurfaceUtils_Zoom.h"
#include "RageSurfaceUtils_Dither.h"
#include "RageSurface_Load.h"
#include "arch/Dialog/Dialog.h"
#include "StepMania.h"
static void GetResolutionFromFileName( RString sPath, int &iWidth, int &iHeight )
{
/* Match:
* Foo (res 512x128).png
* Also allow, eg:
* Foo (dither, res 512x128).png
* Be careful that this doesn't get mixed up with frame dimensions. */
static Regex re( "\\([^\\)]*res ([0-9]+)x([0-9]+).*\\)" );
vector<RString> asMatches;
if( !re.Compare(sPath, asMatches) )
return;
iWidth = StringToInt( asMatches[0] );
iHeight = StringToInt( asMatches[1] );
}
RageBitmapTexture::RageBitmapTexture( RageTextureID name ) :
RageTexture( name ), m_uTexHandle(0)
{
Create();
}
RageBitmapTexture::~RageBitmapTexture()
{
Destroy();
}
void RageBitmapTexture::Reload()
{
Destroy();
Create();
}
/*
* Each dwMaxSize, dwTextureColorDepth and iAlphaBits are maximums; we may
* use less. iAlphaBits must be 0, 1 or 4.
*
* XXX: change iAlphaBits == 4 to iAlphaBits == 8 to indicate "as much alpha
* as needed", since that's what it really is; still only use 4 in 16-bit textures.
*
* Dither forces dithering when loading 16-bit textures.
* Stretch forces the loaded image to fill the texture completely.
*/
void RageBitmapTexture::Create()
{
RageTextureID actualID = GetID();
ASSERT( actualID.filename != "" );
/* Load the image into a RageSurface. */
RString error;
RageSurface *pImg = RageSurfaceUtils::LoadFile( actualID.filename, error );
/* Tolerate corrupt/unknown images. */
if( pImg == NULL )
{
RString sWarning = ssprintf( "RageBitmapTexture: Couldn't load %s: %s", actualID.filename.c_str(), error.c_str() );
Dialog::OK( sWarning );
pImg = RageSurfaceUtils::MakeDummySurface( 64, 64 );
ASSERT( pImg != NULL );
}
if( actualID.bHotPinkColorKey )
RageSurfaceUtils::ApplyHotPinkColorKey( pImg );
{
/* Do this after setting the color key for paletted images; it'll also return
* TRAIT_NO_TRANSPARENCY if the color key is never used. */
int iTraits = RageSurfaceUtils::FindSurfaceTraits( pImg );
if( iTraits & RageSurfaceUtils::TRAIT_NO_TRANSPARENCY )
actualID.iAlphaBits = 0;
else if( iTraits & RageSurfaceUtils::TRAIT_BOOL_TRANSPARENCY )
actualID.iAlphaBits = 1;
}
// look in the file name for a format hints
RString sHintString = GetID().filename + actualID.AdditionalTextureHints;
sHintString.MakeLower();
if( sHintString.find("32bpp") != string::npos ) actualID.iColorDepth = 32;
else if( sHintString.find("16bpp") != string::npos ) actualID.iColorDepth = 16;
if( sHintString.find("dither") != string::npos ) actualID.bDither = true;
if( sHintString.find("stretch") != string::npos ) actualID.bStretch = true;
if( sHintString.find("mipmaps") != string::npos ) actualID.bMipMaps = true;
if( sHintString.find("nomipmaps") != string::npos ) actualID.bMipMaps = false; // check for "nomipmaps" after "mipmaps"
/* If the image is marked grayscale, then use all bits not used for alpha
* for the intensity. This way, if an image has no alpha, you get an 8-bit
* grayscale; if it only has boolean transparency, you get a 7-bit grayscale. */
if( sHintString.find("grayscale") != string::npos ) actualID.iGrayscaleBits = 8-actualID.iAlphaBits;
/* This indicates that the only component in the texture is alpha; assume all
* color is white. */
if( sHintString.find("alphamap") != string::npos ) actualID.iGrayscaleBits = 0;
/* No iGrayscaleBits for images that are already paletted. We don't support
* that; and that hint is intended for use on images that are already grayscale,
* it's not intended to change a color image into a grayscale image. */
if( actualID.iGrayscaleBits != -1 && pImg->format->BitsPerPixel == 8 )
actualID.iGrayscaleBits = -1;
/* Cap the max texture size to the hardware max. */
actualID.iMaxSize = min( actualID.iMaxSize, DISPLAY->GetMaxTextureSize() );
/* Save information about the source. */
m_iSourceWidth = pImg->w;
m_iSourceHeight = pImg->h;
/* in-game imsage dimensions are the same as the source graphic */
m_iImageWidth = m_iSourceWidth;
m_iImageHeight = m_iSourceHeight;
/* if "doubleres" (high resolution) and we're not allowing high res textures, then image dimensions are half of the source */
if( sHintString.find("doubleres") != string::npos )
{
if( !StepMania::GetHighResolutionTextures() )
{
m_iImageWidth = m_iImageWidth / 2;
m_iImageHeight = m_iImageHeight / 2;
}
}
/* image size cannot exceed max size */
m_iImageWidth = min( m_iImageWidth, actualID.iMaxSize );
m_iImageHeight = min( m_iImageHeight, actualID.iMaxSize );
/* Texture dimensions need to be a power of two; jump to the next. */
m_iTextureWidth = power_of_two(m_iImageWidth);
m_iTextureHeight = power_of_two(m_iImageHeight);
/* If we're under 8x8, increase it, to avoid filtering problems on odd hardware. */
if( m_iTextureWidth < 8 || m_iTextureHeight < 8 )
{
actualID.bStretch = true;
m_iTextureWidth = max( 8, m_iTextureWidth );
m_iTextureHeight = max( 8, m_iTextureHeight );
}
ASSERT_M( m_iTextureWidth <= actualID.iMaxSize, ssprintf("w %i, %i", m_iTextureWidth, actualID.iMaxSize) );
ASSERT_M( m_iTextureHeight <= actualID.iMaxSize, ssprintf("h %i, %i", m_iTextureHeight, actualID.iMaxSize) );
if( actualID.bStretch )
{
/* The hints asked for the image to be stretched to the texture size,
* probably for tiling. */
m_iImageWidth = m_iTextureWidth;
m_iImageHeight = m_iTextureHeight;
}
if( pImg->w != m_iImageWidth || pImg->h != m_iImageHeight )
RageSurfaceUtils::Zoom( pImg, m_iImageWidth, m_iImageHeight );
if( actualID.iGrayscaleBits != -1 && DISPLAY->SupportsTextureFormat(RagePixelFormat_PAL) )
{
RageSurface *pGrayscale = RageSurfaceUtils::PalettizeToGrayscale( pImg, actualID.iGrayscaleBits, actualID.iAlphaBits );
delete pImg;
pImg = pGrayscale;
}
// Figure out which texture format we want the renderer to use.
RagePixelFormat pixfmt;
// If the source is palleted, always load as paletted if supported.
if( pImg->format->BitsPerPixel == 8 && DISPLAY->SupportsTextureFormat(RagePixelFormat_PAL) )
{
pixfmt = RagePixelFormat_PAL;
}
else
{
// not paletted
switch( actualID.iColorDepth )
{
case 16:
{
// Bits of alpha in the source:
int iSourceAlphaBits = 8 - pImg->format->Loss[3];
// Don't use more than we were hinted to.
iSourceAlphaBits = min( actualID.iAlphaBits, iSourceAlphaBits );
switch( iSourceAlphaBits )
{
case 0:
case 1:
pixfmt = RagePixelFormat_RGB5A1;
break;
default:
pixfmt = RagePixelFormat_RGBA4;
break;
}
}
break;
case 32:
pixfmt = RagePixelFormat_RGBA8;
break;
default: FAIL_M( ssprintf("%i", actualID.iColorDepth) );
}
}
// Make we're using a supported format. Every card supports either RGBA8 or RGBA4.
if( !DISPLAY->SupportsTextureFormat(pixfmt) )
{
pixfmt = RagePixelFormat_RGBA8;
if( !DISPLAY->SupportsTextureFormat(pixfmt) )
pixfmt = RagePixelFormat_RGBA4;
}
/* Dither if appropriate.
* XXX: This is a special case: don't bother dithering to RGBA8888.
* We actually want to dither only if the destination has greater color depth
* on at least one color channel than the source. For example, it doesn't
* make sense to do this when pixfmt is RGBA5551 if the image is only RGBA555. */
if( actualID.bDither &&
(pixfmt==RagePixelFormat_RGBA4 || pixfmt==RagePixelFormat_RGB5A1) )
{
// Dither down to the destination format.
const RageDisplay::RagePixelFormatDesc *pfd = DISPLAY->GetPixelFormatDesc(pixfmt);
RageSurface *dst = CreateSurface( pImg->w, pImg->h, pfd->bpp,
pfd->masks[0], pfd->masks[1], pfd->masks[2], pfd->masks[3] );
RageSurfaceUtils::ErrorDiffusionDither( pImg, dst );
delete pImg;
pImg = dst;
}
/* This needs to be done *after* the final resize, since that resize
* may introduce new alpha bits that need to be set. It needs to be
* done *before* we set up the palette, since it might change it. */
RageSurfaceUtils::FixHiddenAlpha( pImg );
/* Scale up to the texture size, if needed. */
RageSurfaceUtils::ConvertSurface( pImg, m_iTextureWidth, m_iTextureHeight,
pImg->fmt.BitsPerPixel, pImg->fmt.Mask[0], pImg->fmt.Mask[1], pImg->fmt.Mask[2], pImg->fmt.Mask[3] );
m_uTexHandle = DISPLAY->CreateTexture( pixfmt, pImg, actualID.bMipMaps );
CreateFrameRects();
{
// Enforce frames in the image have even dimensions.
// Otherwise, pixel/texel alignment will be off.
int iDimensionMultiple = 2;
if( sHintString.find("doubleres") != string::npos )
{
iDimensionMultiple = 4;
}
bool bRunCheck = true;
// Don't check if the artist intentionally blanked the image by making it very tiny.
if( this->GetSourceWidth()<=iDimensionMultiple || this->GetSourceHeight()<=iDimensionMultiple )
bRunCheck = false;
// HACK: Don't check song graphics. Many of them are weird dimensions.
if( !TEXTUREMAN->GetOddDimensionWarning() )
bRunCheck = false;
if( bRunCheck )
{
float fFrameWidth = this->GetSourceWidth() / (float)this->GetFramesWide();
float fFrameHeight = this->GetSourceHeight() / (float)this->GetFramesHigh();
float fBetterFrameWidth = ceilf(fFrameWidth/iDimensionMultiple) * iDimensionMultiple;
float fBetterFrameHeight = ceilf(fFrameHeight/iDimensionMultiple) * iDimensionMultiple;
float fBetterSourceWidth = this->GetFramesWide() * fBetterFrameWidth;
float fBetterSourceHeight = this->GetFramesHigh() * fBetterFrameHeight;
if( fFrameWidth!=fBetterFrameWidth || fFrameHeight!=fBetterFrameHeight )
{
RString sWarning = ssprintf(
"The graphic '%s' has frame dimensions that aren't a multiple of %d.\n"
"The entire image is %dx%d and frame size is %.1fx%.1f.\n"
"Image quality will be much improved if you resize the graphic to %.0fx%.0f, which is a frame size of %.0fx%.0f.",
actualID.filename.c_str(),
iDimensionMultiple,
this->GetSourceWidth(), this->GetSourceHeight(),
fFrameWidth, fFrameHeight,
fBetterSourceWidth, fBetterSourceHeight,
fBetterFrameWidth, fBetterFrameHeight );
LOG->Warn( "%s", sWarning.c_str() );
Dialog::OK( sWarning, "FRAME_DIMENSIONS_WARNING" );
}
}
}
delete pImg;
// Check for hints that override the apparent "size".
GetResolutionFromFileName( actualID.filename, m_iSourceWidth, m_iSourceHeight );
/* if "doubleres" (high resolution) then we want the image to appear in-game
* with dimensions 1/2 of the source. So, cut down the source dimension here
* after everything above is finished operating with the real image
* source dimensions. */
if( sHintString.find("doubleres") != string::npos )
{
m_iSourceWidth = m_iSourceWidth / 2;
m_iSourceHeight = m_iSourceHeight / 2;
}
RString sProperties;
sProperties += RagePixelFormatToString( pixfmt ) + " ";
if( actualID.iAlphaBits == 0 ) sProperties += "opaque ";
if( actualID.iAlphaBits == 1 ) sProperties += "matte ";
if( actualID.bStretch ) sProperties += "stretch ";
if( actualID.bDither ) sProperties += "dither ";
sProperties.erase( sProperties.size()-1 );
LOG->Trace( "RageBitmapTexture: Loaded '%s' (%ux%u); %s, source %d,%d; image %d,%d.",
actualID.filename.c_str(), GetTextureWidth(), GetTextureHeight(),
sProperties.c_str(), m_iSourceWidth, m_iSourceHeight,
m_iImageWidth, m_iImageHeight );
}
void RageBitmapTexture::Destroy()
{
DISPLAY->DeleteTexture( m_uTexHandle );
}
/*
* Copyright (c) 2001-2004 Chris Danford, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageBitmapTexture.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageTextureManager.h"
#include "RageDisplay.h"
#include "RageTypes.h"
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "RageSurfaceUtils_Zoom.h"
#include "RageSurfaceUtils_Dither.h"
#include "RageSurface_Load.h"
#include "arch/Dialog/Dialog.h"
#include "StepMania.h"
static void GetResolutionFromFileName( RString sPath, int &iWidth, int &iHeight )
{
/* Match:
* Foo (res 512x128).png
* Also allow, eg:
* Foo (dither, res 512x128).png
* Be careful that this doesn't get mixed up with frame dimensions. */
static Regex re( "\\([^\\)]*res ([0-9]+)x([0-9]+).*\\)" );
vector<RString> asMatches;
if( !re.Compare(sPath, asMatches) )
return;
iWidth = StringToInt( asMatches[0] );
iHeight = StringToInt( asMatches[1] );
}
RageBitmapTexture::RageBitmapTexture( RageTextureID name ) :
RageTexture( name ), m_uTexHandle(0)
{
Create();
}
RageBitmapTexture::~RageBitmapTexture()
{
Destroy();
}
void RageBitmapTexture::Reload()
{
Destroy();
Create();
}
/*
* Each dwMaxSize, dwTextureColorDepth and iAlphaBits are maximums; we may
* use less. iAlphaBits must be 0, 1 or 4.
*
* XXX: change iAlphaBits == 4 to iAlphaBits == 8 to indicate "as much alpha
* as needed", since that's what it really is; still only use 4 in 16-bit textures.
*
* Dither forces dithering when loading 16-bit textures.
* Stretch forces the loaded image to fill the texture completely.
*/
void RageBitmapTexture::Create()
{
RageTextureID actualID = GetID();
ASSERT( actualID.filename != "" );
/* Load the image into a RageSurface. */
RString error;
RageSurface *pImg = RageSurfaceUtils::LoadFile( actualID.filename, error );
/* Tolerate corrupt/unknown images. */
if( pImg == NULL )
{
RString sWarning = ssprintf( "RageBitmapTexture: Couldn't load %s: %s", actualID.filename.c_str(), error.c_str() );
Dialog::OK( sWarning );
pImg = RageSurfaceUtils::MakeDummySurface( 64, 64 );
ASSERT( pImg != nullptr );
}
if( actualID.bHotPinkColorKey )
RageSurfaceUtils::ApplyHotPinkColorKey( pImg );
{
/* Do this after setting the color key for paletted images; it'll also return
* TRAIT_NO_TRANSPARENCY if the color key is never used. */
int iTraits = RageSurfaceUtils::FindSurfaceTraits( pImg );
if( iTraits & RageSurfaceUtils::TRAIT_NO_TRANSPARENCY )
actualID.iAlphaBits = 0;
else if( iTraits & RageSurfaceUtils::TRAIT_BOOL_TRANSPARENCY )
actualID.iAlphaBits = 1;
}
// look in the file name for a format hints
RString sHintString = GetID().filename + actualID.AdditionalTextureHints;
sHintString.MakeLower();
if( sHintString.find("32bpp") != string::npos ) actualID.iColorDepth = 32;
else if( sHintString.find("16bpp") != string::npos ) actualID.iColorDepth = 16;
if( sHintString.find("dither") != string::npos ) actualID.bDither = true;
if( sHintString.find("stretch") != string::npos ) actualID.bStretch = true;
if( sHintString.find("mipmaps") != string::npos ) actualID.bMipMaps = true;
if( sHintString.find("nomipmaps") != string::npos ) actualID.bMipMaps = false; // check for "nomipmaps" after "mipmaps"
/* If the image is marked grayscale, then use all bits not used for alpha
* for the intensity. This way, if an image has no alpha, you get an 8-bit
* grayscale; if it only has boolean transparency, you get a 7-bit grayscale. */
if( sHintString.find("grayscale") != string::npos ) actualID.iGrayscaleBits = 8-actualID.iAlphaBits;
/* This indicates that the only component in the texture is alpha; assume all
* color is white. */
if( sHintString.find("alphamap") != string::npos ) actualID.iGrayscaleBits = 0;
/* No iGrayscaleBits for images that are already paletted. We don't support
* that; and that hint is intended for use on images that are already grayscale,
* it's not intended to change a color image into a grayscale image. */
if( actualID.iGrayscaleBits != -1 && pImg->format->BitsPerPixel == 8 )
actualID.iGrayscaleBits = -1;
/* Cap the max texture size to the hardware max. */
actualID.iMaxSize = min( actualID.iMaxSize, DISPLAY->GetMaxTextureSize() );
/* Save information about the source. */
m_iSourceWidth = pImg->w;
m_iSourceHeight = pImg->h;
/* in-game imsage dimensions are the same as the source graphic */
m_iImageWidth = m_iSourceWidth;
m_iImageHeight = m_iSourceHeight;
/* if "doubleres" (high resolution) and we're not allowing high res textures, then image dimensions are half of the source */
if( sHintString.find("doubleres") != string::npos )
{
if( !StepMania::GetHighResolutionTextures() )
{
m_iImageWidth = m_iImageWidth / 2;
m_iImageHeight = m_iImageHeight / 2;
}
}
/* image size cannot exceed max size */
m_iImageWidth = min( m_iImageWidth, actualID.iMaxSize );
m_iImageHeight = min( m_iImageHeight, actualID.iMaxSize );
/* Texture dimensions need to be a power of two; jump to the next. */
m_iTextureWidth = power_of_two(m_iImageWidth);
m_iTextureHeight = power_of_two(m_iImageHeight);
/* If we're under 8x8, increase it, to avoid filtering problems on odd hardware. */
if( m_iTextureWidth < 8 || m_iTextureHeight < 8 )
{
actualID.bStretch = true;
m_iTextureWidth = max( 8, m_iTextureWidth );
m_iTextureHeight = max( 8, m_iTextureHeight );
}
ASSERT_M( m_iTextureWidth <= actualID.iMaxSize, ssprintf("w %i, %i", m_iTextureWidth, actualID.iMaxSize) );
ASSERT_M( m_iTextureHeight <= actualID.iMaxSize, ssprintf("h %i, %i", m_iTextureHeight, actualID.iMaxSize) );
if( actualID.bStretch )
{
/* The hints asked for the image to be stretched to the texture size,
* probably for tiling. */
m_iImageWidth = m_iTextureWidth;
m_iImageHeight = m_iTextureHeight;
}
if( pImg->w != m_iImageWidth || pImg->h != m_iImageHeight )
RageSurfaceUtils::Zoom( pImg, m_iImageWidth, m_iImageHeight );
if( actualID.iGrayscaleBits != -1 && DISPLAY->SupportsTextureFormat(RagePixelFormat_PAL) )
{
RageSurface *pGrayscale = RageSurfaceUtils::PalettizeToGrayscale( pImg, actualID.iGrayscaleBits, actualID.iAlphaBits );
delete pImg;
pImg = pGrayscale;
}
// Figure out which texture format we want the renderer to use.
RagePixelFormat pixfmt;
// If the source is palleted, always load as paletted if supported.
if( pImg->format->BitsPerPixel == 8 && DISPLAY->SupportsTextureFormat(RagePixelFormat_PAL) )
{
pixfmt = RagePixelFormat_PAL;
}
else
{
// not paletted
switch( actualID.iColorDepth )
{
case 16:
{
// Bits of alpha in the source:
int iSourceAlphaBits = 8 - pImg->format->Loss[3];
// Don't use more than we were hinted to.
iSourceAlphaBits = min( actualID.iAlphaBits, iSourceAlphaBits );
switch( iSourceAlphaBits )
{
case 0:
case 1:
pixfmt = RagePixelFormat_RGB5A1;
break;
default:
pixfmt = RagePixelFormat_RGBA4;
break;
}
}
break;
case 32:
pixfmt = RagePixelFormat_RGBA8;
break;
default: FAIL_M( ssprintf("%i", actualID.iColorDepth) );
}
}
// Make we're using a supported format. Every card supports either RGBA8 or RGBA4.
if( !DISPLAY->SupportsTextureFormat(pixfmt) )
{
pixfmt = RagePixelFormat_RGBA8;
if( !DISPLAY->SupportsTextureFormat(pixfmt) )
pixfmt = RagePixelFormat_RGBA4;
}
/* Dither if appropriate.
* XXX: This is a special case: don't bother dithering to RGBA8888.
* We actually want to dither only if the destination has greater color depth
* on at least one color channel than the source. For example, it doesn't
* make sense to do this when pixfmt is RGBA5551 if the image is only RGBA555. */
if( actualID.bDither &&
(pixfmt==RagePixelFormat_RGBA4 || pixfmt==RagePixelFormat_RGB5A1) )
{
// Dither down to the destination format.
const RageDisplay::RagePixelFormatDesc *pfd = DISPLAY->GetPixelFormatDesc(pixfmt);
RageSurface *dst = CreateSurface( pImg->w, pImg->h, pfd->bpp,
pfd->masks[0], pfd->masks[1], pfd->masks[2], pfd->masks[3] );
RageSurfaceUtils::ErrorDiffusionDither( pImg, dst );
delete pImg;
pImg = dst;
}
/* This needs to be done *after* the final resize, since that resize
* may introduce new alpha bits that need to be set. It needs to be
* done *before* we set up the palette, since it might change it. */
RageSurfaceUtils::FixHiddenAlpha( pImg );
/* Scale up to the texture size, if needed. */
RageSurfaceUtils::ConvertSurface( pImg, m_iTextureWidth, m_iTextureHeight,
pImg->fmt.BitsPerPixel, pImg->fmt.Mask[0], pImg->fmt.Mask[1], pImg->fmt.Mask[2], pImg->fmt.Mask[3] );
m_uTexHandle = DISPLAY->CreateTexture( pixfmt, pImg, actualID.bMipMaps );
CreateFrameRects();
{
// Enforce frames in the image have even dimensions.
// Otherwise, pixel/texel alignment will be off.
int iDimensionMultiple = 2;
if( sHintString.find("doubleres") != string::npos )
{
iDimensionMultiple = 4;
}
bool bRunCheck = true;
// Don't check if the artist intentionally blanked the image by making it very tiny.
if( this->GetSourceWidth()<=iDimensionMultiple || this->GetSourceHeight()<=iDimensionMultiple )
bRunCheck = false;
// HACK: Don't check song graphics. Many of them are weird dimensions.
if( !TEXTUREMAN->GetOddDimensionWarning() )
bRunCheck = false;
if( bRunCheck )
{
float fFrameWidth = this->GetSourceWidth() / (float)this->GetFramesWide();
float fFrameHeight = this->GetSourceHeight() / (float)this->GetFramesHigh();
float fBetterFrameWidth = ceilf(fFrameWidth/iDimensionMultiple) * iDimensionMultiple;
float fBetterFrameHeight = ceilf(fFrameHeight/iDimensionMultiple) * iDimensionMultiple;
float fBetterSourceWidth = this->GetFramesWide() * fBetterFrameWidth;
float fBetterSourceHeight = this->GetFramesHigh() * fBetterFrameHeight;
if( fFrameWidth!=fBetterFrameWidth || fFrameHeight!=fBetterFrameHeight )
{
RString sWarning = ssprintf(
"The graphic '%s' has frame dimensions that aren't a multiple of %d.\n"
"The entire image is %dx%d and frame size is %.1fx%.1f.\n"
"Image quality will be much improved if you resize the graphic to %.0fx%.0f, which is a frame size of %.0fx%.0f.",
actualID.filename.c_str(),
iDimensionMultiple,
this->GetSourceWidth(), this->GetSourceHeight(),
fFrameWidth, fFrameHeight,
fBetterSourceWidth, fBetterSourceHeight,
fBetterFrameWidth, fBetterFrameHeight );
LOG->Warn( "%s", sWarning.c_str() );
Dialog::OK( sWarning, "FRAME_DIMENSIONS_WARNING" );
}
}
}
delete pImg;
// Check for hints that override the apparent "size".
GetResolutionFromFileName( actualID.filename, m_iSourceWidth, m_iSourceHeight );
/* if "doubleres" (high resolution) then we want the image to appear in-game
* with dimensions 1/2 of the source. So, cut down the source dimension here
* after everything above is finished operating with the real image
* source dimensions. */
if( sHintString.find("doubleres") != string::npos )
{
m_iSourceWidth = m_iSourceWidth / 2;
m_iSourceHeight = m_iSourceHeight / 2;
}
RString sProperties;
sProperties += RagePixelFormatToString( pixfmt ) + " ";
if( actualID.iAlphaBits == 0 ) sProperties += "opaque ";
if( actualID.iAlphaBits == 1 ) sProperties += "matte ";
if( actualID.bStretch ) sProperties += "stretch ";
if( actualID.bDither ) sProperties += "dither ";
sProperties.erase( sProperties.size()-1 );
LOG->Trace( "RageBitmapTexture: Loaded '%s' (%ux%u); %s, source %d,%d; image %d,%d.",
actualID.filename.c_str(), GetTextureWidth(), GetTextureHeight(),
sProperties.c_str(), m_iSourceWidth, m_iSourceHeight,
m_iImageWidth, m_iImageHeight );
}
void RageBitmapTexture::Destroy()
{
DISPLAY->DeleteTexture( m_uTexHandle );
}
/*
* Copyright (c) 2001-2004 Chris Danford, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1472 -1472
View File
File diff suppressed because it is too large Load Diff
+1005 -1005
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1359,7 +1359,7 @@ void RageCompiledGeometryHWOGL::Draw( int iMeshIndex ) const
#define BUFFER_OFFSET(o) ((char*)(o))
ASSERT( glDrawRangeElements != NULL );
ASSERT( glDrawRangeElements != nullptr );
glDrawRangeElements(
GL_TRIANGLES,
meshInfo.iVertexStart, // minimum array index contained in indices
@@ -1735,7 +1735,7 @@ void RageDisplay_Legacy::SetBlendMode( BlendMode mode )
{
glEnable(GL_BLEND);
if (glBlendEquation != NULL)
if (glBlendEquation != nullptr)
{
if (mode == BLEND_INVERT_DEST)
glBlendEquation( GL_FUNC_SUBTRACT );
@@ -2487,7 +2487,7 @@ void RageDisplay_Legacy::SetRenderTarget( unsigned iTexture, bool bPreserveTextu
}
/* If we already had a render target, disable it. */
if (g_pCurrentRenderTarget != NULL)
if (g_pCurrentRenderTarget != nullptr)
SetRenderTarget(0, true);
/* Enable the new render target. */
+1 -1
View File
@@ -55,7 +55,7 @@ void RageException::Throw( const char *sFmt, ... )
ASSERT_M( g_HandlerThreadID == RageThread::GetInvalidThreadID() || g_HandlerThreadID == RageThread::GetCurrentThreadID(),
ssprintf("RageException::Throw() on another thread: %s", error.c_str()) );
if( g_CleanupHandler != NULL )
if( g_CleanupHandler != nullptr )
g_CleanupHandler( error );
exit(1);
+468 -468
View File
@@ -1,468 +1,468 @@
/*
* This provides an interface to open files in RageFileManager's namespace
* This is just a simple RageFileBasic wrapper on top of another RageFileBasic;
* when a file is open, is acts like the underlying RageFileBasic, except that
* a few extra sanity checks are made to check file modes.
*/
#include "global.h"
#include "RageFileBasic.h"
#include "RageFile.h"
#include "RageUtil.h"
#include "RageFileDriver.h"
RageFile::RageFile()
{
m_File = NULL;
}
RageFile::RageFile( const RageFile &cpy ):
RageFileBasic( cpy )
{
/* This will copy the file driver, including its internal file pointer. */
m_File = cpy.m_File->Copy();
m_Path = cpy.m_Path;
m_Mode = cpy.m_Mode;
}
RageFile *RageFile::Copy() const
{
return new RageFile( *this );
}
RString RageFile::GetPath() const
{
if ( !IsOpen() )
return RString();
RString sRet = m_File->GetDisplayPath();
if( sRet != "" )
return sRet;
return GetRealPath();
}
bool RageFile::Open( const RString& path, int mode )
{
ASSERT( FILEMAN != NULL );
Close();
m_Path = path;
FixSlashesInPlace(m_Path);
m_Mode = mode;
if( (m_Mode&READ) && (m_Mode&WRITE) )
{
SetError( "Reading and writing are mutually exclusive" );
return false;
}
if( !(m_Mode&READ) && !(m_Mode&WRITE) )
{
SetError( "Neither reading nor writing specified" );
return false;
}
int error;
m_File = FILEMAN->Open( path, mode, error );
if( m_File == NULL )
{
SetError( strerror(error) );
return false;
}
return true;
}
void RageFile::Close()
{
if( m_File == NULL )
return;
delete m_File;
if( m_Mode & WRITE )
FILEMAN->CacheFile( m_File, m_Path );
m_File = NULL;
}
#define ASSERT_OPEN ASSERT_M( IsOpen(), ssprintf("\"%s\" is not open.", m_Path.c_str()) );
#define ASSERT_READ ASSERT_OPEN; ASSERT_M( !!(m_Mode&READ), ssprintf("\"%s\" is not open for reading", m_Path.c_str()) );
#define ASSERT_WRITE ASSERT_OPEN; ASSERT_M( !!(m_Mode&WRITE), ssprintf("\"%s\" is not open for writing", m_Path.c_str()) );
int RageFile::GetLine( RString &out )
{
ASSERT_READ;
return m_File->GetLine( out );
}
int RageFile::PutLine( const RString &str )
{
ASSERT_WRITE;
return m_File->PutLine( str );
}
void RageFile::EnableCRC32( bool on )
{
ASSERT_OPEN;
m_File->EnableCRC32( on );
}
bool RageFile::GetCRC32( uint32_t *iRet )
{
ASSERT_OPEN;
return m_File->GetCRC32( iRet );
}
bool RageFile::AtEOF() const
{
ASSERT_READ;
return m_File->AtEOF();
}
void RageFile::ClearError()
{
if( m_File != NULL )
m_File->ClearError();
m_sError = "";
}
RString RageFile::GetError() const
{
if( m_File != NULL && m_File->GetError() != "" )
return m_File->GetError();
return m_sError;
}
void RageFile::SetError( const RString &err )
{
if( m_File != NULL )
m_File->ClearError();
m_sError = err;
}
int RageFile::Read( void *pBuffer, size_t iBytes )
{
ASSERT_READ;
return m_File->Read( pBuffer, iBytes );
}
int RageFile::Seek( int offset )
{
ASSERT_READ;
return m_File->Seek( offset );
}
int RageFile::Tell() const
{
ASSERT_READ;
return m_File->Tell();
}
int RageFile::GetFileSize() const
{
ASSERT_READ;
return m_File->GetFileSize();
}
int RageFile::GetFD()
{
ASSERT_READ;
return m_File->GetFD();
}
int RageFile::Read( RString &buffer, int bytes )
{
ASSERT_READ;
return m_File->Read( buffer, bytes );
}
int RageFile::Write( const void *buffer, size_t bytes )
{
ASSERT_WRITE;
return m_File->Write( buffer, bytes );
}
int RageFile::Write( const void *buffer, size_t bytes, int nmemb )
{
ASSERT_WRITE;
return m_File->Write( buffer, bytes, nmemb );
}
int RageFile::Flush()
{
if( !m_File )
{
SetError( "Not open" );
return -1;
}
return m_File->Flush();
}
int RageFile::Read( void *buffer, size_t bytes, int nmemb )
{
ASSERT_READ;
return m_File->Read( buffer, bytes, nmemb );
}
int RageFile::Seek( int offset, int whence )
{
ASSERT_READ;
return m_File->Seek( offset, whence );
}
void FileReading::ReadBytes( RageFileBasic &f, void *buf, int size, RString &sError )
{
if( sError.size() != 0 )
return;
int ret = f.Read( buf, size );
if( ret == -1 )
sError = f.GetError();
else if( ret < size )
sError = "Unexpected end of file";
}
RString FileReading::ReadString( RageFileBasic &f, int size, RString &sError )
{
if( sError.size() != 0 )
return RString();
RString sBuf;
int ret = f.Read( sBuf, size );
if( ret == -1 )
sError = f.GetError();
else if( ret < size )
sError = "Unexpected end of file";
return sBuf;
}
void FileReading::SkipBytes( RageFileBasic &f, int iBytes, RString &sError )
{
if( sError.size() != 0 )
return;
iBytes += f.Tell();
FileReading::Seek( f, iBytes, sError );
}
void FileReading::Seek( RageFileBasic &f, int iOffset, RString &sError )
{
if( sError.size() != 0 )
return;
int iGot = f.Seek( iOffset );
if( iGot == iOffset )
return;
if( iGot == -1 )
sError = f.GetError();
else if( iGot < iOffset )
sError = "Unexpected end of file";
}
uint8_t FileReading::read_8( RageFileBasic &f, RString &sError )
{
uint8_t val;
ReadBytes( f, &val, sizeof(uint8_t), sError );
if( sError.size() == 0 )
return val;
else
return 0;
}
uint16_t FileReading::read_u16_le( RageFileBasic &f, RString &sError )
{
uint16_t val;
ReadBytes( f, &val, sizeof(uint16_t), sError );
if( sError.size() == 0 )
return Swap16LE( val );
else
return 0;
}
int16_t FileReading::read_16_le( RageFileBasic &f, RString &sError )
{
int16_t val;
ReadBytes( f, &val, sizeof(int16_t), sError );
if( sError.size() == 0 )
return Swap16LE( val );
else
return 0;
}
uint32_t FileReading::read_u32_le( RageFileBasic &f, RString &sError )
{
uint32_t val;
ReadBytes( f, &val, sizeof(uint32_t), sError );
if( sError.size() == 0 )
return Swap32LE( val );
else
return 0;
}
int32_t FileReading::read_32_le( RageFileBasic &f, RString &sError )
{
int32_t val;
ReadBytes( f, &val, sizeof(int32_t), sError );
if( sError.size() == 0 )
return Swap32LE( val );
else
return 0;
}
// lua start
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the RageFile. */
class LunaRageFile: public Luna<RageFile>
{
public:
static int destroy( T* p, lua_State *L )
{
SAFE_DELETE(p);
return 1;
}
static int Open( T* p, lua_State *L )
{
lua_pushboolean( L, p->Open( SArg(1), IArg(2) ) );
return 1;
}
static int Close( T* p, lua_State *L )
{
p->Close();
return 1;
}
static int Write( T* p, lua_State *L )
{
lua_pushinteger( L, p->Write( SArg(1) ) );
return 1;
}
static int Read( T* p, lua_State *L )
{
RString string;
p->Read(string);
lua_pushstring( L, string );
return 1;
}
static int ReadBytes( T* p, lua_State *L )
{
RString string;
p->Read( string, IArg(1) );
lua_pushstring( L, string );
return 1;
}
static int Seek( T* p, lua_State *L )
{
lua_pushinteger( L, p->Seek( IArg(1) ) );
return 1;
}
static int Tell( T* p, lua_State *L )
{
lua_pushinteger( L, p->Tell() );
return 1;
}
static int GetLine( T* p, lua_State *L )
{
RString string;
p->GetLine(string);
lua_pushstring( L, string );
return 1;
}
static int PutLine( T* p, lua_State *L )
{
lua_pushinteger( L, p->PutLine( SArg(1) ) );
return 1;
}
static int GetError( T* p, lua_State *L )
{
RString error;
error = p->GetError();
lua_pushstring( L, error );
return 1;
}
static int ClearError( T* p, lua_State *L )
{
p->ClearError();
return 1;
}
static int AtEOF( T* p, lua_State *L )
{
lua_pushboolean( L, p->AtEOF() );
return 1;
}
LunaRageFile()
{
ADD_METHOD( Open );
ADD_METHOD( Close );
ADD_METHOD( Write );
ADD_METHOD( Read );
ADD_METHOD( ReadBytes );
ADD_METHOD( Seek );
ADD_METHOD( Tell );
ADD_METHOD( GetLine );
ADD_METHOD( PutLine );
ADD_METHOD( destroy );
ADD_METHOD( GetError );
ADD_METHOD( ClearError );
ADD_METHOD( AtEOF );
}
};
LUA_REGISTER_CLASS( RageFile )
/** @brief Utilities for working with RageFiles. */
namespace RageFileUtil
{
int CreateRageFile( lua_State *L )
{
RageFile *pFile = new RageFile;
pFile->PushSelf( L );
return 1;
}
const luaL_Reg RageFileUtilTable[] =
{
LIST_METHOD( CreateRageFile ),
{ NULL, NULL }
};
LUA_REGISTER_NAMESPACE( RageFileUtil );
}
/*
* Copyright (c) 2003-2004 Glenn Maynard, Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This provides an interface to open files in RageFileManager's namespace
* This is just a simple RageFileBasic wrapper on top of another RageFileBasic;
* when a file is open, is acts like the underlying RageFileBasic, except that
* a few extra sanity checks are made to check file modes.
*/
#include "global.h"
#include "RageFileBasic.h"
#include "RageFile.h"
#include "RageUtil.h"
#include "RageFileDriver.h"
RageFile::RageFile()
{
m_File = NULL;
}
RageFile::RageFile( const RageFile &cpy ):
RageFileBasic( cpy )
{
/* This will copy the file driver, including its internal file pointer. */
m_File = cpy.m_File->Copy();
m_Path = cpy.m_Path;
m_Mode = cpy.m_Mode;
}
RageFile *RageFile::Copy() const
{
return new RageFile( *this );
}
RString RageFile::GetPath() const
{
if ( !IsOpen() )
return RString();
RString sRet = m_File->GetDisplayPath();
if( sRet != "" )
return sRet;
return GetRealPath();
}
bool RageFile::Open( const RString& path, int mode )
{
ASSERT( FILEMAN != nullptr );
Close();
m_Path = path;
FixSlashesInPlace(m_Path);
m_Mode = mode;
if( (m_Mode&READ) && (m_Mode&WRITE) )
{
SetError( "Reading and writing are mutually exclusive" );
return false;
}
if( !(m_Mode&READ) && !(m_Mode&WRITE) )
{
SetError( "Neither reading nor writing specified" );
return false;
}
int error;
m_File = FILEMAN->Open( path, mode, error );
if( m_File == NULL )
{
SetError( strerror(error) );
return false;
}
return true;
}
void RageFile::Close()
{
if( m_File == NULL )
return;
delete m_File;
if( m_Mode & WRITE )
FILEMAN->CacheFile( m_File, m_Path );
m_File = NULL;
}
#define ASSERT_OPEN ASSERT_M( IsOpen(), ssprintf("\"%s\" is not open.", m_Path.c_str()) );
#define ASSERT_READ ASSERT_OPEN; ASSERT_M( !!(m_Mode&READ), ssprintf("\"%s\" is not open for reading", m_Path.c_str()) );
#define ASSERT_WRITE ASSERT_OPEN; ASSERT_M( !!(m_Mode&WRITE), ssprintf("\"%s\" is not open for writing", m_Path.c_str()) );
int RageFile::GetLine( RString &out )
{
ASSERT_READ;
return m_File->GetLine( out );
}
int RageFile::PutLine( const RString &str )
{
ASSERT_WRITE;
return m_File->PutLine( str );
}
void RageFile::EnableCRC32( bool on )
{
ASSERT_OPEN;
m_File->EnableCRC32( on );
}
bool RageFile::GetCRC32( uint32_t *iRet )
{
ASSERT_OPEN;
return m_File->GetCRC32( iRet );
}
bool RageFile::AtEOF() const
{
ASSERT_READ;
return m_File->AtEOF();
}
void RageFile::ClearError()
{
if( m_File != nullptr )
m_File->ClearError();
m_sError = "";
}
RString RageFile::GetError() const
{
if( m_File != nullptr && m_File->GetError() != "" )
return m_File->GetError();
return m_sError;
}
void RageFile::SetError( const RString &err )
{
if( m_File != nullptr )
m_File->ClearError();
m_sError = err;
}
int RageFile::Read( void *pBuffer, size_t iBytes )
{
ASSERT_READ;
return m_File->Read( pBuffer, iBytes );
}
int RageFile::Seek( int offset )
{
ASSERT_READ;
return m_File->Seek( offset );
}
int RageFile::Tell() const
{
ASSERT_READ;
return m_File->Tell();
}
int RageFile::GetFileSize() const
{
ASSERT_READ;
return m_File->GetFileSize();
}
int RageFile::GetFD()
{
ASSERT_READ;
return m_File->GetFD();
}
int RageFile::Read( RString &buffer, int bytes )
{
ASSERT_READ;
return m_File->Read( buffer, bytes );
}
int RageFile::Write( const void *buffer, size_t bytes )
{
ASSERT_WRITE;
return m_File->Write( buffer, bytes );
}
int RageFile::Write( const void *buffer, size_t bytes, int nmemb )
{
ASSERT_WRITE;
return m_File->Write( buffer, bytes, nmemb );
}
int RageFile::Flush()
{
if( !m_File )
{
SetError( "Not open" );
return -1;
}
return m_File->Flush();
}
int RageFile::Read( void *buffer, size_t bytes, int nmemb )
{
ASSERT_READ;
return m_File->Read( buffer, bytes, nmemb );
}
int RageFile::Seek( int offset, int whence )
{
ASSERT_READ;
return m_File->Seek( offset, whence );
}
void FileReading::ReadBytes( RageFileBasic &f, void *buf, int size, RString &sError )
{
if( sError.size() != 0 )
return;
int ret = f.Read( buf, size );
if( ret == -1 )
sError = f.GetError();
else if( ret < size )
sError = "Unexpected end of file";
}
RString FileReading::ReadString( RageFileBasic &f, int size, RString &sError )
{
if( sError.size() != 0 )
return RString();
RString sBuf;
int ret = f.Read( sBuf, size );
if( ret == -1 )
sError = f.GetError();
else if( ret < size )
sError = "Unexpected end of file";
return sBuf;
}
void FileReading::SkipBytes( RageFileBasic &f, int iBytes, RString &sError )
{
if( sError.size() != 0 )
return;
iBytes += f.Tell();
FileReading::Seek( f, iBytes, sError );
}
void FileReading::Seek( RageFileBasic &f, int iOffset, RString &sError )
{
if( sError.size() != 0 )
return;
int iGot = f.Seek( iOffset );
if( iGot == iOffset )
return;
if( iGot == -1 )
sError = f.GetError();
else if( iGot < iOffset )
sError = "Unexpected end of file";
}
uint8_t FileReading::read_8( RageFileBasic &f, RString &sError )
{
uint8_t val;
ReadBytes( f, &val, sizeof(uint8_t), sError );
if( sError.size() == 0 )
return val;
else
return 0;
}
uint16_t FileReading::read_u16_le( RageFileBasic &f, RString &sError )
{
uint16_t val;
ReadBytes( f, &val, sizeof(uint16_t), sError );
if( sError.size() == 0 )
return Swap16LE( val );
else
return 0;
}
int16_t FileReading::read_16_le( RageFileBasic &f, RString &sError )
{
int16_t val;
ReadBytes( f, &val, sizeof(int16_t), sError );
if( sError.size() == 0 )
return Swap16LE( val );
else
return 0;
}
uint32_t FileReading::read_u32_le( RageFileBasic &f, RString &sError )
{
uint32_t val;
ReadBytes( f, &val, sizeof(uint32_t), sError );
if( sError.size() == 0 )
return Swap32LE( val );
else
return 0;
}
int32_t FileReading::read_32_le( RageFileBasic &f, RString &sError )
{
int32_t val;
ReadBytes( f, &val, sizeof(int32_t), sError );
if( sError.size() == 0 )
return Swap32LE( val );
else
return 0;
}
// lua start
#include "LuaBinding.h"
/** @brief Allow Lua to have access to the RageFile. */
class LunaRageFile: public Luna<RageFile>
{
public:
static int destroy( T* p, lua_State *L )
{
SAFE_DELETE(p);
return 1;
}
static int Open( T* p, lua_State *L )
{
lua_pushboolean( L, p->Open( SArg(1), IArg(2) ) );
return 1;
}
static int Close( T* p, lua_State *L )
{
p->Close();
return 1;
}
static int Write( T* p, lua_State *L )
{
lua_pushinteger( L, p->Write( SArg(1) ) );
return 1;
}
static int Read( T* p, lua_State *L )
{
RString string;
p->Read(string);
lua_pushstring( L, string );
return 1;
}
static int ReadBytes( T* p, lua_State *L )
{
RString string;
p->Read( string, IArg(1) );
lua_pushstring( L, string );
return 1;
}
static int Seek( T* p, lua_State *L )
{
lua_pushinteger( L, p->Seek( IArg(1) ) );
return 1;
}
static int Tell( T* p, lua_State *L )
{
lua_pushinteger( L, p->Tell() );
return 1;
}
static int GetLine( T* p, lua_State *L )
{
RString string;
p->GetLine(string);
lua_pushstring( L, string );
return 1;
}
static int PutLine( T* p, lua_State *L )
{
lua_pushinteger( L, p->PutLine( SArg(1) ) );
return 1;
}
static int GetError( T* p, lua_State *L )
{
RString error;
error = p->GetError();
lua_pushstring( L, error );
return 1;
}
static int ClearError( T* p, lua_State *L )
{
p->ClearError();
return 1;
}
static int AtEOF( T* p, lua_State *L )
{
lua_pushboolean( L, p->AtEOF() );
return 1;
}
LunaRageFile()
{
ADD_METHOD( Open );
ADD_METHOD( Close );
ADD_METHOD( Write );
ADD_METHOD( Read );
ADD_METHOD( ReadBytes );
ADD_METHOD( Seek );
ADD_METHOD( Tell );
ADD_METHOD( GetLine );
ADD_METHOD( PutLine );
ADD_METHOD( destroy );
ADD_METHOD( GetError );
ADD_METHOD( ClearError );
ADD_METHOD( AtEOF );
}
};
LUA_REGISTER_CLASS( RageFile )
/** @brief Utilities for working with RageFiles. */
namespace RageFileUtil
{
int CreateRageFile( lua_State *L )
{
RageFile *pFile = new RageFile;
pFile->PushSelf( L );
return 1;
}
const luaL_Reg RageFileUtilTable[] =
{
LIST_METHOD( CreateRageFile ),
{ NULL, NULL }
};
LUA_REGISTER_NAMESPACE( RageFileUtil );
}
/*
* Copyright (c) 2003-2004 Glenn Maynard, Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1 -1
View File
@@ -45,7 +45,7 @@ public:
bool Open( const RString& path, int mode = READ );
void Close();
bool IsOpen() const { return m_File != NULL; }
bool IsOpen() const { return m_File != nullptr; }
bool AtEOF() const;
RString GetError() const;
+477 -477
View File
@@ -1,477 +1,477 @@
#include "global.h"
#include "RageFileBasic.h"
#include "RageUtil.h"
#include "RageUtil_AutoPtr.h"
REGISTER_CLASS_TRAITS( RageFileBasic, pCopy->Copy() );
RageFileObj::RageFileObj()
{
m_pReadBuffer = NULL;
m_pWriteBuffer = NULL;
ResetReadBuf();
m_iReadBufAvail = 0;
m_iWriteBufferPos = 0;
m_iWriteBufferUsed = 0;
m_bEOF = false;
m_iFilePos = 0;
m_bCRC32Enabled = false;
m_iCRC32 = 0;
}
RageFileObj::RageFileObj( const RageFileObj &cpy ):
RageFileBasic(cpy)
{
/* If the original file has a buffer, copy it. */
if( cpy.m_pReadBuffer != NULL )
{
m_pReadBuffer = new char[BSIZE];
memcpy( m_pReadBuffer, cpy.m_pReadBuffer, BSIZE );
int iOffsetIntoBuffer = cpy.m_pReadBuf - cpy.m_pReadBuffer;
m_pReadBuf = m_pReadBuffer + iOffsetIntoBuffer;
}
else
{
m_pReadBuffer = NULL;
}
if( cpy.m_pWriteBuffer != NULL )
{
m_pWriteBuffer = new char[cpy.m_iWriteBufferSize];
memcpy( m_pWriteBuffer, cpy.m_pWriteBuffer, m_iWriteBufferUsed );
}
else
{
m_pWriteBuffer = NULL;
}
m_iReadBufAvail = cpy.m_iReadBufAvail;
m_bEOF = cpy.m_bEOF;
m_iFilePos = cpy.m_iFilePos;
m_iWriteBufferPos = cpy.m_iWriteBufferPos;
m_iWriteBufferSize = cpy.m_iWriteBufferSize;
m_iWriteBufferUsed = cpy.m_iWriteBufferUsed;
m_bCRC32Enabled = cpy.m_bCRC32Enabled;
m_iCRC32 = cpy.m_iCRC32;
}
RageFileObj::~RageFileObj()
{
delete [] m_pReadBuffer;
delete [] m_pWriteBuffer;
}
int RageFileObj::Seek( int iOffset )
{
/* If we're already at the requested position, short circuit and don't flush
* our buffer. */
if( iOffset == m_iFilePos )
return m_iFilePos;
m_bEOF = false;
/* If we're calculating a CRC32, disable it. */
m_bCRC32Enabled = false;
/* Note that seeks do not flush the write buffer. Instead, we flush lazily, on the next
* actual Write (or Flush). Seek is not allowed to fail, and users should not need to
* flush before seeking to do proper error checking. */
ResetReadBuf();
int iPos = SeekInternal( iOffset );
if( iPos != -1 )
m_iFilePos = iPos;
return iPos;
}
int RageFileObj::Seek( int offset, int whence )
{
switch( whence )
{
case SEEK_CUR:
return Seek( Tell() + offset );
case SEEK_END:
offset += GetFileSize();
}
return Seek( (int) offset );
}
int RageFileObj::Read( void *pBuffer, size_t iBytes )
{
int iRet = 0;
while( !m_bEOF && iBytes > 0 )
{
if( m_pReadBuffer != NULL && m_iReadBufAvail )
{
/* Copy data out of the buffer first. */
int iFromBuffer = min( (int) iBytes, m_iReadBufAvail );
memcpy( pBuffer, m_pReadBuf, iFromBuffer );
if( m_bCRC32Enabled )
CRC32( m_iCRC32, pBuffer, iFromBuffer );
iRet += iFromBuffer;
m_iFilePos += iFromBuffer;
iBytes -= iFromBuffer;
m_iReadBufAvail -= iFromBuffer;
m_pReadBuf += iFromBuffer;
pBuffer = (char *) pBuffer + iFromBuffer;
}
if( !iBytes )
break;
ASSERT( m_iReadBufAvail == 0 );
/* If buffering is disabled, or the block is bigger than the buffer,
* read the remainder of the data directly into the desteination buffer. */
if( m_pReadBuffer == NULL || iBytes >= BSIZE )
{
/* We have a lot more to read, so don't waste time copying it into the
* buffer. */
int iFromFile = this->ReadInternal( pBuffer, iBytes );
if( iFromFile == -1 )
return -1;
if( iFromFile == 0 )
m_bEOF = true;
if( m_bCRC32Enabled )
CRC32( m_iCRC32, pBuffer, iFromFile );
iRet += iFromFile;
m_iFilePos += iFromFile;
return iRet;
}
/* If buffering is enabled, and we need more data, fill the buffer. */
m_pReadBuf = m_pReadBuffer;
int iGot = FillReadBuf();
if( iGot == -1 )
return iGot;
if( iGot == 0 )
m_bEOF = true;
}
return iRet;
}
int RageFileObj::Read( RString &sBuffer, int iBytes )
{
sBuffer.reserve( iBytes != -1? iBytes: this->GetFileSize() );
int iRet = 0;
char buf[4096];
while( iBytes == -1 || iRet < iBytes )
{
int ToRead = sizeof(buf);
if( iBytes != -1 )
ToRead = min( ToRead, iBytes-iRet );
const int iGot = Read( buf, ToRead );
if( iGot == 0 )
break;
if( iGot == -1 )
return -1;
sBuffer.append( buf, iGot );
iRet += iGot;
}
sBuffer.erase( sBuffer.begin()+iRet, sBuffer.end() );
return iRet;
}
int RageFileObj::Read( void *pBuffer, size_t iBytes, int iNmemb )
{
const int iRet = Read( pBuffer, iBytes*iNmemb );
if( iRet == -1 )
return -1;
/* If we're reading 10-byte blocks, and we got 27 bytes, we have 7 extra bytes.
* Seek back. XXX: seeking is very slow for eg. deflated ZIPs. If the block is
* small enough, we may be able to stuff the extra data into the buffer. */
const int iExtra = iRet % iBytes;
Seek( Tell()-iExtra );
return iRet/iBytes;
}
/* Empty the write buffer to disk. Return -1 on error, 0 on success. */
int RageFileObj::EmptyWriteBuf()
{
if( m_pWriteBuffer == NULL )
return 0;
if( m_iWriteBufferUsed )
{
/* The write buffer may not align with the actual file, if we've seeked. Only
* seek if needed. */
bool bSeeked = (m_iWriteBufferPos+m_iWriteBufferUsed != m_iFilePos);
if( bSeeked )
SeekInternal( m_iWriteBufferPos );
int iRet = WriteInternal( m_pWriteBuffer, m_iWriteBufferUsed );
if( bSeeked )
SeekInternal( m_iFilePos );
if( iRet == -1 )
return iRet;
}
m_iWriteBufferPos = m_iFilePos;
m_iWriteBufferUsed = 0;
return 0;
}
int RageFileObj::Write( const void *pBuffer, size_t iBytes )
{
if( m_pWriteBuffer != NULL )
{
/* If the file position has moved away from the write buffer, or the
* incoming data won't fit in the buffer, flush. */
if( m_iWriteBufferPos+m_iWriteBufferUsed != m_iFilePos || m_iWriteBufferUsed + (int)iBytes > m_iWriteBufferSize )
{
int iRet = EmptyWriteBuf();
if( iRet == -1 )
return iRet;
}
if( m_iWriteBufferUsed + (int)iBytes <= m_iWriteBufferSize )
{
memcpy( m_pWriteBuffer+m_iWriteBufferUsed, pBuffer, iBytes );
m_iWriteBufferUsed += iBytes;
m_iFilePos += iBytes;
if( m_bCRC32Enabled )
CRC32( m_iCRC32, pBuffer, iBytes );
return iBytes;
}
/* We're writing a lot of data, and it won't fit in the buffer. We already
* flushed above, so m_iWriteBufferUsed; fall through and write the block normally. */
ASSERT_M( m_iWriteBufferUsed == 0, ssprintf("%i", m_iWriteBufferUsed) );
}
int iRet = WriteInternal( pBuffer, iBytes );
if( iRet != -1 )
{
m_iFilePos += iRet;
if( m_bCRC32Enabled )
CRC32( m_iCRC32, pBuffer, iBytes );
}
return iRet;
}
int RageFileObj::Write( const void *pBuffer, size_t iBytes, int iNmemb )
{
/* Simple write. We never return partial writes. */
int iRet = Write( pBuffer, iBytes*iNmemb ) / iBytes;
if( iRet == -1 )
return -1;
return iRet / iBytes;
}
int RageFileObj::Flush()
{
int iRet = EmptyWriteBuf();
if( iRet == -1 )
return iRet;
return FlushInternal();
}
void RageFileObj::EnableReadBuffering()
{
if( m_pReadBuffer == NULL )
m_pReadBuffer = new char[BSIZE];
}
void RageFileObj::EnableWriteBuffering( int iBytes )
{
if( m_pWriteBuffer == NULL )
{
m_pWriteBuffer = new char[iBytes];
m_iWriteBufferPos = m_iFilePos;
m_iWriteBufferSize = iBytes;
}
}
void RageFileObj::EnableCRC32( bool bOn )
{
if( !bOn )
{
m_bCRC32Enabled = false;
return;
}
m_bCRC32Enabled = true;
m_iCRC32 = 0;
}
bool RageFileObj::GetCRC32( uint32_t *iRet )
{
if( !m_bCRC32Enabled )
return false;
*iRet = m_iCRC32;
return true;
}
/* Read up to the next \n, and return it in out. Strip the \n. If the \n is
* preceded by a \r (DOS newline), strip that, too. */
int RageFileObj::GetLine( RString &sOut )
{
sOut = "";
if( m_bEOF )
return 0;
EnableReadBuffering();
bool bGotData = false;
while( 1 )
{
bool bDone = false;
/* Find the end of the block we'll move to out. */
char *p = (char *) memchr( m_pReadBuf, '\n', m_iReadBufAvail );
bool bReAddCR = false;
if( p == NULL )
{
/* Hack: If the last character of the buffer is \r, then it's likely that an
* \r\n has been split across buffers. Move everything else, then move the
* \r to the beginning of the buffer and handle it the next time around the loop. */
if( m_iReadBufAvail && m_pReadBuf[m_iReadBufAvail-1] == '\r' )
{
bReAddCR = true;
--m_iReadBufAvail;
}
p = m_pReadBuf+m_iReadBufAvail; /* everything */
}
else
{
bDone = true;
}
if( p >= m_pReadBuf )
{
char *RealEnd = p;
if( bDone && p > m_pReadBuf && p[-1] == '\r' )
--RealEnd; /* not including \r */
sOut.append( m_pReadBuf, RealEnd );
if( bDone )
++p; /* skip \n */
const int iUsed = p-m_pReadBuf;
if( iUsed )
{
m_iReadBufAvail -= iUsed;
m_iFilePos += iUsed;
bGotData = true;
m_pReadBuf = p;
}
}
if( bReAddCR )
{
ASSERT( m_iReadBufAvail == 0 );
m_pReadBuf = m_pReadBuffer;
m_pReadBuffer[m_iReadBufAvail] = '\r';
++m_iReadBufAvail;
}
if( bDone )
break;
/* We need more data. */
m_pReadBuf = m_pReadBuffer;
const int iSize = FillReadBuf();
/* If we've read data already, then don't mark EOF yet. Wait until the
* next time we're called. */
if( iSize == 0 && !bGotData )
{
m_bEOF = true;
return 0;
}
if( iSize == -1 )
return -1; // error
if( iSize == 0 )
break; // EOF or error
}
return bGotData? 1:0;
}
// Always use "\r\n". Even though the program may be running on Unix, the
// files written to a memory card are likely to be edited using Windows.
//#if defined(WIN32)
#define NEWLINE "\r\n"
//#else
//#define NEWLINE "\n"
//#endif
int RageFileObj::PutLine( const RString &sStr )
{
if( Write(sStr) == -1 )
return -1;
return Write( RString(NEWLINE) );
}
/* Fill the internal buffer. This never marks EOF, since this is an internal, hidden
* read; EOF should only be set as a result of a real read. (That is, disabling buffering
* shouldn't cause the results of AtEOF to change.) */
int RageFileObj::FillReadBuf()
{
/* Don't call this unless buffering is enabled. */
ASSERT( m_pReadBuffer != NULL );
/* The buffer starts at m_Buffer; any data in it starts at m_pReadBuf; space between
* the two is old data that we've read. (Don't mangle that data; we can use it
* for seeking backwards.) */
const int iBufAvail = BSIZE - (m_pReadBuf-m_pReadBuffer) - m_iReadBufAvail;
ASSERT_M( iBufAvail >= 0, ssprintf("%p, %p, %i", m_pReadBuf, m_pReadBuffer, (int) BSIZE ) );
const int iSize = this->ReadInternal( m_pReadBuf+m_iReadBufAvail, iBufAvail );
if( iSize > 0 )
m_iReadBufAvail += iSize;
return iSize;
}
void RageFileObj::ResetReadBuf()
{
m_iReadBufAvail = 0;
m_pReadBuf = m_pReadBuffer;
}
/*
* Copyright (c) 2003-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageFileBasic.h"
#include "RageUtil.h"
#include "RageUtil_AutoPtr.h"
REGISTER_CLASS_TRAITS( RageFileBasic, pCopy->Copy() );
RageFileObj::RageFileObj()
{
m_pReadBuffer = NULL;
m_pWriteBuffer = NULL;
ResetReadBuf();
m_iReadBufAvail = 0;
m_iWriteBufferPos = 0;
m_iWriteBufferUsed = 0;
m_bEOF = false;
m_iFilePos = 0;
m_bCRC32Enabled = false;
m_iCRC32 = 0;
}
RageFileObj::RageFileObj( const RageFileObj &cpy ):
RageFileBasic(cpy)
{
/* If the original file has a buffer, copy it. */
if( cpy.m_pReadBuffer != nullptr )
{
m_pReadBuffer = new char[BSIZE];
memcpy( m_pReadBuffer, cpy.m_pReadBuffer, BSIZE );
int iOffsetIntoBuffer = cpy.m_pReadBuf - cpy.m_pReadBuffer;
m_pReadBuf = m_pReadBuffer + iOffsetIntoBuffer;
}
else
{
m_pReadBuffer = NULL;
}
if( cpy.m_pWriteBuffer != nullptr )
{
m_pWriteBuffer = new char[cpy.m_iWriteBufferSize];
memcpy( m_pWriteBuffer, cpy.m_pWriteBuffer, m_iWriteBufferUsed );
}
else
{
m_pWriteBuffer = NULL;
}
m_iReadBufAvail = cpy.m_iReadBufAvail;
m_bEOF = cpy.m_bEOF;
m_iFilePos = cpy.m_iFilePos;
m_iWriteBufferPos = cpy.m_iWriteBufferPos;
m_iWriteBufferSize = cpy.m_iWriteBufferSize;
m_iWriteBufferUsed = cpy.m_iWriteBufferUsed;
m_bCRC32Enabled = cpy.m_bCRC32Enabled;
m_iCRC32 = cpy.m_iCRC32;
}
RageFileObj::~RageFileObj()
{
delete [] m_pReadBuffer;
delete [] m_pWriteBuffer;
}
int RageFileObj::Seek( int iOffset )
{
/* If we're already at the requested position, short circuit and don't flush
* our buffer. */
if( iOffset == m_iFilePos )
return m_iFilePos;
m_bEOF = false;
/* If we're calculating a CRC32, disable it. */
m_bCRC32Enabled = false;
/* Note that seeks do not flush the write buffer. Instead, we flush lazily, on the next
* actual Write (or Flush). Seek is not allowed to fail, and users should not need to
* flush before seeking to do proper error checking. */
ResetReadBuf();
int iPos = SeekInternal( iOffset );
if( iPos != -1 )
m_iFilePos = iPos;
return iPos;
}
int RageFileObj::Seek( int offset, int whence )
{
switch( whence )
{
case SEEK_CUR:
return Seek( Tell() + offset );
case SEEK_END:
offset += GetFileSize();
}
return Seek( (int) offset );
}
int RageFileObj::Read( void *pBuffer, size_t iBytes )
{
int iRet = 0;
while( !m_bEOF && iBytes > 0 )
{
if( m_pReadBuffer != nullptr && m_iReadBufAvail )
{
/* Copy data out of the buffer first. */
int iFromBuffer = min( (int) iBytes, m_iReadBufAvail );
memcpy( pBuffer, m_pReadBuf, iFromBuffer );
if( m_bCRC32Enabled )
CRC32( m_iCRC32, pBuffer, iFromBuffer );
iRet += iFromBuffer;
m_iFilePos += iFromBuffer;
iBytes -= iFromBuffer;
m_iReadBufAvail -= iFromBuffer;
m_pReadBuf += iFromBuffer;
pBuffer = (char *) pBuffer + iFromBuffer;
}
if( !iBytes )
break;
ASSERT( m_iReadBufAvail == 0 );
/* If buffering is disabled, or the block is bigger than the buffer,
* read the remainder of the data directly into the desteination buffer. */
if( m_pReadBuffer == NULL || iBytes >= BSIZE )
{
/* We have a lot more to read, so don't waste time copying it into the
* buffer. */
int iFromFile = this->ReadInternal( pBuffer, iBytes );
if( iFromFile == -1 )
return -1;
if( iFromFile == 0 )
m_bEOF = true;
if( m_bCRC32Enabled )
CRC32( m_iCRC32, pBuffer, iFromFile );
iRet += iFromFile;
m_iFilePos += iFromFile;
return iRet;
}
/* If buffering is enabled, and we need more data, fill the buffer. */
m_pReadBuf = m_pReadBuffer;
int iGot = FillReadBuf();
if( iGot == -1 )
return iGot;
if( iGot == 0 )
m_bEOF = true;
}
return iRet;
}
int RageFileObj::Read( RString &sBuffer, int iBytes )
{
sBuffer.reserve( iBytes != -1? iBytes: this->GetFileSize() );
int iRet = 0;
char buf[4096];
while( iBytes == -1 || iRet < iBytes )
{
int ToRead = sizeof(buf);
if( iBytes != -1 )
ToRead = min( ToRead, iBytes-iRet );
const int iGot = Read( buf, ToRead );
if( iGot == 0 )
break;
if( iGot == -1 )
return -1;
sBuffer.append( buf, iGot );
iRet += iGot;
}
sBuffer.erase( sBuffer.begin()+iRet, sBuffer.end() );
return iRet;
}
int RageFileObj::Read( void *pBuffer, size_t iBytes, int iNmemb )
{
const int iRet = Read( pBuffer, iBytes*iNmemb );
if( iRet == -1 )
return -1;
/* If we're reading 10-byte blocks, and we got 27 bytes, we have 7 extra bytes.
* Seek back. XXX: seeking is very slow for eg. deflated ZIPs. If the block is
* small enough, we may be able to stuff the extra data into the buffer. */
const int iExtra = iRet % iBytes;
Seek( Tell()-iExtra );
return iRet/iBytes;
}
/* Empty the write buffer to disk. Return -1 on error, 0 on success. */
int RageFileObj::EmptyWriteBuf()
{
if( m_pWriteBuffer == NULL )
return 0;
if( m_iWriteBufferUsed )
{
/* The write buffer may not align with the actual file, if we've seeked. Only
* seek if needed. */
bool bSeeked = (m_iWriteBufferPos+m_iWriteBufferUsed != m_iFilePos);
if( bSeeked )
SeekInternal( m_iWriteBufferPos );
int iRet = WriteInternal( m_pWriteBuffer, m_iWriteBufferUsed );
if( bSeeked )
SeekInternal( m_iFilePos );
if( iRet == -1 )
return iRet;
}
m_iWriteBufferPos = m_iFilePos;
m_iWriteBufferUsed = 0;
return 0;
}
int RageFileObj::Write( const void *pBuffer, size_t iBytes )
{
if( m_pWriteBuffer != nullptr )
{
/* If the file position has moved away from the write buffer, or the
* incoming data won't fit in the buffer, flush. */
if( m_iWriteBufferPos+m_iWriteBufferUsed != m_iFilePos || m_iWriteBufferUsed + (int)iBytes > m_iWriteBufferSize )
{
int iRet = EmptyWriteBuf();
if( iRet == -1 )
return iRet;
}
if( m_iWriteBufferUsed + (int)iBytes <= m_iWriteBufferSize )
{
memcpy( m_pWriteBuffer+m_iWriteBufferUsed, pBuffer, iBytes );
m_iWriteBufferUsed += iBytes;
m_iFilePos += iBytes;
if( m_bCRC32Enabled )
CRC32( m_iCRC32, pBuffer, iBytes );
return iBytes;
}
/* We're writing a lot of data, and it won't fit in the buffer. We already
* flushed above, so m_iWriteBufferUsed; fall through and write the block normally. */
ASSERT_M( m_iWriteBufferUsed == 0, ssprintf("%i", m_iWriteBufferUsed) );
}
int iRet = WriteInternal( pBuffer, iBytes );
if( iRet != -1 )
{
m_iFilePos += iRet;
if( m_bCRC32Enabled )
CRC32( m_iCRC32, pBuffer, iBytes );
}
return iRet;
}
int RageFileObj::Write( const void *pBuffer, size_t iBytes, int iNmemb )
{
/* Simple write. We never return partial writes. */
int iRet = Write( pBuffer, iBytes*iNmemb ) / iBytes;
if( iRet == -1 )
return -1;
return iRet / iBytes;
}
int RageFileObj::Flush()
{
int iRet = EmptyWriteBuf();
if( iRet == -1 )
return iRet;
return FlushInternal();
}
void RageFileObj::EnableReadBuffering()
{
if( m_pReadBuffer == NULL )
m_pReadBuffer = new char[BSIZE];
}
void RageFileObj::EnableWriteBuffering( int iBytes )
{
if( m_pWriteBuffer == NULL )
{
m_pWriteBuffer = new char[iBytes];
m_iWriteBufferPos = m_iFilePos;
m_iWriteBufferSize = iBytes;
}
}
void RageFileObj::EnableCRC32( bool bOn )
{
if( !bOn )
{
m_bCRC32Enabled = false;
return;
}
m_bCRC32Enabled = true;
m_iCRC32 = 0;
}
bool RageFileObj::GetCRC32( uint32_t *iRet )
{
if( !m_bCRC32Enabled )
return false;
*iRet = m_iCRC32;
return true;
}
/* Read up to the next \n, and return it in out. Strip the \n. If the \n is
* preceded by a \r (DOS newline), strip that, too. */
int RageFileObj::GetLine( RString &sOut )
{
sOut = "";
if( m_bEOF )
return 0;
EnableReadBuffering();
bool bGotData = false;
while( 1 )
{
bool bDone = false;
/* Find the end of the block we'll move to out. */
char *p = (char *) memchr( m_pReadBuf, '\n', m_iReadBufAvail );
bool bReAddCR = false;
if( p == NULL )
{
/* Hack: If the last character of the buffer is \r, then it's likely that an
* \r\n has been split across buffers. Move everything else, then move the
* \r to the beginning of the buffer and handle it the next time around the loop. */
if( m_iReadBufAvail && m_pReadBuf[m_iReadBufAvail-1] == '\r' )
{
bReAddCR = true;
--m_iReadBufAvail;
}
p = m_pReadBuf+m_iReadBufAvail; /* everything */
}
else
{
bDone = true;
}
if( p >= m_pReadBuf )
{
char *RealEnd = p;
if( bDone && p > m_pReadBuf && p[-1] == '\r' )
--RealEnd; /* not including \r */
sOut.append( m_pReadBuf, RealEnd );
if( bDone )
++p; /* skip \n */
const int iUsed = p-m_pReadBuf;
if( iUsed )
{
m_iReadBufAvail -= iUsed;
m_iFilePos += iUsed;
bGotData = true;
m_pReadBuf = p;
}
}
if( bReAddCR )
{
ASSERT( m_iReadBufAvail == 0 );
m_pReadBuf = m_pReadBuffer;
m_pReadBuffer[m_iReadBufAvail] = '\r';
++m_iReadBufAvail;
}
if( bDone )
break;
/* We need more data. */
m_pReadBuf = m_pReadBuffer;
const int iSize = FillReadBuf();
/* If we've read data already, then don't mark EOF yet. Wait until the
* next time we're called. */
if( iSize == 0 && !bGotData )
{
m_bEOF = true;
return 0;
}
if( iSize == -1 )
return -1; // error
if( iSize == 0 )
break; // EOF or error
}
return bGotData? 1:0;
}
// Always use "\r\n". Even though the program may be running on Unix, the
// files written to a memory card are likely to be edited using Windows.
//#if defined(WIN32)
#define NEWLINE "\r\n"
//#else
//#define NEWLINE "\n"
//#endif
int RageFileObj::PutLine( const RString &sStr )
{
if( Write(sStr) == -1 )
return -1;
return Write( RString(NEWLINE) );
}
/* Fill the internal buffer. This never marks EOF, since this is an internal, hidden
* read; EOF should only be set as a result of a real read. (That is, disabling buffering
* shouldn't cause the results of AtEOF to change.) */
int RageFileObj::FillReadBuf()
{
/* Don't call this unless buffering is enabled. */
ASSERT( m_pReadBuffer != nullptr );
/* The buffer starts at m_Buffer; any data in it starts at m_pReadBuf; space between
* the two is old data that we've read. (Don't mangle that data; we can use it
* for seeking backwards.) */
const int iBufAvail = BSIZE - (m_pReadBuf-m_pReadBuffer) - m_iReadBufAvail;
ASSERT_M( iBufAvail >= 0, ssprintf("%p, %p, %i", m_pReadBuf, m_pReadBuffer, (int) BSIZE ) );
const int iSize = this->ReadInternal( m_pReadBuf+m_iReadBufAvail, iBufAvail );
if( iSize > 0 )
m_iReadBufAvail += iSize;
return iSize;
}
void RageFileObj::ResetReadBuf()
{
m_iReadBufAvail = 0;
m_pReadBuf = m_pReadBuffer;
}
/*
* Copyright (c) 2003-2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -92,7 +92,7 @@ RageFileDriver *RageFileManager::GetFileDriver( RString sMountpoint )
void RageFileManager::ReleaseFileDriver( RageFileDriver *pDriver )
{
ASSERT( pDriver != NULL );
ASSERT( pDriver != nullptr );
g_Mutex->Lock();
unsigned i;
+5 -5
View File
@@ -101,7 +101,7 @@ void RageInput::WindowReset()
void RageInput::AddHandler( InputHandler *pHandler )
{
ASSERT( pHandler != NULL );
ASSERT( pHandler != nullptr );
LoadedInputHandler hand;
hand.m_pDevice = pHandler;
@@ -125,7 +125,7 @@ InputHandler *RageInput::GetHandlerForDevice( const InputDevice id )
RString RageInput::GetDeviceSpecificInputString( const DeviceInput &di )
{
InputHandler *pDriver = GetHandlerForDevice( di.device );
if( pDriver != NULL )
if( pDriver != nullptr )
return pDriver->GetDeviceSpecificInputString(di);
else
return di.ToString();
@@ -134,7 +134,7 @@ RString RageInput::GetDeviceSpecificInputString( const DeviceInput &di )
RString RageInput::GetLocalizedInputString( const DeviceInput &di )
{
InputHandler *pDriver = GetHandlerForDevice( di.device );
if( pDriver != NULL )
if( pDriver != nullptr )
return pDriver->GetLocalizedInputString(di);
else
return Capitalize( DeviceButtonToString(di.button) );
@@ -143,7 +143,7 @@ RString RageInput::GetLocalizedInputString( const DeviceInput &di )
wchar_t RageInput::DeviceInputToChar( DeviceInput di, bool bUseCurrentKeyModifiers )
{
InputHandler *pDriver = GetHandlerForDevice( di.device );
if( pDriver != NULL )
if( pDriver != nullptr )
return pDriver->DeviceButtonToChar(di.button, bUseCurrentKeyModifiers);
else
return '\0';
@@ -152,7 +152,7 @@ wchar_t RageInput::DeviceInputToChar( DeviceInput di, bool bUseCurrentKeyModifie
InputDeviceState RageInput::GetInputDeviceState( InputDevice id )
{
InputHandler *pDriver = GetHandlerForDevice( id );
if( pDriver != NULL )
if( pDriver != nullptr )
return pDriver->GetInputDeviceState(id);
else
return InputDeviceState_NoInputHandler;
+734 -734
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -69,13 +69,13 @@ void RageSoundManager::Shutdown()
void RageSoundManager::StartMixing( RageSoundBase *pSound )
{
if( m_pDriver != NULL )
if( m_pDriver != nullptr )
m_pDriver->StartMixing( pSound );
}
void RageSoundManager::StopMixing( RageSoundBase *pSound )
{
if( m_pDriver != NULL )
if( m_pDriver != nullptr )
m_pDriver->StopMixing( pSound );
}
@@ -118,7 +118,7 @@ void RageSoundManager::Update()
g_SoundManMutex.Unlock(); /* finished with m_mapPreloadedSounds */
if( m_pDriver != NULL )
if( m_pDriver != nullptr )
m_pDriver->Update();
}
+225 -225
View File
@@ -1,225 +1,225 @@
#include "global.h"
#include "RageSoundReader_Extend.h"
#include "RageLog.h"
#include "RageSoundUtil.h"
#include "RageUtil.h"
/*
* Add support for negative seeks (adding a delay), extending a sound
* beyond its end (m_LengthSeconds and M_CONTINUE), looping and fading.
* This filter is normally inserted before extended buffering, implementing
* properties that can seek the sound; this results in buffered seeks, but
* changes to these properties are delayed.
*/
RageSoundReader_Extend::RageSoundReader_Extend( RageSoundReader *pSource ):
RageSoundReader_Filter( pSource )
{
ASSERT_M(pSource != NULL, "The music file was not found! Was it deleted or moved while the game was on?");
m_iPositionFrames = pSource->GetNextSourceFrame();
m_StopMode = M_STOP;
m_iStartFrames = 0;
m_iLengthFrames = -1;
m_iFadeOutFrames = 0;
m_iFadeInFrames = 0;
m_bIgnoreFadeInFrames = false;
}
int RageSoundReader_Extend::SetPosition( int iFrame )
{
m_bIgnoreFadeInFrames = false;
m_iPositionFrames = iFrame;
int iRet = m_pSource->SetPosition( max(iFrame, 0) );
if( iRet < 0 )
return iRet;
if( m_iLengthFrames != -1 )
return m_iPositionFrames < GetEndFrame();
/* If we're in CONTINUE and we seek past the end of the file, don't return EOF. */
if( m_StopMode == M_CONTINUE )
return 1;
return iRet;
}
int RageSoundReader_Extend::GetEndFrame() const
{
if( m_iLengthFrames == -1 )
return -1;
return m_iStartFrames + m_iLengthFrames;
}
int RageSoundReader_Extend::GetData( float *pBuffer, int iFrames )
{
int iFramesToRead = iFrames;
if( m_iLengthFrames != -1 )
{
int iFramesLeft = GetEndFrame() - m_iPositionFrames;
iFramesLeft = max( 0, iFramesLeft );
iFramesToRead = min( iFramesToRead, iFramesLeft );
}
if( iFrames && !iFramesToRead )
return RageSoundReader::END_OF_FILE;
if( m_iPositionFrames < 0 )
{
iFramesToRead = min( iFramesToRead, -m_iPositionFrames );
memset( pBuffer, 0, iFramesToRead * sizeof(float) * this->GetNumChannels() );
return iFramesToRead;
}
int iNewPositionFrames = m_pSource->GetNextSourceFrame();
int iRet = RageSoundReader_Filter::Read( pBuffer, iFramesToRead );
/* Update the position from the source. If the source is at EOF, skip this,
* so we'll extrapolate in M_CONTINUE. */
if( iRet != RageSoundReader::END_OF_FILE )
m_iPositionFrames = iNewPositionFrames;
return iRet;
}
int RageSoundReader_Extend::Read( float *pBuffer, int iFrames )
{
int iFramesRead = GetData( pBuffer, iFrames );
if( iFramesRead == RageSoundReader::END_OF_FILE )
{
if( (m_iLengthFrames != -1 && m_iPositionFrames < GetEndFrame()) ||
m_StopMode == M_CONTINUE )
{
iFramesRead = iFrames;
if( m_StopMode != M_CONTINUE )
iFramesRead = min( GetEndFrame() - m_iPositionFrames, iFramesRead );
memset( pBuffer, 0, iFramesRead * sizeof(float) * this->GetNumChannels() );
}
}
if( iFramesRead > 0 )
{
int iFullVolumePositionFrames = 0;
int iSilencePositionFrames = 0;
if( m_iFadeInFrames != 0 && !m_bIgnoreFadeInFrames )
{
iSilencePositionFrames = 0;
iFullVolumePositionFrames = m_iFadeInFrames;
}
/* We want to fade when there's m_iFadeFrames frames left, but if
* m_LengthFrames is -1, we don't know the length we're playing.
* (m_LengthFrames is the length to play, not the length of the
* source.) If we don't know the length, don't fade. */
if( m_iFadeOutFrames != 0 && m_iLengthFrames != -1 )
{
iSilencePositionFrames = GetEndFrame();
iFullVolumePositionFrames = iSilencePositionFrames - m_iFadeOutFrames;
}
if( iSilencePositionFrames != iFullVolumePositionFrames )
{
const int iStartSecond = m_iPositionFrames;
const int iEndSecond = m_iPositionFrames + iFramesRead;
const float fStartVolume = SCALE( iStartSecond, iFullVolumePositionFrames, iSilencePositionFrames, 1.0f, 0.0f );
const float fEndVolume = SCALE( iEndSecond, iFullVolumePositionFrames, iSilencePositionFrames, 1.0f, 0.0f );
RageSoundUtil::Fade( pBuffer, iFramesRead, this->GetNumChannels(), fStartVolume, fEndVolume );
}
m_iPositionFrames += iFramesRead;
}
if( iFramesRead == RageSoundReader::END_OF_FILE && m_StopMode == M_LOOP )
{
this->SetPosition( m_iStartFrames );
/* If we're not fading out at the end, then only fade in once. Ignore
* m_iFadeInFrames until seeked, so we only fade in once. */
if( m_iFadeOutFrames == 0 )
m_bIgnoreFadeInFrames = true;
return STREAM_LOOPED;
}
return iFramesRead;
}
int RageSoundReader_Extend::GetNextSourceFrame() const
{
return m_iPositionFrames;
}
bool RageSoundReader_Extend::SetProperty( const RString &sProperty, float fValue )
{
if( sProperty == "StartSecond" )
{
m_iStartFrames = lrintf( fValue * this->GetSampleRate() );
return true;
}
if( sProperty == "LengthSeconds" )
{
if( fValue == -1 )
m_iLengthFrames = -1;
else
m_iLengthFrames = lrintf( fValue * this->GetSampleRate() );
return true;
}
if( sProperty == "Loop" )
{
m_StopMode = M_LOOP;
return true;
}
if( sProperty == "Stop" )
{
m_StopMode = M_STOP;
return true;
}
if( sProperty == "Continue" )
{
m_StopMode = M_CONTINUE;
return true;
}
if( sProperty == "FadeInSeconds" )
{
m_iFadeInFrames = lrintf( fValue * this->GetSampleRate() );
return true;
}
if( sProperty == "FadeSeconds" || sProperty == "FadeOutSeconds" )
{
m_iFadeOutFrames = lrintf( fValue * this->GetSampleRate() );
return true;
}
return false;
}
/*
* Copyright (c) 2003-2006 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSoundReader_Extend.h"
#include "RageLog.h"
#include "RageSoundUtil.h"
#include "RageUtil.h"
/*
* Add support for negative seeks (adding a delay), extending a sound
* beyond its end (m_LengthSeconds and M_CONTINUE), looping and fading.
* This filter is normally inserted before extended buffering, implementing
* properties that can seek the sound; this results in buffered seeks, but
* changes to these properties are delayed.
*/
RageSoundReader_Extend::RageSoundReader_Extend( RageSoundReader *pSource ):
RageSoundReader_Filter( pSource )
{
ASSERT_M(pSource != nullptr, "The music file was not found! Was it deleted or moved while the game was on?");
m_iPositionFrames = pSource->GetNextSourceFrame();
m_StopMode = M_STOP;
m_iStartFrames = 0;
m_iLengthFrames = -1;
m_iFadeOutFrames = 0;
m_iFadeInFrames = 0;
m_bIgnoreFadeInFrames = false;
}
int RageSoundReader_Extend::SetPosition( int iFrame )
{
m_bIgnoreFadeInFrames = false;
m_iPositionFrames = iFrame;
int iRet = m_pSource->SetPosition( max(iFrame, 0) );
if( iRet < 0 )
return iRet;
if( m_iLengthFrames != -1 )
return m_iPositionFrames < GetEndFrame();
/* If we're in CONTINUE and we seek past the end of the file, don't return EOF. */
if( m_StopMode == M_CONTINUE )
return 1;
return iRet;
}
int RageSoundReader_Extend::GetEndFrame() const
{
if( m_iLengthFrames == -1 )
return -1;
return m_iStartFrames + m_iLengthFrames;
}
int RageSoundReader_Extend::GetData( float *pBuffer, int iFrames )
{
int iFramesToRead = iFrames;
if( m_iLengthFrames != -1 )
{
int iFramesLeft = GetEndFrame() - m_iPositionFrames;
iFramesLeft = max( 0, iFramesLeft );
iFramesToRead = min( iFramesToRead, iFramesLeft );
}
if( iFrames && !iFramesToRead )
return RageSoundReader::END_OF_FILE;
if( m_iPositionFrames < 0 )
{
iFramesToRead = min( iFramesToRead, -m_iPositionFrames );
memset( pBuffer, 0, iFramesToRead * sizeof(float) * this->GetNumChannels() );
return iFramesToRead;
}
int iNewPositionFrames = m_pSource->GetNextSourceFrame();
int iRet = RageSoundReader_Filter::Read( pBuffer, iFramesToRead );
/* Update the position from the source. If the source is at EOF, skip this,
* so we'll extrapolate in M_CONTINUE. */
if( iRet != RageSoundReader::END_OF_FILE )
m_iPositionFrames = iNewPositionFrames;
return iRet;
}
int RageSoundReader_Extend::Read( float *pBuffer, int iFrames )
{
int iFramesRead = GetData( pBuffer, iFrames );
if( iFramesRead == RageSoundReader::END_OF_FILE )
{
if( (m_iLengthFrames != -1 && m_iPositionFrames < GetEndFrame()) ||
m_StopMode == M_CONTINUE )
{
iFramesRead = iFrames;
if( m_StopMode != M_CONTINUE )
iFramesRead = min( GetEndFrame() - m_iPositionFrames, iFramesRead );
memset( pBuffer, 0, iFramesRead * sizeof(float) * this->GetNumChannels() );
}
}
if( iFramesRead > 0 )
{
int iFullVolumePositionFrames = 0;
int iSilencePositionFrames = 0;
if( m_iFadeInFrames != 0 && !m_bIgnoreFadeInFrames )
{
iSilencePositionFrames = 0;
iFullVolumePositionFrames = m_iFadeInFrames;
}
/* We want to fade when there's m_iFadeFrames frames left, but if
* m_LengthFrames is -1, we don't know the length we're playing.
* (m_LengthFrames is the length to play, not the length of the
* source.) If we don't know the length, don't fade. */
if( m_iFadeOutFrames != 0 && m_iLengthFrames != -1 )
{
iSilencePositionFrames = GetEndFrame();
iFullVolumePositionFrames = iSilencePositionFrames - m_iFadeOutFrames;
}
if( iSilencePositionFrames != iFullVolumePositionFrames )
{
const int iStartSecond = m_iPositionFrames;
const int iEndSecond = m_iPositionFrames + iFramesRead;
const float fStartVolume = SCALE( iStartSecond, iFullVolumePositionFrames, iSilencePositionFrames, 1.0f, 0.0f );
const float fEndVolume = SCALE( iEndSecond, iFullVolumePositionFrames, iSilencePositionFrames, 1.0f, 0.0f );
RageSoundUtil::Fade( pBuffer, iFramesRead, this->GetNumChannels(), fStartVolume, fEndVolume );
}
m_iPositionFrames += iFramesRead;
}
if( iFramesRead == RageSoundReader::END_OF_FILE && m_StopMode == M_LOOP )
{
this->SetPosition( m_iStartFrames );
/* If we're not fading out at the end, then only fade in once. Ignore
* m_iFadeInFrames until seeked, so we only fade in once. */
if( m_iFadeOutFrames == 0 )
m_bIgnoreFadeInFrames = true;
return STREAM_LOOPED;
}
return iFramesRead;
}
int RageSoundReader_Extend::GetNextSourceFrame() const
{
return m_iPositionFrames;
}
bool RageSoundReader_Extend::SetProperty( const RString &sProperty, float fValue )
{
if( sProperty == "StartSecond" )
{
m_iStartFrames = lrintf( fValue * this->GetSampleRate() );
return true;
}
if( sProperty == "LengthSeconds" )
{
if( fValue == -1 )
m_iLengthFrames = -1;
else
m_iLengthFrames = lrintf( fValue * this->GetSampleRate() );
return true;
}
if( sProperty == "Loop" )
{
m_StopMode = M_LOOP;
return true;
}
if( sProperty == "Stop" )
{
m_StopMode = M_STOP;
return true;
}
if( sProperty == "Continue" )
{
m_StopMode = M_CONTINUE;
return true;
}
if( sProperty == "FadeInSeconds" )
{
m_iFadeInFrames = lrintf( fValue * this->GetSampleRate() );
return true;
}
if( sProperty == "FadeSeconds" || sProperty == "FadeOutSeconds" )
{
m_iFadeOutFrames = lrintf( fValue * this->GetSampleRate() );
return true;
}
return false;
}
/*
* Copyright (c) 2003-2006 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1177 -1177
View File
File diff suppressed because it is too large Load Diff
+191 -191
View File
@@ -1,191 +1,191 @@
/* This reader simply precaches all of the data from another reader. This
* reduces CPU usage for sounds that are played several times at once. */
#include "global.h"
#include "RageSoundReader_Preload.h"
#include "RageUtil.h"
#include "RageSoundUtil.h"
#include "Preference.h"
/* If true, preloaded sounds are stored in 16-bit instead of floats. Most
* processing happens after preloading, and it's usually a waste to store high-
* resolution data for sound effects. */
Preference<bool> g_bSoundPreload16bit( "SoundPreload16bit", true );
/* If a sound is smaller than this, we'll load it entirely into memory. */
Preference<int> g_iSoundPreloadMaxSamples( "SoundPreloadMaxSamples", 1024*1024 );
#define samplesize (m_bBufferIs16Bit? sizeof(int16_t):sizeof(float))
#define framesize (samplesize * m_iChannels)
bool RageSoundReader_Preload::PreloadSound( RageSoundReader *&pSound )
{
RageSoundReader_Preload *pPreload = new RageSoundReader_Preload;
if( !pPreload->Open(pSound) )
{
/* Preload failed. It read some data, so we need to rewind the reader. */
pSound->SetPosition( 0 );
delete pPreload;
return false;
}
pSound = pPreload;
return true;
}
RageSoundReader_Preload::RageSoundReader_Preload():
m_Buffer( new RString ), m_bBufferIs16Bit(false),
m_iPosition(0), m_iSampleRate(0), m_iChannels(0), m_fRate(0.0f)
{
m_bBufferIs16Bit = g_bSoundPreload16bit.Get();
}
int RageSoundReader_Preload::GetTotalFrames() const
{
return m_Buffer->size() / framesize;
}
bool RageSoundReader_Preload::Open( RageSoundReader *pSource )
{
ASSERT( pSource != NULL );
m_iSampleRate = pSource->GetSampleRate();
m_iChannels = pSource->GetNumChannels();
m_fRate = pSource->GetStreamToSourceRatio();
int iMaxSamples = g_iSoundPreloadMaxSamples.Get();
/* Check the length, and see if we think it'll fit in the buffer. */
int iLen = pSource->GetLength_Fast();
if( iLen != -1 )
{
float fSecs = iLen / 1000.f;
int iFrames = lrintf( fSecs * m_iSampleRate ); /* seconds -> frames */
int iSamples = unsigned( iFrames * m_iChannels ); /* frames -> samples */
if( iSamples > iMaxSamples )
return false; /* Don't bother trying to preload it. */
int iBytes = unsigned( iSamples * samplesize ); /* samples -> bytes */
m_Buffer.Get()->reserve( iBytes );
}
while(1)
{
/* If the rate changes, we won't preload it. */
if( pSource->GetStreamToSourceRatio() != m_fRate )
return false; /* Don't bother trying to preload it. */
float buffer[1024];
int iCnt = pSource->Read( buffer, ARRAYLEN(buffer) / m_iChannels );
if( iCnt == END_OF_FILE )
break;
if( iCnt < 0 )
return false;
/* Add the buffer. */
if( m_bBufferIs16Bit )
{
int16_t buffer16[1024];
RageSoundUtil::ConvertFloatToNativeInt16( buffer, buffer16, iCnt*m_iChannels );
m_Buffer.Get()->append( (char *) buffer16, (char *) (buffer16+iCnt*m_iChannels) );
}
else
{
m_Buffer.Get()->append( (char *) buffer, (char *) (buffer+iCnt*m_iChannels) );
}
if( m_Buffer.Get()->size() > iMaxSamples * samplesize )
return false; /* too big */
}
m_iPosition = 0;
delete pSource;
return true;
}
int RageSoundReader_Preload::GetLength() const
{
return int(float(GetTotalFrames()) * 1000.f / m_iSampleRate);
}
int RageSoundReader_Preload::GetLength_Fast() const
{
return GetLength();
}
int RageSoundReader_Preload::SetPosition( int iFrame )
{
m_iPosition = iFrame;
m_iPosition = lrintf(m_iPosition / m_fRate);
if( m_iPosition >= int(m_Buffer->size() / framesize) )
{
m_iPosition = m_Buffer->size() / framesize;
return 0;
}
return 1;
}
int RageSoundReader_Preload::GetNextSourceFrame() const
{
return lrintf(m_iPosition * m_fRate);
}
int RageSoundReader_Preload::Read( float *pBuffer, int iFrames )
{
const int iSizeFrames = m_Buffer->size() / framesize;
const int iFramesAvail = iSizeFrames - m_iPosition;
iFrames = min( iFrames, iFramesAvail );
if( iFrames == 0 )
return END_OF_FILE;
if( m_bBufferIs16Bit )
{
const int16_t *pIn = (const int16_t *) (m_Buffer->data() + (m_iPosition * framesize));
RageSoundUtil::ConvertNativeInt16ToFloat( pIn, pBuffer, iFrames * m_iChannels );
}
else
{
memcpy( pBuffer, m_Buffer->data() + (m_iPosition * framesize), iFrames * framesize );
}
m_iPosition += iFrames;
return iFrames;
}
RageSoundReader_Preload *RageSoundReader_Preload::Copy() const
{
return new RageSoundReader_Preload(*this);
}
int RageSoundReader_Preload::GetReferenceCount() const
{
return m_Buffer.GetReferenceCount();
}
/*
* Copyright (c) 2003 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* This reader simply precaches all of the data from another reader. This
* reduces CPU usage for sounds that are played several times at once. */
#include "global.h"
#include "RageSoundReader_Preload.h"
#include "RageUtil.h"
#include "RageSoundUtil.h"
#include "Preference.h"
/* If true, preloaded sounds are stored in 16-bit instead of floats. Most
* processing happens after preloading, and it's usually a waste to store high-
* resolution data for sound effects. */
Preference<bool> g_bSoundPreload16bit( "SoundPreload16bit", true );
/* If a sound is smaller than this, we'll load it entirely into memory. */
Preference<int> g_iSoundPreloadMaxSamples( "SoundPreloadMaxSamples", 1024*1024 );
#define samplesize (m_bBufferIs16Bit? sizeof(int16_t):sizeof(float))
#define framesize (samplesize * m_iChannels)
bool RageSoundReader_Preload::PreloadSound( RageSoundReader *&pSound )
{
RageSoundReader_Preload *pPreload = new RageSoundReader_Preload;
if( !pPreload->Open(pSound) )
{
/* Preload failed. It read some data, so we need to rewind the reader. */
pSound->SetPosition( 0 );
delete pPreload;
return false;
}
pSound = pPreload;
return true;
}
RageSoundReader_Preload::RageSoundReader_Preload():
m_Buffer( new RString ), m_bBufferIs16Bit(false),
m_iPosition(0), m_iSampleRate(0), m_iChannels(0), m_fRate(0.0f)
{
m_bBufferIs16Bit = g_bSoundPreload16bit.Get();
}
int RageSoundReader_Preload::GetTotalFrames() const
{
return m_Buffer->size() / framesize;
}
bool RageSoundReader_Preload::Open( RageSoundReader *pSource )
{
ASSERT( pSource != nullptr );
m_iSampleRate = pSource->GetSampleRate();
m_iChannels = pSource->GetNumChannels();
m_fRate = pSource->GetStreamToSourceRatio();
int iMaxSamples = g_iSoundPreloadMaxSamples.Get();
/* Check the length, and see if we think it'll fit in the buffer. */
int iLen = pSource->GetLength_Fast();
if( iLen != -1 )
{
float fSecs = iLen / 1000.f;
int iFrames = lrintf( fSecs * m_iSampleRate ); /* seconds -> frames */
int iSamples = unsigned( iFrames * m_iChannels ); /* frames -> samples */
if( iSamples > iMaxSamples )
return false; /* Don't bother trying to preload it. */
int iBytes = unsigned( iSamples * samplesize ); /* samples -> bytes */
m_Buffer.Get()->reserve( iBytes );
}
while(1)
{
/* If the rate changes, we won't preload it. */
if( pSource->GetStreamToSourceRatio() != m_fRate )
return false; /* Don't bother trying to preload it. */
float buffer[1024];
int iCnt = pSource->Read( buffer, ARRAYLEN(buffer) / m_iChannels );
if( iCnt == END_OF_FILE )
break;
if( iCnt < 0 )
return false;
/* Add the buffer. */
if( m_bBufferIs16Bit )
{
int16_t buffer16[1024];
RageSoundUtil::ConvertFloatToNativeInt16( buffer, buffer16, iCnt*m_iChannels );
m_Buffer.Get()->append( (char *) buffer16, (char *) (buffer16+iCnt*m_iChannels) );
}
else
{
m_Buffer.Get()->append( (char *) buffer, (char *) (buffer+iCnt*m_iChannels) );
}
if( m_Buffer.Get()->size() > iMaxSamples * samplesize )
return false; /* too big */
}
m_iPosition = 0;
delete pSource;
return true;
}
int RageSoundReader_Preload::GetLength() const
{
return int(float(GetTotalFrames()) * 1000.f / m_iSampleRate);
}
int RageSoundReader_Preload::GetLength_Fast() const
{
return GetLength();
}
int RageSoundReader_Preload::SetPosition( int iFrame )
{
m_iPosition = iFrame;
m_iPosition = lrintf(m_iPosition / m_fRate);
if( m_iPosition >= int(m_Buffer->size() / framesize) )
{
m_iPosition = m_Buffer->size() / framesize;
return 0;
}
return 1;
}
int RageSoundReader_Preload::GetNextSourceFrame() const
{
return lrintf(m_iPosition * m_fRate);
}
int RageSoundReader_Preload::Read( float *pBuffer, int iFrames )
{
const int iSizeFrames = m_Buffer->size() / framesize;
const int iFramesAvail = iSizeFrames - m_iPosition;
iFrames = min( iFrames, iFramesAvail );
if( iFrames == 0 )
return END_OF_FILE;
if( m_bBufferIs16Bit )
{
const int16_t *pIn = (const int16_t *) (m_Buffer->data() + (m_iPosition * framesize));
RageSoundUtil::ConvertNativeInt16ToFloat( pIn, pBuffer, iFrames * m_iChannels );
}
else
{
memcpy( pBuffer, m_Buffer->data() + (m_iPosition * framesize), iFrames * framesize );
}
m_iPosition += iFrames;
return iFrames;
}
RageSoundReader_Preload *RageSoundReader_Preload::Copy() const
{
return new RageSoundReader_Preload(*this);
}
int RageSoundReader_Preload::GetReferenceCount() const
{
return m_Buffer.GetReferenceCount();
}
/*
* Copyright (c) 2003 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1 -1
View File
@@ -667,7 +667,7 @@ int RageSoundReader_Resample_Good::Read( float *pBuf, int iFrames )
{
int iFramesNeeded = m_apResamplers[0]->NumInputsForOutputSamples(iFrames);
float *pTmpBuf = (float *) alloca( iFramesNeeded * sizeof(float) * iChannels );
ASSERT( pTmpBuf != NULL );
ASSERT( pTmpBuf != nullptr );
int iFramesIn = m_pSource->Read( pTmpBuf, iFramesNeeded );
if( iFramesIn < 0 )
return iFramesIn;
+330 -330
View File
@@ -1,330 +1,330 @@
#include "global.h"
#include "RageUtil.h"
#include "RageSoundReader_Vorbisfile.h"
#include "RageLog.h"
#if defined(INTEGER_VORBIS)
#include <tremor/ivorbisfile.h>
#else
#include <../extern/vorbis/vorbis/vorbisfile.h>
#endif
#if defined(_MSC_VER)
#pragma comment(lib, OGG_LIB_DIR "ogg_static.lib")
#pragma comment(lib, OGG_LIB_DIR "vorbis_static.lib")
#pragma comment(lib, OGG_LIB_DIR "vorbisfile_static.lib")
#endif // _MSC_VER
#include <cstring>
#include <cerrno>
#include "RageFile.h"
static size_t OggRageFile_read_func( void *ptr, size_t size, size_t nmemb, void *datasource )
{
RageFileBasic *f = (RageFileBasic *) datasource;
return f->Read( ptr, size, nmemb );
}
static int OggRageFile_seek_func( void *datasource, ogg_int64_t offset, int whence )
{
RageFileBasic *f = (RageFileBasic *) datasource;
return f->Seek( (int) offset, whence );
}
static int OggRageFile_close_func( void *datasource )
{
return 0;
}
static long OggRageFile_tell_func( void *datasource )
{
RageFileBasic *f = (RageFileBasic *) datasource;
return f->Tell();
}
static RString ov_ssprintf( int err, const char *fmt, ...)
{
va_list va;
va_start( va, fmt );
RString s = vssprintf( fmt, va );
va_end( va );
RString errstr;
switch( err )
{
/* XXX: In the case of OV_EREAD, can we snoop at errno? */
case OV_EREAD: errstr = "Read error"; break;
case OV_EFAULT: errstr = "Internal error"; break;
case OV_EIMPL: errstr = "Feature not implemented"; break;
case OV_EINVAL: errstr = "Invalid argument"; break;
case OV_ENOTVORBIS: errstr = "Not Vorbis data"; break;
case OV_EBADHEADER: errstr = "Invalid Vorbis bitstream header"; break;
case OV_EVERSION: errstr = "Vorbis version mismatch"; break;
case OV_ENOTAUDIO: errstr = "OV_ENOTAUDIO"; break;
case OV_EBADPACKET: errstr = "OV_EBADPACKET"; break;
case OV_EBADLINK: errstr = "Link corrupted"; break;
case OV_ENOSEEK: errstr = "Stream is not seekable"; break;
default: errstr = ssprintf( "unknown error %i", err ); break;
}
return s + ssprintf( " (%s)", errstr.c_str() );
}
RageSoundReader_FileReader::OpenResult RageSoundReader_Vorbisfile::Open( RageFileBasic *pFile )
{
m_pFile = pFile;
vf = new OggVorbis_File;
memset( vf, 0, sizeof(*vf) );
ov_callbacks callbacks;
callbacks.read_func = OggRageFile_read_func;
callbacks.seek_func = OggRageFile_seek_func;
callbacks.close_func = OggRageFile_close_func;
callbacks.tell_func = OggRageFile_tell_func;
int ret = ov_open_callbacks( pFile, vf, NULL, 0, callbacks );
if( ret < 0 )
{
SetError( ov_ssprintf(ret, "ov_open failed") );
delete vf;
vf = NULL;
switch( ret )
{
case OV_ENOTVORBIS:
return OPEN_UNKNOWN_FILE_FORMAT;
default:
return OPEN_FATAL_ERROR;
}
}
eof = false;
read_offset = (int) ov_pcm_tell(vf);
vorbis_info *vi = ov_info( vf, -1 );
channels = vi->channels;
return OPEN_OK;
}
int RageSoundReader_Vorbisfile::GetLength() const
{
#if defined(INTEGER_VORBIS)
int len = ov_time_total(vf, -1);
#else
int len = int(ov_time_total(vf, -1) * 1000);
#endif
if( len == OV_EINVAL )
RageException::Throw( "RageSoundReader_Vorbisfile::GetLength: ov_time_total returned OV_EINVAL." );
return len;
}
int RageSoundReader_Vorbisfile::SetPosition( int iFrame )
{
eof = false;
const ogg_int64_t sample = ogg_int64_t(iFrame);
int ret = ov_pcm_seek( vf, sample );
if(ret < 0)
{
/* Returns OV_EINVAL on EOF. */
if( ret == OV_EINVAL )
{
eof = true;
return 0;
}
SetError( ov_ssprintf(ret, "ogg: SetPosition failed") );
return -1;
}
read_offset = (int) ov_pcm_tell(vf);
return 1;
}
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;
}
int RageSoundReader_Vorbisfile::GetSampleRate() const
{
ASSERT(vf != NULL);
vorbis_info *vi = ov_info(vf, -1);
ASSERT(vi != NULL);
return vi->rate;
}
int RageSoundReader_Vorbisfile::GetNextSourceFrame() const
{
ASSERT(vf != NULL);
int iFrame = (int)ov_pcm_tell( vf );
return iFrame;
}
RageSoundReader_Vorbisfile::RageSoundReader_Vorbisfile()
{
vf = NULL;
}
RageSoundReader_Vorbisfile::~RageSoundReader_Vorbisfile()
{
if(vf)
ov_clear(vf);
delete vf;
}
RageSoundReader_Vorbisfile *RageSoundReader_Vorbisfile::Copy() const
{
RageFileBasic *pFile = m_pFile->Copy();
pFile->Seek(0);
RageSoundReader_Vorbisfile *ret = new RageSoundReader_Vorbisfile;
/* If we were able to open the sound in the first place, we expect to
* be able to reopen it. */
if( ret->Open(pFile) != OPEN_OK )
FAIL_M( ssprintf("Copying sound failed: %s", ret->GetError().c_str()) );
return ret;
}
/*
* Copyright (c) 2003 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageUtil.h"
#include "RageSoundReader_Vorbisfile.h"
#include "RageLog.h"
#if defined(INTEGER_VORBIS)
#include <tremor/ivorbisfile.h>
#else
#include <../extern/vorbis/vorbis/vorbisfile.h>
#endif
#if defined(_MSC_VER)
#pragma comment(lib, OGG_LIB_DIR "ogg_static.lib")
#pragma comment(lib, OGG_LIB_DIR "vorbis_static.lib")
#pragma comment(lib, OGG_LIB_DIR "vorbisfile_static.lib")
#endif // _MSC_VER
#include <cstring>
#include <cerrno>
#include "RageFile.h"
static size_t OggRageFile_read_func( void *ptr, size_t size, size_t nmemb, void *datasource )
{
RageFileBasic *f = (RageFileBasic *) datasource;
return f->Read( ptr, size, nmemb );
}
static int OggRageFile_seek_func( void *datasource, ogg_int64_t offset, int whence )
{
RageFileBasic *f = (RageFileBasic *) datasource;
return f->Seek( (int) offset, whence );
}
static int OggRageFile_close_func( void *datasource )
{
return 0;
}
static long OggRageFile_tell_func( void *datasource )
{
RageFileBasic *f = (RageFileBasic *) datasource;
return f->Tell();
}
static RString ov_ssprintf( int err, const char *fmt, ...)
{
va_list va;
va_start( va, fmt );
RString s = vssprintf( fmt, va );
va_end( va );
RString errstr;
switch( err )
{
/* XXX: In the case of OV_EREAD, can we snoop at errno? */
case OV_EREAD: errstr = "Read error"; break;
case OV_EFAULT: errstr = "Internal error"; break;
case OV_EIMPL: errstr = "Feature not implemented"; break;
case OV_EINVAL: errstr = "Invalid argument"; break;
case OV_ENOTVORBIS: errstr = "Not Vorbis data"; break;
case OV_EBADHEADER: errstr = "Invalid Vorbis bitstream header"; break;
case OV_EVERSION: errstr = "Vorbis version mismatch"; break;
case OV_ENOTAUDIO: errstr = "OV_ENOTAUDIO"; break;
case OV_EBADPACKET: errstr = "OV_EBADPACKET"; break;
case OV_EBADLINK: errstr = "Link corrupted"; break;
case OV_ENOSEEK: errstr = "Stream is not seekable"; break;
default: errstr = ssprintf( "unknown error %i", err ); break;
}
return s + ssprintf( " (%s)", errstr.c_str() );
}
RageSoundReader_FileReader::OpenResult RageSoundReader_Vorbisfile::Open( RageFileBasic *pFile )
{
m_pFile = pFile;
vf = new OggVorbis_File;
memset( vf, 0, sizeof(*vf) );
ov_callbacks callbacks;
callbacks.read_func = OggRageFile_read_func;
callbacks.seek_func = OggRageFile_seek_func;
callbacks.close_func = OggRageFile_close_func;
callbacks.tell_func = OggRageFile_tell_func;
int ret = ov_open_callbacks( pFile, vf, NULL, 0, callbacks );
if( ret < 0 )
{
SetError( ov_ssprintf(ret, "ov_open failed") );
delete vf;
vf = NULL;
switch( ret )
{
case OV_ENOTVORBIS:
return OPEN_UNKNOWN_FILE_FORMAT;
default:
return OPEN_FATAL_ERROR;
}
}
eof = false;
read_offset = (int) ov_pcm_tell(vf);
vorbis_info *vi = ov_info( vf, -1 );
channels = vi->channels;
return OPEN_OK;
}
int RageSoundReader_Vorbisfile::GetLength() const
{
#if defined(INTEGER_VORBIS)
int len = ov_time_total(vf, -1);
#else
int len = int(ov_time_total(vf, -1) * 1000);
#endif
if( len == OV_EINVAL )
RageException::Throw( "RageSoundReader_Vorbisfile::GetLength: ov_time_total returned OV_EINVAL." );
return len;
}
int RageSoundReader_Vorbisfile::SetPosition( int iFrame )
{
eof = false;
const ogg_int64_t sample = ogg_int64_t(iFrame);
int ret = ov_pcm_seek( vf, sample );
if(ret < 0)
{
/* Returns OV_EINVAL on EOF. */
if( ret == OV_EINVAL )
{
eof = true;
return 0;
}
SetError( ov_ssprintf(ret, "ogg: SetPosition failed") );
return -1;
}
read_offset = (int) ov_pcm_tell(vf);
return 1;
}
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 != nullptr );
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;
}
int RageSoundReader_Vorbisfile::GetSampleRate() const
{
ASSERT(vf != nullptr);
vorbis_info *vi = ov_info(vf, -1);
ASSERT(vi != nullptr);
return vi->rate;
}
int RageSoundReader_Vorbisfile::GetNextSourceFrame() const
{
ASSERT(vf != nullptr);
int iFrame = (int)ov_pcm_tell( vf );
return iFrame;
}
RageSoundReader_Vorbisfile::RageSoundReader_Vorbisfile()
{
vf = NULL;
}
RageSoundReader_Vorbisfile::~RageSoundReader_Vorbisfile()
{
if(vf)
ov_clear(vf);
delete vf;
}
RageSoundReader_Vorbisfile *RageSoundReader_Vorbisfile::Copy() const
{
RageFileBasic *pFile = m_pFile->Copy();
pFile->Seek(0);
RageSoundReader_Vorbisfile *ret = new RageSoundReader_Vorbisfile;
/* If we were able to open the sound in the first place, we expect to
* be able to reopen it. */
if( ret->Open(pFile) != OPEN_OK )
FAIL_M( ssprintf("Copying sound failed: %s", ret->GetError().c_str()) );
return ret;
}
/*
* Copyright (c) 2003 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
File diff suppressed because it is too large Load Diff
+280 -280
View File
@@ -1,280 +1,280 @@
#include "global.h"
#include "RageSurface.h"
#include "RageUtil.h"
bool RageSurfaceColor::operator== ( const RageSurfaceColor &rhs ) const
{
return rhs.r == r && rhs.g == g && rhs.b == b && rhs.a == a;
}
int32_t RageSurfacePalette::FindColor( const RageSurfaceColor &color ) const
{
for( int i = 0; i < ncolors; ++i )
if( colors[i] == color )
return i;
return -1;
}
/* XXX: untested */
int32_t RageSurfacePalette::FindClosestColor( const RageSurfaceColor &color ) const
{
int iBest = -1;
int iBestDist = INT_MAX;
for( int i = 0; i < ncolors; ++i )
{
if( colors[i] == color )
return i;
int iDist = abs( colors[i].r - color.r ) +
abs( colors[i].g - color.g ) +
abs( colors[i].b - color.b ) +
abs( colors[i].a - color.a );
if( iDist < iBestDist )
{
iBestDist = iDist ;
iBest = i;
}
}
return iBest;
}
RageSurfaceFormat::RageSurfaceFormat():
Rmask(Mask[0]), Gmask(Mask[1]), Bmask(Mask[2]), Amask(Mask[3]),
Rshift(Shift[0]), Gshift(Shift[1]), Bshift(Shift[2]), Ashift(Shift[3])
{
palette = NULL;
}
RageSurfaceFormat::RageSurfaceFormat( const RageSurfaceFormat &cpy ):
Rmask(Mask[0]), Gmask(Mask[1]), Bmask(Mask[2]), Amask(Mask[3]),
Rshift(Shift[0]), Gshift(Shift[1]), Bshift(Shift[2]), Ashift(Shift[3])
{
memcpy( this, &cpy, sizeof(RageSurfaceFormat) );
if( palette )
palette = new RageSurfacePalette( *palette );
}
RageSurfaceFormat::~RageSurfaceFormat()
{
delete palette;
}
void RageSurfaceFormat::GetRGB( uint32_t val, uint8_t *r, uint8_t *g, uint8_t *b ) const
{
if( BytesPerPixel == 1 )
{
ASSERT( palette != NULL );
*r = palette->colors[val].r;
*g = palette->colors[val].g;
*b = palette->colors[val].b;
} else {
*r = int8_t( (val & Mask[0]) >> Shift[0] << Loss[0] );
*g = int8_t( (val & Mask[1]) >> Shift[1] << Loss[1] );
*b = int8_t( (val & Mask[2]) >> Shift[2] << Loss[2] );
}
}
bool RageSurfaceFormat::MapRGBA( uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint32_t &val ) const
{
if( BytesPerPixel == 1 )
{
RageSurfaceColor c( r, g, b, a );
int32_t n = palette->FindColor( c );
if( n == -1 )
return false;
val = (uint32_t) n;
} else {
val =
(r >> Loss[0] << Shift[0]) |
(g >> Loss[1] << Shift[1]) |
(b >> Loss[2] << Shift[2]) |
(a >> Loss[3] << Shift[3]);
}
return true;
}
bool RageSurfaceFormat::operator== ( const RageSurfaceFormat &rhs ) const
{
if( !Equivalent(rhs) )
return false;
if( BytesPerPixel == 1 )
if( memcmp( palette, rhs.palette, sizeof(RageSurfaceFormat) ) )
return false;
return true;
}
bool RageSurfaceFormat::Equivalent( const RageSurfaceFormat &rhs ) const
{
#define COMP(a) if( a != rhs.a ) return false;
COMP( BytesPerPixel );
COMP( Rmask );
COMP( Gmask );
COMP( Bmask );
COMP( Amask );
return true;
}
RageSurface::RageSurface()
{
format = &fmt;
pixels = NULL;
pixels_owned = true;
}
RageSurface::RageSurface( const RageSurface &cpy )
{
format = &fmt;
w = cpy.w;
h = cpy.h;
pitch = cpy.pitch;
flags = cpy.flags;
pixels_owned = true;
if( cpy.pixels )
{
pixels = new uint8_t[ pitch*h ];
memcpy( pixels, cpy.pixels, pitch*h );
}
else
pixels = NULL;
}
RageSurface::~RageSurface()
{
if( pixels_owned )
delete [] pixels;
}
static int GetShiftFromMask( uint32_t mask )
{
if( !mask )
return 0;
int iShift = 0;
while( (mask & 1) == 0 )
{
mask >>= 1;
++iShift;
}
return iShift;
}
static int GetBitsFromMask( uint32_t mask )
{
if( !mask )
return 0;
mask >>= GetShiftFromMask(mask);
int iBits = 0;
while( (mask & 1) == 1 )
{
mask >>= 1;
++iBits;
}
return iBits;
}
void SetupFormat( RageSurfaceFormat &fmt,
int width, int height, int BitsPerPixel, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask )
{
fmt.BitsPerPixel = BitsPerPixel;
fmt.BytesPerPixel = BitsPerPixel/8;
if( fmt.BytesPerPixel == 1 )
{
ZERO( fmt.Mask );
ZERO( fmt.Shift );
// Loss for paletted textures is zero; the actual palette entries are 8-bit.
ZERO( fmt.Loss );
fmt.palette = new RageSurfacePalette;
fmt.palette->ncolors = 256;
}
else
{
fmt.Mask[0] = Rmask;
fmt.Mask[1] = Gmask;
fmt.Mask[2] = Bmask;
fmt.Mask[3] = Amask;
fmt.Shift[0] = GetShiftFromMask( Rmask );
fmt.Shift[1] = GetShiftFromMask( Gmask );
fmt.Shift[2] = GetShiftFromMask( Bmask );
fmt.Shift[3] = GetShiftFromMask( Amask );
fmt.Loss[0] = (uint8_t) (8-GetBitsFromMask( Rmask ));
fmt.Loss[1] = (uint8_t) (8-GetBitsFromMask( Gmask ));
fmt.Loss[2] = (uint8_t) (8-GetBitsFromMask( Bmask ));
fmt.Loss[3] = (uint8_t) (8-GetBitsFromMask( Amask ));
}
}
RageSurface *CreateSurface( int width, int height, int BitsPerPixel, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask )
{
RageSurface *pImg = new RageSurface;
SetupFormat( pImg->fmt, width, height, BitsPerPixel, Rmask, Gmask, Bmask, Amask );
pImg->w = width;
pImg->h = height;
pImg->flags = 0;
pImg->pitch = width*BitsPerPixel/8;
pImg->pixels = new uint8_t[ pImg->pitch*height ];
/*
if( BitsPerPixel == 8 )
{
pImg->fmt.palette = new RageSurfacePalette;
}
*/
return pImg;
}
RageSurface *CreateSurfaceFrom( int width, int height, int BitsPerPixel, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask, uint8_t *pPixels, uint32_t pitch )
{
RageSurface *pImg = new RageSurface;
SetupFormat( pImg->fmt, width, height, BitsPerPixel, Rmask, Gmask, Bmask, Amask );
pImg->w = width;
pImg->h = height;
pImg->flags = 0;
pImg->pitch = pitch;
pImg->pixels = pPixels;
pImg->pixels_owned = false;
return pImg;
}
/*
* (c) 2001-2004 Glenn Maynard, Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSurface.h"
#include "RageUtil.h"
bool RageSurfaceColor::operator== ( const RageSurfaceColor &rhs ) const
{
return rhs.r == r && rhs.g == g && rhs.b == b && rhs.a == a;
}
int32_t RageSurfacePalette::FindColor( const RageSurfaceColor &color ) const
{
for( int i = 0; i < ncolors; ++i )
if( colors[i] == color )
return i;
return -1;
}
/* XXX: untested */
int32_t RageSurfacePalette::FindClosestColor( const RageSurfaceColor &color ) const
{
int iBest = -1;
int iBestDist = INT_MAX;
for( int i = 0; i < ncolors; ++i )
{
if( colors[i] == color )
return i;
int iDist = abs( colors[i].r - color.r ) +
abs( colors[i].g - color.g ) +
abs( colors[i].b - color.b ) +
abs( colors[i].a - color.a );
if( iDist < iBestDist )
{
iBestDist = iDist ;
iBest = i;
}
}
return iBest;
}
RageSurfaceFormat::RageSurfaceFormat():
Rmask(Mask[0]), Gmask(Mask[1]), Bmask(Mask[2]), Amask(Mask[3]),
Rshift(Shift[0]), Gshift(Shift[1]), Bshift(Shift[2]), Ashift(Shift[3])
{
palette = NULL;
}
RageSurfaceFormat::RageSurfaceFormat( const RageSurfaceFormat &cpy ):
Rmask(Mask[0]), Gmask(Mask[1]), Bmask(Mask[2]), Amask(Mask[3]),
Rshift(Shift[0]), Gshift(Shift[1]), Bshift(Shift[2]), Ashift(Shift[3])
{
memcpy( this, &cpy, sizeof(RageSurfaceFormat) );
if( palette )
palette = new RageSurfacePalette( *palette );
}
RageSurfaceFormat::~RageSurfaceFormat()
{
delete palette;
}
void RageSurfaceFormat::GetRGB( uint32_t val, uint8_t *r, uint8_t *g, uint8_t *b ) const
{
if( BytesPerPixel == 1 )
{
ASSERT( palette != nullptr );
*r = palette->colors[val].r;
*g = palette->colors[val].g;
*b = palette->colors[val].b;
} else {
*r = int8_t( (val & Mask[0]) >> Shift[0] << Loss[0] );
*g = int8_t( (val & Mask[1]) >> Shift[1] << Loss[1] );
*b = int8_t( (val & Mask[2]) >> Shift[2] << Loss[2] );
}
}
bool RageSurfaceFormat::MapRGBA( uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint32_t &val ) const
{
if( BytesPerPixel == 1 )
{
RageSurfaceColor c( r, g, b, a );
int32_t n = palette->FindColor( c );
if( n == -1 )
return false;
val = (uint32_t) n;
} else {
val =
(r >> Loss[0] << Shift[0]) |
(g >> Loss[1] << Shift[1]) |
(b >> Loss[2] << Shift[2]) |
(a >> Loss[3] << Shift[3]);
}
return true;
}
bool RageSurfaceFormat::operator== ( const RageSurfaceFormat &rhs ) const
{
if( !Equivalent(rhs) )
return false;
if( BytesPerPixel == 1 )
if( memcmp( palette, rhs.palette, sizeof(RageSurfaceFormat) ) )
return false;
return true;
}
bool RageSurfaceFormat::Equivalent( const RageSurfaceFormat &rhs ) const
{
#define COMP(a) if( a != rhs.a ) return false;
COMP( BytesPerPixel );
COMP( Rmask );
COMP( Gmask );
COMP( Bmask );
COMP( Amask );
return true;
}
RageSurface::RageSurface()
{
format = &fmt;
pixels = NULL;
pixels_owned = true;
}
RageSurface::RageSurface( const RageSurface &cpy )
{
format = &fmt;
w = cpy.w;
h = cpy.h;
pitch = cpy.pitch;
flags = cpy.flags;
pixels_owned = true;
if( cpy.pixels )
{
pixels = new uint8_t[ pitch*h ];
memcpy( pixels, cpy.pixels, pitch*h );
}
else
pixels = NULL;
}
RageSurface::~RageSurface()
{
if( pixels_owned )
delete [] pixels;
}
static int GetShiftFromMask( uint32_t mask )
{
if( !mask )
return 0;
int iShift = 0;
while( (mask & 1) == 0 )
{
mask >>= 1;
++iShift;
}
return iShift;
}
static int GetBitsFromMask( uint32_t mask )
{
if( !mask )
return 0;
mask >>= GetShiftFromMask(mask);
int iBits = 0;
while( (mask & 1) == 1 )
{
mask >>= 1;
++iBits;
}
return iBits;
}
void SetupFormat( RageSurfaceFormat &fmt,
int width, int height, int BitsPerPixel, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask )
{
fmt.BitsPerPixel = BitsPerPixel;
fmt.BytesPerPixel = BitsPerPixel/8;
if( fmt.BytesPerPixel == 1 )
{
ZERO( fmt.Mask );
ZERO( fmt.Shift );
// Loss for paletted textures is zero; the actual palette entries are 8-bit.
ZERO( fmt.Loss );
fmt.palette = new RageSurfacePalette;
fmt.palette->ncolors = 256;
}
else
{
fmt.Mask[0] = Rmask;
fmt.Mask[1] = Gmask;
fmt.Mask[2] = Bmask;
fmt.Mask[3] = Amask;
fmt.Shift[0] = GetShiftFromMask( Rmask );
fmt.Shift[1] = GetShiftFromMask( Gmask );
fmt.Shift[2] = GetShiftFromMask( Bmask );
fmt.Shift[3] = GetShiftFromMask( Amask );
fmt.Loss[0] = (uint8_t) (8-GetBitsFromMask( Rmask ));
fmt.Loss[1] = (uint8_t) (8-GetBitsFromMask( Gmask ));
fmt.Loss[2] = (uint8_t) (8-GetBitsFromMask( Bmask ));
fmt.Loss[3] = (uint8_t) (8-GetBitsFromMask( Amask ));
}
}
RageSurface *CreateSurface( int width, int height, int BitsPerPixel, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask )
{
RageSurface *pImg = new RageSurface;
SetupFormat( pImg->fmt, width, height, BitsPerPixel, Rmask, Gmask, Bmask, Amask );
pImg->w = width;
pImg->h = height;
pImg->flags = 0;
pImg->pitch = width*BitsPerPixel/8;
pImg->pixels = new uint8_t[ pImg->pitch*height ];
/*
if( BitsPerPixel == 8 )
{
pImg->fmt.palette = new RageSurfacePalette;
}
*/
return pImg;
}
RageSurface *CreateSurfaceFrom( int width, int height, int BitsPerPixel, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask, uint8_t *pPixels, uint32_t pitch )
{
RageSurface *pImg = new RageSurface;
SetupFormat( pImg->fmt, width, height, BitsPerPixel, Rmask, Gmask, Bmask, Amask );
pImg->w = width;
pImg->h = height;
pImg->flags = 0;
pImg->pitch = pitch;
pImg->pixels = pPixels;
pImg->pixels_owned = false;
return pImg;
}
/*
* (c) 2001-2004 Glenn Maynard, Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+1072 -1072
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+144 -144
View File
@@ -1,144 +1,144 @@
#include "global.h"
#include "RageSurface_Load.h"
#include "RageSurface_Load_PNG.h"
#include "RageSurface_Load_JPEG.h"
#include "RageSurface_Load_GIF.h"
#include "RageSurface_Load_BMP.h"
#include "RageUtil.h"
#include "RageFile.h"
#include "RageLog.h"
#include <set>
static RageSurface *TryOpenFile( RString sPath, bool bHeaderOnly, RString &error, RString format, bool &bKeepTrying )
{
RageSurface *ret = NULL;
RageSurfaceUtils::OpenResult result;
if( !format.CompareNoCase("png") )
result = RageSurface_Load_PNG( sPath, ret, bHeaderOnly, error );
else if( !format.CompareNoCase("gif") )
result = RageSurface_Load_GIF( sPath, ret, bHeaderOnly, error );
else if( !format.CompareNoCase("jpg") || !format.CompareNoCase("jpeg") )
result = RageSurface_Load_JPEG( sPath, ret, bHeaderOnly, error );
else if( !format.CompareNoCase("bmp") )
result = RageSurface_Load_BMP( sPath, ret, bHeaderOnly, error );
else
{
error = "Unsupported format";
bKeepTrying = true;
return NULL;
}
if( result == RageSurfaceUtils::OPEN_OK )
{
ASSERT( ret != NULL );
return ret;
}
LOG->Trace( "Format %s failed: %s", format.c_str(), error.c_str() );
/*
* The file failed to open, or failed to read. This indicates a problem that will
* affect all readers, so don't waste time trying more readers. (OPEN_IO_ERROR)
*
* Errors fall in two categories:
* OPEN_UNKNOWN_FILE_FORMAT: Data was successfully read from the file, but it's the
* wrong file format. The error message always looks like "unknown file format" or
* "Not Vorbis data"; ignore it so we always give a consistent error message, and
* continue trying other file formats.
*
* OPEN_FATAL_ERROR: Either the file was opened successfully and appears to be the
* correct format, but a fatal format-specific error was encountered that will probably
* not be fixed by using a different reader (for example, an Ogg file that doesn't
* actually contain any audio streams); or the file failed to open or read ("I/O
* error", "permission denied"), in which case all other readers will probably fail,
* too. The returned error is used, and no other formats will be tried.
*/
bKeepTrying = (result != RageSurfaceUtils::OPEN_FATAL_ERROR);
switch( result )
{
case RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT:
bKeepTrying = true;
error = "Unknown file format";
break;
case RageSurfaceUtils::OPEN_FATAL_ERROR:
/* The file matched, but failed to load. We know it's this type of data;
* don't bother trying the other file types. */
bKeepTrying = false;
break;
default: break;
}
return NULL;
}
RageSurface *RageSurfaceUtils::LoadFile( const RString &sPath, RString &error, bool bHeaderOnly )
{
{
RageFile TestOpen;
if( !TestOpen.Open( sPath ) )
{
error = TestOpen.GetError();
return NULL;
}
}
set<RString> FileTypes;
FileTypes.insert("png");
FileTypes.insert("jpg");
FileTypes.insert("jpeg");
FileTypes.insert("gif");
FileTypes.insert("bmp");
RString format = GetExtension(sPath);
format.MakeLower();
bool bKeepTrying = true;
/* If the extension matches a format, try that first. */
if( FileTypes.find(format) != FileTypes.end() )
{
RageSurface *ret = TryOpenFile( sPath, bHeaderOnly, error, format, bKeepTrying );
if( ret )
return ret;
FileTypes.erase( format );
}
for( set<RString>::iterator it = FileTypes.begin(); bKeepTrying && it != FileTypes.end(); ++it )
{
RageSurface *ret = TryOpenFile( sPath, bHeaderOnly, error, *it, bKeepTrying );
if( ret )
{
LOG->UserLog( "Graphic file", sPath, "is really %s", it->c_str() );
return ret;
}
}
return NULL;
}
/*
* (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSurface_Load.h"
#include "RageSurface_Load_PNG.h"
#include "RageSurface_Load_JPEG.h"
#include "RageSurface_Load_GIF.h"
#include "RageSurface_Load_BMP.h"
#include "RageUtil.h"
#include "RageFile.h"
#include "RageLog.h"
#include <set>
static RageSurface *TryOpenFile( RString sPath, bool bHeaderOnly, RString &error, RString format, bool &bKeepTrying )
{
RageSurface *ret = NULL;
RageSurfaceUtils::OpenResult result;
if( !format.CompareNoCase("png") )
result = RageSurface_Load_PNG( sPath, ret, bHeaderOnly, error );
else if( !format.CompareNoCase("gif") )
result = RageSurface_Load_GIF( sPath, ret, bHeaderOnly, error );
else if( !format.CompareNoCase("jpg") || !format.CompareNoCase("jpeg") )
result = RageSurface_Load_JPEG( sPath, ret, bHeaderOnly, error );
else if( !format.CompareNoCase("bmp") )
result = RageSurface_Load_BMP( sPath, ret, bHeaderOnly, error );
else
{
error = "Unsupported format";
bKeepTrying = true;
return NULL;
}
if( result == RageSurfaceUtils::OPEN_OK )
{
ASSERT( ret != nullptr );
return ret;
}
LOG->Trace( "Format %s failed: %s", format.c_str(), error.c_str() );
/*
* The file failed to open, or failed to read. This indicates a problem that will
* affect all readers, so don't waste time trying more readers. (OPEN_IO_ERROR)
*
* Errors fall in two categories:
* OPEN_UNKNOWN_FILE_FORMAT: Data was successfully read from the file, but it's the
* wrong file format. The error message always looks like "unknown file format" or
* "Not Vorbis data"; ignore it so we always give a consistent error message, and
* continue trying other file formats.
*
* OPEN_FATAL_ERROR: Either the file was opened successfully and appears to be the
* correct format, but a fatal format-specific error was encountered that will probably
* not be fixed by using a different reader (for example, an Ogg file that doesn't
* actually contain any audio streams); or the file failed to open or read ("I/O
* error", "permission denied"), in which case all other readers will probably fail,
* too. The returned error is used, and no other formats will be tried.
*/
bKeepTrying = (result != RageSurfaceUtils::OPEN_FATAL_ERROR);
switch( result )
{
case RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT:
bKeepTrying = true;
error = "Unknown file format";
break;
case RageSurfaceUtils::OPEN_FATAL_ERROR:
/* The file matched, but failed to load. We know it's this type of data;
* don't bother trying the other file types. */
bKeepTrying = false;
break;
default: break;
}
return NULL;
}
RageSurface *RageSurfaceUtils::LoadFile( const RString &sPath, RString &error, bool bHeaderOnly )
{
{
RageFile TestOpen;
if( !TestOpen.Open( sPath ) )
{
error = TestOpen.GetError();
return NULL;
}
}
set<RString> FileTypes;
FileTypes.insert("png");
FileTypes.insert("jpg");
FileTypes.insert("jpeg");
FileTypes.insert("gif");
FileTypes.insert("bmp");
RString format = GetExtension(sPath);
format.MakeLower();
bool bKeepTrying = true;
/* If the extension matches a format, try that first. */
if( FileTypes.find(format) != FileTypes.end() )
{
RageSurface *ret = TryOpenFile( sPath, bHeaderOnly, error, format, bKeepTrying );
if( ret )
return ret;
FileTypes.erase( format );
}
for( set<RString>::iterator it = FileTypes.begin(); bKeepTrying && it != FileTypes.end(); ++it )
{
RageSurface *ret = TryOpenFile( sPath, bHeaderOnly, error, *it, bKeepTrying );
if( ret )
{
LOG->UserLog( "Graphic file", sPath, "is really %s", it->c_str() );
return ret;
}
}
return NULL;
}
/*
* (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+236 -236
View File
@@ -1,236 +1,236 @@
#include "global.h"
#include "RageSurface_Load_BMP.h"
#include "RageFile.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageSurface.h"
using namespace FileReading;
/* Tested with http://entropymine.com/jason/bmpsuite/. */
enum
{
COMP_BI_RGB = 0,
COMP_BI_RLE4, /* unsupported */
COMP_BI_RLE8, /* unsupported */
COMP_BI_BITFIELDS
};
/* When returning error, the first error encountered takes priority. */
#define FATAL_ERROR(s) \
{ \
if( sError.size() == 0 ) sError = (s); \
return RageSurfaceUtils::OPEN_FATAL_ERROR; \
}
static RageSurfaceUtils::OpenResult LoadBMP( RageFile &f, RageSurface *&img, RString &sError )
{
char magic[2];
ReadBytes( f, magic, 2, sError );
if( magic[0] != 'B' || magic[1] != 'M' )
{
sError = "not a BMP";
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT;
}
img = NULL;
read_u32_le( f, sError ); /* file size */
read_u32_le( f, sError ); /* unused */
uint32_t iDataOffset = read_u32_le( f, sError );
uint32_t iHeaderSize = read_u32_le( f, sError );
uint32_t iWidth, iHeight, iPlanes, iBPP, iCompression = COMP_BI_RGB, iColors = 0;
if( iHeaderSize == 12 )
{
/* OS/2 format */
iWidth = read_u16_le( f, sError );
iHeight = read_u16_le( f, sError );
iPlanes = read_u16_le( f, sError );
iBPP = read_u16_le( f, sError );
}
else if( iHeaderSize == 40 )
{
iWidth = read_u32_le( f, sError );
iHeight = read_u32_le( f, sError );
iPlanes = read_u16_le( f, sError );
iBPP = read_u16_le( f, sError );
iCompression = read_u32_le( f, sError );
read_u32_le( f, sError ); /* bitmap size */
read_u32_le( f, sError ); /* horiz resolution */
read_u32_le( f, sError ); /* vert resolution */
iColors = read_u32_le( f, sError );
read_u32_le( f, sError ); /* "important" colors */
}
else
FATAL_ERROR( ssprintf( "expected header size of 40, got %u", iHeaderSize ) );
if( iBPP <= 8 && iColors == 0 )
iColors = 1 << iBPP;
if( iPlanes != 1 )
FATAL_ERROR( ssprintf( "expected one plane, got %u", iPlanes ) );
if( iBPP != 1 && iBPP != 4 && iBPP != 8 && iBPP != 16 && iBPP != 24 && iBPP != 32 )
FATAL_ERROR( ssprintf( "unsupported bpp %u", iBPP ) );
if( iCompression != COMP_BI_RGB && iCompression != COMP_BI_BITFIELDS )
FATAL_ERROR( ssprintf( "unsupported compression %u", iCompression ) );
if( iCompression == COMP_BI_BITFIELDS && iBPP <= 8 )
FATAL_ERROR( ssprintf( "BI_BITFIELDS unexpected with bpp %u", iBPP ) );
int iFileBPP = iBPP;
iBPP = max( iBPP, 8u );
int Rmask = 0, Gmask = 0, Bmask = 0, Amask = 0;
switch( iBPP )
{
case 16:
Rmask = Swap16LE( 0x7C00 );
Gmask = Swap16LE( 0x03E0 );
Bmask = Swap16LE( 0x001F );
break;
case 24:
Rmask = Swap24LE( 0xFF0000 );
Gmask = Swap24LE( 0x00FF00 );
Bmask = Swap24LE( 0x0000FF );
break;
case 32:
Rmask = Swap32LE( 0x00FF0000 );
Gmask = Swap32LE( 0x0000FF00 );
Bmask = Swap32LE( 0x000000FF );
break;
}
if( iCompression == COMP_BI_BITFIELDS )
{
Rmask = read_u32_le( f, sError );
Gmask = read_u32_le( f, sError );
Bmask = read_u32_le( f, sError );
}
/* Stop on error before we use any of the values we just read. */
if( sError.size() != 0 )
return RageSurfaceUtils::OPEN_FATAL_ERROR;
img = CreateSurface( iWidth, iHeight, iBPP, Rmask, Gmask, Bmask, Amask );
if( iBPP == 8 )
{
RageSurfaceColor Palette[256];
ZERO( Palette );
if( iColors > 256 )
FATAL_ERROR( ssprintf( "unexpected colors %i", iColors ) );
for( unsigned i = 0; i < iColors; ++i )
{
Palette[i].b = read_8( f, sError );
Palette[i].g = read_8( f, sError );
Palette[i].r = read_8( f, sError );
Palette[i].a = 0xFF;
/* Windows BMP palettes are padded to 32bpp. */
if( iHeaderSize == 40 )
read_8( f, sError );
}
memcpy( img->fmt.palette->colors, Palette, sizeof(Palette) );
}
/* Stop on error before we seek, so we don't return the wrong error message. */
if( sError.size() != 0 )
return RageSurfaceUtils::OPEN_FATAL_ERROR;
int iFilePitch = iFileBPP * iWidth; // in bits
iFilePitch = (iFilePitch+7) / 8; // in bytes: round up
iFilePitch = (iFilePitch+3) & ~3; // round up a multiple of 4
{
int ret = f.Seek( iDataOffset );
if( ret == -1 )
FATAL_ERROR( f.GetError() );
if( ret != (int) iDataOffset )
FATAL_ERROR( "Unexpected end of file" );
}
for( int y = (int) iHeight-1; y >= 0; --y )
{
uint8_t *pRow = img->pixels + img->pitch*y;
RString buf;
f.Read( buf, iFilePitch );
/* Expand 1- and 4-bits to 8-bits. */
if( iFileBPP == 1 )
{
for( unsigned x = 0; x < iWidth; ++x )
{
int iByteNo = x >> 3;
int iBitNo = 7-(x&7);
int iBit = 1 << iBitNo;
pRow[x] = !!(buf[iByteNo] & iBit);
}
}
else if( iFileBPP == 4 )
{
for( unsigned x = 0; x < iWidth; ++x )
{
if( (x & 1) == 0 )
pRow[x] = buf[x/2] & 0x0F;
else
pRow[x] = (buf[x/2] >> 4) & 0x0F;
}
}
else
memcpy( pRow, buf.data(), img->pitch );
}
return sError.size() != 0? RageSurfaceUtils::OPEN_FATAL_ERROR: RageSurfaceUtils::OPEN_OK;
}
RageSurfaceUtils::OpenResult RageSurface_Load_BMP( const RString &sPath, RageSurface *&img, bool bHeaderOnly, RString &error )
{
RageFile f;
if( !f.Open( sPath ) )
{
error = f.GetError();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
RageSurfaceUtils::OpenResult ret;
img = NULL;
ret = LoadBMP( f, img, error );
if( ret != RageSurfaceUtils::OPEN_OK && img != NULL )
{
delete img;
img = NULL;
}
return ret;
}
/*
* Copyright (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSurface_Load_BMP.h"
#include "RageFile.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageSurface.h"
using namespace FileReading;
/* Tested with http://entropymine.com/jason/bmpsuite/. */
enum
{
COMP_BI_RGB = 0,
COMP_BI_RLE4, /* unsupported */
COMP_BI_RLE8, /* unsupported */
COMP_BI_BITFIELDS
};
/* When returning error, the first error encountered takes priority. */
#define FATAL_ERROR(s) \
{ \
if( sError.size() == 0 ) sError = (s); \
return RageSurfaceUtils::OPEN_FATAL_ERROR; \
}
static RageSurfaceUtils::OpenResult LoadBMP( RageFile &f, RageSurface *&img, RString &sError )
{
char magic[2];
ReadBytes( f, magic, 2, sError );
if( magic[0] != 'B' || magic[1] != 'M' )
{
sError = "not a BMP";
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT;
}
img = NULL;
read_u32_le( f, sError ); /* file size */
read_u32_le( f, sError ); /* unused */
uint32_t iDataOffset = read_u32_le( f, sError );
uint32_t iHeaderSize = read_u32_le( f, sError );
uint32_t iWidth, iHeight, iPlanes, iBPP, iCompression = COMP_BI_RGB, iColors = 0;
if( iHeaderSize == 12 )
{
/* OS/2 format */
iWidth = read_u16_le( f, sError );
iHeight = read_u16_le( f, sError );
iPlanes = read_u16_le( f, sError );
iBPP = read_u16_le( f, sError );
}
else if( iHeaderSize == 40 )
{
iWidth = read_u32_le( f, sError );
iHeight = read_u32_le( f, sError );
iPlanes = read_u16_le( f, sError );
iBPP = read_u16_le( f, sError );
iCompression = read_u32_le( f, sError );
read_u32_le( f, sError ); /* bitmap size */
read_u32_le( f, sError ); /* horiz resolution */
read_u32_le( f, sError ); /* vert resolution */
iColors = read_u32_le( f, sError );
read_u32_le( f, sError ); /* "important" colors */
}
else
FATAL_ERROR( ssprintf( "expected header size of 40, got %u", iHeaderSize ) );
if( iBPP <= 8 && iColors == 0 )
iColors = 1 << iBPP;
if( iPlanes != 1 )
FATAL_ERROR( ssprintf( "expected one plane, got %u", iPlanes ) );
if( iBPP != 1 && iBPP != 4 && iBPP != 8 && iBPP != 16 && iBPP != 24 && iBPP != 32 )
FATAL_ERROR( ssprintf( "unsupported bpp %u", iBPP ) );
if( iCompression != COMP_BI_RGB && iCompression != COMP_BI_BITFIELDS )
FATAL_ERROR( ssprintf( "unsupported compression %u", iCompression ) );
if( iCompression == COMP_BI_BITFIELDS && iBPP <= 8 )
FATAL_ERROR( ssprintf( "BI_BITFIELDS unexpected with bpp %u", iBPP ) );
int iFileBPP = iBPP;
iBPP = max( iBPP, 8u );
int Rmask = 0, Gmask = 0, Bmask = 0, Amask = 0;
switch( iBPP )
{
case 16:
Rmask = Swap16LE( 0x7C00 );
Gmask = Swap16LE( 0x03E0 );
Bmask = Swap16LE( 0x001F );
break;
case 24:
Rmask = Swap24LE( 0xFF0000 );
Gmask = Swap24LE( 0x00FF00 );
Bmask = Swap24LE( 0x0000FF );
break;
case 32:
Rmask = Swap32LE( 0x00FF0000 );
Gmask = Swap32LE( 0x0000FF00 );
Bmask = Swap32LE( 0x000000FF );
break;
}
if( iCompression == COMP_BI_BITFIELDS )
{
Rmask = read_u32_le( f, sError );
Gmask = read_u32_le( f, sError );
Bmask = read_u32_le( f, sError );
}
/* Stop on error before we use any of the values we just read. */
if( sError.size() != 0 )
return RageSurfaceUtils::OPEN_FATAL_ERROR;
img = CreateSurface( iWidth, iHeight, iBPP, Rmask, Gmask, Bmask, Amask );
if( iBPP == 8 )
{
RageSurfaceColor Palette[256];
ZERO( Palette );
if( iColors > 256 )
FATAL_ERROR( ssprintf( "unexpected colors %i", iColors ) );
for( unsigned i = 0; i < iColors; ++i )
{
Palette[i].b = read_8( f, sError );
Palette[i].g = read_8( f, sError );
Palette[i].r = read_8( f, sError );
Palette[i].a = 0xFF;
/* Windows BMP palettes are padded to 32bpp. */
if( iHeaderSize == 40 )
read_8( f, sError );
}
memcpy( img->fmt.palette->colors, Palette, sizeof(Palette) );
}
/* Stop on error before we seek, so we don't return the wrong error message. */
if( sError.size() != 0 )
return RageSurfaceUtils::OPEN_FATAL_ERROR;
int iFilePitch = iFileBPP * iWidth; // in bits
iFilePitch = (iFilePitch+7) / 8; // in bytes: round up
iFilePitch = (iFilePitch+3) & ~3; // round up a multiple of 4
{
int ret = f.Seek( iDataOffset );
if( ret == -1 )
FATAL_ERROR( f.GetError() );
if( ret != (int) iDataOffset )
FATAL_ERROR( "Unexpected end of file" );
}
for( int y = (int) iHeight-1; y >= 0; --y )
{
uint8_t *pRow = img->pixels + img->pitch*y;
RString buf;
f.Read( buf, iFilePitch );
/* Expand 1- and 4-bits to 8-bits. */
if( iFileBPP == 1 )
{
for( unsigned x = 0; x < iWidth; ++x )
{
int iByteNo = x >> 3;
int iBitNo = 7-(x&7);
int iBit = 1 << iBitNo;
pRow[x] = !!(buf[iByteNo] & iBit);
}
}
else if( iFileBPP == 4 )
{
for( unsigned x = 0; x < iWidth; ++x )
{
if( (x & 1) == 0 )
pRow[x] = buf[x/2] & 0x0F;
else
pRow[x] = (buf[x/2] >> 4) & 0x0F;
}
}
else
memcpy( pRow, buf.data(), img->pitch );
}
return sError.size() != 0? RageSurfaceUtils::OPEN_FATAL_ERROR: RageSurfaceUtils::OPEN_OK;
}
RageSurfaceUtils::OpenResult RageSurface_Load_BMP( const RString &sPath, RageSurface *&img, bool bHeaderOnly, RString &error )
{
RageFile f;
if( !f.Open( sPath ) )
{
error = f.GetError();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
RageSurfaceUtils::OpenResult ret;
img = NULL;
ret = LoadBMP( f, img, error );
if( ret != RageSurfaceUtils::OPEN_OK && img != nullptr )
{
delete img;
img = NULL;
}
return ret;
}
/*
* Copyright (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+299 -299
View File
@@ -1,299 +1,299 @@
#include "global.h"
#include "RageSurface_Load_PNG.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageFile.h"
#include "RageSurface.h"
#if defined(_WINDOWS)
# include "png.h"
# if defined(_MSC_VER)
# pragma comment(lib, "libpng.lib")
# pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
# endif // _MSC_VER
#else
# include <../extern/libpng/include/png.h>
#endif
namespace
{
void RageFile_png_read( png_struct *png, png_byte *p, png_size_t size )
{
CHECKPOINT;
RageFile *f = (RageFile *) png_get_io_ptr(png);
int got = f->Read( p, size );
if( got == -1 )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns here, it may never be destructed and we could leak. */
static char error[256];
strncpy( error, f->GetError(), sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( png, error );
}
else if( got != (int) size )
png_error( png, "Unexpected EOF" );
}
struct error_info
{
char *err;
const char *fn;
};
void PNG_Error( png_struct *png, const char *error )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_error_ptr(png);
strncpy( info->err, error, 1024 );
info->err[1023] = 0;
LOG->Trace( "loading \"%s\": err: %s", info->fn, info->err );
longjmp( png_jmpbuf(png), 1 );
}
void PNG_Warning( png_struct *png, const char *warning )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_io_ptr(png);
LOG->Trace( "loading \"%s\": warning: %s", info->fn, warning );
}
/* Since libpng forces us to use longjmp (gross!), this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static RageSurface *RageSurface_Load_PNG( RageFile *f, const char *fn, char errorbuf[1024], bool bHeaderOnly )
{
error_info error;
error.err = errorbuf;
error.fn = fn;
png_struct *png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
if( png == NULL )
{
sprintf( errorbuf, "creating png_create_read_struct failed");
return NULL;
}
png_info *info_ptr = png_create_info_struct(png);
if( info_ptr == NULL )
{
png_destroy_read_struct( &png, NULL, NULL );
sprintf( errorbuf, "creating png_create_info_struct failed");
return NULL;
}
RageSurface *volatile img = NULL;
CHECKPOINT;
if( setjmp(png_jmpbuf(png) ))
{
png_destroy_read_struct( &png, &info_ptr, NULL );
delete img;
return NULL;
}
CHECKPOINT;
png_set_read_fn( png, f, RageFile_png_read );
png_read_info( png, info_ptr );
png_uint_32 width, height;
int bit_depth, color_type;
png_get_IHDR( png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL );
/* If bHeaderOnly is true, don't allocate the pixel storage space or decompress
* the image. Just return an empty surface with only the width and height set. */
if( bHeaderOnly )
{
CHECKPOINT;
img = CreateSurfaceFrom( width, height, 32, 0, 0, 0, 0, NULL, width*4 );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
CHECKPOINT;
png_set_strip_16(png); /* 16bit->8bit */
png_set_packing( png ); /* 1,2,4 bit->8 bit */
/* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
png_set_expand_gray_1_2_4_to_8( png );
/* These are set for type == PALETTE. */
RageSurfaceColor colors[256];
int iColorKey = -1;
/* We import three types of files: paletted, RGBX and RGBA. The only difference
* between RGBX and RGBA is that RGBX won't set the alpha mask, so it's easier
* to tell later on that there's no alpha (without actually having to do a pixel scan). */
enum { PALETTE, RGBX, RGBA } type;
switch( color_type )
{
case PNG_COLOR_TYPE_GRAY:
/* Fake PNG_COLOR_TYPE_GRAY. */
for( int i = 0; i < 256; ++i )
{
colors[i].r = colors[i].g = colors[i].b = (int8_t) i;
colors[i].a = 0xFF;
}
type = PALETTE;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
type = RGBA;
png_set_gray_to_rgb( png );
break;
case PNG_COLOR_TYPE_PALETTE:
type = PALETTE;
break;
case PNG_COLOR_TYPE_RGB:
type = RGBX;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
type = RGBA;
break;
default:
FAIL_M(ssprintf( "%i", color_type) );
}
CHECKPOINT;
if( color_type == PNG_COLOR_TYPE_GRAY )
{
png_color_16 *trans;
if( png_get_tRNS( png, info_ptr, NULL, NULL, &trans ) == PNG_INFO_tRNS )
iColorKey = trans->gray;
}
else if( color_type == PNG_COLOR_TYPE_PALETTE )
{
int num_palette;
png_color *palette;
int ret = png_get_PLTE( png, info_ptr, &palette, &num_palette );
ASSERT( ret == PNG_INFO_PLTE );
png_byte *trans = NULL;
int num_trans = 0;
png_get_tRNS( png, info_ptr, &trans, &num_trans, NULL );
for( int i = 0; i < num_palette; ++i )
{
colors[i].r = palette[i].red;
colors[i].g = palette[i].green;
colors[i].b = palette[i].blue;
colors[i].a = 0xFF;
if( i < num_trans )
colors[i].a = trans[i];
}
}
else
{
/* If we have RGB image and tRNS, it's a color key. Just convert it to RGBA. */
if( png_get_valid(png, info_ptr, PNG_INFO_tRNS) )
{
/* We don't care about RGB color keys; just convert them to alpha. */
png_set_tRNS_to_alpha( png );
type = RGBA;
}
/* RGB->RGBX */
png_set_filler( png, 0xff, PNG_FILLER_AFTER );
}
png_set_interlace_handling( png );
CHECKPOINT;
png_read_update_info( png, info_ptr );
switch( type )
{
case PALETTE:
img = CreateSurface( width, height, 8, 0, 0, 0, 0 );
memcpy( img->fmt.palette->colors, colors, 256*sizeof(RageSurfaceColor) );
if( iColorKey != -1 )
img->format->palette->colors[ iColorKey ].a = 0;
break;
case RGBX:
case RGBA:
img = CreateSurface( width, height, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( type == RGBA? 0x000000FF:0x00000000 ) );
break;
default:
FAIL_M(ssprintf( "%i", type) );
}
ASSERT( img != NULL );
/* alloca to prevent memleaks if libpng longjmps us */
png_byte **row_pointers = (png_byte **) alloca( sizeof(png_byte*) * height );
CHECKPOINT_M( ssprintf("%p",row_pointers) );
for( unsigned y = 0; y < height; ++y )
{
png_byte *p = (png_byte *) img->pixels;
row_pointers[y] = p + img->pitch*y;
}
CHECKPOINT;
png_read_image( png, row_pointers );
CHECKPOINT;
png_read_end( png, info_ptr );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
};
RageSurfaceUtils::OpenResult RageSurface_Load_PNG( const RString &sPath, RageSurface *&ret, bool bHeaderOnly, RString &error )
{
RageFile f;
if( !f.Open( sPath ) )
{
error = f.GetError();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
char errorbuf[1024];
ret = RageSurface_Load_PNG( &f, sPath, errorbuf, bHeaderOnly );
if( ret == NULL )
{
error = errorbuf;
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; // XXX
}
return RageSurfaceUtils::OPEN_OK;
}
/*
* (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "RageSurface_Load_PNG.h"
#include "RageUtil.h"
#include "RageLog.h"
#include "RageFile.h"
#include "RageSurface.h"
#if defined(_WINDOWS)
# include "png.h"
# if defined(_MSC_VER)
# pragma comment(lib, "libpng.lib")
# pragma warning(disable: 4611) /* interaction between '_setjmp' and C++ object destruction is non-portable */
# endif // _MSC_VER
#else
# include <../extern/libpng/include/png.h>
#endif
namespace
{
void RageFile_png_read( png_struct *png, png_byte *p, png_size_t size )
{
CHECKPOINT;
RageFile *f = (RageFile *) png_get_io_ptr(png);
int got = f->Read( p, size );
if( got == -1 )
{
/* png_error will call PNG_Error, which will longjmp. If we just pass
* GetError().c_str() to it, a temporary may be created; since control
* never returns here, it may never be destructed and we could leak. */
static char error[256];
strncpy( error, f->GetError(), sizeof(error) );
error[sizeof(error)-1] = 0;
png_error( png, error );
}
else if( got != (int) size )
png_error( png, "Unexpected EOF" );
}
struct error_info
{
char *err;
const char *fn;
};
void PNG_Error( png_struct *png, const char *error )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_error_ptr(png);
strncpy( info->err, error, 1024 );
info->err[1023] = 0;
LOG->Trace( "loading \"%s\": err: %s", info->fn, info->err );
longjmp( png_jmpbuf(png), 1 );
}
void PNG_Warning( png_struct *png, const char *warning )
{
CHECKPOINT;
error_info *info = (error_info *) png_get_io_ptr(png);
LOG->Trace( "loading \"%s\": warning: %s", info->fn, warning );
}
/* Since libpng forces us to use longjmp (gross!), this function shouldn't create any C++
* objects, and needs to watch out for memleaks. */
static RageSurface *RageSurface_Load_PNG( RageFile *f, const char *fn, char errorbuf[1024], bool bHeaderOnly )
{
error_info error;
error.err = errorbuf;
error.fn = fn;
png_struct *png = png_create_read_struct( PNG_LIBPNG_VER_STRING, &error, PNG_Error, PNG_Warning );
if( png == NULL )
{
sprintf( errorbuf, "creating png_create_read_struct failed");
return NULL;
}
png_info *info_ptr = png_create_info_struct(png);
if( info_ptr == NULL )
{
png_destroy_read_struct( &png, NULL, NULL );
sprintf( errorbuf, "creating png_create_info_struct failed");
return NULL;
}
RageSurface *volatile img = NULL;
CHECKPOINT;
if( setjmp(png_jmpbuf(png) ))
{
png_destroy_read_struct( &png, &info_ptr, NULL );
delete img;
return NULL;
}
CHECKPOINT;
png_set_read_fn( png, f, RageFile_png_read );
png_read_info( png, info_ptr );
png_uint_32 width, height;
int bit_depth, color_type;
png_get_IHDR( png, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL );
/* If bHeaderOnly is true, don't allocate the pixel storage space or decompress
* the image. Just return an empty surface with only the width and height set. */
if( bHeaderOnly )
{
CHECKPOINT;
img = CreateSurfaceFrom( width, height, 32, 0, 0, 0, 0, NULL, width*4 );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
CHECKPOINT;
png_set_strip_16(png); /* 16bit->8bit */
png_set_packing( png ); /* 1,2,4 bit->8 bit */
/* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
png_set_expand_gray_1_2_4_to_8( png );
/* These are set for type == PALETTE. */
RageSurfaceColor colors[256];
int iColorKey = -1;
/* We import three types of files: paletted, RGBX and RGBA. The only difference
* between RGBX and RGBA is that RGBX won't set the alpha mask, so it's easier
* to tell later on that there's no alpha (without actually having to do a pixel scan). */
enum { PALETTE, RGBX, RGBA } type;
switch( color_type )
{
case PNG_COLOR_TYPE_GRAY:
/* Fake PNG_COLOR_TYPE_GRAY. */
for( int i = 0; i < 256; ++i )
{
colors[i].r = colors[i].g = colors[i].b = (int8_t) i;
colors[i].a = 0xFF;
}
type = PALETTE;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
type = RGBA;
png_set_gray_to_rgb( png );
break;
case PNG_COLOR_TYPE_PALETTE:
type = PALETTE;
break;
case PNG_COLOR_TYPE_RGB:
type = RGBX;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
type = RGBA;
break;
default:
FAIL_M(ssprintf( "%i", color_type) );
}
CHECKPOINT;
if( color_type == PNG_COLOR_TYPE_GRAY )
{
png_color_16 *trans;
if( png_get_tRNS( png, info_ptr, NULL, NULL, &trans ) == PNG_INFO_tRNS )
iColorKey = trans->gray;
}
else if( color_type == PNG_COLOR_TYPE_PALETTE )
{
int num_palette;
png_color *palette;
int ret = png_get_PLTE( png, info_ptr, &palette, &num_palette );
ASSERT( ret == PNG_INFO_PLTE );
png_byte *trans = NULL;
int num_trans = 0;
png_get_tRNS( png, info_ptr, &trans, &num_trans, NULL );
for( int i = 0; i < num_palette; ++i )
{
colors[i].r = palette[i].red;
colors[i].g = palette[i].green;
colors[i].b = palette[i].blue;
colors[i].a = 0xFF;
if( i < num_trans )
colors[i].a = trans[i];
}
}
else
{
/* If we have RGB image and tRNS, it's a color key. Just convert it to RGBA. */
if( png_get_valid(png, info_ptr, PNG_INFO_tRNS) )
{
/* We don't care about RGB color keys; just convert them to alpha. */
png_set_tRNS_to_alpha( png );
type = RGBA;
}
/* RGB->RGBX */
png_set_filler( png, 0xff, PNG_FILLER_AFTER );
}
png_set_interlace_handling( png );
CHECKPOINT;
png_read_update_info( png, info_ptr );
switch( type )
{
case PALETTE:
img = CreateSurface( width, height, 8, 0, 0, 0, 0 );
memcpy( img->fmt.palette->colors, colors, 256*sizeof(RageSurfaceColor) );
if( iColorKey != -1 )
img->format->palette->colors[ iColorKey ].a = 0;
break;
case RGBX:
case RGBA:
img = CreateSurface( width, height, 32,
Swap32BE( 0xFF000000 ),
Swap32BE( 0x00FF0000 ),
Swap32BE( 0x0000FF00 ),
Swap32BE( type == RGBA? 0x000000FF:0x00000000 ) );
break;
default:
FAIL_M(ssprintf( "%i", type) );
}
ASSERT( img != nullptr );
/* alloca to prevent memleaks if libpng longjmps us */
png_byte **row_pointers = (png_byte **) alloca( sizeof(png_byte*) * height );
CHECKPOINT_M( ssprintf("%p",row_pointers) );
for( unsigned y = 0; y < height; ++y )
{
png_byte *p = (png_byte *) img->pixels;
row_pointers[y] = p + img->pitch*y;
}
CHECKPOINT;
png_read_image( png, row_pointers );
CHECKPOINT;
png_read_end( png, info_ptr );
png_destroy_read_struct( &png, &info_ptr, NULL );
return img;
}
};
RageSurfaceUtils::OpenResult RageSurface_Load_PNG( const RString &sPath, RageSurface *&ret, bool bHeaderOnly, RString &error )
{
RageFile f;
if( !f.Open( sPath ) )
{
error = f.GetError();
return RageSurfaceUtils::OPEN_FATAL_ERROR;
}
char errorbuf[1024];
ret = RageSurface_Load_PNG( &f, sPath, errorbuf, bHeaderOnly );
if( ret == NULL )
{
error = errorbuf;
return RageSurfaceUtils::OPEN_UNKNOWN_FILE_FORMAT; // XXX
}
return RageSurfaceUtils::OPEN_OK;
}
/*
* (c) 2004 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+74 -74
View File
@@ -1,74 +1,74 @@
/*
* Preemptively load textures before use, by loading it and keeping
* a reference to it. By putting a RageTexturePreloader inside the
* object doing the preloading, the preload will exist for the lifetime
* of that object.
*/
#include "global.h"
#include "RageTexturePreloader.h"
#include "RageTextureManager.h"
RageTexturePreloader &RageTexturePreloader::operator=( const RageTexturePreloader &rhs )
{
if( &rhs == this )
return *this;
UnloadAll();
for( unsigned i = 0; i < rhs.m_apTextures.size(); ++i )
{
RageTexture *pTexture = TEXTUREMAN->CopyTexture( rhs.m_apTextures[i] );
m_apTextures.push_back( pTexture );
}
return *this;
}
void RageTexturePreloader::Load( const RageTextureID &ID )
{
ASSERT( TEXTUREMAN != NULL );
RageTexture *pTexture = TEXTUREMAN->LoadTexture( ID );
m_apTextures.push_back( pTexture );
}
void RageTexturePreloader::UnloadAll()
{
if( TEXTUREMAN == NULL )
return;
for( unsigned i = 0; i < m_apTextures.size(); ++i )
TEXTUREMAN->UnloadTexture( m_apTextures[i] );
m_apTextures.clear();
}
RageTexturePreloader::~RageTexturePreloader()
{
UnloadAll();
}
/*
* (c) 2005 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Preemptively load textures before use, by loading it and keeping
* a reference to it. By putting a RageTexturePreloader inside the
* object doing the preloading, the preload will exist for the lifetime
* of that object.
*/
#include "global.h"
#include "RageTexturePreloader.h"
#include "RageTextureManager.h"
RageTexturePreloader &RageTexturePreloader::operator=( const RageTexturePreloader &rhs )
{
if( &rhs == this )
return *this;
UnloadAll();
for( unsigned i = 0; i < rhs.m_apTextures.size(); ++i )
{
RageTexture *pTexture = TEXTUREMAN->CopyTexture( rhs.m_apTextures[i] );
m_apTextures.push_back( pTexture );
}
return *this;
}
void RageTexturePreloader::Load( const RageTextureID &ID )
{
ASSERT( TEXTUREMAN != nullptr );
RageTexture *pTexture = TEXTUREMAN->LoadTexture( ID );
m_apTextures.push_back( pTexture );
}
void RageTexturePreloader::UnloadAll()
{
if( TEXTUREMAN == NULL )
return;
for( unsigned i = 0; i < m_apTextures.size(); ++i )
TEXTUREMAN->UnloadTexture( m_apTextures[i] );
m_apTextures.clear();
}
RageTexturePreloader::~RageTexturePreloader()
{
UnloadAll();
}
/*
* (c) 2005 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+11 -11
View File
@@ -94,12 +94,12 @@ void ThreadSlot::ThreadCheckpoint::Set( const char *szFile, int iLine, const cha
m_szMessage = szMessage;
/* Skip any path components. */
if( m_szFile != NULL )
if( m_szFile != nullptr )
{
const char *p = strrchr( m_szFile, '/' );
if( p == NULL )
p = strrchr( m_szFile, '\\' );
if( p != NULL && p[1] != '\0' )
if( p != nullptr && p[1] != '\0' )
m_szFile = p+1;
}
@@ -215,7 +215,7 @@ RageThread::RageThread( const RageThread &cpy ):
RageThread::~RageThread()
{
if( m_pSlot != NULL )
if( m_pSlot != nullptr )
Wait();
}
@@ -310,8 +310,8 @@ bool RageThread::EnumThreadIDs( int n, uint64_t &iID )
int RageThread::Wait()
{
ASSERT( m_pSlot != NULL );
ASSERT( m_pSlot->m_pImpl != NULL );
ASSERT( m_pSlot != nullptr );
ASSERT( m_pSlot->m_pImpl != nullptr );
int ret = m_pSlot->m_pImpl->Wait();
LockMut( GetThreadSlotsLock() );
@@ -323,14 +323,14 @@ int RageThread::Wait()
}
void RageThread::Halt(bool Kill) {
ASSERT( m_pSlot != NULL );
ASSERT( m_pSlot->m_pImpl != NULL );
ASSERT( m_pSlot != nullptr );
ASSERT( m_pSlot->m_pImpl != nullptr );
m_pSlot->m_pImpl->Halt(Kill);
}
void RageThread::Resume() {
ASSERT( m_pSlot != NULL );
ASSERT( m_pSlot->m_pImpl != NULL );
ASSERT( m_pSlot != nullptr );
ASSERT( m_pSlot->m_pImpl != nullptr );
m_pSlot->m_pImpl->Resume();
}
@@ -432,7 +432,7 @@ void Checkpoints::GetLogs( char *pBuf, int iSize, const char *delim )
strcat( pBuf, buf );
strcat( pBuf, delim );
for( int line = 1; (buf = GetCheckpointLog(slotno, line)) != NULL; ++line )
for( int line = 1; (buf = GetCheckpointLog(slotno, line)) != nullptr; ++line )
{
strcat( pBuf, buf );
strcat( pBuf, delim );
@@ -704,7 +704,7 @@ bool RageEvent::Wait( RageTimer *pTimeout )
ASSERT( m_LockCnt == 0 );
/* A zero RageTimer also means no timeout. */
if( pTimeout != NULL && pTimeout->IsZero() )
if( pTimeout != nullptr && pTimeout->IsZero() )
pTimeout = NULL;
bool bRet = m_pEvent->Wait( pTimeout );
+225 -225
View File
@@ -1,225 +1,225 @@
#ifndef RAGE_THREADS_H
#define RAGE_THREADS_H
struct ThreadSlot;
class RageTimer;
/** @brief Thread, mutex, semaphore, and event classes. */
class RageThread
{
public:
RageThread();
RageThread( const RageThread &cpy );
~RageThread();
void SetName( const RString &n ) { m_sName = n; }
RString GetName() const { return m_sName; }
void Create( int (*fn)(void *), void *data );
void Halt( bool Kill=false);
void Resume();
/* For crash handlers: kill or suspend all threads (except for
* the running one) immediately. */
static void HaltAllThreads( bool Kill=false );
/* If HaltAllThreads was called (with Kill==false), resume. */
static void ResumeAllThreads();
static uint64_t GetCurrentThreadID();
static const char *GetCurrentThreadName();
static const char *GetThreadNameByID( uint64_t iID );
static bool EnumThreadIDs( int n, uint64_t &iID );
int Wait();
bool IsCreated() const { return m_pSlot != NULL; }
/* A system can define HAVE_TLS, indicating that it can compile thread_local
* code, but an individual environment may not actually have functional TLS.
* If this returns false, thread_local variables are considered undefined. */
static bool GetSupportsTLS() { return s_bSystemSupportsTLS; }
static void SetSupportsTLS( bool b ) { s_bSystemSupportsTLS = b; }
static bool GetIsShowingDialog() { return s_bIsShowingDialog; }
static void SetIsShowingDialog( bool b ) { s_bIsShowingDialog = b; }
static uint64_t GetInvalidThreadID();
private:
ThreadSlot *m_pSlot;
RString m_sName;
static bool s_bSystemSupportsTLS;
static bool s_bIsShowingDialog;
// Swallow up warnings. If they must be used, define them.
RageThread& operator=(const RageThread& rhs);
};
/**
* @brief Register a thread created outside of RageThread.
*
* This gives it a name for RageThread::GetCurrentThreadName,
* and allocates a slot for checkpoints. */
class RageThreadRegister
{
public:
RageThreadRegister( const RString &sName );
~RageThreadRegister();
private:
ThreadSlot *m_pSlot;
// Swallow up warnings. If they must be used, define them.
RageThreadRegister& operator=(const RageThreadRegister& rhs);
RageThreadRegister(const RageThreadRegister& rhs);
};
namespace Checkpoints
{
void LogCheckpoints( bool yes=true );
void SetCheckpoint( const char *file, int line, const char *message );
void GetLogs( char *pBuf, int iSize, const char *delim );
};
#define CHECKPOINT (Checkpoints::SetCheckpoint(__FILE__, __LINE__, NULL))
#define CHECKPOINT_M(m) (Checkpoints::SetCheckpoint(__FILE__, __LINE__, m))
/* Mutex class that follows the behavior of Windows mutexes: if the same
* thread locks the same mutex twice, we just increase a refcount; a mutex
* is considered unlocked when the refcount reaches zero. This is more
* convenient, though much slower on some archs. (We don't have any tightly-
* coupled threads, so that's OK.) */
class MutexImpl;
class RageMutex
{
public:
RString GetName() const { return m_sName; }
void SetName( const RString &s ) { m_sName = s; }
virtual void Lock();
virtual bool TryLock();
virtual void Unlock();
virtual bool IsLockedByThisThread() const;
RageMutex( const RString &name );
virtual ~RageMutex();
protected:
MutexImpl *m_pMutex;
RString m_sName;
int m_UniqueID;
uint64_t m_LockedBy;
int m_LockCnt;
void MarkLockedMutex();
private:
// Swallow up warnings. If they must be used, define them.
RageMutex& operator=(const RageMutex& rhs);
RageMutex(const RageMutex& rhs);
};
/**
* @brief Lock a mutex on construction, unlock it on destruction.
*
* Helps for functions with more than one return path. */
class LockMutex
{
RageMutex &mutex;
const char *file;
int line;
float locked_at;
bool locked;
public:
LockMutex(RageMutex &mut, const char *file, int line);
LockMutex(RageMutex &mut): mutex(mut), file(NULL), line(-1), locked_at(-1), locked(true) { mutex.Lock(); }
~LockMutex();
LockMutex(LockMutex &cpy): mutex(cpy.mutex), file(NULL), line(-1), locked_at(cpy.locked_at), locked(true) { mutex.Lock(); }
/**
* @brief Unlock the mutex (before this would normally go out of scope).
*
* This can only be called once. */
void Unlock();
private:
// Swallow up warnings. If they must be used, define them.
LockMutex& operator=(const LockMutex& rhs);
};
#define LockMut(m) LockMutex UNIQUE_NAME(LocalLock) (m, __FILE__, __LINE__)
class EventImpl;
class RageEvent: public RageMutex
{
public:
RageEvent( RString name );
~RageEvent();
/*
* If pTimeout is non-NULL, the event will be automatically signalled at the given
* time. Note that implementing this timeout is optional; not all archs support it.
* If false is returned, the wait timed out (and the mutex is locked, as if the
* event had been signalled).
*/
bool Wait( RageTimer *pTimeout = NULL );
void Signal();
void Broadcast();
bool WaitTimeoutSupported() const;
// Swallow up warnings. If they must be used, define them.
RageEvent& operator=(const RageEvent& rhs);
RageEvent(const RageEvent& rhs);
private:
EventImpl *m_pEvent;
};
class SemaImpl;
class RageSemaphore
{
public:
RageSemaphore( RString sName, int iInitialValue = 0 );
~RageSemaphore();
RString GetName() const { return m_sName; }
int GetValue() const;
void Post();
void Wait( bool bFailOnTimeout=true );
bool TryWait();
private:
SemaImpl *m_pSema;
RString m_sName;
// Swallow up warnings. If they must be used, define them.
RageSemaphore& operator=(const RageSemaphore& rhs);
RageSemaphore(const RageSemaphore& rhs);
};
#endif
/**
* @file
* @author Glenn Maynard (c) 2001-2004
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef RAGE_THREADS_H
#define RAGE_THREADS_H
struct ThreadSlot;
class RageTimer;
/** @brief Thread, mutex, semaphore, and event classes. */
class RageThread
{
public:
RageThread();
RageThread( const RageThread &cpy );
~RageThread();
void SetName( const RString &n ) { m_sName = n; }
RString GetName() const { return m_sName; }
void Create( int (*fn)(void *), void *data );
void Halt( bool Kill=false);
void Resume();
/* For crash handlers: kill or suspend all threads (except for
* the running one) immediately. */
static void HaltAllThreads( bool Kill=false );
/* If HaltAllThreads was called (with Kill==false), resume. */
static void ResumeAllThreads();
static uint64_t GetCurrentThreadID();
static const char *GetCurrentThreadName();
static const char *GetThreadNameByID( uint64_t iID );
static bool EnumThreadIDs( int n, uint64_t &iID );
int Wait();
bool IsCreated() const { return m_pSlot != nullptr; }
/* A system can define HAVE_TLS, indicating that it can compile thread_local
* code, but an individual environment may not actually have functional TLS.
* If this returns false, thread_local variables are considered undefined. */
static bool GetSupportsTLS() { return s_bSystemSupportsTLS; }
static void SetSupportsTLS( bool b ) { s_bSystemSupportsTLS = b; }
static bool GetIsShowingDialog() { return s_bIsShowingDialog; }
static void SetIsShowingDialog( bool b ) { s_bIsShowingDialog = b; }
static uint64_t GetInvalidThreadID();
private:
ThreadSlot *m_pSlot;
RString m_sName;
static bool s_bSystemSupportsTLS;
static bool s_bIsShowingDialog;
// Swallow up warnings. If they must be used, define them.
RageThread& operator=(const RageThread& rhs);
};
/**
* @brief Register a thread created outside of RageThread.
*
* This gives it a name for RageThread::GetCurrentThreadName,
* and allocates a slot for checkpoints. */
class RageThreadRegister
{
public:
RageThreadRegister( const RString &sName );
~RageThreadRegister();
private:
ThreadSlot *m_pSlot;
// Swallow up warnings. If they must be used, define them.
RageThreadRegister& operator=(const RageThreadRegister& rhs);
RageThreadRegister(const RageThreadRegister& rhs);
};
namespace Checkpoints
{
void LogCheckpoints( bool yes=true );
void SetCheckpoint( const char *file, int line, const char *message );
void GetLogs( char *pBuf, int iSize, const char *delim );
};
#define CHECKPOINT (Checkpoints::SetCheckpoint(__FILE__, __LINE__, NULL))
#define CHECKPOINT_M(m) (Checkpoints::SetCheckpoint(__FILE__, __LINE__, m))
/* Mutex class that follows the behavior of Windows mutexes: if the same
* thread locks the same mutex twice, we just increase a refcount; a mutex
* is considered unlocked when the refcount reaches zero. This is more
* convenient, though much slower on some archs. (We don't have any tightly-
* coupled threads, so that's OK.) */
class MutexImpl;
class RageMutex
{
public:
RString GetName() const { return m_sName; }
void SetName( const RString &s ) { m_sName = s; }
virtual void Lock();
virtual bool TryLock();
virtual void Unlock();
virtual bool IsLockedByThisThread() const;
RageMutex( const RString &name );
virtual ~RageMutex();
protected:
MutexImpl *m_pMutex;
RString m_sName;
int m_UniqueID;
uint64_t m_LockedBy;
int m_LockCnt;
void MarkLockedMutex();
private:
// Swallow up warnings. If they must be used, define them.
RageMutex& operator=(const RageMutex& rhs);
RageMutex(const RageMutex& rhs);
};
/**
* @brief Lock a mutex on construction, unlock it on destruction.
*
* Helps for functions with more than one return path. */
class LockMutex
{
RageMutex &mutex;
const char *file;
int line;
float locked_at;
bool locked;
public:
LockMutex(RageMutex &mut, const char *file, int line);
LockMutex(RageMutex &mut): mutex(mut), file(NULL), line(-1), locked_at(-1), locked(true) { mutex.Lock(); }
~LockMutex();
LockMutex(LockMutex &cpy): mutex(cpy.mutex), file(NULL), line(-1), locked_at(cpy.locked_at), locked(true) { mutex.Lock(); }
/**
* @brief Unlock the mutex (before this would normally go out of scope).
*
* This can only be called once. */
void Unlock();
private:
// Swallow up warnings. If they must be used, define them.
LockMutex& operator=(const LockMutex& rhs);
};
#define LockMut(m) LockMutex UNIQUE_NAME(LocalLock) (m, __FILE__, __LINE__)
class EventImpl;
class RageEvent: public RageMutex
{
public:
RageEvent( RString name );
~RageEvent();
/*
* If pTimeout is non-NULL, the event will be automatically signalled at the given
* time. Note that implementing this timeout is optional; not all archs support it.
* If false is returned, the wait timed out (and the mutex is locked, as if the
* event had been signalled).
*/
bool Wait( RageTimer *pTimeout = NULL );
void Signal();
void Broadcast();
bool WaitTimeoutSupported() const;
// Swallow up warnings. If they must be used, define them.
RageEvent& operator=(const RageEvent& rhs);
RageEvent(const RageEvent& rhs);
private:
EventImpl *m_pEvent;
};
class SemaImpl;
class RageSemaphore
{
public:
RageSemaphore( RString sName, int iInitialValue = 0 );
~RageSemaphore();
RString GetName() const { return m_sName; }
int GetValue() const;
void Post();
void Wait( bool bFailOnTimeout=true );
bool TryWait();
private:
SemaImpl *m_pSema;
RString m_sName;
// Swallow up warnings. If they must be used, define them.
RageSemaphore& operator=(const RageSemaphore& rhs);
RageSemaphore(const RageSemaphore& rhs);
};
#endif
/**
* @file
* @author Glenn Maynard (c) 2001-2004
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+4 -4
View File
@@ -1027,7 +1027,7 @@ bool GetCommandlineArgument( const RString &option, RString *argument, int iInde
RString GetCwd()
{
char buf[PATH_MAX];
bool ret = getcwd(buf, PATH_MAX) != NULL;
bool ret = getcwd(buf, PATH_MAX) != nullptr;
ASSERT(ret);
return buf;
}
@@ -2274,7 +2274,7 @@ bool FileCopy( RageFileBasic &in, RageFileBasic &out, RString &sError, bool *bRe
if( in.Read(data, 1024*32) == -1 )
{
sError = ssprintf( "read error: %s", in.GetError().c_str() );
if( bReadError != NULL )
if( bReadError != nullptr )
*bReadError = true;
return false;
}
@@ -2284,7 +2284,7 @@ bool FileCopy( RageFileBasic &in, RageFileBasic &out, RString &sError, bool *bRe
if( i == -1 )
{
sError = ssprintf( "write error: %s", out.GetError().c_str() );
if( bReadError != NULL )
if( bReadError != nullptr )
*bReadError = false;
return false;
}
@@ -2293,7 +2293,7 @@ bool FileCopy( RageFileBasic &in, RageFileBasic &out, RString &sError, bool *bRe
if( out.Flush() == -1 )
{
sError = ssprintf( "write error: %s", out.GetError().c_str() );
if( bReadError != NULL )
if( bReadError != nullptr )
*bReadError = false;
return false;
}
+219 -219
View File
@@ -1,219 +1,219 @@
/* AutoPtrCopyOnWrite - Simple smart pointer template. */
#ifndef RAGE_UTIL_AUTO_PTR_H
#define RAGE_UTIL_AUTO_PTR_H
/*
* This is a simple copy-on-write refcounted smart pointer. Once constructed, all read-only
* access to the object is made without extra copying. If you need read-write access, you
* can get a pointer with Get(), which will cause the object to deep-copy. (Don't free
* the resulting pointer.)
*
* Note that there are no non-const operator* or operator-> overloads, because that would
* cause all const access by code with non-const permissions to deep-copy. For example,
*
* AutoPtrCopyOnWrite<int> a( new int(1) );
* AutoPtrCopyOnWrite<int> b( a );
* printf( "%i\n", *a );
*
* If we have a non-const operator*, this *a will use it (even though it only needs const
* access), and will copy the underlying object wastefully. g++ std::string has this behavior,
* which is why it's important to qualify strings as "const" when const access is desired,
* but that's brittle, so let's make all potential deep-copying explicit.
*/
template<class T>
class AutoPtrCopyOnWrite
{
public:
/* This constructor only exists to make us work with STL containers. */
inline AutoPtrCopyOnWrite(): m_pPtr(NULL), m_iRefCount(new int(1))
{
}
explicit inline AutoPtrCopyOnWrite( T *p ): m_pPtr(p), m_iRefCount(new int(1))
{
}
inline AutoPtrCopyOnWrite( const AutoPtrCopyOnWrite &rhs ):
m_pPtr(rhs.m_pPtr), m_iRefCount(rhs.m_iRefCount)
{
++(*m_iRefCount);
}
void Swap( AutoPtrCopyOnWrite<T> &rhs )
{
swap( m_pPtr, rhs.m_pPtr );
swap( m_iRefCount, rhs.m_iRefCount );
}
inline AutoPtrCopyOnWrite<T> &operator=( const AutoPtrCopyOnWrite &rhs )
{
AutoPtrCopyOnWrite<T> obj( rhs );
this->Swap( obj );
return *this;
}
~AutoPtrCopyOnWrite()
{
--(*m_iRefCount);
if( *m_iRefCount == 0 )
{
delete m_pPtr;
delete m_iRefCount;
}
}
/* Get a non-const pointer. This will deep-copy the object if necessary. */
T *Get()
{
if( *m_iRefCount > 1 )
{
--*m_iRefCount;
m_pPtr = new T(*m_pPtr);
m_iRefCount = new int(1);
}
return m_pPtr;
}
int GetReferenceCount() const { return *m_iRefCount; }
const T &operator *() const { return *m_pPtr; }
const T *operator ->() const { return m_pPtr; }
private:
T *m_pPtr;
int *m_iRefCount;
};
template<class T>
inline void swap( AutoPtrCopyOnWrite<T> &a, AutoPtrCopyOnWrite<T> &b )
{
a.Swap(b);
}
/*
* This smart pointer template is used to safely hide implementations from
* headers, to reduce dependencies. This is the same as declaring a pointer
* to a class, and allocating/deallocating it in the implementation: only
* the implementation needs to include that class. This makes copying
* and deletion automatic, so you don't need to include a copy ctor or
* remember to delete it.
*
* There's one subtlety: in order to copy or delete an object, we need its
* definition. This is intended to avoid pulling in the definition. So,
* we use a traits class to hide it. Use REGISTER_CLASS_TRAITS for each
* class used with this template.
*
* Concepts from http://www.gotw.ca/gotw/062.htm.
*/
template<class T>
struct HiddenPtrTraits
{
static T *Copy( const T *pCopy );
static void Delete( T *p );
};
#define REGISTER_CLASS_TRAITS(T, CopyExpr) \
template<> T *HiddenPtrTraits<T>::Copy( const T *pCopy ) { return CopyExpr; } \
template<> void HiddenPtrTraits<T>::Delete( T *p ) { delete p; }
template<class T>
class HiddenPtr
{
public:
const T& operator*() const { return *m_pPtr; }
const T* operator->() const { return m_pPtr; }
T& operator*() { return *m_pPtr; }
T* operator->() { return m_pPtr; }
explicit HiddenPtr( T *p = NULL ): m_pPtr(p) {}
HiddenPtr( const HiddenPtr<T> &cpy ): m_pPtr(NULL)
{
if( cpy.m_pPtr != NULL )
m_pPtr = HiddenPtrTraits<T>::Copy( cpy.m_pPtr );
}
#if 0 // broken VC6
template<class U>
HiddenPtr( const HiddenPtr<U> &cpy )
{
if( cpy.m_pPtr == NULL )
m_pPtr = NULL;
else
m_pPtr = HiddenPtrTraits<U>::Copy( cpy.m_pPtr );
}
#endif
~HiddenPtr()
{
HiddenPtrTraits<T>::Delete( m_pPtr );
}
void Swap( HiddenPtr<T> &rhs ) { swap( m_pPtr, rhs.m_pPtr ); }
HiddenPtr<T> &operator=( T *p )
{
HiddenPtr<T> t( p );
Swap( t );
return *this;
}
HiddenPtr<T> &operator=( const HiddenPtr &cpy )
{
HiddenPtr<T> t( cpy );
Swap( t );
return *this;
}
#if 0 // broken VC6
template<class U>
HiddenPtr<T> &operator=( const HiddenPtr<U> &cpy )
{
HiddenPtr<T> t( cpy );
Swap( t );
return *this;
}
#endif
private:
T *m_pPtr;
#if 0 // broken VC6
template<class U>
friend class HiddenPtr;
#endif
};
template<class T>
inline void swap( HiddenPtr<T> &a, HiddenPtr<T> &b )
{
a.Swap(b);
}
#endif
/*
* (c) 2005 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* AutoPtrCopyOnWrite - Simple smart pointer template. */
#ifndef RAGE_UTIL_AUTO_PTR_H
#define RAGE_UTIL_AUTO_PTR_H
/*
* This is a simple copy-on-write refcounted smart pointer. Once constructed, all read-only
* access to the object is made without extra copying. If you need read-write access, you
* can get a pointer with Get(), which will cause the object to deep-copy. (Don't free
* the resulting pointer.)
*
* Note that there are no non-const operator* or operator-> overloads, because that would
* cause all const access by code with non-const permissions to deep-copy. For example,
*
* AutoPtrCopyOnWrite<int> a( new int(1) );
* AutoPtrCopyOnWrite<int> b( a );
* printf( "%i\n", *a );
*
* If we have a non-const operator*, this *a will use it (even though it only needs const
* access), and will copy the underlying object wastefully. g++ std::string has this behavior,
* which is why it's important to qualify strings as "const" when const access is desired,
* but that's brittle, so let's make all potential deep-copying explicit.
*/
template<class T>
class AutoPtrCopyOnWrite
{
public:
/* This constructor only exists to make us work with STL containers. */
inline AutoPtrCopyOnWrite(): m_pPtr(NULL), m_iRefCount(new int(1))
{
}
explicit inline AutoPtrCopyOnWrite( T *p ): m_pPtr(p), m_iRefCount(new int(1))
{
}
inline AutoPtrCopyOnWrite( const AutoPtrCopyOnWrite &rhs ):
m_pPtr(rhs.m_pPtr), m_iRefCount(rhs.m_iRefCount)
{
++(*m_iRefCount);
}
void Swap( AutoPtrCopyOnWrite<T> &rhs )
{
swap( m_pPtr, rhs.m_pPtr );
swap( m_iRefCount, rhs.m_iRefCount );
}
inline AutoPtrCopyOnWrite<T> &operator=( const AutoPtrCopyOnWrite &rhs )
{
AutoPtrCopyOnWrite<T> obj( rhs );
this->Swap( obj );
return *this;
}
~AutoPtrCopyOnWrite()
{
--(*m_iRefCount);
if( *m_iRefCount == 0 )
{
delete m_pPtr;
delete m_iRefCount;
}
}
/* Get a non-const pointer. This will deep-copy the object if necessary. */
T *Get()
{
if( *m_iRefCount > 1 )
{
--*m_iRefCount;
m_pPtr = new T(*m_pPtr);
m_iRefCount = new int(1);
}
return m_pPtr;
}
int GetReferenceCount() const { return *m_iRefCount; }
const T &operator *() const { return *m_pPtr; }
const T *operator ->() const { return m_pPtr; }
private:
T *m_pPtr;
int *m_iRefCount;
};
template<class T>
inline void swap( AutoPtrCopyOnWrite<T> &a, AutoPtrCopyOnWrite<T> &b )
{
a.Swap(b);
}
/*
* This smart pointer template is used to safely hide implementations from
* headers, to reduce dependencies. This is the same as declaring a pointer
* to a class, and allocating/deallocating it in the implementation: only
* the implementation needs to include that class. This makes copying
* and deletion automatic, so you don't need to include a copy ctor or
* remember to delete it.
*
* There's one subtlety: in order to copy or delete an object, we need its
* definition. This is intended to avoid pulling in the definition. So,
* we use a traits class to hide it. Use REGISTER_CLASS_TRAITS for each
* class used with this template.
*
* Concepts from http://www.gotw.ca/gotw/062.htm.
*/
template<class T>
struct HiddenPtrTraits
{
static T *Copy( const T *pCopy );
static void Delete( T *p );
};
#define REGISTER_CLASS_TRAITS(T, CopyExpr) \
template<> T *HiddenPtrTraits<T>::Copy( const T *pCopy ) { return CopyExpr; } \
template<> void HiddenPtrTraits<T>::Delete( T *p ) { delete p; }
template<class T>
class HiddenPtr
{
public:
const T& operator*() const { return *m_pPtr; }
const T* operator->() const { return m_pPtr; }
T& operator*() { return *m_pPtr; }
T* operator->() { return m_pPtr; }
explicit HiddenPtr( T *p = NULL ): m_pPtr(p) {}
HiddenPtr( const HiddenPtr<T> &cpy ): m_pPtr(NULL)
{
if( cpy.m_pPtr != nullptr )
m_pPtr = HiddenPtrTraits<T>::Copy( cpy.m_pPtr );
}
#if 0 // broken VC6
template<class U>
HiddenPtr( const HiddenPtr<U> &cpy )
{
if( cpy.m_pPtr == NULL )
m_pPtr = NULL;
else
m_pPtr = HiddenPtrTraits<U>::Copy( cpy.m_pPtr );
}
#endif
~HiddenPtr()
{
HiddenPtrTraits<T>::Delete( m_pPtr );
}
void Swap( HiddenPtr<T> &rhs ) { swap( m_pPtr, rhs.m_pPtr ); }
HiddenPtr<T> &operator=( T *p )
{
HiddenPtr<T> t( p );
Swap( t );
return *this;
}
HiddenPtr<T> &operator=( const HiddenPtr &cpy )
{
HiddenPtr<T> t( cpy );
Swap( t );
return *this;
}
#if 0 // broken VC6
template<class U>
HiddenPtr<T> &operator=( const HiddenPtr<U> &cpy )
{
HiddenPtr<T> t( cpy );
Swap( t );
return *this;
}
#endif
private:
T *m_pPtr;
#if 0 // broken VC6
template<class U>
friend class HiddenPtr;
#endif
};
template<class T>
inline void swap( HiddenPtr<T> &a, HiddenPtr<T> &b )
{
a.Swap(b);
}
#endif
/*
* (c) 2005 Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+2 -2
View File
@@ -31,7 +31,7 @@ public:
~CachedObject()
{
if( m_pObject != NULL )
if( m_pObject != nullptr )
ClearCacheSpecific( m_pObject );
}
@@ -145,7 +145,7 @@ public:
CachedObjectHelpers::Lock();
m_pCache = p;
m_bCacheIsSet = true;
if( p != NULL )
if( p != nullptr )
p->m_CachedObject.m_pObject = p;
CachedObjectHelpers::Unlock();
}
+648 -648
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -180,7 +180,7 @@ void RoomWheel::Move( int n )
if( n == 0 && m_iSelection >= m_offset )
{
const RoomWheelItemData* data = GetItem( m_iSelection-m_offset );
if( data != NULL )
if( data != nullptr )
SCREENMAN->PostMessageToTopScreen( SM_RoomInfoDeploy, 0 );
}
else
+2 -2
View File
@@ -104,9 +104,9 @@ void ScoreKeeperNormal::Load(
for( unsigned i=0; i<apSteps.size(); i++ )
{
Song* pSong = apSongs[i];
ASSERT( pSong != NULL );
ASSERT( pSong != nullptr );
Steps* pSteps = apSteps[i];
ASSERT( pSteps != NULL );
ASSERT( pSteps != nullptr );
const AttackArray &aa = asModifiers[i];
NoteData ndTemp;
pSteps->GetNoteData( ndTemp );
+233 -233
View File
@@ -1,233 +1,233 @@
#include "global.h"
#include "ScoreKeeperRave.h"
#include "ThemeManager.h"
#include "RageUtil.h"
#include "GameState.h"
#include "Character.h"
#include "ScreenManager.h"
#include "PrefsManager.h"
#include "ThemeMetric.h"
#include "PlayerState.h"
#include "NoteTypes.h"
ThemeMetric<float> ATTACK_DURATION_SECONDS ("ScoreKeeperRave","AttackDurationSeconds");
static const float g_fSuperMeterPercentChangeInit[] =
{
+0.02f, // SE_CheckpointHit
+0.05f, // SE_W1
+0.04f, // SE_W2
+0.02f, // SE_W3
+0.00f, // SE_W4
+0.00f, // SE_W5
-0.20f, // SE_Miss
-0.40f, // SE_HitMine
-0.02f, // SE_CheckpointMiss
+0.04f, // SE_Held
-0.20f, // SE_LetGo
};
COMPILE_ASSERT( ARRAYLEN(g_fSuperMeterPercentChangeInit) == NUM_ScoreEvent );
static void SuperMeterPercentChangeInit( size_t /*ScoreEvent*/ i, RString &sNameOut, float &defaultValueOut )
{
sNameOut = "SuperMeterPercentChange" + ScoreEventToString( (ScoreEvent)i );
defaultValueOut = g_fSuperMeterPercentChangeInit[i];
}
static Preference1D<float> g_fSuperMeterPercentChange( SuperMeterPercentChangeInit, NUM_ScoreEvent );
ScoreKeeperRave::ScoreKeeperRave( PlayerState *pPlayerState, PlayerStageStats *pPlayerStageStats ) :
ScoreKeeper(pPlayerState, pPlayerStageStats)
{
}
void ScoreKeeperRave::HandleTapScore( const TapNote &tn )
{
TapNoteScore score = tn.result.tns;
float fPercentToMove = 0;
if( score == TNS_HitMine )
fPercentToMove = g_fSuperMeterPercentChange[SE_HitMine];
AddSuperMeterDelta( fPercentToMove );
}
#define CROSSED( val ) (fOld < val && fNew >= val)
#define CROSSED_ATTACK_LEVEL( level ) CROSSED(1.f/NUM_ATTACK_LEVELS*(level+1))
void ScoreKeeperRave::HandleTapRowScore( const NoteData &nd, int iRow )
{
TapNoteScore scoreOfLastTap;
int iNumTapsInRow;
float fPercentToMove = 0.0f;
GetScoreOfLastTapInRow( nd, iRow, scoreOfLastTap, iNumTapsInRow );
if( iNumTapsInRow <= 0 )
return;
switch( scoreOfLastTap )
{
DEFAULT_FAIL( scoreOfLastTap );
case TNS_W1: fPercentToMove = g_fSuperMeterPercentChange[SE_W1]; break;
case TNS_W2: fPercentToMove = g_fSuperMeterPercentChange[SE_W2]; break;
case TNS_W3: fPercentToMove = g_fSuperMeterPercentChange[SE_W3]; break;
case TNS_W4: fPercentToMove = g_fSuperMeterPercentChange[SE_W4]; break;
case TNS_W5: fPercentToMove = g_fSuperMeterPercentChange[SE_W5]; break;
case TNS_Miss: fPercentToMove = g_fSuperMeterPercentChange[SE_Miss]; break;
}
AddSuperMeterDelta( fPercentToMove );
}
void ScoreKeeperRave::HandleHoldScore( const TapNote &tn )
{
// todo: should hit mine be handled in HandleTapRow score instead? -aj
TapNoteScore tapScore = tn.result.tns;
float fPercentToMove = 0.0f;
switch( tapScore )
{
case TNS_HitMine:
fPercentToMove = g_fSuperMeterPercentChange[SE_HitMine];
break;
default: break;
}
// Playing with this code enabled seems to feel "wrong", but I'm leaving it
// in for player feedback. -aj
HoldNoteScore holdScore = tn.HoldResult.hns;
switch( holdScore )
{
case HNS_Held: fPercentToMove = g_fSuperMeterPercentChange[SE_Held]; break;
case HNS_LetGo: fPercentToMove = g_fSuperMeterPercentChange[SE_LetGo]; break;
default: break;
}
AddSuperMeterDelta( fPercentToMove );
}
extern ThemeMetric<bool> PENALIZE_TAP_SCORE_NONE;
void ScoreKeeperRave::HandleTapScoreNone()
{
if( PENALIZE_TAP_SCORE_NONE )
{
float fPercentToMove = g_fSuperMeterPercentChange[SE_Miss];
AddSuperMeterDelta( fPercentToMove );
}
}
void ScoreKeeperRave::AddSuperMeterDelta( float fUnscaledPercentChange )
{
if( PREFSMAN->m_bMercifulDrain && fUnscaledPercentChange<0 )
{
float fSuperPercentage = m_pPlayerState->m_fSuperMeter / NUM_ATTACK_LEVELS;
fUnscaledPercentChange *= SCALE( fSuperPercentage, 0.f, 1.f, 0.5f, 1.f);
}
// more mercy: Grow super meter slower or faster depending on life.
if( PREFSMAN->m_bMercifulSuperMeter )
{
float fLifePercentage = 0;
switch( m_pPlayerState->m_PlayerNumber )
{
case PLAYER_1: fLifePercentage = GAMESTATE->m_fTugLifePercentP1; break;
case PLAYER_2: fLifePercentage = 1 - GAMESTATE->m_fTugLifePercentP1; break;
default:
FAIL_M(ssprintf("Invalid player number: %i", m_pPlayerState->m_PlayerNumber));
}
CLAMP( fLifePercentage, 0.f, 1.f );
if( fUnscaledPercentChange > 0 )
fUnscaledPercentChange *= SCALE( fLifePercentage, 0.f, 1.f, 1.7f, 0.3f);
else // fUnscaledPercentChange <= 0
fUnscaledPercentChange /= SCALE( fLifePercentage, 0.f, 1.f, 1.7f, 0.3f);
}
// mercy: drop super meter faster if at a higher level
if( fUnscaledPercentChange < 0 )
fUnscaledPercentChange *= SCALE( m_pPlayerState->m_fSuperMeter, 0.f, 1.f, 0.01f, 1.f );
AttackLevel oldAL = (AttackLevel)(int)m_pPlayerState->m_fSuperMeter;
float fPercentToMove = fUnscaledPercentChange;
m_pPlayerState->m_fSuperMeter += fPercentToMove * m_pPlayerState->m_fSuperMeterGrowthScale;
CLAMP( m_pPlayerState->m_fSuperMeter, 0.f, NUM_ATTACK_LEVELS );
AttackLevel newAL = (AttackLevel)(int)m_pPlayerState->m_fSuperMeter;
if( newAL > oldAL )
{
LaunchAttack( oldAL );
if( newAL == NUM_ATTACK_LEVELS ) // hit upper bounds of meter
m_pPlayerState->m_fSuperMeter -= 1.f;
}
// mercy: if losing remove attacks on life drain
if( fUnscaledPercentChange < 0 )
{
bool bWinning;
switch( m_pPlayerState->m_PlayerNumber )
{
case PLAYER_1: bWinning = GAMESTATE->m_fTugLifePercentP1 > 0.5f; break;
case PLAYER_2: bWinning = GAMESTATE->m_fTugLifePercentP1 < 0.5f; break;
default:
bWinning = false;
FAIL_M(ssprintf("Invalid player number: %i", m_pPlayerState->m_PlayerNumber));
}
if( !bWinning )
m_pPlayerState->EndActiveAttacks();
}
}
void ScoreKeeperRave::LaunchAttack( AttackLevel al )
{
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
RString* asAttacks = GAMESTATE->m_pCurCharacters[pn]->m_sAttacks[al]; // [NUM_ATTACKS_PER_LEVEL]
RString sAttackToGive;
if (GAMESTATE->m_pCurCharacters[pn] != NULL)
sAttackToGive = asAttacks[ RandomInt(NUM_ATTACKS_PER_LEVEL) ];
else
{
// "If you add any noteskins here, you need to make sure they're cached, too." -?
// Noteskins probably won't work here anymore. -aj
RString DefaultAttacks[8] = { "1.5x", "2.0x", "0.5x", "reverse", "sudden", "boost", "brake", "wave" };
sAttackToGive = DefaultAttacks[ RandomInt(8) ];
}
PlayerNumber pnToAttack = OPPOSITE_PLAYER[pn];
PlayerState *pPlayerStateToAttack = GAMESTATE->m_pPlayerState[pnToAttack];
Attack a;
a.level = al;
a.fSecsRemaining = ATTACK_DURATION_SECONDS;
a.sModifiers = sAttackToGive;
// remove current attack (if any)
pPlayerStateToAttack->RemoveActiveAttacks();
// apply new attack
pPlayerStateToAttack->LaunchAttack( a );
// SCREENMAN->SystemMessage( ssprintf( "attacking %d with %s", pnToAttack, sAttackToGive.c_str() ) );
}
/*
* (c) 2001-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#include "ScoreKeeperRave.h"
#include "ThemeManager.h"
#include "RageUtil.h"
#include "GameState.h"
#include "Character.h"
#include "ScreenManager.h"
#include "PrefsManager.h"
#include "ThemeMetric.h"
#include "PlayerState.h"
#include "NoteTypes.h"
ThemeMetric<float> ATTACK_DURATION_SECONDS ("ScoreKeeperRave","AttackDurationSeconds");
static const float g_fSuperMeterPercentChangeInit[] =
{
+0.02f, // SE_CheckpointHit
+0.05f, // SE_W1
+0.04f, // SE_W2
+0.02f, // SE_W3
+0.00f, // SE_W4
+0.00f, // SE_W5
-0.20f, // SE_Miss
-0.40f, // SE_HitMine
-0.02f, // SE_CheckpointMiss
+0.04f, // SE_Held
-0.20f, // SE_LetGo
};
COMPILE_ASSERT( ARRAYLEN(g_fSuperMeterPercentChangeInit) == NUM_ScoreEvent );
static void SuperMeterPercentChangeInit( size_t /*ScoreEvent*/ i, RString &sNameOut, float &defaultValueOut )
{
sNameOut = "SuperMeterPercentChange" + ScoreEventToString( (ScoreEvent)i );
defaultValueOut = g_fSuperMeterPercentChangeInit[i];
}
static Preference1D<float> g_fSuperMeterPercentChange( SuperMeterPercentChangeInit, NUM_ScoreEvent );
ScoreKeeperRave::ScoreKeeperRave( PlayerState *pPlayerState, PlayerStageStats *pPlayerStageStats ) :
ScoreKeeper(pPlayerState, pPlayerStageStats)
{
}
void ScoreKeeperRave::HandleTapScore( const TapNote &tn )
{
TapNoteScore score = tn.result.tns;
float fPercentToMove = 0;
if( score == TNS_HitMine )
fPercentToMove = g_fSuperMeterPercentChange[SE_HitMine];
AddSuperMeterDelta( fPercentToMove );
}
#define CROSSED( val ) (fOld < val && fNew >= val)
#define CROSSED_ATTACK_LEVEL( level ) CROSSED(1.f/NUM_ATTACK_LEVELS*(level+1))
void ScoreKeeperRave::HandleTapRowScore( const NoteData &nd, int iRow )
{
TapNoteScore scoreOfLastTap;
int iNumTapsInRow;
float fPercentToMove = 0.0f;
GetScoreOfLastTapInRow( nd, iRow, scoreOfLastTap, iNumTapsInRow );
if( iNumTapsInRow <= 0 )
return;
switch( scoreOfLastTap )
{
DEFAULT_FAIL( scoreOfLastTap );
case TNS_W1: fPercentToMove = g_fSuperMeterPercentChange[SE_W1]; break;
case TNS_W2: fPercentToMove = g_fSuperMeterPercentChange[SE_W2]; break;
case TNS_W3: fPercentToMove = g_fSuperMeterPercentChange[SE_W3]; break;
case TNS_W4: fPercentToMove = g_fSuperMeterPercentChange[SE_W4]; break;
case TNS_W5: fPercentToMove = g_fSuperMeterPercentChange[SE_W5]; break;
case TNS_Miss: fPercentToMove = g_fSuperMeterPercentChange[SE_Miss]; break;
}
AddSuperMeterDelta( fPercentToMove );
}
void ScoreKeeperRave::HandleHoldScore( const TapNote &tn )
{
// todo: should hit mine be handled in HandleTapRow score instead? -aj
TapNoteScore tapScore = tn.result.tns;
float fPercentToMove = 0.0f;
switch( tapScore )
{
case TNS_HitMine:
fPercentToMove = g_fSuperMeterPercentChange[SE_HitMine];
break;
default: break;
}
// Playing with this code enabled seems to feel "wrong", but I'm leaving it
// in for player feedback. -aj
HoldNoteScore holdScore = tn.HoldResult.hns;
switch( holdScore )
{
case HNS_Held: fPercentToMove = g_fSuperMeterPercentChange[SE_Held]; break;
case HNS_LetGo: fPercentToMove = g_fSuperMeterPercentChange[SE_LetGo]; break;
default: break;
}
AddSuperMeterDelta( fPercentToMove );
}
extern ThemeMetric<bool> PENALIZE_TAP_SCORE_NONE;
void ScoreKeeperRave::HandleTapScoreNone()
{
if( PENALIZE_TAP_SCORE_NONE )
{
float fPercentToMove = g_fSuperMeterPercentChange[SE_Miss];
AddSuperMeterDelta( fPercentToMove );
}
}
void ScoreKeeperRave::AddSuperMeterDelta( float fUnscaledPercentChange )
{
if( PREFSMAN->m_bMercifulDrain && fUnscaledPercentChange<0 )
{
float fSuperPercentage = m_pPlayerState->m_fSuperMeter / NUM_ATTACK_LEVELS;
fUnscaledPercentChange *= SCALE( fSuperPercentage, 0.f, 1.f, 0.5f, 1.f);
}
// more mercy: Grow super meter slower or faster depending on life.
if( PREFSMAN->m_bMercifulSuperMeter )
{
float fLifePercentage = 0;
switch( m_pPlayerState->m_PlayerNumber )
{
case PLAYER_1: fLifePercentage = GAMESTATE->m_fTugLifePercentP1; break;
case PLAYER_2: fLifePercentage = 1 - GAMESTATE->m_fTugLifePercentP1; break;
default:
FAIL_M(ssprintf("Invalid player number: %i", m_pPlayerState->m_PlayerNumber));
}
CLAMP( fLifePercentage, 0.f, 1.f );
if( fUnscaledPercentChange > 0 )
fUnscaledPercentChange *= SCALE( fLifePercentage, 0.f, 1.f, 1.7f, 0.3f);
else // fUnscaledPercentChange <= 0
fUnscaledPercentChange /= SCALE( fLifePercentage, 0.f, 1.f, 1.7f, 0.3f);
}
// mercy: drop super meter faster if at a higher level
if( fUnscaledPercentChange < 0 )
fUnscaledPercentChange *= SCALE( m_pPlayerState->m_fSuperMeter, 0.f, 1.f, 0.01f, 1.f );
AttackLevel oldAL = (AttackLevel)(int)m_pPlayerState->m_fSuperMeter;
float fPercentToMove = fUnscaledPercentChange;
m_pPlayerState->m_fSuperMeter += fPercentToMove * m_pPlayerState->m_fSuperMeterGrowthScale;
CLAMP( m_pPlayerState->m_fSuperMeter, 0.f, NUM_ATTACK_LEVELS );
AttackLevel newAL = (AttackLevel)(int)m_pPlayerState->m_fSuperMeter;
if( newAL > oldAL )
{
LaunchAttack( oldAL );
if( newAL == NUM_ATTACK_LEVELS ) // hit upper bounds of meter
m_pPlayerState->m_fSuperMeter -= 1.f;
}
// mercy: if losing remove attacks on life drain
if( fUnscaledPercentChange < 0 )
{
bool bWinning;
switch( m_pPlayerState->m_PlayerNumber )
{
case PLAYER_1: bWinning = GAMESTATE->m_fTugLifePercentP1 > 0.5f; break;
case PLAYER_2: bWinning = GAMESTATE->m_fTugLifePercentP1 < 0.5f; break;
default:
bWinning = false;
FAIL_M(ssprintf("Invalid player number: %i", m_pPlayerState->m_PlayerNumber));
}
if( !bWinning )
m_pPlayerState->EndActiveAttacks();
}
}
void ScoreKeeperRave::LaunchAttack( AttackLevel al )
{
PlayerNumber pn = m_pPlayerState->m_PlayerNumber;
RString* asAttacks = GAMESTATE->m_pCurCharacters[pn]->m_sAttacks[al]; // [NUM_ATTACKS_PER_LEVEL]
RString sAttackToGive;
if (GAMESTATE->m_pCurCharacters[pn] != nullptr)
sAttackToGive = asAttacks[ RandomInt(NUM_ATTACKS_PER_LEVEL) ];
else
{
// "If you add any noteskins here, you need to make sure they're cached, too." -?
// Noteskins probably won't work here anymore. -aj
RString DefaultAttacks[8] = { "1.5x", "2.0x", "0.5x", "reverse", "sudden", "boost", "brake", "wave" };
sAttackToGive = DefaultAttacks[ RandomInt(8) ];
}
PlayerNumber pnToAttack = OPPOSITE_PLAYER[pn];
PlayerState *pPlayerStateToAttack = GAMESTATE->m_pPlayerState[pnToAttack];
Attack a;
a.level = al;
a.fSecsRemaining = ATTACK_DURATION_SECONDS;
a.sModifiers = sAttackToGive;
// remove current attack (if any)
pPlayerStateToAttack->RemoveActiveAttacks();
// apply new attack
pPlayerStateToAttack->LaunchAttack( a );
// SCREENMAN->SystemMessage( ssprintf( "attacking %d with %s", pnToAttack, sAttackToGive.c_str() ) );
}
/*
* (c) 2001-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+8 -8
View File
@@ -1102,8 +1102,8 @@ void ScreenEdit::Init()
SubscribeToMessage( "Judgment" );
ASSERT( GAMESTATE->m_pCurSong != NULL );
ASSERT( GAMESTATE->m_pCurSteps[PLAYER_1] != NULL );
ASSERT( GAMESTATE->m_pCurSong != nullptr );
ASSERT( GAMESTATE->m_pCurSteps[PLAYER_1] != nullptr );
EDIT_MODE.Load( m_sName, "EditMode" );
ScreenWithMenuElements::Init();
@@ -2112,7 +2112,7 @@ bool ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
// save current steps
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
ASSERT( pSteps != NULL );
ASSERT( pSteps != nullptr );
pSteps->SetNoteData( m_NoteDataEdit );
// Get all Steps of this StepsType
@@ -3087,7 +3087,7 @@ void ScreenEdit::TransitionEditState( EditState em )
/* FirstBeat affects backgrounds, so commit changes to memory (not to disk)
* and recalc it. */
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
ASSERT( pSteps != NULL );
ASSERT( pSteps != nullptr );
pSteps->SetNoteData( m_NoteDataEdit );
m_pSong->ReCalculateRadarValuesAndLastSecond();
@@ -3493,7 +3493,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
GAMESTATE->m_pCurCourse.Set( pCourse );
GAMESTATE->m_iEditCourseEntryIndex.Set( iCourseEntryIndex );
ASSERT( GAMESTATE->m_pCurCourse != NULL );
ASSERT( GAMESTATE->m_pCurCourse != nullptr );
}
}
else if (SM == SM_BackFromKeysoundTrack)
@@ -5520,8 +5520,8 @@ void ScreenEdit::SetupCourseAttacks()
void ScreenEdit::CopyToLastSave()
{
ASSERT( GAMESTATE->m_pCurSong != NULL );
ASSERT( GAMESTATE->m_pCurSteps[PLAYER_1] != NULL );
ASSERT( GAMESTATE->m_pCurSong != nullptr );
ASSERT( GAMESTATE->m_pCurSteps[PLAYER_1] != nullptr );
m_SongLastSave = *GAMESTATE->m_pCurSong;
m_vStepsLastSave.clear();
const vector<Steps*> &vSteps = GAMESTATE->m_pCurSong->GetStepsByStepsType( GAMESTATE->m_pCurSteps[PLAYER_1]->m_StepsType );
@@ -5543,7 +5543,7 @@ void ScreenEdit::CopyFromLastSave()
void ScreenEdit::RevertFromDisk()
{
ASSERT( GAMESTATE->m_pCurSteps[PLAYER_1] != NULL );
ASSERT( GAMESTATE->m_pCurSteps[PLAYER_1] != nullptr );
StepsID id;
id.FromSteps( GAMESTATE->m_pCurSteps[PLAYER_1] );
ASSERT( id.IsValid() );
+3 -3
View File
@@ -220,7 +220,7 @@ bool ScreenEditMenu::MenuStart( const InputEventPlus & )
{
case EditMenuAction_Delete:
{
ASSERT( pSteps != NULL );
ASSERT( pSteps != nullptr );
if( pSteps->IsAutogen() )
{
SCREENMAN->PlayInvalidSound();
@@ -238,7 +238,7 @@ bool ScreenEditMenu::MenuStart( const InputEventPlus & )
case EditMenuAction_Practice:
break;
case EditMenuAction_Delete:
ASSERT( pSteps != NULL );
ASSERT( pSteps != nullptr );
ScreenPrompt::Prompt( SM_None, STEPS_WILL_BE_LOST.GetValue() + "\n\n" + CONTINUE_WITH_DELETE.GetValue(),
PROMPT_YES_NO, ANSWER_NO );
break;
@@ -298,7 +298,7 @@ bool ScreenEditMenu::MenuStart( const InputEventPlus & )
case EditMenuAction_Practice:
{
// Prepare for ScreenEdit
ASSERT( pSteps != NULL );
ASSERT( pSteps != nullptr );
bool bPromptToNameSteps = (action == EditMenuAction_Create && dc == Difficulty_Edit);
if( bPromptToNameSteps )
{
+10 -10
View File
@@ -428,7 +428,7 @@ void ScreenGameplay::Init()
GAMESTATE->m_pCurSteps[p].Set( GAMESTATE->m_pCurSteps[ GAMESTATE->GetFirstHumanPlayer() ] );
FOREACH_EnabledPlayer(p)
ASSERT( GAMESTATE->m_pCurSteps[p].Get() != NULL );
ASSERT( GAMESTATE->m_pCurSteps[p].Get() != nullptr );
}
/* Increment the course play count. */
@@ -814,28 +814,28 @@ void ScreenGameplay::InitSongQueues()
if( GAMESTATE->IsCourseMode() )
{
Course* pCourse = GAMESTATE->m_pCurCourse;
ASSERT( pCourse != NULL );
ASSERT( pCourse != nullptr );
m_apSongsQueue.clear();
PlayerNumber pnMaster = GAMESTATE->GetMasterPlayerNumber();
Trail *pTrail = GAMESTATE->m_pCurTrail[pnMaster];
ASSERT( pTrail != NULL );
ASSERT( pTrail != nullptr );
for (TrailEntry const &e : pTrail->m_vEntries)
{
ASSERT( e.pSong != NULL );
ASSERT( e.pSong != nullptr );
m_apSongsQueue.push_back( e.pSong );
}
FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi )
{
Trail *lTrail = GAMESTATE->m_pCurTrail[ pi->GetStepsAndTrailIndex() ];
ASSERT( lTrail != NULL );
ASSERT( lTrail != nullptr );
pi->m_vpStepsQueue.clear();
pi->m_asModifiersQueue.clear();
for (TrailEntry const &e : lTrail->m_vEntries)
{
ASSERT( e.pSteps != NULL );
ASSERT( e.pSteps != nullptr );
pi->m_vpStepsQueue.push_back( e.pSteps );
AttackArray a;
e.GetAttackArray( a );
@@ -1094,7 +1094,7 @@ void ScreenGameplay::LoadNextSong()
Steps* pSteps = GAMESTATE->m_pCurSteps[ pi->GetStepsAndTrailIndex() ];
++pi->GetPlayerStageStats()->m_iStepsPlayed;
ASSERT( GAMESTATE->m_pCurSteps[ pi->GetStepsAndTrailIndex() ] != NULL );
ASSERT( GAMESTATE->m_pCurSteps[ pi->GetStepsAndTrailIndex() ] != nullptr );
if( pi->m_ptextStepsDescription )
pi->m_ptextStepsDescription->SetText( pSteps->GetDescription() );
@@ -1285,10 +1285,10 @@ void ScreenGameplay::LoadLights()
// First, check if the song has explicit lights
m_CabinetLightsNoteData.Init();
ASSERT( GAMESTATE->m_pCurSong != NULL );
ASSERT( GAMESTATE->m_pCurSong != nullptr );
const Steps *pSteps = SongUtil::GetClosestNotes( GAMESTATE->m_pCurSong, StepsType_lights_cabinet, Difficulty_Medium );
if( pSteps != NULL )
if( pSteps != nullptr )
{
pSteps->GetNoteData( m_CabinetLightsNoteData );
return;
@@ -1751,7 +1751,7 @@ void ScreenGameplay::Update( float fDeltaTime )
DancingCharacters *pCharacter = NULL;
if( m_pSongBackground )
pCharacter = m_pSongBackground->GetDancingCharacters();
if( pCharacter != NULL )
if( pCharacter != nullptr )
{
TapNoteScore tns = pi->m_pPlayer->GetLastTapNoteScore();
+2 -2
View File
@@ -15,8 +15,8 @@ ScreenGameplayLesson::ScreenGameplayLesson()
void ScreenGameplayLesson::Init()
{
ASSERT( GAMESTATE->GetCurrentStyle() != NULL );
ASSERT( GAMESTATE->m_pCurSong != NULL );
ASSERT( GAMESTATE->GetCurrentStyle() != nullptr );
ASSERT( GAMESTATE->m_pCurSong != nullptr );
/* Now that we've set up, init the base class. */
ScreenGameplayNormal::Init();
+4 -4
View File
@@ -116,9 +116,9 @@ void ScoreScroller::ConfigureActor( Actor *pActor, int iItem )
const ScoreRowItemData &data = m_vScoreRowItemData[iItem];
Message msg("Set");
if( data.m_pSong != NULL )
if( data.m_pSong != nullptr )
msg.SetParam( "Song", data.m_pSong );
if( data.m_pCourse != NULL )
if( data.m_pCourse != nullptr )
msg.SetParam( "Course", data.m_pCourse );
@@ -133,7 +133,7 @@ void ScoreScroller::ConfigureActor( Actor *pActor, int iItem )
Difficulty dc = iter.first;
StepsType st = iter.second;
if( data.m_pSong != NULL )
if( data.m_pSong != nullptr )
{
const Song* pSong = data.m_pSong;
Steps *pSteps = SongUtil::GetStepsByDifficulty( pSong, st, dc, false );
@@ -141,7 +141,7 @@ void ScoreScroller::ConfigureActor( Actor *pActor, int iItem )
pSteps = NULL;
LuaHelpers::Push( L, pSteps );
}
else if( data.m_pCourse != NULL )
else if( data.m_pCourse != nullptr )
{
const Course* pCourse = data.m_pCourse;
Trail *pTrail = pCourse->GetTrail( st, dc );
+2 -2
View File
@@ -149,7 +149,7 @@ void ScreenHowToPlay::Init()
const Style* pStyle = GAMESTATE->GetCurrentStyle();
Steps *pSteps = SongUtil::GetClosestNotes( &m_Song, pStyle->m_StepsType, Difficulty_Beginner );
ASSERT_M( pSteps != NULL, ssprintf("No playable steps of StepsType '%s' for ScreenHowToPlay", StringConversion::ToString(pStyle->m_StepsType).c_str()) );
ASSERT_M( pSteps != nullptr, ssprintf("No playable steps of StepsType '%s' for ScreenHowToPlay", StringConversion::ToString(pStyle->m_StepsType).c_str()) );
m_Song.m_SongTiming.TidyUpData( false );
pSteps->m_Timing.TidyUpData( true );
@@ -248,7 +248,7 @@ void ScreenHowToPlay::Step()
void ScreenHowToPlay::Update( float fDelta )
{
if( GAMESTATE->m_pCurSong != NULL )
if( GAMESTATE->m_pCurSong != nullptr )
{
RageTimer tm;
GAMESTATE->UpdateSongPosition( m_fFakeSecondsIntoSong, GAMESTATE->m_pCurSong->m_SongTiming, tm, true );
+4 -4
View File
@@ -34,7 +34,7 @@ void ScreenJukebox::SetSong()
/* Check to see if there is a theme course. If there is a course that has
* the exact same name as the theme, then we pick a song from this course. */
Course *pCourse = SONGMAN->GetCourseFromName( THEME->GetCurThemeName() );
if( pCourse != NULL )
if( pCourse != nullptr )
for ( unsigned i = 0; i < pCourse->m_vEntries.size(); i++ )
if( pCourse->m_vEntries[i].IsFixedSong() )
vSongs.push_back( pCourse->m_vEntries[i].songID.ToSong() );
@@ -73,7 +73,7 @@ void ScreenJukebox::SetSong()
Song* pSong = vSongs[RandomInt(vSongs.size())];
ASSERT( pSong != NULL );
ASSERT( pSong != nullptr );
if( !pSong->HasMusic() )
continue; // skip
if( !pSong->NormallyDisplayed() )
@@ -152,7 +152,7 @@ void ScreenJukebox::SetSong()
FOREACH_PlayerNumber( p )
{
GAMESTATE->m_pCurTrail[p].Set( lCourse->GetTrail( GAMESTATE->GetCurrentStyle()->m_StepsType ) );
ASSERT( GAMESTATE->m_pCurTrail[p] != NULL );
ASSERT( GAMESTATE->m_pCurTrail[p] != nullptr );
}
}
}
@@ -172,7 +172,7 @@ ScreenJukebox::ScreenJukebox()
void ScreenJukebox::Init()
{
// ScreenJukeboxMenu must set this
ASSERT( GAMESTATE->GetCurrentStyle() != NULL );
ASSERT( GAMESTATE->GetCurrentStyle() != nullptr );
GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR );
SetSong();
+3 -3
View File
@@ -770,14 +770,14 @@ void ScreenManager::PopAllScreens()
void ScreenManager::PostMessageToTopScreen( ScreenMessage SM, float fDelay )
{
Screen* pTopScreen = GetTopScreen();
if( pTopScreen != NULL )
if( pTopScreen != nullptr )
pTopScreen->PostScreenMessage( SM, fDelay );
}
void ScreenManager::SendMessageToTopScreen( ScreenMessage SM )
{
Screen* pTopScreen = GetTopScreen();
if( pTopScreen != NULL )
if( pTopScreen != nullptr )
pTopScreen->HandleScreenMessage( SM );
}
@@ -858,7 +858,7 @@ public:
static int GetTopScreen( T* p, lua_State *L )
{
Actor *pScreen = p->GetTopScreen();
if( pScreen != NULL )
if( pScreen != nullptr )
pScreen->PushSelf(L);
else
lua_pushnil( L );
+1 -1
View File
@@ -59,7 +59,7 @@ void ScreenMiniMenu::Init()
void ScreenMiniMenu::BeginScreen()
{
ASSERT( g_pMenuDef != NULL );
ASSERT( g_pMenuDef != nullptr );
LoadMenu( g_pMenuDef );
m_SMSendOnOK = g_SendOnOK;
+343 -343
View File
@@ -1,343 +1,343 @@
#include "global.h"
#if !defined(WITHOUT_NETWORKING)
#include "ScreenNetRoom.h"
#include "ScreenManager.h"
#include "NetworkSyncManager.h"
#include "GameState.h"
#include "ThemeManager.h"
#include "ScreenTextEntry.h"
#include "WheelItemBase.h"
#include "InputEventPlus.h"
#include "LocalizedString.h"
AutoScreenMessage( SM_SMOnlinePack );
AutoScreenMessage( SM_BackFromRoomName );
AutoScreenMessage( SM_BackFromRoomDesc );
AutoScreenMessage( SM_BackFromRoomPass );
AutoScreenMessage( SM_BackFromReqPass );
AutoScreenMessage( SM_RoomInfoRetract );
AutoScreenMessage( SM_RoomInfoDeploy );
static LocalizedString ENTER_ROOM_DESCRIPTION ("ScreenNetRoom","Enter a description for the room:");
static LocalizedString ENTER_ROOM_PASSWORD ("ScreenNetRoom","Enter a password for the room (blank, no password):");
static LocalizedString ENTER_ROOM_REQPASSWORD ("ScreenNetRoom","Enter Room's Password:");
REGISTER_SCREEN_CLASS( ScreenNetRoom );
void ScreenNetRoom::Init()
{
GAMESTATE->FinishStage();
ScreenNetSelectBase::Init();
m_soundChangeSel.Load( THEME->GetPathS("ScreenNetRoom","change sel") );
m_iRoomPlace = 0;
m_RoomWheel.SetName( "RoomWheel" );
m_RoomWheel.Load( "RoomWheel" );
m_RoomWheel.BeginScreen();
LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_RoomWheel );
this->AddChild( &m_RoomWheel );
// Since the room info display does not start active, and it is activated by
// code elsewhere, it should not be put on screen to begin with.
m_roomInfo.SetName( "RoomInfoDisplay" );
m_roomInfo.Load( "RoomInfoDisplay" );
m_roomInfo.SetDrawOrder( 1 );
this->AddChild( &m_roomInfo );
this->SortByDrawOrder();
NSMAN->ReportNSSOnOff( 7 );
}
bool ScreenNetRoom::Input( const InputEventPlus &input )
{
if( (input.MenuI == GAME_BUTTON_LEFT || input.MenuI == GAME_BUTTON_RIGHT) && input.type == IET_RELEASE )
m_RoomWheel.Move( 0 );
return ScreenNetSelectBase::Input( input );
}
void ScreenNetRoom::HandleScreenMessage( const ScreenMessage SM )
{
if( SM == SM_GoToPrevScreen )
{
SCREENMAN->SetNewScreen( THEME->GetMetric (m_sName, "PrevScreen") );
}
else if( SM == SM_GoToNextScreen )
{
SCREENMAN->SetNewScreen( THEME->GetMetric (m_sName, "NextScreen") );
}
else if( SM == SM_BackFromReqPass )
{
if ( !ScreenTextEntry::s_bCancelledLast )
{
NSMAN->m_SMOnlinePacket.ClearPacket();
NSMAN->m_SMOnlinePacket.Write1( 1 );
NSMAN->m_SMOnlinePacket.Write1( 1 ); //Type (enter a room)
NSMAN->m_SMOnlinePacket.WriteNT( m_sLastPickedRoom );
NSMAN->m_SMOnlinePacket.WriteNT( ScreenTextEntry::s_sLastAnswer );
NSMAN->SendSMOnline( );
}
}
else if( SM == SM_SMOnlinePack )
{
switch( NSMAN->m_SMOnlinePacket.Read1() )
{
case 1:
switch ( NSMAN->m_SMOnlinePacket.Read1() )
{
case 0: //Room title Change
{
RString title, subtitle;
title = NSMAN->m_SMOnlinePacket.ReadNT();
subtitle = NSMAN->m_SMOnlinePacket.ReadNT();
Message msg( MessageIDToString(Message_UpdateScreenHeader) );
msg.SetParam( "Header", title );
msg.SetParam( "Subheader", subtitle );
MESSAGEMAN->Broadcast( msg );
if ( NSMAN->m_SMOnlinePacket.Read1() != 0 )
{
RString SMOnlineSelectScreen = THEME->GetMetric( m_sName, "MusicSelectScreen" );
SCREENMAN->SetNewScreen( SMOnlineSelectScreen );
}
}
case 1: //Rooms list change
{
int numRooms = NSMAN->m_SMOnlinePacket.Read1();
m_Rooms.clear();
for( int i=0; i<numRooms; ++i )
{
RoomData tmpRoomData;
tmpRoomData.SetName( NSMAN->m_SMOnlinePacket.ReadNT() );
tmpRoomData.SetDescription( NSMAN->m_SMOnlinePacket.ReadNT() );
m_Rooms.push_back( tmpRoomData );
}
//Abide by protocol and read room status
for( int i=0; i<numRooms; ++i )
m_Rooms[i].SetState( NSMAN->m_SMOnlinePacket.Read1() );
for( int i=0; i<numRooms; ++i )
m_Rooms[i].SetFlags( NSMAN->m_SMOnlinePacket.Read1() );
if( m_iRoomPlace<0 )
m_iRoomPlace=0;
if( m_iRoomPlace >= (int) m_Rooms.size() )
m_iRoomPlace=m_Rooms.size()-1;
UpdateRoomsList();
}
}
break;
case 3:
RoomInfo info;
info.songTitle = NSMAN->m_SMOnlinePacket.ReadNT();
info.songSubTitle = NSMAN->m_SMOnlinePacket.ReadNT();
info.songArtist = NSMAN->m_SMOnlinePacket.ReadNT();
info.numPlayers = NSMAN->m_SMOnlinePacket.Read1();
info.maxPlayers = NSMAN->m_SMOnlinePacket.Read1();
info.players.resize( info.numPlayers );
for( int i = 0; i < info.numPlayers; ++i )
info.players[i] = NSMAN->m_SMOnlinePacket.ReadNT();
m_roomInfo.SetRoomInfo( info );
break;
}
}
else if ( SM == SM_BackFromRoomName )
{
if ( !ScreenTextEntry::s_bCancelledLast )
{
m_newRoomName = ScreenTextEntry::s_sLastAnswer;
ScreenTextEntry::TextEntry( SM_BackFromRoomDesc, ENTER_ROOM_DESCRIPTION, "", 255 );
}
}
else if( SM == SM_BackFromRoomDesc )
{
if ( !ScreenTextEntry::s_bCancelledLast )
{
m_newRoomDesc = ScreenTextEntry::s_sLastAnswer;
ScreenTextEntry::TextEntry( SM_BackFromRoomPass, ENTER_ROOM_PASSWORD, "", 255 );
}
}
else if( SM == SM_BackFromRoomPass )
{
if ( !ScreenTextEntry::s_bCancelledLast )
{
m_newRoomPass = ScreenTextEntry::s_sLastAnswer;
CreateNewRoom( m_newRoomName, m_newRoomDesc, m_newRoomPass);
}
}
else if ( SM == SM_RoomInfoRetract )
{
m_roomInfo.RetractInfoBox();
}
else if ( SM == SM_RoomInfoDeploy )
{
int i = m_RoomWheel.GetCurrentIndex() - m_RoomWheel.GetPerminateOffset();
const RoomWheelItemData* data = m_RoomWheel.GetItem(i);
if( data != NULL )
m_roomInfo.SetRoom( data );
}
ScreenNetSelectBase::HandleScreenMessage( SM );
}
void ScreenNetRoom::TweenOffScreen()
{
NSMAN->ReportNSSOnOff( 6 );
}
bool ScreenNetRoom::MenuStart( const InputEventPlus &input )
{
m_RoomWheel.Select();
RoomWheelItemData* rwd = dynamic_cast<RoomWheelItemData*>( m_RoomWheel.LastSelected() );
if( rwd )
{
if ( rwd->m_iFlags % 2 )
{
m_sLastPickedRoom = rwd->m_sText;
ScreenTextEntry::TextEntry( SM_BackFromReqPass, ENTER_ROOM_REQPASSWORD, "", 255 );
}
else
{
NSMAN->m_SMOnlinePacket.ClearPacket();
NSMAN->m_SMOnlinePacket.Write1( 1 );
NSMAN->m_SMOnlinePacket.Write1( 1 ); //Type (enter a room)
NSMAN->m_SMOnlinePacket.WriteNT( rwd->m_sText );
NSMAN->SendSMOnline( );
}
}
ScreenNetSelectBase::MenuStart( input );
return true;
}
bool ScreenNetRoom::MenuBack( const InputEventPlus &input )
{
TweenOffScreen();
Cancel( SM_GoToPrevScreen );
ScreenNetSelectBase::MenuBack( input );
return true;
}
bool ScreenNetRoom::MenuLeft( const InputEventPlus &input )
{
bool bHandled = false;
if( input.type == IET_FIRST_PRESS )
{
m_RoomWheel.Move( -1 );
bHandled = true;
}
return ScreenNetSelectBase::MenuLeft( input ) || bHandled;
}
bool ScreenNetRoom::MenuRight( const InputEventPlus &input )
{
bool bHandled = false;
if( input.type == IET_FIRST_PRESS )
{
m_RoomWheel.Move( 1 );
bHandled = true;
}
return ScreenNetSelectBase::MenuRight( input ) || bHandled;
}
void ScreenNetRoom::UpdateRoomsList()
{
int difference = 0;
RoomWheelItemData* itemData = NULL;
difference = m_RoomWheel.GetNumItems() - m_Rooms.size();
if( !m_RoomWheel.IsEmpty() )
{
if( difference > 0 )
for( int x = 0; x < difference; ++x )
m_RoomWheel.RemoveItem( m_RoomWheel.GetNumItems() - 1 );
else
{
difference = abs( difference );
for( int x = 0; x < difference; ++x )
m_RoomWheel.AddItem( new RoomWheelItemData(WheelItemDataType_Generic, "", "", RageColor(1,1,1,1)) );
}
}
else
{
for ( unsigned int x = 0; x < m_Rooms.size(); ++x)
m_RoomWheel.AddItem( new RoomWheelItemData(WheelItemDataType_Generic, "", "", RageColor(1,1,1,1)) );
}
for( unsigned int i = 0; i < m_Rooms.size(); ++i )
{
itemData = m_RoomWheel.GetItem( i );
itemData->m_sText = m_Rooms[i].Name();
itemData->m_sDesc = m_Rooms[i].Description();
itemData->m_iFlags = m_Rooms[i].GetFlags();
switch( m_Rooms[i].State() )
{
case 0:
itemData->m_color = THEME->GetMetricC( m_sName, "OpenRoomColor");
break;
case 2:
itemData->m_color = THEME->GetMetricC( m_sName, "InGameRoomColor");
break;
default:
itemData->m_color = THEME->GetMetricC( m_sName, "OpenRoomColor");
break;
}
if ( m_Rooms[i].GetFlags() % 2 )
itemData->m_color = THEME->GetMetricC( m_sName, "PasswdRoomColor");
}
m_RoomWheel.RebuildWheelItems();
}
void ScreenNetRoom::CreateNewRoom( const RString& rName, const RString& rDesc, const RString& rPass )
{
NSMAN->m_SMOnlinePacket.ClearPacket();
NSMAN->m_SMOnlinePacket.Write1( (uint8_t)2 ); // Create room command
NSMAN->m_SMOnlinePacket.Write1( 1 ); // Type game room
NSMAN->m_SMOnlinePacket.WriteNT( rName );
NSMAN->m_SMOnlinePacket.WriteNT( rDesc );
if ( !rPass.empty() )
NSMAN->m_SMOnlinePacket.WriteNT( rPass );
NSMAN->SendSMOnline( );
}
#endif
/*
* (c) 2004 Charles Lohr, Josh Allen
* (c) 2001-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "global.h"
#if !defined(WITHOUT_NETWORKING)
#include "ScreenNetRoom.h"
#include "ScreenManager.h"
#include "NetworkSyncManager.h"
#include "GameState.h"
#include "ThemeManager.h"
#include "ScreenTextEntry.h"
#include "WheelItemBase.h"
#include "InputEventPlus.h"
#include "LocalizedString.h"
AutoScreenMessage( SM_SMOnlinePack );
AutoScreenMessage( SM_BackFromRoomName );
AutoScreenMessage( SM_BackFromRoomDesc );
AutoScreenMessage( SM_BackFromRoomPass );
AutoScreenMessage( SM_BackFromReqPass );
AutoScreenMessage( SM_RoomInfoRetract );
AutoScreenMessage( SM_RoomInfoDeploy );
static LocalizedString ENTER_ROOM_DESCRIPTION ("ScreenNetRoom","Enter a description for the room:");
static LocalizedString ENTER_ROOM_PASSWORD ("ScreenNetRoom","Enter a password for the room (blank, no password):");
static LocalizedString ENTER_ROOM_REQPASSWORD ("ScreenNetRoom","Enter Room's Password:");
REGISTER_SCREEN_CLASS( ScreenNetRoom );
void ScreenNetRoom::Init()
{
GAMESTATE->FinishStage();
ScreenNetSelectBase::Init();
m_soundChangeSel.Load( THEME->GetPathS("ScreenNetRoom","change sel") );
m_iRoomPlace = 0;
m_RoomWheel.SetName( "RoomWheel" );
m_RoomWheel.Load( "RoomWheel" );
m_RoomWheel.BeginScreen();
LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_RoomWheel );
this->AddChild( &m_RoomWheel );
// Since the room info display does not start active, and it is activated by
// code elsewhere, it should not be put on screen to begin with.
m_roomInfo.SetName( "RoomInfoDisplay" );
m_roomInfo.Load( "RoomInfoDisplay" );
m_roomInfo.SetDrawOrder( 1 );
this->AddChild( &m_roomInfo );
this->SortByDrawOrder();
NSMAN->ReportNSSOnOff( 7 );
}
bool ScreenNetRoom::Input( const InputEventPlus &input )
{
if( (input.MenuI == GAME_BUTTON_LEFT || input.MenuI == GAME_BUTTON_RIGHT) && input.type == IET_RELEASE )
m_RoomWheel.Move( 0 );
return ScreenNetSelectBase::Input( input );
}
void ScreenNetRoom::HandleScreenMessage( const ScreenMessage SM )
{
if( SM == SM_GoToPrevScreen )
{
SCREENMAN->SetNewScreen( THEME->GetMetric (m_sName, "PrevScreen") );
}
else if( SM == SM_GoToNextScreen )
{
SCREENMAN->SetNewScreen( THEME->GetMetric (m_sName, "NextScreen") );
}
else if( SM == SM_BackFromReqPass )
{
if ( !ScreenTextEntry::s_bCancelledLast )
{
NSMAN->m_SMOnlinePacket.ClearPacket();
NSMAN->m_SMOnlinePacket.Write1( 1 );
NSMAN->m_SMOnlinePacket.Write1( 1 ); //Type (enter a room)
NSMAN->m_SMOnlinePacket.WriteNT( m_sLastPickedRoom );
NSMAN->m_SMOnlinePacket.WriteNT( ScreenTextEntry::s_sLastAnswer );
NSMAN->SendSMOnline( );
}
}
else if( SM == SM_SMOnlinePack )
{
switch( NSMAN->m_SMOnlinePacket.Read1() )
{
case 1:
switch ( NSMAN->m_SMOnlinePacket.Read1() )
{
case 0: //Room title Change
{
RString title, subtitle;
title = NSMAN->m_SMOnlinePacket.ReadNT();
subtitle = NSMAN->m_SMOnlinePacket.ReadNT();
Message msg( MessageIDToString(Message_UpdateScreenHeader) );
msg.SetParam( "Header", title );
msg.SetParam( "Subheader", subtitle );
MESSAGEMAN->Broadcast( msg );
if ( NSMAN->m_SMOnlinePacket.Read1() != 0 )
{
RString SMOnlineSelectScreen = THEME->GetMetric( m_sName, "MusicSelectScreen" );
SCREENMAN->SetNewScreen( SMOnlineSelectScreen );
}
}
case 1: //Rooms list change
{
int numRooms = NSMAN->m_SMOnlinePacket.Read1();
m_Rooms.clear();
for( int i=0; i<numRooms; ++i )
{
RoomData tmpRoomData;
tmpRoomData.SetName( NSMAN->m_SMOnlinePacket.ReadNT() );
tmpRoomData.SetDescription( NSMAN->m_SMOnlinePacket.ReadNT() );
m_Rooms.push_back( tmpRoomData );
}
//Abide by protocol and read room status
for( int i=0; i<numRooms; ++i )
m_Rooms[i].SetState( NSMAN->m_SMOnlinePacket.Read1() );
for( int i=0; i<numRooms; ++i )
m_Rooms[i].SetFlags( NSMAN->m_SMOnlinePacket.Read1() );
if( m_iRoomPlace<0 )
m_iRoomPlace=0;
if( m_iRoomPlace >= (int) m_Rooms.size() )
m_iRoomPlace=m_Rooms.size()-1;
UpdateRoomsList();
}
}
break;
case 3:
RoomInfo info;
info.songTitle = NSMAN->m_SMOnlinePacket.ReadNT();
info.songSubTitle = NSMAN->m_SMOnlinePacket.ReadNT();
info.songArtist = NSMAN->m_SMOnlinePacket.ReadNT();
info.numPlayers = NSMAN->m_SMOnlinePacket.Read1();
info.maxPlayers = NSMAN->m_SMOnlinePacket.Read1();
info.players.resize( info.numPlayers );
for( int i = 0; i < info.numPlayers; ++i )
info.players[i] = NSMAN->m_SMOnlinePacket.ReadNT();
m_roomInfo.SetRoomInfo( info );
break;
}
}
else if ( SM == SM_BackFromRoomName )
{
if ( !ScreenTextEntry::s_bCancelledLast )
{
m_newRoomName = ScreenTextEntry::s_sLastAnswer;
ScreenTextEntry::TextEntry( SM_BackFromRoomDesc, ENTER_ROOM_DESCRIPTION, "", 255 );
}
}
else if( SM == SM_BackFromRoomDesc )
{
if ( !ScreenTextEntry::s_bCancelledLast )
{
m_newRoomDesc = ScreenTextEntry::s_sLastAnswer;
ScreenTextEntry::TextEntry( SM_BackFromRoomPass, ENTER_ROOM_PASSWORD, "", 255 );
}
}
else if( SM == SM_BackFromRoomPass )
{
if ( !ScreenTextEntry::s_bCancelledLast )
{
m_newRoomPass = ScreenTextEntry::s_sLastAnswer;
CreateNewRoom( m_newRoomName, m_newRoomDesc, m_newRoomPass);
}
}
else if ( SM == SM_RoomInfoRetract )
{
m_roomInfo.RetractInfoBox();
}
else if ( SM == SM_RoomInfoDeploy )
{
int i = m_RoomWheel.GetCurrentIndex() - m_RoomWheel.GetPerminateOffset();
const RoomWheelItemData* data = m_RoomWheel.GetItem(i);
if( data != nullptr )
m_roomInfo.SetRoom( data );
}
ScreenNetSelectBase::HandleScreenMessage( SM );
}
void ScreenNetRoom::TweenOffScreen()
{
NSMAN->ReportNSSOnOff( 6 );
}
bool ScreenNetRoom::MenuStart( const InputEventPlus &input )
{
m_RoomWheel.Select();
RoomWheelItemData* rwd = dynamic_cast<RoomWheelItemData*>( m_RoomWheel.LastSelected() );
if( rwd )
{
if ( rwd->m_iFlags % 2 )
{
m_sLastPickedRoom = rwd->m_sText;
ScreenTextEntry::TextEntry( SM_BackFromReqPass, ENTER_ROOM_REQPASSWORD, "", 255 );
}
else
{
NSMAN->m_SMOnlinePacket.ClearPacket();
NSMAN->m_SMOnlinePacket.Write1( 1 );
NSMAN->m_SMOnlinePacket.Write1( 1 ); //Type (enter a room)
NSMAN->m_SMOnlinePacket.WriteNT( rwd->m_sText );
NSMAN->SendSMOnline( );
}
}
ScreenNetSelectBase::MenuStart( input );
return true;
}
bool ScreenNetRoom::MenuBack( const InputEventPlus &input )
{
TweenOffScreen();
Cancel( SM_GoToPrevScreen );
ScreenNetSelectBase::MenuBack( input );
return true;
}
bool ScreenNetRoom::MenuLeft( const InputEventPlus &input )
{
bool bHandled = false;
if( input.type == IET_FIRST_PRESS )
{
m_RoomWheel.Move( -1 );
bHandled = true;
}
return ScreenNetSelectBase::MenuLeft( input ) || bHandled;
}
bool ScreenNetRoom::MenuRight( const InputEventPlus &input )
{
bool bHandled = false;
if( input.type == IET_FIRST_PRESS )
{
m_RoomWheel.Move( 1 );
bHandled = true;
}
return ScreenNetSelectBase::MenuRight( input ) || bHandled;
}
void ScreenNetRoom::UpdateRoomsList()
{
int difference = 0;
RoomWheelItemData* itemData = NULL;
difference = m_RoomWheel.GetNumItems() - m_Rooms.size();
if( !m_RoomWheel.IsEmpty() )
{
if( difference > 0 )
for( int x = 0; x < difference; ++x )
m_RoomWheel.RemoveItem( m_RoomWheel.GetNumItems() - 1 );
else
{
difference = abs( difference );
for( int x = 0; x < difference; ++x )
m_RoomWheel.AddItem( new RoomWheelItemData(WheelItemDataType_Generic, "", "", RageColor(1,1,1,1)) );
}
}
else
{
for ( unsigned int x = 0; x < m_Rooms.size(); ++x)
m_RoomWheel.AddItem( new RoomWheelItemData(WheelItemDataType_Generic, "", "", RageColor(1,1,1,1)) );
}
for( unsigned int i = 0; i < m_Rooms.size(); ++i )
{
itemData = m_RoomWheel.GetItem( i );
itemData->m_sText = m_Rooms[i].Name();
itemData->m_sDesc = m_Rooms[i].Description();
itemData->m_iFlags = m_Rooms[i].GetFlags();
switch( m_Rooms[i].State() )
{
case 0:
itemData->m_color = THEME->GetMetricC( m_sName, "OpenRoomColor");
break;
case 2:
itemData->m_color = THEME->GetMetricC( m_sName, "InGameRoomColor");
break;
default:
itemData->m_color = THEME->GetMetricC( m_sName, "OpenRoomColor");
break;
}
if ( m_Rooms[i].GetFlags() % 2 )
itemData->m_color = THEME->GetMetricC( m_sName, "PasswdRoomColor");
}
m_RoomWheel.RebuildWheelItems();
}
void ScreenNetRoom::CreateNewRoom( const RString& rName, const RString& rDesc, const RString& rPass )
{
NSMAN->m_SMOnlinePacket.ClearPacket();
NSMAN->m_SMOnlinePacket.Write1( (uint8_t)2 ); // Create room command
NSMAN->m_SMOnlinePacket.Write1( 1 ); // Type game room
NSMAN->m_SMOnlinePacket.WriteNT( rName );
NSMAN->m_SMOnlinePacket.WriteNT( rDesc );
if ( !rPass.empty() )
NSMAN->m_SMOnlinePacket.WriteNT( rPass );
NSMAN->SendSMOnline( );
}
#endif
/*
* (c) 2004 Charles Lohr, Josh Allen
* (c) 2001-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/

Some files were not shown because too many files have changed in this diff Show More