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:
+2
-2
@@ -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
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -281,7 +281,7 @@ void ConcurrentRenderer::Stop()
|
||||
|
||||
void ConcurrentRenderer::RenderThread()
|
||||
{
|
||||
ASSERT( SCREENMAN != NULL );
|
||||
ASSERT( SCREENMAN != nullptr );
|
||||
|
||||
while( !m_bShutdown )
|
||||
{
|
||||
|
||||
+884
-884
File diff suppressed because it is too large
Load Diff
+10
-10
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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" );
|
||||
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+1005
-1005
File diff suppressed because it is too large
Load Diff
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
+568
-568
File diff suppressed because it is too large
Load Diff
+966
-966
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+191
-191
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
+648
-648
File diff suppressed because it is too large
Load Diff
+280
-280
@@ -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
File diff suppressed because it is too large
Load Diff
+614
-614
File diff suppressed because it is too large
Load Diff
+144
-144
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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() );
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user