[opengl] merge (part 1?)
This commit is contained in:
+79
-79
@@ -1,79 +1,79 @@
|
||||
#include "global.h"
|
||||
#include "ActiveAttackList.h"
|
||||
#include "RageUtil.h"
|
||||
#include "GameState.h"
|
||||
#include "Inventory.h"
|
||||
#include "RageTimer.h"
|
||||
#include "PlayerOptions.h"
|
||||
#include "PlayerState.h"
|
||||
|
||||
ActiveAttackList::ActiveAttackList()
|
||||
{
|
||||
}
|
||||
|
||||
void ActiveAttackList::Init( const PlayerState* pPlayerState )
|
||||
{
|
||||
m_pPlayerState = pPlayerState;
|
||||
}
|
||||
|
||||
void ActiveAttackList::Update( float fDelta )
|
||||
{
|
||||
bool bTimeToRefresh =
|
||||
IsFirstUpdate() || // check this before running Actor::Update()
|
||||
m_pPlayerState->m_bAttackBeganThisUpdate ||
|
||||
m_pPlayerState->m_bAttackEndedThisUpdate;
|
||||
|
||||
BitmapText::Update( fDelta );
|
||||
|
||||
if( bTimeToRefresh )
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void ActiveAttackList::Refresh()
|
||||
{
|
||||
const AttackArray& attacks = m_pPlayerState->m_ActiveAttacks;
|
||||
|
||||
vector<RString> vsThemedMods;
|
||||
for( unsigned i=0; i<attacks.size(); i++ )
|
||||
{
|
||||
const Attack& attack = attacks[i];
|
||||
|
||||
if( !attack.bOn )
|
||||
continue; // hasn't started yet
|
||||
if( !attack.bShowInAttackList )
|
||||
continue;
|
||||
|
||||
PlayerOptions po;
|
||||
po.FromString( attack.sModifiers );
|
||||
po.GetLocalizedMods( vsThemedMods );
|
||||
}
|
||||
|
||||
RString s = join( "\n", vsThemedMods );
|
||||
|
||||
this->SetText( s ); // BitmapText will not rebuild vertices if these strings are the same.
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 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 "ActiveAttackList.h"
|
||||
#include "RageUtil.h"
|
||||
#include "GameState.h"
|
||||
#include "Inventory.h"
|
||||
#include "RageTimer.h"
|
||||
#include "PlayerOptions.h"
|
||||
#include "PlayerState.h"
|
||||
|
||||
ActiveAttackList::ActiveAttackList()
|
||||
{
|
||||
}
|
||||
|
||||
void ActiveAttackList::Init( const PlayerState* pPlayerState )
|
||||
{
|
||||
m_pPlayerState = pPlayerState;
|
||||
}
|
||||
|
||||
void ActiveAttackList::Update( float fDelta )
|
||||
{
|
||||
bool bTimeToRefresh =
|
||||
IsFirstUpdate() || // check this before running Actor::Update()
|
||||
m_pPlayerState->m_bAttackBeganThisUpdate ||
|
||||
m_pPlayerState->m_bAttackEndedThisUpdate;
|
||||
|
||||
BitmapText::Update( fDelta );
|
||||
|
||||
if( bTimeToRefresh )
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void ActiveAttackList::Refresh()
|
||||
{
|
||||
const AttackArray& attacks = m_pPlayerState->m_ActiveAttacks;
|
||||
|
||||
vector<RString> vsThemedMods;
|
||||
for( unsigned i=0; i<attacks.size(); i++ )
|
||||
{
|
||||
const Attack& attack = attacks[i];
|
||||
|
||||
if( !attack.bOn )
|
||||
continue; // hasn't started yet
|
||||
if( !attack.bShowInAttackList )
|
||||
continue;
|
||||
|
||||
PlayerOptions po;
|
||||
po.FromString( attack.sModifiers );
|
||||
po.GetLocalizedMods( vsThemedMods );
|
||||
}
|
||||
|
||||
RString s = join( "\n", vsThemedMods );
|
||||
|
||||
this->SetText( s ); // BitmapText will not rebuild vertices if these strings are the same.
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 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.
|
||||
*/
|
||||
|
||||
+56
-56
@@ -1,56 +1,56 @@
|
||||
#ifndef ACTIVE_ATTACK_LIST_H
|
||||
#define ACTIVE_ATTACK_LIST_H
|
||||
|
||||
#include "BitmapText.h"
|
||||
class PlayerState;
|
||||
|
||||
/** @brief Shows currently active Player modifiers during gameplay. */
|
||||
class ActiveAttackList : public BitmapText
|
||||
{
|
||||
public:
|
||||
/** @brief The constructor that does nothing. */
|
||||
ActiveAttackList();
|
||||
/**
|
||||
* @brief Set up the PlayerState.
|
||||
* @param pPlayerState the PlayerState involved with the attacks. */
|
||||
void Init( const PlayerState* pPlayerState );
|
||||
/**
|
||||
* @brief Look into updating the list.
|
||||
* @param fDelta the present time. */
|
||||
virtual void Update( float fDelta );
|
||||
/** @brief Refresh the list of attacks. */
|
||||
void Refresh();
|
||||
|
||||
protected:
|
||||
/** @brief the PlayerState of the Player who is dealing with the attack list. */
|
||||
const PlayerState* m_pPlayerState;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 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 ACTIVE_ATTACK_LIST_H
|
||||
#define ACTIVE_ATTACK_LIST_H
|
||||
|
||||
#include "BitmapText.h"
|
||||
class PlayerState;
|
||||
|
||||
/** @brief Shows currently active Player modifiers during gameplay. */
|
||||
class ActiveAttackList : public BitmapText
|
||||
{
|
||||
public:
|
||||
/** @brief The constructor that does nothing. */
|
||||
ActiveAttackList();
|
||||
/**
|
||||
* @brief Set up the PlayerState.
|
||||
* @param pPlayerState the PlayerState involved with the attacks. */
|
||||
void Init( const PlayerState* pPlayerState );
|
||||
/**
|
||||
* @brief Look into updating the list.
|
||||
* @param fDelta the present time. */
|
||||
virtual void Update( float fDelta );
|
||||
/** @brief Refresh the list of attacks. */
|
||||
void Refresh();
|
||||
|
||||
protected:
|
||||
/** @brief the PlayerState of the Player who is dealing with the attack list. */
|
||||
const PlayerState* m_pPlayerState;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 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.
|
||||
*/
|
||||
|
||||
+1728
-1728
File diff suppressed because it is too large
Load Diff
+705
-705
File diff suppressed because it is too large
Load Diff
+630
-630
File diff suppressed because it is too large
Load Diff
+164
-164
@@ -1,164 +1,164 @@
|
||||
#ifndef ACTORFRAME_H
|
||||
#define ACTORFRAME_H
|
||||
|
||||
#include "Actor.h"
|
||||
|
||||
/** @brief A container for other Actors. */
|
||||
class ActorFrame : public Actor
|
||||
{
|
||||
public:
|
||||
ActorFrame();
|
||||
ActorFrame( const ActorFrame &cpy );
|
||||
virtual ~ActorFrame();
|
||||
|
||||
/** @brief Set up the initial state. */
|
||||
virtual void InitState();
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
virtual ActorFrame *Copy() const;
|
||||
|
||||
/**
|
||||
* @brief Add a new child to the ActorFrame.
|
||||
* @param pActor the new Actor to add. */
|
||||
virtual void AddChild( Actor *pActor );
|
||||
/**
|
||||
* @brief Remove the specified child from the ActorFrame.
|
||||
* @param pActor the Actor to remove. */
|
||||
virtual void RemoveChild( Actor *pActor );
|
||||
void TransferChildren( ActorFrame *pTo );
|
||||
Actor* GetChild( const RString &sName );
|
||||
vector<Actor*> GetChildren() { return m_SubActors; }
|
||||
int GetNumChildren() const { return m_SubActors.size(); }
|
||||
|
||||
/** @brief Remove all of the children from the frame. */
|
||||
void RemoveAllChildren();
|
||||
/**
|
||||
* @brief Move a particular actor to the tail.
|
||||
* @param pActor the actor to go to the tail.
|
||||
*/
|
||||
void MoveToTail( Actor* pActor );
|
||||
/**
|
||||
* @brief Move a particular actor to the head.
|
||||
* @param pActor the actor to go to the head.
|
||||
*/
|
||||
void MoveToHead( Actor* pActor );
|
||||
void SortByDrawOrder();
|
||||
void SetDrawByZPosition( bool b );
|
||||
|
||||
void SetDrawFunction( const LuaReference &DrawFunction ) { m_DrawFunction = DrawFunction; }
|
||||
void SetUpdateFunction( const LuaReference &UpdateFunction ) { m_UpdateFunction = UpdateFunction; }
|
||||
|
||||
LuaReference GetDrawFunction() const { return m_DrawFunction; }
|
||||
virtual bool AutoLoadChildren() const { return false; } // derived classes override to automatically LoadChildrenFromNode
|
||||
void DeleteChildrenWhenDone( bool bDelete=true ) { m_bDeleteChildren = bDelete; }
|
||||
void DeleteAllChildren();
|
||||
|
||||
// Commands
|
||||
virtual void PushSelf( lua_State *L );
|
||||
void PushChildrenTable( lua_State *L );
|
||||
void PlayCommandOnChildren( const RString &sCommandName, const LuaReference *pParamTable = NULL );
|
||||
void PlayCommandOnLeaves( const RString &sCommandName, const LuaReference *pParamTable = NULL );
|
||||
|
||||
virtual void RunCommandsRecursively( const LuaReference& cmds, const LuaReference *pParamTable = NULL );
|
||||
virtual void RunCommandsOnChildren( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); /* but not on self */
|
||||
void RunCommandsOnChildren( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommandsOnChildren( *cmds, pParamTable ); } // convenience
|
||||
virtual void RunCommandsOnLeaves( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); /* but not on self */
|
||||
|
||||
virtual void UpdateInternal( float fDeltaTime );
|
||||
virtual void BeginDraw();
|
||||
virtual void DrawPrimitives();
|
||||
virtual void EndDraw();
|
||||
|
||||
// propagated commands
|
||||
virtual void SetDiffuse( RageColor c );
|
||||
virtual void SetDiffuseAlpha( float f );
|
||||
virtual void SetBaseAlpha( float f );
|
||||
virtual void SetZTestMode( ZTestMode mode );
|
||||
virtual void SetZWrite( bool b );
|
||||
virtual void FinishTweening();
|
||||
virtual void HurryTweening( float factor );
|
||||
|
||||
void SetUpdateRate( float fUpdateRate ) { m_fUpdateRate = fUpdateRate; }
|
||||
void SetFOV( float fFOV ) { m_fFOV = fFOV; }
|
||||
void SetVanishPoint( float fX, float fY) { m_fVanishX = fX; m_fVanishY = fY; }
|
||||
|
||||
void SetCustomLighting( bool bCustomLighting ) { m_bOverrideLighting = bCustomLighting; }
|
||||
void SetAmbientLightColor( RageColor c ) { m_ambientColor = c; }
|
||||
void SetDiffuseLightColor( RageColor c ) { m_diffuseColor = c; }
|
||||
void SetSpecularLightColor( RageColor c ) { m_specularColor = c; }
|
||||
void SetLightDirection( RageVector3 vec ) { m_lightDirection = vec; }
|
||||
|
||||
virtual void SetPropagateCommands( bool b );
|
||||
|
||||
/** @brief Amount of time until all tweens (and all children's tweens) have stopped: */
|
||||
virtual float GetTweenTimeLeft() const;
|
||||
|
||||
virtual void HandleMessage( const Message &msg );
|
||||
virtual void RunCommands( const LuaReference& cmds, const LuaReference *pParamTable = NULL );
|
||||
void RunCommands( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommands( *cmds, pParamTable ); } // convenience
|
||||
|
||||
protected:
|
||||
void LoadChildrenFromNode( const XNode* pNode );
|
||||
|
||||
/** @brief The children Actors used by the ActorFrame. */
|
||||
vector<Actor*> m_SubActors;
|
||||
bool m_bPropagateCommands;
|
||||
bool m_bDeleteChildren;
|
||||
bool m_bDrawByZPosition;
|
||||
LuaReference m_UpdateFunction;
|
||||
LuaReference m_DrawFunction;
|
||||
|
||||
// state effects
|
||||
float m_fUpdateRate;
|
||||
float m_fFOV; // -1 = no change
|
||||
float m_fVanishX;
|
||||
float m_fVanishY;
|
||||
/**
|
||||
* @brief A flad to see if an override for the lighting is needed.
|
||||
*
|
||||
* If true, set lightning to m_bLightning. */
|
||||
bool m_bOverrideLighting;
|
||||
bool m_bLighting;
|
||||
|
||||
// lighting variables
|
||||
RageColor m_ambientColor;
|
||||
RageColor m_diffuseColor;
|
||||
RageColor m_specularColor;
|
||||
RageVector3 m_lightDirection;
|
||||
};
|
||||
/** @brief an ActorFrame that handles deleting children Actors automatically. */
|
||||
class ActorFrameAutoDeleteChildren : public ActorFrame
|
||||
{
|
||||
public:
|
||||
ActorFrameAutoDeleteChildren() { DeleteChildrenWhenDone(true); }
|
||||
virtual bool AutoLoadChildren() const { return true; }
|
||||
virtual ActorFrameAutoDeleteChildren *Copy() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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 ACTORFRAME_H
|
||||
#define ACTORFRAME_H
|
||||
|
||||
#include "Actor.h"
|
||||
|
||||
/** @brief A container for other Actors. */
|
||||
class ActorFrame : public Actor
|
||||
{
|
||||
public:
|
||||
ActorFrame();
|
||||
ActorFrame( const ActorFrame &cpy );
|
||||
virtual ~ActorFrame();
|
||||
|
||||
/** @brief Set up the initial state. */
|
||||
virtual void InitState();
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
virtual ActorFrame *Copy() const;
|
||||
|
||||
/**
|
||||
* @brief Add a new child to the ActorFrame.
|
||||
* @param pActor the new Actor to add. */
|
||||
virtual void AddChild( Actor *pActor );
|
||||
/**
|
||||
* @brief Remove the specified child from the ActorFrame.
|
||||
* @param pActor the Actor to remove. */
|
||||
virtual void RemoveChild( Actor *pActor );
|
||||
void TransferChildren( ActorFrame *pTo );
|
||||
Actor* GetChild( const RString &sName );
|
||||
vector<Actor*> GetChildren() { return m_SubActors; }
|
||||
int GetNumChildren() const { return m_SubActors.size(); }
|
||||
|
||||
/** @brief Remove all of the children from the frame. */
|
||||
void RemoveAllChildren();
|
||||
/**
|
||||
* @brief Move a particular actor to the tail.
|
||||
* @param pActor the actor to go to the tail.
|
||||
*/
|
||||
void MoveToTail( Actor* pActor );
|
||||
/**
|
||||
* @brief Move a particular actor to the head.
|
||||
* @param pActor the actor to go to the head.
|
||||
*/
|
||||
void MoveToHead( Actor* pActor );
|
||||
void SortByDrawOrder();
|
||||
void SetDrawByZPosition( bool b );
|
||||
|
||||
void SetDrawFunction( const LuaReference &DrawFunction ) { m_DrawFunction = DrawFunction; }
|
||||
void SetUpdateFunction( const LuaReference &UpdateFunction ) { m_UpdateFunction = UpdateFunction; }
|
||||
|
||||
LuaReference GetDrawFunction() const { return m_DrawFunction; }
|
||||
virtual bool AutoLoadChildren() const { return false; } // derived classes override to automatically LoadChildrenFromNode
|
||||
void DeleteChildrenWhenDone( bool bDelete=true ) { m_bDeleteChildren = bDelete; }
|
||||
void DeleteAllChildren();
|
||||
|
||||
// Commands
|
||||
virtual void PushSelf( lua_State *L );
|
||||
void PushChildrenTable( lua_State *L );
|
||||
void PlayCommandOnChildren( const RString &sCommandName, const LuaReference *pParamTable = NULL );
|
||||
void PlayCommandOnLeaves( const RString &sCommandName, const LuaReference *pParamTable = NULL );
|
||||
|
||||
virtual void RunCommandsRecursively( const LuaReference& cmds, const LuaReference *pParamTable = NULL );
|
||||
virtual void RunCommandsOnChildren( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); /* but not on self */
|
||||
void RunCommandsOnChildren( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommandsOnChildren( *cmds, pParamTable ); } // convenience
|
||||
virtual void RunCommandsOnLeaves( const LuaReference& cmds, const LuaReference *pParamTable = NULL ); /* but not on self */
|
||||
|
||||
virtual void UpdateInternal( float fDeltaTime );
|
||||
virtual void BeginDraw();
|
||||
virtual void DrawPrimitives();
|
||||
virtual void EndDraw();
|
||||
|
||||
// propagated commands
|
||||
virtual void SetDiffuse( RageColor c );
|
||||
virtual void SetDiffuseAlpha( float f );
|
||||
virtual void SetBaseAlpha( float f );
|
||||
virtual void SetZTestMode( ZTestMode mode );
|
||||
virtual void SetZWrite( bool b );
|
||||
virtual void FinishTweening();
|
||||
virtual void HurryTweening( float factor );
|
||||
|
||||
void SetUpdateRate( float fUpdateRate ) { m_fUpdateRate = fUpdateRate; }
|
||||
void SetFOV( float fFOV ) { m_fFOV = fFOV; }
|
||||
void SetVanishPoint( float fX, float fY) { m_fVanishX = fX; m_fVanishY = fY; }
|
||||
|
||||
void SetCustomLighting( bool bCustomLighting ) { m_bOverrideLighting = bCustomLighting; }
|
||||
void SetAmbientLightColor( RageColor c ) { m_ambientColor = c; }
|
||||
void SetDiffuseLightColor( RageColor c ) { m_diffuseColor = c; }
|
||||
void SetSpecularLightColor( RageColor c ) { m_specularColor = c; }
|
||||
void SetLightDirection( RageVector3 vec ) { m_lightDirection = vec; }
|
||||
|
||||
virtual void SetPropagateCommands( bool b );
|
||||
|
||||
/** @brief Amount of time until all tweens (and all children's tweens) have stopped: */
|
||||
virtual float GetTweenTimeLeft() const;
|
||||
|
||||
virtual void HandleMessage( const Message &msg );
|
||||
virtual void RunCommands( const LuaReference& cmds, const LuaReference *pParamTable = NULL );
|
||||
void RunCommands( const apActorCommands& cmds, const LuaReference *pParamTable = NULL ) { this->RunCommands( *cmds, pParamTable ); } // convenience
|
||||
|
||||
protected:
|
||||
void LoadChildrenFromNode( const XNode* pNode );
|
||||
|
||||
/** @brief The children Actors used by the ActorFrame. */
|
||||
vector<Actor*> m_SubActors;
|
||||
bool m_bPropagateCommands;
|
||||
bool m_bDeleteChildren;
|
||||
bool m_bDrawByZPosition;
|
||||
LuaReference m_UpdateFunction;
|
||||
LuaReference m_DrawFunction;
|
||||
|
||||
// state effects
|
||||
float m_fUpdateRate;
|
||||
float m_fFOV; // -1 = no change
|
||||
float m_fVanishX;
|
||||
float m_fVanishY;
|
||||
/**
|
||||
* @brief A flad to see if an override for the lighting is needed.
|
||||
*
|
||||
* If true, set lightning to m_bLightning. */
|
||||
bool m_bOverrideLighting;
|
||||
bool m_bLighting;
|
||||
|
||||
// lighting variables
|
||||
RageColor m_ambientColor;
|
||||
RageColor m_diffuseColor;
|
||||
RageColor m_specularColor;
|
||||
RageVector3 m_lightDirection;
|
||||
};
|
||||
/** @brief an ActorFrame that handles deleting children Actors automatically. */
|
||||
class ActorFrameAutoDeleteChildren : public ActorFrame
|
||||
{
|
||||
public:
|
||||
ActorFrameAutoDeleteChildren() { DeleteChildrenWhenDone(true); }
|
||||
virtual bool AutoLoadChildren() const { return true; }
|
||||
virtual ActorFrameAutoDeleteChildren *Copy() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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.
|
||||
*/
|
||||
|
||||
+127
-127
@@ -1,127 +1,127 @@
|
||||
#include "global.h"
|
||||
#include "ActorFrameTexture.h"
|
||||
#include "RageTextureRenderTarget.h"
|
||||
#include "RageTextureManager.h"
|
||||
#include "ActorUtil.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS_WITH_NAME( ActorFrameTextureAutoDeleteChildren, ActorFrameTexture );
|
||||
ActorFrameTexture *ActorFrameTexture::Copy() const { return new ActorFrameTexture(*this); }
|
||||
|
||||
ActorFrameTexture::ActorFrameTexture()
|
||||
{
|
||||
m_bDepthBuffer = false;
|
||||
m_bAlphaBuffer = false;
|
||||
m_bFloat = false;
|
||||
m_bPreserveTexture = false;
|
||||
static uint64_t i = 0;
|
||||
++i;
|
||||
m_sTextureName = ssprintf( ConvertI64FormatString("ActorFrameTexture %lli"), i );
|
||||
|
||||
m_pRenderTarget = NULL;
|
||||
}
|
||||
|
||||
ActorFrameTexture::ActorFrameTexture( const ActorFrameTexture &cpy ):
|
||||
ActorFrame(cpy)
|
||||
{
|
||||
FAIL_M( "ActorFrameTexture copy not implemented" );
|
||||
}
|
||||
|
||||
ActorFrameTexture::~ActorFrameTexture()
|
||||
{
|
||||
/* Release our reference to the texture. */
|
||||
TEXTUREMAN->UnloadTexture( m_pRenderTarget );
|
||||
}
|
||||
|
||||
void ActorFrameTexture::Create()
|
||||
{
|
||||
ASSERT( m_pRenderTarget == NULL );
|
||||
RageTextureID id( m_sTextureName );
|
||||
id.Policy = RageTextureID::TEX_VOLATILE;
|
||||
|
||||
RenderTargetParam param;
|
||||
param.bWithDepthBuffer = m_bDepthBuffer;
|
||||
param.bWithAlpha = m_bAlphaBuffer;
|
||||
param.bFloat = m_bFloat;
|
||||
param.iWidth = (int) m_size.x;
|
||||
param.iHeight = (int) m_size.y;
|
||||
m_pRenderTarget = new RageTextureRenderTarget( id, param );
|
||||
m_pRenderTarget->m_bWasUsed = true;
|
||||
|
||||
/* This passes ownership of m_pRenderTarget to TEXTUREMAN, but we retain
|
||||
* our reference to it until we call TEXTUREMAN->UnloadTexture. */
|
||||
TEXTUREMAN->RegisterTexture( id, m_pRenderTarget );
|
||||
}
|
||||
|
||||
void ActorFrameTexture::DrawPrimitives()
|
||||
{
|
||||
if( m_pRenderTarget == NULL )
|
||||
return;
|
||||
|
||||
m_pRenderTarget->BeginRenderingTo( m_bPreserveTexture );
|
||||
|
||||
ActorFrame::DrawPrimitives();
|
||||
|
||||
m_pRenderTarget->FinishRenderingTo();
|
||||
}
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the ActorFrameTexture. */
|
||||
class LunaActorFrameTexture : public Luna<ActorFrameTexture>
|
||||
{
|
||||
public:
|
||||
static int Create( T* p, lua_State *L ) { p->Create(); return 0; }
|
||||
static int EnableDepthBuffer( T* p, lua_State *L ) { p->EnableDepthBuffer(BArg(1)); return 0; }
|
||||
static int EnableAlphaBuffer( T* p, lua_State *L ) { p->EnableAlphaBuffer(BArg(1)); return 0; }
|
||||
static int EnableFloat( T* p, lua_State *L ) { p->EnableFloat(BArg(1)); return 0; }
|
||||
static int EnablePreserveTexture( T* p, lua_State *L ) { p->EnablePreserveTexture(BArg(1)); return 0; }
|
||||
static int SetTextureName( T* p, lua_State *L ) { p->SetTextureName(SArg(1)); return 0; }
|
||||
static int GetTexture( T* p, lua_State *L )
|
||||
{
|
||||
RageTexture *pTexture = p->GetTexture();
|
||||
if( pTexture == NULL )
|
||||
return 0;
|
||||
pTexture->PushSelf(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LunaActorFrameTexture()
|
||||
{
|
||||
ADD_METHOD( Create );
|
||||
ADD_METHOD( EnableDepthBuffer );
|
||||
ADD_METHOD( EnableAlphaBuffer );
|
||||
ADD_METHOD( EnableFloat );
|
||||
ADD_METHOD( EnablePreserveTexture );
|
||||
ADD_METHOD( SetTextureName );
|
||||
ADD_METHOD( GetTexture );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( ActorFrameTexture, ActorFrame )
|
||||
// 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 "ActorFrameTexture.h"
|
||||
#include "RageTextureRenderTarget.h"
|
||||
#include "RageTextureManager.h"
|
||||
#include "ActorUtil.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS_WITH_NAME( ActorFrameTextureAutoDeleteChildren, ActorFrameTexture );
|
||||
ActorFrameTexture *ActorFrameTexture::Copy() const { return new ActorFrameTexture(*this); }
|
||||
|
||||
ActorFrameTexture::ActorFrameTexture()
|
||||
{
|
||||
m_bDepthBuffer = false;
|
||||
m_bAlphaBuffer = false;
|
||||
m_bFloat = false;
|
||||
m_bPreserveTexture = false;
|
||||
static uint64_t i = 0;
|
||||
++i;
|
||||
m_sTextureName = ssprintf( ConvertI64FormatString("ActorFrameTexture %lli"), i );
|
||||
|
||||
m_pRenderTarget = NULL;
|
||||
}
|
||||
|
||||
ActorFrameTexture::ActorFrameTexture( const ActorFrameTexture &cpy ):
|
||||
ActorFrame(cpy)
|
||||
{
|
||||
FAIL_M( "ActorFrameTexture copy not implemented" );
|
||||
}
|
||||
|
||||
ActorFrameTexture::~ActorFrameTexture()
|
||||
{
|
||||
/* Release our reference to the texture. */
|
||||
TEXTUREMAN->UnloadTexture( m_pRenderTarget );
|
||||
}
|
||||
|
||||
void ActorFrameTexture::Create()
|
||||
{
|
||||
ASSERT( m_pRenderTarget == NULL );
|
||||
RageTextureID id( m_sTextureName );
|
||||
id.Policy = RageTextureID::TEX_VOLATILE;
|
||||
|
||||
RenderTargetParam param;
|
||||
param.bWithDepthBuffer = m_bDepthBuffer;
|
||||
param.bWithAlpha = m_bAlphaBuffer;
|
||||
param.bFloat = m_bFloat;
|
||||
param.iWidth = (int) m_size.x;
|
||||
param.iHeight = (int) m_size.y;
|
||||
m_pRenderTarget = new RageTextureRenderTarget( id, param );
|
||||
m_pRenderTarget->m_bWasUsed = true;
|
||||
|
||||
/* This passes ownership of m_pRenderTarget to TEXTUREMAN, but we retain
|
||||
* our reference to it until we call TEXTUREMAN->UnloadTexture. */
|
||||
TEXTUREMAN->RegisterTexture( id, m_pRenderTarget );
|
||||
}
|
||||
|
||||
void ActorFrameTexture::DrawPrimitives()
|
||||
{
|
||||
if( m_pRenderTarget == NULL )
|
||||
return;
|
||||
|
||||
m_pRenderTarget->BeginRenderingTo( m_bPreserveTexture );
|
||||
|
||||
ActorFrame::DrawPrimitives();
|
||||
|
||||
m_pRenderTarget->FinishRenderingTo();
|
||||
}
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the ActorFrameTexture. */
|
||||
class LunaActorFrameTexture : public Luna<ActorFrameTexture>
|
||||
{
|
||||
public:
|
||||
static int Create( T* p, lua_State *L ) { p->Create(); return 0; }
|
||||
static int EnableDepthBuffer( T* p, lua_State *L ) { p->EnableDepthBuffer(BArg(1)); return 0; }
|
||||
static int EnableAlphaBuffer( T* p, lua_State *L ) { p->EnableAlphaBuffer(BArg(1)); return 0; }
|
||||
static int EnableFloat( T* p, lua_State *L ) { p->EnableFloat(BArg(1)); return 0; }
|
||||
static int EnablePreserveTexture( T* p, lua_State *L ) { p->EnablePreserveTexture(BArg(1)); return 0; }
|
||||
static int SetTextureName( T* p, lua_State *L ) { p->SetTextureName(SArg(1)); return 0; }
|
||||
static int GetTexture( T* p, lua_State *L )
|
||||
{
|
||||
RageTexture *pTexture = p->GetTexture();
|
||||
if( pTexture == NULL )
|
||||
return 0;
|
||||
pTexture->PushSelf(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LunaActorFrameTexture()
|
||||
{
|
||||
ADD_METHOD( Create );
|
||||
ADD_METHOD( EnableDepthBuffer );
|
||||
ADD_METHOD( EnableAlphaBuffer );
|
||||
ADD_METHOD( EnableFloat );
|
||||
ADD_METHOD( EnablePreserveTexture );
|
||||
ADD_METHOD( SetTextureName );
|
||||
ADD_METHOD( GetTexture );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( ActorFrameTexture, ActorFrame )
|
||||
// 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.
|
||||
*/
|
||||
|
||||
+88
-88
@@ -1,88 +1,88 @@
|
||||
#ifndef ACTOR_FRAME_TEXTURE_H
|
||||
#define ACTOR_FRAME_TEXTURE_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
class RageTextureRenderTarget;
|
||||
|
||||
class ActorFrameTexture: public ActorFrame
|
||||
{
|
||||
public:
|
||||
ActorFrameTexture();
|
||||
ActorFrameTexture( const ActorFrameTexture &cpy );
|
||||
virtual ~ActorFrameTexture();
|
||||
virtual ActorFrameTexture *Copy() const;
|
||||
|
||||
/**
|
||||
* @brief Set the texture name.
|
||||
*
|
||||
* This can be used with RageTextureManager (and users, eg. Sprite)
|
||||
* to load the texture. If no name is supplied, a unique one will
|
||||
* be generated. In that case, the only way to access the texture
|
||||
* is via GetTextureName.
|
||||
* @param sName the new name. */
|
||||
void SetTextureName( const RString &sName ) { m_sTextureName = sName; }
|
||||
/**
|
||||
* @brief Retrieve the texture name.
|
||||
* @return the texture name. */
|
||||
RString GetTextureName() const { return m_sTextureName; }
|
||||
RageTextureRenderTarget *GetTexture() { return m_pRenderTarget; }
|
||||
|
||||
void EnableDepthBuffer( bool b ) { m_bDepthBuffer = b; }
|
||||
void EnableAlphaBuffer( bool b ) { m_bAlphaBuffer = b; }
|
||||
void EnableFloat( bool b ) { m_bFloat = b; }
|
||||
void EnablePreserveTexture( bool b ) { m_bPreserveTexture = b; }
|
||||
|
||||
void Create();
|
||||
|
||||
virtual void DrawPrimitives();
|
||||
|
||||
// Commands
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
private:
|
||||
RageTextureRenderTarget *m_pRenderTarget;
|
||||
|
||||
bool m_bDepthBuffer;
|
||||
bool m_bAlphaBuffer;
|
||||
bool m_bFloat;
|
||||
bool m_bPreserveTexture;
|
||||
/** @brief the name of this ActorFrameTexture. */
|
||||
RString m_sTextureName;
|
||||
};
|
||||
|
||||
class ActorFrameTextureAutoDeleteChildren : public ActorFrameTexture
|
||||
{
|
||||
public:
|
||||
ActorFrameTextureAutoDeleteChildren() { DeleteChildrenWhenDone(true); }
|
||||
virtual bool AutoLoadChildren() const { return true; }
|
||||
virtual ActorFrameTextureAutoDeleteChildren *Copy() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Glenn Maynard (c) 2006
|
||||
* @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 ACTOR_FRAME_TEXTURE_H
|
||||
#define ACTOR_FRAME_TEXTURE_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
class RageTextureRenderTarget;
|
||||
|
||||
class ActorFrameTexture: public ActorFrame
|
||||
{
|
||||
public:
|
||||
ActorFrameTexture();
|
||||
ActorFrameTexture( const ActorFrameTexture &cpy );
|
||||
virtual ~ActorFrameTexture();
|
||||
virtual ActorFrameTexture *Copy() const;
|
||||
|
||||
/**
|
||||
* @brief Set the texture name.
|
||||
*
|
||||
* This can be used with RageTextureManager (and users, eg. Sprite)
|
||||
* to load the texture. If no name is supplied, a unique one will
|
||||
* be generated. In that case, the only way to access the texture
|
||||
* is via GetTextureName.
|
||||
* @param sName the new name. */
|
||||
void SetTextureName( const RString &sName ) { m_sTextureName = sName; }
|
||||
/**
|
||||
* @brief Retrieve the texture name.
|
||||
* @return the texture name. */
|
||||
RString GetTextureName() const { return m_sTextureName; }
|
||||
RageTextureRenderTarget *GetTexture() { return m_pRenderTarget; }
|
||||
|
||||
void EnableDepthBuffer( bool b ) { m_bDepthBuffer = b; }
|
||||
void EnableAlphaBuffer( bool b ) { m_bAlphaBuffer = b; }
|
||||
void EnableFloat( bool b ) { m_bFloat = b; }
|
||||
void EnablePreserveTexture( bool b ) { m_bPreserveTexture = b; }
|
||||
|
||||
void Create();
|
||||
|
||||
virtual void DrawPrimitives();
|
||||
|
||||
// Commands
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
private:
|
||||
RageTextureRenderTarget *m_pRenderTarget;
|
||||
|
||||
bool m_bDepthBuffer;
|
||||
bool m_bAlphaBuffer;
|
||||
bool m_bFloat;
|
||||
bool m_bPreserveTexture;
|
||||
/** @brief the name of this ActorFrameTexture. */
|
||||
RString m_sTextureName;
|
||||
};
|
||||
|
||||
class ActorFrameTextureAutoDeleteChildren : public ActorFrameTexture
|
||||
{
|
||||
public:
|
||||
ActorFrameTextureAutoDeleteChildren() { DeleteChildrenWhenDone(true); }
|
||||
virtual bool AutoLoadChildren() const { return true; }
|
||||
virtual ActorFrameTextureAutoDeleteChildren *Copy() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Glenn Maynard (c) 2006
|
||||
* @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.
|
||||
*/
|
||||
|
||||
+215
-215
@@ -1,215 +1,215 @@
|
||||
#include "global.h"
|
||||
#include <cassert>
|
||||
|
||||
#include "ActorMultiTexture.h"
|
||||
#include "RageTextureManager.h"
|
||||
#include "XmlFile.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageDisplay.h"
|
||||
#include "RageTexture.h"
|
||||
#include "RageUtil.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "Foreach.h"
|
||||
#include "LuaBinding.h"
|
||||
#include "LuaManager.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS( ActorMultiTexture );
|
||||
|
||||
|
||||
ActorMultiTexture::ActorMultiTexture()
|
||||
{
|
||||
m_EffectMode = EffectMode_Normal;
|
||||
}
|
||||
|
||||
|
||||
ActorMultiTexture::~ActorMultiTexture()
|
||||
{
|
||||
ClearTextures();
|
||||
}
|
||||
|
||||
ActorMultiTexture::ActorMultiTexture( const ActorMultiTexture &cpy ):
|
||||
Actor( cpy )
|
||||
{
|
||||
#define CPY(a) a = cpy.a
|
||||
CPY( m_Rect );
|
||||
CPY( m_aTextureUnits );
|
||||
#undef CPY
|
||||
|
||||
FOREACH( TextureUnitState, m_aTextureUnits, tex )
|
||||
tex->m_pTexture = TEXTUREMAN->CopyTexture( tex->m_pTexture );
|
||||
}
|
||||
|
||||
void ActorMultiTexture::SetTextureCoords( const RectF &r )
|
||||
{
|
||||
m_Rect = r;
|
||||
}
|
||||
|
||||
void ActorMultiTexture::LoadFromNode( const XNode* pNode )
|
||||
{
|
||||
m_Rect = RectF( 0, 0, 1, 1 );
|
||||
Actor::LoadFromNode( pNode );
|
||||
}
|
||||
|
||||
void ActorMultiTexture::SetSizeFromTexture( RageTexture *pTexture )
|
||||
{
|
||||
ActorMultiTexture::m_size.x = pTexture->GetSourceWidth();
|
||||
ActorMultiTexture::m_size.y = pTexture->GetSourceHeight();
|
||||
}
|
||||
|
||||
void ActorMultiTexture::ClearTextures()
|
||||
{
|
||||
FOREACH( TextureUnitState, m_aTextureUnits, tex )
|
||||
TEXTUREMAN->UnloadTexture( tex->m_pTexture );
|
||||
m_aTextureUnits.clear();
|
||||
}
|
||||
|
||||
int ActorMultiTexture::AddTexture( RageTexture *pTexture )
|
||||
{
|
||||
ASSERT( pTexture != NULL );
|
||||
LOG->Trace( "ActorMultiTexture::AddTexture( %s )", pTexture->GetID().filename.c_str() );
|
||||
|
||||
m_aTextureUnits.push_back( TextureUnitState() );
|
||||
m_aTextureUnits.back().m_pTexture = TEXTUREMAN->CopyTexture( pTexture );
|
||||
return m_aTextureUnits.size() - 1;
|
||||
}
|
||||
|
||||
void ActorMultiTexture::SetTextureMode( int iIndex, TextureMode tm )
|
||||
{
|
||||
ASSERT( iIndex < (int) m_aTextureUnits.size() );
|
||||
m_aTextureUnits[iIndex].m_TextureMode = tm;
|
||||
}
|
||||
|
||||
void ActorMultiTexture::DrawPrimitives()
|
||||
{
|
||||
Actor::SetGlobalRenderStates(); // set Actor-specified render states
|
||||
|
||||
RectF quadVerticies;
|
||||
quadVerticies.left = -m_size.x/2.0f;
|
||||
quadVerticies.right = +m_size.x/2.0f;
|
||||
quadVerticies.top = -m_size.y/2.0f;
|
||||
quadVerticies.bottom = +m_size.y/2.0f;
|
||||
|
||||
DISPLAY->ClearAllTextures();
|
||||
for( size_t i = 0; i < m_aTextureUnits.size(); ++i )
|
||||
{
|
||||
TextureUnit tu = enum_add2(TextureUnit_1, i);
|
||||
DISPLAY->SetTexture( tu, m_aTextureUnits[i].m_pTexture->GetTexHandle() );
|
||||
DISPLAY->SetTextureWrapping( tu, m_bTextureWrapping );
|
||||
DISPLAY->SetTextureMode( tu, m_aTextureUnits[i].m_TextureMode );
|
||||
}
|
||||
|
||||
DISPLAY->SetEffectMode( m_EffectMode );
|
||||
|
||||
static RageSpriteVertex v[4];
|
||||
v[0].p = RageVector3( quadVerticies.left, quadVerticies.top, 0 ); // top left
|
||||
v[1].p = RageVector3( quadVerticies.left, quadVerticies.bottom, 0 ); // bottom left
|
||||
v[2].p = RageVector3( quadVerticies.right, quadVerticies.bottom, 0 ); // bottom right
|
||||
v[3].p = RageVector3( quadVerticies.right, quadVerticies.top, 0 ); // top right
|
||||
|
||||
const RectF *pTexCoordRect = &m_Rect;
|
||||
v[0].t = RageVector2( pTexCoordRect->left, pTexCoordRect->top ); // top left
|
||||
v[1].t = RageVector2( pTexCoordRect->left, pTexCoordRect->bottom ); // bottom left
|
||||
v[2].t = RageVector2( pTexCoordRect->right, pTexCoordRect->bottom ); // bottom right
|
||||
v[3].t = RageVector2( pTexCoordRect->right, pTexCoordRect->top ); // top right
|
||||
|
||||
v[0].c = m_pTempState->diffuse[0]; // top left
|
||||
v[1].c = m_pTempState->diffuse[2]; // bottom left
|
||||
v[2].c = m_pTempState->diffuse[3]; // bottom right
|
||||
v[3].c = m_pTempState->diffuse[1]; // top right
|
||||
|
||||
DISPLAY->DrawQuad( v );
|
||||
|
||||
for( size_t i = 0; i < m_aTextureUnits.size(); ++i )
|
||||
DISPLAY->SetTexture( enum_add2(TextureUnit_1, i), 0 );
|
||||
|
||||
DISPLAY->SetEffectMode( EffectMode_Normal );
|
||||
}
|
||||
|
||||
bool ActorMultiTexture::EarlyAbortDraw() const
|
||||
{
|
||||
return m_aTextureUnits.empty();
|
||||
}
|
||||
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the ActorMultiTexture. */
|
||||
class LunaActorMultiTexture: public Luna<ActorMultiTexture>
|
||||
{
|
||||
public:
|
||||
static int ClearTextures( T* p, lua_State *L )
|
||||
{
|
||||
p->ClearTextures();
|
||||
return 0;
|
||||
}
|
||||
static int AddTexture( T* p, lua_State *L )
|
||||
{
|
||||
RageTexture *pTexture = Luna<RageTexture>::check(L, 1);
|
||||
int iRet = p->AddTexture( pTexture );
|
||||
lua_pushinteger( L, iRet );
|
||||
return 1;
|
||||
}
|
||||
static int SetTextureMode( T* p, lua_State *L )
|
||||
{
|
||||
int iIndex = IArg(1);
|
||||
TextureMode tm = Enum::Check<TextureMode>(L, 2);
|
||||
p->SetTextureMode( iIndex, tm );
|
||||
return 0;
|
||||
}
|
||||
static int SetTextureCoords( T* p, lua_State *L )
|
||||
{
|
||||
p->SetTextureCoords( RectF(FArg(1), FArg(2), FArg(3), FArg(4)) );
|
||||
return 0;
|
||||
}
|
||||
static int SetSizeFromTexture( T* p, lua_State *L )
|
||||
{
|
||||
RageTexture *pTexture = Luna<RageTexture>::check(L, 1);
|
||||
p->SetSizeFromTexture( pTexture );
|
||||
return 0;
|
||||
}
|
||||
static int SetEffectMode( T* p, lua_State *L )
|
||||
{
|
||||
EffectMode em = Enum::Check<EffectMode>(L, 1);
|
||||
p->SetEffectMode( em );
|
||||
return 0;
|
||||
}
|
||||
|
||||
LunaActorMultiTexture()
|
||||
{
|
||||
ADD_METHOD( ClearTextures );
|
||||
ADD_METHOD( AddTexture );
|
||||
ADD_METHOD( SetTextureMode );
|
||||
ADD_METHOD( SetTextureCoords );
|
||||
ADD_METHOD( SetSizeFromTexture );
|
||||
ADD_METHOD( SetEffectMode );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( ActorMultiTexture, Actor )
|
||||
// lua end
|
||||
|
||||
/*
|
||||
* (c) 2001-2007 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 <cassert>
|
||||
|
||||
#include "ActorMultiTexture.h"
|
||||
#include "RageTextureManager.h"
|
||||
#include "XmlFile.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageDisplay.h"
|
||||
#include "RageTexture.h"
|
||||
#include "RageUtil.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "Foreach.h"
|
||||
#include "LuaBinding.h"
|
||||
#include "LuaManager.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS( ActorMultiTexture );
|
||||
|
||||
|
||||
ActorMultiTexture::ActorMultiTexture()
|
||||
{
|
||||
m_EffectMode = EffectMode_Normal;
|
||||
}
|
||||
|
||||
|
||||
ActorMultiTexture::~ActorMultiTexture()
|
||||
{
|
||||
ClearTextures();
|
||||
}
|
||||
|
||||
ActorMultiTexture::ActorMultiTexture( const ActorMultiTexture &cpy ):
|
||||
Actor( cpy )
|
||||
{
|
||||
#define CPY(a) a = cpy.a
|
||||
CPY( m_Rect );
|
||||
CPY( m_aTextureUnits );
|
||||
#undef CPY
|
||||
|
||||
FOREACH( TextureUnitState, m_aTextureUnits, tex )
|
||||
tex->m_pTexture = TEXTUREMAN->CopyTexture( tex->m_pTexture );
|
||||
}
|
||||
|
||||
void ActorMultiTexture::SetTextureCoords( const RectF &r )
|
||||
{
|
||||
m_Rect = r;
|
||||
}
|
||||
|
||||
void ActorMultiTexture::LoadFromNode( const XNode* pNode )
|
||||
{
|
||||
m_Rect = RectF( 0, 0, 1, 1 );
|
||||
Actor::LoadFromNode( pNode );
|
||||
}
|
||||
|
||||
void ActorMultiTexture::SetSizeFromTexture( RageTexture *pTexture )
|
||||
{
|
||||
ActorMultiTexture::m_size.x = pTexture->GetSourceWidth();
|
||||
ActorMultiTexture::m_size.y = pTexture->GetSourceHeight();
|
||||
}
|
||||
|
||||
void ActorMultiTexture::ClearTextures()
|
||||
{
|
||||
FOREACH( TextureUnitState, m_aTextureUnits, tex )
|
||||
TEXTUREMAN->UnloadTexture( tex->m_pTexture );
|
||||
m_aTextureUnits.clear();
|
||||
}
|
||||
|
||||
int ActorMultiTexture::AddTexture( RageTexture *pTexture )
|
||||
{
|
||||
ASSERT( pTexture != NULL );
|
||||
LOG->Trace( "ActorMultiTexture::AddTexture( %s )", pTexture->GetID().filename.c_str() );
|
||||
|
||||
m_aTextureUnits.push_back( TextureUnitState() );
|
||||
m_aTextureUnits.back().m_pTexture = TEXTUREMAN->CopyTexture( pTexture );
|
||||
return m_aTextureUnits.size() - 1;
|
||||
}
|
||||
|
||||
void ActorMultiTexture::SetTextureMode( int iIndex, TextureMode tm )
|
||||
{
|
||||
ASSERT( iIndex < (int) m_aTextureUnits.size() );
|
||||
m_aTextureUnits[iIndex].m_TextureMode = tm;
|
||||
}
|
||||
|
||||
void ActorMultiTexture::DrawPrimitives()
|
||||
{
|
||||
Actor::SetGlobalRenderStates(); // set Actor-specified render states
|
||||
|
||||
RectF quadVerticies;
|
||||
quadVerticies.left = -m_size.x/2.0f;
|
||||
quadVerticies.right = +m_size.x/2.0f;
|
||||
quadVerticies.top = -m_size.y/2.0f;
|
||||
quadVerticies.bottom = +m_size.y/2.0f;
|
||||
|
||||
DISPLAY->ClearAllTextures();
|
||||
for( size_t i = 0; i < m_aTextureUnits.size(); ++i )
|
||||
{
|
||||
TextureUnit tu = enum_add2(TextureUnit_1, i);
|
||||
DISPLAY->SetTexture( tu, m_aTextureUnits[i].m_pTexture->GetTexHandle() );
|
||||
DISPLAY->SetTextureWrapping( tu, m_bTextureWrapping );
|
||||
DISPLAY->SetTextureMode( tu, m_aTextureUnits[i].m_TextureMode );
|
||||
}
|
||||
|
||||
DISPLAY->SetEffectMode( m_EffectMode );
|
||||
|
||||
static RageSpriteVertex v[4];
|
||||
v[0].p = RageVector3( quadVerticies.left, quadVerticies.top, 0 ); // top left
|
||||
v[1].p = RageVector3( quadVerticies.left, quadVerticies.bottom, 0 ); // bottom left
|
||||
v[2].p = RageVector3( quadVerticies.right, quadVerticies.bottom, 0 ); // bottom right
|
||||
v[3].p = RageVector3( quadVerticies.right, quadVerticies.top, 0 ); // top right
|
||||
|
||||
const RectF *pTexCoordRect = &m_Rect;
|
||||
v[0].t = RageVector2( pTexCoordRect->left, pTexCoordRect->top ); // top left
|
||||
v[1].t = RageVector2( pTexCoordRect->left, pTexCoordRect->bottom ); // bottom left
|
||||
v[2].t = RageVector2( pTexCoordRect->right, pTexCoordRect->bottom ); // bottom right
|
||||
v[3].t = RageVector2( pTexCoordRect->right, pTexCoordRect->top ); // top right
|
||||
|
||||
v[0].c = m_pTempState->diffuse[0]; // top left
|
||||
v[1].c = m_pTempState->diffuse[2]; // bottom left
|
||||
v[2].c = m_pTempState->diffuse[3]; // bottom right
|
||||
v[3].c = m_pTempState->diffuse[1]; // top right
|
||||
|
||||
DISPLAY->DrawQuad( v );
|
||||
|
||||
for( size_t i = 0; i < m_aTextureUnits.size(); ++i )
|
||||
DISPLAY->SetTexture( enum_add2(TextureUnit_1, i), 0 );
|
||||
|
||||
DISPLAY->SetEffectMode( EffectMode_Normal );
|
||||
}
|
||||
|
||||
bool ActorMultiTexture::EarlyAbortDraw() const
|
||||
{
|
||||
return m_aTextureUnits.empty();
|
||||
}
|
||||
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the ActorMultiTexture. */
|
||||
class LunaActorMultiTexture: public Luna<ActorMultiTexture>
|
||||
{
|
||||
public:
|
||||
static int ClearTextures( T* p, lua_State *L )
|
||||
{
|
||||
p->ClearTextures();
|
||||
return 0;
|
||||
}
|
||||
static int AddTexture( T* p, lua_State *L )
|
||||
{
|
||||
RageTexture *pTexture = Luna<RageTexture>::check(L, 1);
|
||||
int iRet = p->AddTexture( pTexture );
|
||||
lua_pushinteger( L, iRet );
|
||||
return 1;
|
||||
}
|
||||
static int SetTextureMode( T* p, lua_State *L )
|
||||
{
|
||||
int iIndex = IArg(1);
|
||||
TextureMode tm = Enum::Check<TextureMode>(L, 2);
|
||||
p->SetTextureMode( iIndex, tm );
|
||||
return 0;
|
||||
}
|
||||
static int SetTextureCoords( T* p, lua_State *L )
|
||||
{
|
||||
p->SetTextureCoords( RectF(FArg(1), FArg(2), FArg(3), FArg(4)) );
|
||||
return 0;
|
||||
}
|
||||
static int SetSizeFromTexture( T* p, lua_State *L )
|
||||
{
|
||||
RageTexture *pTexture = Luna<RageTexture>::check(L, 1);
|
||||
p->SetSizeFromTexture( pTexture );
|
||||
return 0;
|
||||
}
|
||||
static int SetEffectMode( T* p, lua_State *L )
|
||||
{
|
||||
EffectMode em = Enum::Check<EffectMode>(L, 1);
|
||||
p->SetEffectMode( em );
|
||||
return 0;
|
||||
}
|
||||
|
||||
LunaActorMultiTexture()
|
||||
{
|
||||
ADD_METHOD( ClearTextures );
|
||||
ADD_METHOD( AddTexture );
|
||||
ADD_METHOD( SetTextureMode );
|
||||
ADD_METHOD( SetTextureCoords );
|
||||
ADD_METHOD( SetSizeFromTexture );
|
||||
ADD_METHOD( SetEffectMode );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( ActorMultiTexture, Actor )
|
||||
// lua end
|
||||
|
||||
/*
|
||||
* (c) 2001-2007 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.
|
||||
*/
|
||||
|
||||
+73
-73
@@ -1,73 +1,73 @@
|
||||
/** @brief ActorMultiTexture - A texture created from multiple textures. */
|
||||
|
||||
#ifndef ACTOR_MULTI_TEXTURE_H
|
||||
#define ACTOR_MULTI_TEXTURE_H
|
||||
|
||||
#include "Actor.h"
|
||||
#include "RageDisplay.h"
|
||||
|
||||
class RageTexture;
|
||||
|
||||
class ActorMultiTexture: public Actor
|
||||
{
|
||||
public:
|
||||
ActorMultiTexture();
|
||||
ActorMultiTexture( const ActorMultiTexture &cpy );
|
||||
virtual ~ActorMultiTexture();
|
||||
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
virtual ActorMultiTexture *Copy() const;
|
||||
|
||||
virtual bool EarlyAbortDraw() const;
|
||||
virtual void DrawPrimitives();
|
||||
|
||||
void ClearTextures();
|
||||
int AddTexture( RageTexture *pTexture );
|
||||
void SetTextureMode( int iIndex, TextureMode tm );
|
||||
|
||||
void SetSizeFromTexture( RageTexture *pTexture );
|
||||
void SetTextureCoords( const RectF &r );
|
||||
void SetEffectMode( EffectMode em ) { m_EffectMode = em; }
|
||||
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
private:
|
||||
EffectMode m_EffectMode;
|
||||
struct TextureUnitState
|
||||
{
|
||||
TextureUnitState(): m_pTexture(NULL), m_TextureMode(TextureMode_Modulate) {}
|
||||
RageTexture *m_pTexture;
|
||||
TextureMode m_TextureMode;
|
||||
};
|
||||
vector<TextureUnitState> m_aTextureUnits;
|
||||
RectF m_Rect;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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.
|
||||
*/
|
||||
/** @brief ActorMultiTexture - A texture created from multiple textures. */
|
||||
|
||||
#ifndef ACTOR_MULTI_TEXTURE_H
|
||||
#define ACTOR_MULTI_TEXTURE_H
|
||||
|
||||
#include "Actor.h"
|
||||
#include "RageDisplay.h"
|
||||
|
||||
class RageTexture;
|
||||
|
||||
class ActorMultiTexture: public Actor
|
||||
{
|
||||
public:
|
||||
ActorMultiTexture();
|
||||
ActorMultiTexture( const ActorMultiTexture &cpy );
|
||||
virtual ~ActorMultiTexture();
|
||||
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
virtual ActorMultiTexture *Copy() const;
|
||||
|
||||
virtual bool EarlyAbortDraw() const;
|
||||
virtual void DrawPrimitives();
|
||||
|
||||
void ClearTextures();
|
||||
int AddTexture( RageTexture *pTexture );
|
||||
void SetTextureMode( int iIndex, TextureMode tm );
|
||||
|
||||
void SetSizeFromTexture( RageTexture *pTexture );
|
||||
void SetTextureCoords( const RectF &r );
|
||||
void SetEffectMode( EffectMode em ) { m_EffectMode = em; }
|
||||
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
private:
|
||||
EffectMode m_EffectMode;
|
||||
struct TextureUnitState
|
||||
{
|
||||
TextureUnitState(): m_pTexture(NULL), m_TextureMode(TextureMode_Modulate) {}
|
||||
RageTexture *m_pTexture;
|
||||
TextureMode m_TextureMode;
|
||||
};
|
||||
vector<TextureUnitState> m_aTextureUnits;
|
||||
RectF m_Rect;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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.
|
||||
*/
|
||||
|
||||
+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 != 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.
|
||||
*/
|
||||
|
||||
+54
-54
@@ -1,54 +1,54 @@
|
||||
#ifndef ACTOR_PROXY_H
|
||||
#define ACTOR_PROXY_H
|
||||
|
||||
#include "Actor.h"
|
||||
|
||||
struct lua_State;
|
||||
/** @brief Renders another actor. */
|
||||
class ActorProxy: public Actor
|
||||
{
|
||||
public:
|
||||
ActorProxy();
|
||||
|
||||
virtual bool EarlyAbortDraw() const;
|
||||
virtual void DrawPrimitives();
|
||||
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
virtual ActorProxy *Copy() const;
|
||||
|
||||
Actor *GetTarget() { return m_pActorTarget; }
|
||||
void SetTarget( Actor *pTarget ) { m_pActorTarget = pTarget; }
|
||||
|
||||
// Lua
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
private:
|
||||
Actor *m_pActorTarget;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
#ifndef ACTOR_PROXY_H
|
||||
#define ACTOR_PROXY_H
|
||||
|
||||
#include "Actor.h"
|
||||
|
||||
struct lua_State;
|
||||
/** @brief Renders another actor. */
|
||||
class ActorProxy: public Actor
|
||||
{
|
||||
public:
|
||||
ActorProxy();
|
||||
|
||||
virtual bool EarlyAbortDraw() const;
|
||||
virtual void DrawPrimitives();
|
||||
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
virtual ActorProxy *Copy() const;
|
||||
|
||||
Actor *GetTarget() { return m_pActorTarget; }
|
||||
void SetTarget( Actor *pTarget ) { m_pActorTarget = pTarget; }
|
||||
|
||||
// Lua
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
private:
|
||||
Actor *m_pActorTarget;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
+397
-397
@@ -1,397 +1,397 @@
|
||||
#include "global.h"
|
||||
#include "ActorScroller.h"
|
||||
#include "Foreach.h"
|
||||
#include "RageUtil.h"
|
||||
#include "XmlFile.h"
|
||||
#include "arch/Dialog/Dialog.h"
|
||||
#include "RageLog.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/* Tricky: We need ActorFrames created in Lua to auto delete their children.
|
||||
* We don't want classes that derive from ActorFrame to auto delete their
|
||||
* children. The name "ActorFrame" is widely used in Lua, so we'll have
|
||||
* that string instead create an ActorFrameAutoDeleteChildren object. */
|
||||
//REGISTER_ACTOR_CLASS( ActorScroller );
|
||||
REGISTER_ACTOR_CLASS_WITH_NAME( ActorScrollerAutoDeleteChildren, ActorScroller );
|
||||
ActorScroller *ActorScroller::Copy() const { return new ActorScroller(*this); }
|
||||
|
||||
|
||||
ActorScroller::ActorScroller()
|
||||
{
|
||||
m_iNumItems = 0;
|
||||
m_fCurrentItem = 0;
|
||||
m_fDestinationItem = 0;
|
||||
m_fSecondsPerItem = 1;
|
||||
m_fSecondsPauseBetweenItems = 0;
|
||||
m_fNumItemsToDraw = 7;
|
||||
m_iFirstSubActorIndex = 0;
|
||||
m_bLoop = false;
|
||||
m_bFastCatchup = false;
|
||||
m_bFunctionDependsOnPositionOffset = true;
|
||||
m_bFunctionDependsOnItemIndex = true;
|
||||
m_fPauseCountdownSeconds = 0;
|
||||
m_fQuantizePixels = 0;
|
||||
|
||||
m_quadMask.SetBlendMode( BLEND_NO_EFFECT ); // don't change color values
|
||||
m_quadMask.SetUseZBuffer( true ); // we want to write to the Zbuffer
|
||||
m_fMaskWidth = 0;
|
||||
m_fMaskHeight = 0;
|
||||
DisableMask();
|
||||
}
|
||||
|
||||
void ActorScroller::Load2()
|
||||
{
|
||||
m_iNumItems = m_SubActors.size();
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
for( unsigned i = 0; i < m_SubActors.size(); ++i )
|
||||
{
|
||||
lua_pushnumber( L, i );
|
||||
this->m_SubActors[i]->m_pLuaInstance->Set( L, "ItemIndex" );
|
||||
}
|
||||
LUA->Release( L );
|
||||
}
|
||||
|
||||
void ActorScroller::SetTransformFromReference( const LuaReference &ref )
|
||||
{
|
||||
m_exprTransformFunction.SetFromReference( ref );
|
||||
|
||||
// Probe to find which of the parameters are used.
|
||||
#define GP(a,b) m_exprTransformFunction.GetTransformCached( a, b, 2 )
|
||||
m_bFunctionDependsOnPositionOffset = (GP(0,0) != GP(1,0)) && (GP(0,1) != GP(1,1));
|
||||
m_bFunctionDependsOnItemIndex = (GP(0,0) != GP(0,1)) && (GP(1,0) != GP(1,1));
|
||||
m_exprTransformFunction.ClearCache();
|
||||
}
|
||||
|
||||
void ActorScroller::SetTransformFromExpression( const RString &sTransformFunction )
|
||||
{
|
||||
LuaReference ref;
|
||||
ref.SetFromExpression( sTransformFunction );
|
||||
SetTransformFromReference( ref );
|
||||
}
|
||||
|
||||
void ActorScroller::SetTransformFromWidth( float fItemWidth )
|
||||
{
|
||||
SetTransformFromExpression( ssprintf("function(self,offset,itemIndex,numItems) self:x(%f*offset) end",fItemWidth) );
|
||||
}
|
||||
|
||||
void ActorScroller::SetTransformFromHeight( float fItemHeight )
|
||||
{
|
||||
SetTransformFromExpression( ssprintf("function(self,offset,itemIndex,numItems) self:y(%f*offset) end",fItemHeight) );
|
||||
}
|
||||
|
||||
void ActorScroller::EnableMask( float fWidth, float fHeight )
|
||||
{
|
||||
m_quadMask.SetVisible( fWidth != 0 && fHeight != 0 );
|
||||
m_quadMask.SetWidth( fWidth );
|
||||
m_fMaskWidth = fWidth;
|
||||
m_quadMask.SetHeight( fHeight );
|
||||
m_fMaskHeight = fHeight;
|
||||
}
|
||||
|
||||
void ActorScroller::DisableMask()
|
||||
{
|
||||
m_quadMask.SetVisible( false );
|
||||
}
|
||||
|
||||
void ActorScroller::ScrollThroughAllItems()
|
||||
{
|
||||
m_fCurrentItem = m_bLoop ? +m_fNumItemsToDraw/2.0f : -(m_fNumItemsToDraw/2.0f)-1;
|
||||
m_fDestinationItem = (float)(m_iNumItems+m_fNumItemsToDraw/2.0f+1);
|
||||
}
|
||||
|
||||
void ActorScroller::ScrollWithPadding( float fItemPaddingStart, float fItemPaddingEnd )
|
||||
{
|
||||
m_fCurrentItem = -fItemPaddingStart;
|
||||
m_fDestinationItem = m_iNumItems-1+fItemPaddingEnd;
|
||||
}
|
||||
|
||||
float ActorScroller::GetSecondsForCompleteScrollThrough() const
|
||||
{
|
||||
float fTotalItems = m_fNumItemsToDraw + m_iNumItems;
|
||||
return fTotalItems * (m_fSecondsPerItem + m_fSecondsPauseBetweenItems );
|
||||
}
|
||||
|
||||
float ActorScroller::GetSecondsToDestination() const
|
||||
{
|
||||
float fTotalItemsToMove = fabsf(m_fCurrentItem - m_fDestinationItem);
|
||||
return fTotalItemsToMove * m_fSecondsPerItem;
|
||||
}
|
||||
|
||||
void ActorScroller::LoadFromNode( const XNode *pNode )
|
||||
{
|
||||
ActorFrame::LoadFromNode( pNode );
|
||||
|
||||
Load2();
|
||||
|
||||
float fNumItemsToDraw = 0;
|
||||
if( pNode->GetAttrValue("NumItemsToDraw", fNumItemsToDraw) )
|
||||
SetNumItemsToDraw( fNumItemsToDraw );
|
||||
|
||||
float fSecondsPerItem = 0;
|
||||
if( pNode->GetAttrValue("SecondsPerItem", fSecondsPerItem) )
|
||||
ActorScroller::SetSecondsPerItem( fSecondsPerItem );
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
pNode->PushAttrValue( L, "TransformFunction" );
|
||||
{
|
||||
LuaReference ref;
|
||||
ref.SetFromStack( L );
|
||||
if( !ref.IsNil() )
|
||||
SetTransformFromReference( ref );
|
||||
}
|
||||
LUA->Release( L );
|
||||
|
||||
int iSubdivisions = 1;
|
||||
if( pNode->GetAttrValue("Subdivisions", iSubdivisions) )
|
||||
ActorScroller::SetNumSubdivisions( iSubdivisions );
|
||||
|
||||
bool bUseMask = false;
|
||||
pNode->GetAttrValue( "UseMask", bUseMask );
|
||||
|
||||
if( bUseMask )
|
||||
{
|
||||
pNode->GetAttrValue( "MaskWidth", m_fMaskWidth );
|
||||
pNode->GetAttrValue( "MaskHeight", m_fMaskHeight );
|
||||
EnableMask( m_fMaskWidth, m_fMaskHeight );
|
||||
}
|
||||
|
||||
pNode->GetAttrValue( "QuantizePixels", m_fQuantizePixels );
|
||||
}
|
||||
|
||||
void ActorScroller::UpdateInternal( float fDeltaTime )
|
||||
{
|
||||
ActorFrame::UpdateInternal( fDeltaTime );
|
||||
|
||||
// If we have no children, the code below will busy loop.
|
||||
if( !m_SubActors.size() )
|
||||
return;
|
||||
|
||||
// handle pause
|
||||
if( fDeltaTime > m_fPauseCountdownSeconds )
|
||||
{
|
||||
fDeltaTime -= m_fPauseCountdownSeconds;
|
||||
m_fPauseCountdownSeconds = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fPauseCountdownSeconds -= fDeltaTime;
|
||||
fDeltaTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if( m_fCurrentItem == m_fDestinationItem )
|
||||
return; // done scrolling
|
||||
|
||||
|
||||
float fOldItemAtTop = m_fCurrentItem;
|
||||
if( m_fSecondsPerItem > 0 )
|
||||
{
|
||||
float fApproachSpeed = fDeltaTime/m_fSecondsPerItem;
|
||||
if( m_bFastCatchup )
|
||||
{
|
||||
float fDistanceToMove = fabsf(m_fCurrentItem - m_fDestinationItem);
|
||||
if( fDistanceToMove > 1 )
|
||||
fApproachSpeed *= fDistanceToMove*fDistanceToMove;
|
||||
}
|
||||
|
||||
fapproach( m_fCurrentItem, m_fDestinationItem, fApproachSpeed );
|
||||
}
|
||||
|
||||
// if items changed, then pause
|
||||
if( (int)fOldItemAtTop != (int)m_fCurrentItem )
|
||||
m_fPauseCountdownSeconds = m_fSecondsPauseBetweenItems;
|
||||
|
||||
if( m_bLoop )
|
||||
m_fCurrentItem = fmodf( m_fCurrentItem, (float) m_iNumItems );
|
||||
}
|
||||
|
||||
void ActorScroller::DrawPrimitives()
|
||||
{
|
||||
PositionItemsAndDrawPrimitives( true );
|
||||
}
|
||||
|
||||
void ActorScroller::PositionItems()
|
||||
{
|
||||
PositionItemsAndDrawPrimitives( false );
|
||||
}
|
||||
|
||||
/* Shift m_SubActors forward by iDist. This will place item m_iFirstSubActorIndex
|
||||
* in m_SubActors[0]. */
|
||||
void ActorScroller::ShiftSubActors( int iDist )
|
||||
{
|
||||
if( iDist != INT_MAX )
|
||||
CircularShift( m_SubActors, iDist );
|
||||
}
|
||||
|
||||
void ActorScroller::PositionItemsAndDrawPrimitives( bool bDrawPrimitives )
|
||||
{
|
||||
if( m_SubActors.empty() )
|
||||
return;
|
||||
|
||||
float fNumItemsToDraw = m_fNumItemsToDraw;
|
||||
if( m_quadMask.GetVisible() )
|
||||
{
|
||||
// write to z buffer so that top and bottom are clipped
|
||||
// Draw an extra item; this is the one that will be masked.
|
||||
fNumItemsToDraw++;
|
||||
float fPositionFullyOffScreenTop = -(fNumItemsToDraw)/2.f;
|
||||
float fPositionFullyOffScreenBottom = (fNumItemsToDraw)/2.f;
|
||||
|
||||
m_exprTransformFunction.TransformItemCached( m_quadMask, fPositionFullyOffScreenTop, -1, m_iNumItems );
|
||||
if( bDrawPrimitives ) m_quadMask.Draw();
|
||||
|
||||
m_exprTransformFunction.TransformItemCached( m_quadMask, fPositionFullyOffScreenBottom, m_iNumItems, m_iNumItems );
|
||||
if( bDrawPrimitives ) m_quadMask.Draw();
|
||||
}
|
||||
|
||||
float fFirstItemToDraw = m_fCurrentItem - fNumItemsToDraw/2.f;
|
||||
float fLastItemToDraw = m_fCurrentItem + fNumItemsToDraw/2.f;
|
||||
int iFirstItemToDraw = (int) ceilf( fFirstItemToDraw );
|
||||
int iLastItemToDraw = (int) ceilf( fLastItemToDraw );
|
||||
if( !m_bLoop )
|
||||
{
|
||||
iFirstItemToDraw = clamp( iFirstItemToDraw, 0, m_iNumItems );
|
||||
iLastItemToDraw = clamp( iLastItemToDraw, 0, m_iNumItems );
|
||||
}
|
||||
|
||||
bool bDelayedDraw = m_bDrawByZPosition && !m_bLoop;
|
||||
vector<Actor*> subs;
|
||||
|
||||
{
|
||||
// Shift m_SubActors so iFirstItemToDraw is at the beginning.
|
||||
int iNewFirstIndex = iFirstItemToDraw;
|
||||
int iDist = iNewFirstIndex - m_iFirstSubActorIndex;
|
||||
m_iFirstSubActorIndex = iNewFirstIndex;
|
||||
ShiftSubActors( iDist );
|
||||
}
|
||||
|
||||
int iNumToDraw = iLastItemToDraw - iFirstItemToDraw;
|
||||
for( int i = 0; i < iNumToDraw; ++i )
|
||||
{
|
||||
int iItem = i + iFirstItemToDraw;
|
||||
float fPosition = iItem - m_fCurrentItem;
|
||||
int iIndex = i; // index into m_SubActors
|
||||
if( m_bLoop )
|
||||
wrap( iIndex, m_SubActors.size() );
|
||||
else if( iIndex < 0 || iIndex >= (int)m_SubActors.size() )
|
||||
continue;
|
||||
|
||||
// Optimization: Zero out unused parameters so that they don't create new,
|
||||
// unnecessary entries in the position cache. On scrollers with lots of
|
||||
// items, especially with Subdivisions > 1, m_exprTransformFunction uses
|
||||
// too much memory.
|
||||
if( !m_bFunctionDependsOnPositionOffset )
|
||||
fPosition = 0;
|
||||
if( !m_bFunctionDependsOnItemIndex )
|
||||
iItem = 0;
|
||||
|
||||
m_exprTransformFunction.TransformItemCached( *m_SubActors[iIndex], fPosition, iItem, m_iNumItems );
|
||||
if( bDrawPrimitives )
|
||||
{
|
||||
if( bDelayedDraw )
|
||||
subs.push_back( m_SubActors[iIndex] );
|
||||
else
|
||||
m_SubActors[iIndex]->Draw();
|
||||
}
|
||||
}
|
||||
|
||||
if( bDelayedDraw )
|
||||
{
|
||||
ActorUtil::SortByZPosition( subs );
|
||||
FOREACH( Actor*, subs, a )
|
||||
(*a)->Draw();
|
||||
}
|
||||
}
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the ActorScroller. */
|
||||
class LunaActorScroller: public Luna<ActorScroller>
|
||||
{
|
||||
public:
|
||||
static int PositionItems( T* p, lua_State *L ) { p->PositionItems(); return 0; }
|
||||
static int SetTransformFromFunction( T* p, lua_State *L )
|
||||
{
|
||||
LuaReference ref;
|
||||
LuaHelpers::FromStack( L, ref, 1 );
|
||||
p->SetTransformFromReference( ref );
|
||||
return 0;
|
||||
}
|
||||
static int SetTransformFromHeight( T* p, lua_State *L ) { p->SetTransformFromHeight(FArg(1)); return 0; }
|
||||
static int SetTransformFromWidth( T* p, lua_State *L ) { p->SetTransformFromWidth(FArg(1)); return 0; }
|
||||
static int SetCurrentAndDestinationItem( T* p, lua_State *L ) { p->SetCurrentAndDestinationItem( FArg(1) ); return 0; }
|
||||
static int SetDestinationItem( T* p, lua_State *L ) { p->SetDestinationItem( FArg(1) ); return 0; }
|
||||
static int GetSecondsToDestination( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecondsToDestination() ); return 1; }
|
||||
static int SetSecondsPerItem( T* p, lua_State *L ) { p->SetSecondsPerItem(FArg(1)); return 0; }
|
||||
static int SetSecondsPauseBetweenItems( T* p, lua_State *L ) { p->SetSecondsPauseBetweenItems(FArg(1)); return 0; }
|
||||
static int SetPauseCountdownSeconds( T* p, lua_State *L ) { p->SetPauseCountdownSeconds(FArg(1)); return 0; }
|
||||
static int SetNumSubdivisions( T* p, lua_State *L ) { p->SetNumSubdivisions(IArg(1)); return 0; }
|
||||
static int ScrollThroughAllItems( T* p, lua_State *L ) { p->ScrollThroughAllItems(); return 0; }
|
||||
static int ScrollWithPadding( T* p, lua_State *L ) { p->ScrollWithPadding(FArg(1),FArg(2)); return 0; }
|
||||
static int SetFastCatchup( T* p, lua_State *L ) { p->SetFastCatchup(BArg(1)); return 0; }
|
||||
static int SetLoop( T* p, lua_State *L ) { p->SetLoop(BArg(1)); return 0; }
|
||||
static int SetMask( T* p, lua_State *L ) { p->EnableMask(FArg(1), FArg(2)); return 0; }
|
||||
|
||||
static int SetNumItemsToDraw( T* p, lua_State *L ) { p->SetNumItemsToDraw(FArg(1)); return 0; }
|
||||
static int GetFullScrollLengthSeconds( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecondsForCompleteScrollThrough() ); return 1; }
|
||||
static int GetCurrentItem( T* p, lua_State *L ) { lua_pushnumber( L, p->GetCurrentItem() ); return 1; }
|
||||
static int GetDestinationItem( T* p, lua_State *L ) { lua_pushnumber( L, p->GetDestinationItem() ); return 1; }
|
||||
static int GetNumItems( T* p, lua_State *L ) { lua_pushnumber( L, p->GetNumItems() ); return 1; }
|
||||
|
||||
LunaActorScroller()
|
||||
{
|
||||
ADD_METHOD( PositionItems );
|
||||
ADD_METHOD( SetTransformFromFunction );
|
||||
ADD_METHOD( SetTransformFromHeight );
|
||||
ADD_METHOD( SetTransformFromWidth );
|
||||
ADD_METHOD( SetCurrentAndDestinationItem );
|
||||
ADD_METHOD( SetDestinationItem );
|
||||
ADD_METHOD( GetSecondsToDestination );
|
||||
ADD_METHOD( SetSecondsPerItem );
|
||||
ADD_METHOD( SetSecondsPauseBetweenItems );
|
||||
ADD_METHOD( SetPauseCountdownSeconds );
|
||||
ADD_METHOD( SetNumSubdivisions );
|
||||
ADD_METHOD( ScrollThroughAllItems );
|
||||
ADD_METHOD( ScrollWithPadding );
|
||||
ADD_METHOD( SetFastCatchup );
|
||||
ADD_METHOD( SetLoop );
|
||||
ADD_METHOD( SetMask );
|
||||
ADD_METHOD( SetNumItemsToDraw );
|
||||
ADD_METHOD( GetFullScrollLengthSeconds );
|
||||
ADD_METHOD( GetCurrentItem );
|
||||
ADD_METHOD( GetDestinationItem );
|
||||
ADD_METHOD( GetNumItems );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( ActorScroller, 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 "ActorScroller.h"
|
||||
#include "Foreach.h"
|
||||
#include "RageUtil.h"
|
||||
#include "XmlFile.h"
|
||||
#include "arch/Dialog/Dialog.h"
|
||||
#include "RageLog.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/* Tricky: We need ActorFrames created in Lua to auto delete their children.
|
||||
* We don't want classes that derive from ActorFrame to auto delete their
|
||||
* children. The name "ActorFrame" is widely used in Lua, so we'll have
|
||||
* that string instead create an ActorFrameAutoDeleteChildren object. */
|
||||
//REGISTER_ACTOR_CLASS( ActorScroller );
|
||||
REGISTER_ACTOR_CLASS_WITH_NAME( ActorScrollerAutoDeleteChildren, ActorScroller );
|
||||
ActorScroller *ActorScroller::Copy() const { return new ActorScroller(*this); }
|
||||
|
||||
|
||||
ActorScroller::ActorScroller()
|
||||
{
|
||||
m_iNumItems = 0;
|
||||
m_fCurrentItem = 0;
|
||||
m_fDestinationItem = 0;
|
||||
m_fSecondsPerItem = 1;
|
||||
m_fSecondsPauseBetweenItems = 0;
|
||||
m_fNumItemsToDraw = 7;
|
||||
m_iFirstSubActorIndex = 0;
|
||||
m_bLoop = false;
|
||||
m_bFastCatchup = false;
|
||||
m_bFunctionDependsOnPositionOffset = true;
|
||||
m_bFunctionDependsOnItemIndex = true;
|
||||
m_fPauseCountdownSeconds = 0;
|
||||
m_fQuantizePixels = 0;
|
||||
|
||||
m_quadMask.SetBlendMode( BLEND_NO_EFFECT ); // don't change color values
|
||||
m_quadMask.SetUseZBuffer( true ); // we want to write to the Zbuffer
|
||||
m_fMaskWidth = 0;
|
||||
m_fMaskHeight = 0;
|
||||
DisableMask();
|
||||
}
|
||||
|
||||
void ActorScroller::Load2()
|
||||
{
|
||||
m_iNumItems = m_SubActors.size();
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
for( unsigned i = 0; i < m_SubActors.size(); ++i )
|
||||
{
|
||||
lua_pushnumber( L, i );
|
||||
this->m_SubActors[i]->m_pLuaInstance->Set( L, "ItemIndex" );
|
||||
}
|
||||
LUA->Release( L );
|
||||
}
|
||||
|
||||
void ActorScroller::SetTransformFromReference( const LuaReference &ref )
|
||||
{
|
||||
m_exprTransformFunction.SetFromReference( ref );
|
||||
|
||||
// Probe to find which of the parameters are used.
|
||||
#define GP(a,b) m_exprTransformFunction.GetTransformCached( a, b, 2 )
|
||||
m_bFunctionDependsOnPositionOffset = (GP(0,0) != GP(1,0)) && (GP(0,1) != GP(1,1));
|
||||
m_bFunctionDependsOnItemIndex = (GP(0,0) != GP(0,1)) && (GP(1,0) != GP(1,1));
|
||||
m_exprTransformFunction.ClearCache();
|
||||
}
|
||||
|
||||
void ActorScroller::SetTransformFromExpression( const RString &sTransformFunction )
|
||||
{
|
||||
LuaReference ref;
|
||||
ref.SetFromExpression( sTransformFunction );
|
||||
SetTransformFromReference( ref );
|
||||
}
|
||||
|
||||
void ActorScroller::SetTransformFromWidth( float fItemWidth )
|
||||
{
|
||||
SetTransformFromExpression( ssprintf("function(self,offset,itemIndex,numItems) self:x(%f*offset) end",fItemWidth) );
|
||||
}
|
||||
|
||||
void ActorScroller::SetTransformFromHeight( float fItemHeight )
|
||||
{
|
||||
SetTransformFromExpression( ssprintf("function(self,offset,itemIndex,numItems) self:y(%f*offset) end",fItemHeight) );
|
||||
}
|
||||
|
||||
void ActorScroller::EnableMask( float fWidth, float fHeight )
|
||||
{
|
||||
m_quadMask.SetVisible( fWidth != 0 && fHeight != 0 );
|
||||
m_quadMask.SetWidth( fWidth );
|
||||
m_fMaskWidth = fWidth;
|
||||
m_quadMask.SetHeight( fHeight );
|
||||
m_fMaskHeight = fHeight;
|
||||
}
|
||||
|
||||
void ActorScroller::DisableMask()
|
||||
{
|
||||
m_quadMask.SetVisible( false );
|
||||
}
|
||||
|
||||
void ActorScroller::ScrollThroughAllItems()
|
||||
{
|
||||
m_fCurrentItem = m_bLoop ? +m_fNumItemsToDraw/2.0f : -(m_fNumItemsToDraw/2.0f)-1;
|
||||
m_fDestinationItem = (float)(m_iNumItems+m_fNumItemsToDraw/2.0f+1);
|
||||
}
|
||||
|
||||
void ActorScroller::ScrollWithPadding( float fItemPaddingStart, float fItemPaddingEnd )
|
||||
{
|
||||
m_fCurrentItem = -fItemPaddingStart;
|
||||
m_fDestinationItem = m_iNumItems-1+fItemPaddingEnd;
|
||||
}
|
||||
|
||||
float ActorScroller::GetSecondsForCompleteScrollThrough() const
|
||||
{
|
||||
float fTotalItems = m_fNumItemsToDraw + m_iNumItems;
|
||||
return fTotalItems * (m_fSecondsPerItem + m_fSecondsPauseBetweenItems );
|
||||
}
|
||||
|
||||
float ActorScroller::GetSecondsToDestination() const
|
||||
{
|
||||
float fTotalItemsToMove = fabsf(m_fCurrentItem - m_fDestinationItem);
|
||||
return fTotalItemsToMove * m_fSecondsPerItem;
|
||||
}
|
||||
|
||||
void ActorScroller::LoadFromNode( const XNode *pNode )
|
||||
{
|
||||
ActorFrame::LoadFromNode( pNode );
|
||||
|
||||
Load2();
|
||||
|
||||
float fNumItemsToDraw = 0;
|
||||
if( pNode->GetAttrValue("NumItemsToDraw", fNumItemsToDraw) )
|
||||
SetNumItemsToDraw( fNumItemsToDraw );
|
||||
|
||||
float fSecondsPerItem = 0;
|
||||
if( pNode->GetAttrValue("SecondsPerItem", fSecondsPerItem) )
|
||||
ActorScroller::SetSecondsPerItem( fSecondsPerItem );
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
pNode->PushAttrValue( L, "TransformFunction" );
|
||||
{
|
||||
LuaReference ref;
|
||||
ref.SetFromStack( L );
|
||||
if( !ref.IsNil() )
|
||||
SetTransformFromReference( ref );
|
||||
}
|
||||
LUA->Release( L );
|
||||
|
||||
int iSubdivisions = 1;
|
||||
if( pNode->GetAttrValue("Subdivisions", iSubdivisions) )
|
||||
ActorScroller::SetNumSubdivisions( iSubdivisions );
|
||||
|
||||
bool bUseMask = false;
|
||||
pNode->GetAttrValue( "UseMask", bUseMask );
|
||||
|
||||
if( bUseMask )
|
||||
{
|
||||
pNode->GetAttrValue( "MaskWidth", m_fMaskWidth );
|
||||
pNode->GetAttrValue( "MaskHeight", m_fMaskHeight );
|
||||
EnableMask( m_fMaskWidth, m_fMaskHeight );
|
||||
}
|
||||
|
||||
pNode->GetAttrValue( "QuantizePixels", m_fQuantizePixels );
|
||||
}
|
||||
|
||||
void ActorScroller::UpdateInternal( float fDeltaTime )
|
||||
{
|
||||
ActorFrame::UpdateInternal( fDeltaTime );
|
||||
|
||||
// If we have no children, the code below will busy loop.
|
||||
if( !m_SubActors.size() )
|
||||
return;
|
||||
|
||||
// handle pause
|
||||
if( fDeltaTime > m_fPauseCountdownSeconds )
|
||||
{
|
||||
fDeltaTime -= m_fPauseCountdownSeconds;
|
||||
m_fPauseCountdownSeconds = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fPauseCountdownSeconds -= fDeltaTime;
|
||||
fDeltaTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if( m_fCurrentItem == m_fDestinationItem )
|
||||
return; // done scrolling
|
||||
|
||||
|
||||
float fOldItemAtTop = m_fCurrentItem;
|
||||
if( m_fSecondsPerItem > 0 )
|
||||
{
|
||||
float fApproachSpeed = fDeltaTime/m_fSecondsPerItem;
|
||||
if( m_bFastCatchup )
|
||||
{
|
||||
float fDistanceToMove = fabsf(m_fCurrentItem - m_fDestinationItem);
|
||||
if( fDistanceToMove > 1 )
|
||||
fApproachSpeed *= fDistanceToMove*fDistanceToMove;
|
||||
}
|
||||
|
||||
fapproach( m_fCurrentItem, m_fDestinationItem, fApproachSpeed );
|
||||
}
|
||||
|
||||
// if items changed, then pause
|
||||
if( (int)fOldItemAtTop != (int)m_fCurrentItem )
|
||||
m_fPauseCountdownSeconds = m_fSecondsPauseBetweenItems;
|
||||
|
||||
if( m_bLoop )
|
||||
m_fCurrentItem = fmodf( m_fCurrentItem, (float) m_iNumItems );
|
||||
}
|
||||
|
||||
void ActorScroller::DrawPrimitives()
|
||||
{
|
||||
PositionItemsAndDrawPrimitives( true );
|
||||
}
|
||||
|
||||
void ActorScroller::PositionItems()
|
||||
{
|
||||
PositionItemsAndDrawPrimitives( false );
|
||||
}
|
||||
|
||||
/* Shift m_SubActors forward by iDist. This will place item m_iFirstSubActorIndex
|
||||
* in m_SubActors[0]. */
|
||||
void ActorScroller::ShiftSubActors( int iDist )
|
||||
{
|
||||
if( iDist != INT_MAX )
|
||||
CircularShift( m_SubActors, iDist );
|
||||
}
|
||||
|
||||
void ActorScroller::PositionItemsAndDrawPrimitives( bool bDrawPrimitives )
|
||||
{
|
||||
if( m_SubActors.empty() )
|
||||
return;
|
||||
|
||||
float fNumItemsToDraw = m_fNumItemsToDraw;
|
||||
if( m_quadMask.GetVisible() )
|
||||
{
|
||||
// write to z buffer so that top and bottom are clipped
|
||||
// Draw an extra item; this is the one that will be masked.
|
||||
fNumItemsToDraw++;
|
||||
float fPositionFullyOffScreenTop = -(fNumItemsToDraw)/2.f;
|
||||
float fPositionFullyOffScreenBottom = (fNumItemsToDraw)/2.f;
|
||||
|
||||
m_exprTransformFunction.TransformItemCached( m_quadMask, fPositionFullyOffScreenTop, -1, m_iNumItems );
|
||||
if( bDrawPrimitives ) m_quadMask.Draw();
|
||||
|
||||
m_exprTransformFunction.TransformItemCached( m_quadMask, fPositionFullyOffScreenBottom, m_iNumItems, m_iNumItems );
|
||||
if( bDrawPrimitives ) m_quadMask.Draw();
|
||||
}
|
||||
|
||||
float fFirstItemToDraw = m_fCurrentItem - fNumItemsToDraw/2.f;
|
||||
float fLastItemToDraw = m_fCurrentItem + fNumItemsToDraw/2.f;
|
||||
int iFirstItemToDraw = (int) ceilf( fFirstItemToDraw );
|
||||
int iLastItemToDraw = (int) ceilf( fLastItemToDraw );
|
||||
if( !m_bLoop )
|
||||
{
|
||||
iFirstItemToDraw = clamp( iFirstItemToDraw, 0, m_iNumItems );
|
||||
iLastItemToDraw = clamp( iLastItemToDraw, 0, m_iNumItems );
|
||||
}
|
||||
|
||||
bool bDelayedDraw = m_bDrawByZPosition && !m_bLoop;
|
||||
vector<Actor*> subs;
|
||||
|
||||
{
|
||||
// Shift m_SubActors so iFirstItemToDraw is at the beginning.
|
||||
int iNewFirstIndex = iFirstItemToDraw;
|
||||
int iDist = iNewFirstIndex - m_iFirstSubActorIndex;
|
||||
m_iFirstSubActorIndex = iNewFirstIndex;
|
||||
ShiftSubActors( iDist );
|
||||
}
|
||||
|
||||
int iNumToDraw = iLastItemToDraw - iFirstItemToDraw;
|
||||
for( int i = 0; i < iNumToDraw; ++i )
|
||||
{
|
||||
int iItem = i + iFirstItemToDraw;
|
||||
float fPosition = iItem - m_fCurrentItem;
|
||||
int iIndex = i; // index into m_SubActors
|
||||
if( m_bLoop )
|
||||
wrap( iIndex, m_SubActors.size() );
|
||||
else if( iIndex < 0 || iIndex >= (int)m_SubActors.size() )
|
||||
continue;
|
||||
|
||||
// Optimization: Zero out unused parameters so that they don't create new,
|
||||
// unnecessary entries in the position cache. On scrollers with lots of
|
||||
// items, especially with Subdivisions > 1, m_exprTransformFunction uses
|
||||
// too much memory.
|
||||
if( !m_bFunctionDependsOnPositionOffset )
|
||||
fPosition = 0;
|
||||
if( !m_bFunctionDependsOnItemIndex )
|
||||
iItem = 0;
|
||||
|
||||
m_exprTransformFunction.TransformItemCached( *m_SubActors[iIndex], fPosition, iItem, m_iNumItems );
|
||||
if( bDrawPrimitives )
|
||||
{
|
||||
if( bDelayedDraw )
|
||||
subs.push_back( m_SubActors[iIndex] );
|
||||
else
|
||||
m_SubActors[iIndex]->Draw();
|
||||
}
|
||||
}
|
||||
|
||||
if( bDelayedDraw )
|
||||
{
|
||||
ActorUtil::SortByZPosition( subs );
|
||||
FOREACH( Actor*, subs, a )
|
||||
(*a)->Draw();
|
||||
}
|
||||
}
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the ActorScroller. */
|
||||
class LunaActorScroller: public Luna<ActorScroller>
|
||||
{
|
||||
public:
|
||||
static int PositionItems( T* p, lua_State *L ) { p->PositionItems(); return 0; }
|
||||
static int SetTransformFromFunction( T* p, lua_State *L )
|
||||
{
|
||||
LuaReference ref;
|
||||
LuaHelpers::FromStack( L, ref, 1 );
|
||||
p->SetTransformFromReference( ref );
|
||||
return 0;
|
||||
}
|
||||
static int SetTransformFromHeight( T* p, lua_State *L ) { p->SetTransformFromHeight(FArg(1)); return 0; }
|
||||
static int SetTransformFromWidth( T* p, lua_State *L ) { p->SetTransformFromWidth(FArg(1)); return 0; }
|
||||
static int SetCurrentAndDestinationItem( T* p, lua_State *L ) { p->SetCurrentAndDestinationItem( FArg(1) ); return 0; }
|
||||
static int SetDestinationItem( T* p, lua_State *L ) { p->SetDestinationItem( FArg(1) ); return 0; }
|
||||
static int GetSecondsToDestination( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecondsToDestination() ); return 1; }
|
||||
static int SetSecondsPerItem( T* p, lua_State *L ) { p->SetSecondsPerItem(FArg(1)); return 0; }
|
||||
static int SetSecondsPauseBetweenItems( T* p, lua_State *L ) { p->SetSecondsPauseBetweenItems(FArg(1)); return 0; }
|
||||
static int SetPauseCountdownSeconds( T* p, lua_State *L ) { p->SetPauseCountdownSeconds(FArg(1)); return 0; }
|
||||
static int SetNumSubdivisions( T* p, lua_State *L ) { p->SetNumSubdivisions(IArg(1)); return 0; }
|
||||
static int ScrollThroughAllItems( T* p, lua_State *L ) { p->ScrollThroughAllItems(); return 0; }
|
||||
static int ScrollWithPadding( T* p, lua_State *L ) { p->ScrollWithPadding(FArg(1),FArg(2)); return 0; }
|
||||
static int SetFastCatchup( T* p, lua_State *L ) { p->SetFastCatchup(BArg(1)); return 0; }
|
||||
static int SetLoop( T* p, lua_State *L ) { p->SetLoop(BArg(1)); return 0; }
|
||||
static int SetMask( T* p, lua_State *L ) { p->EnableMask(FArg(1), FArg(2)); return 0; }
|
||||
|
||||
static int SetNumItemsToDraw( T* p, lua_State *L ) { p->SetNumItemsToDraw(FArg(1)); return 0; }
|
||||
static int GetFullScrollLengthSeconds( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSecondsForCompleteScrollThrough() ); return 1; }
|
||||
static int GetCurrentItem( T* p, lua_State *L ) { lua_pushnumber( L, p->GetCurrentItem() ); return 1; }
|
||||
static int GetDestinationItem( T* p, lua_State *L ) { lua_pushnumber( L, p->GetDestinationItem() ); return 1; }
|
||||
static int GetNumItems( T* p, lua_State *L ) { lua_pushnumber( L, p->GetNumItems() ); return 1; }
|
||||
|
||||
LunaActorScroller()
|
||||
{
|
||||
ADD_METHOD( PositionItems );
|
||||
ADD_METHOD( SetTransformFromFunction );
|
||||
ADD_METHOD( SetTransformFromHeight );
|
||||
ADD_METHOD( SetTransformFromWidth );
|
||||
ADD_METHOD( SetCurrentAndDestinationItem );
|
||||
ADD_METHOD( SetDestinationItem );
|
||||
ADD_METHOD( GetSecondsToDestination );
|
||||
ADD_METHOD( SetSecondsPerItem );
|
||||
ADD_METHOD( SetSecondsPauseBetweenItems );
|
||||
ADD_METHOD( SetPauseCountdownSeconds );
|
||||
ADD_METHOD( SetNumSubdivisions );
|
||||
ADD_METHOD( ScrollThroughAllItems );
|
||||
ADD_METHOD( ScrollWithPadding );
|
||||
ADD_METHOD( SetFastCatchup );
|
||||
ADD_METHOD( SetLoop );
|
||||
ADD_METHOD( SetMask );
|
||||
ADD_METHOD( SetNumItemsToDraw );
|
||||
ADD_METHOD( GetFullScrollLengthSeconds );
|
||||
ADD_METHOD( GetCurrentItem );
|
||||
ADD_METHOD( GetDestinationItem );
|
||||
ADD_METHOD( GetNumItems );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( ActorScroller, 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.
|
||||
*/
|
||||
|
||||
+123
-123
@@ -1,123 +1,123 @@
|
||||
#ifndef ActorScroller_H
|
||||
#define ActorScroller_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
#include "Quad.h"
|
||||
class XNode;
|
||||
#include "LuaExpressionTransform.h"
|
||||
/** @brief ActorFrame that moves its children. */
|
||||
class ActorScroller : public ActorFrame
|
||||
{
|
||||
public:
|
||||
ActorScroller();
|
||||
|
||||
void SetTransformFromReference( const LuaReference &ref );
|
||||
void SetTransformFromExpression( const RString &sTransformFunction );
|
||||
void SetTransformFromWidth( float fItemWidth );
|
||||
void SetTransformFromHeight( float fItemHeight );
|
||||
|
||||
void Load2();
|
||||
|
||||
void EnableMask( float fWidth, float fHeight );
|
||||
void DisableMask();
|
||||
|
||||
virtual void UpdateInternal( float fDelta );
|
||||
virtual void DrawPrimitives(); // handles drawing and doesn't call ActorFrame::DrawPrimitives
|
||||
|
||||
void PositionItems();
|
||||
|
||||
void LoadFromNode( const XNode *pNode );
|
||||
virtual ActorScroller *Copy() const;
|
||||
|
||||
void SetLoop( bool bLoop ) { m_bLoop = bLoop; }
|
||||
void SetNumItemsToDraw( float fNumItemsToDraw ) { m_fNumItemsToDraw = fNumItemsToDraw; }
|
||||
void SetDestinationItem( float fItemIndex ) { m_fDestinationItem = fItemIndex; }
|
||||
void SetCurrentAndDestinationItem( float fItemIndex ) { m_fCurrentItem = m_fDestinationItem = fItemIndex; }
|
||||
float GetCurrentItem() const { return m_fCurrentItem; }
|
||||
float GetDestinationItem() const { return m_fDestinationItem; }
|
||||
void ScrollThroughAllItems();
|
||||
void ScrollWithPadding( float fItemPaddingStart, float fItemPaddingEnd );
|
||||
void SetPauseCountdownSeconds( float fSecs ) { m_fPauseCountdownSeconds = fSecs; }
|
||||
void SetFastCatchup( bool bOn ) { m_bFastCatchup = bOn; }
|
||||
void SetSecondsPerItem( float fSeconds ) { m_fSecondsPerItem = fSeconds; }
|
||||
void SetSecondsPauseBetweenItems( float fSeconds ) { m_fSecondsPauseBetweenItems = fSeconds; }
|
||||
void SetNumSubdivisions( int iNumSubdivisions ) { m_exprTransformFunction.SetNumSubdivisions( iNumSubdivisions ); }
|
||||
float GetSecondsForCompleteScrollThrough() const;
|
||||
float GetSecondsToDestination() const;
|
||||
int GetNumItems() const { return m_iNumItems; }
|
||||
|
||||
// Commands
|
||||
void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
void PositionItemsAndDrawPrimitives( bool bDrawPrimitives );
|
||||
virtual void ShiftSubActors( int iDist );
|
||||
|
||||
int m_iNumItems;
|
||||
/**
|
||||
* @brief the current item we are focused on.
|
||||
*
|
||||
* An item at the center of the list, usually between 0 and m_SubActors.size(),
|
||||
* will approach its destination.
|
||||
*
|
||||
* The above comment was paraphrased from what was here previously. It could use
|
||||
* some clearing up. -Wolfman2000 */
|
||||
float m_fCurrentItem;
|
||||
float m_fDestinationItem;
|
||||
/**
|
||||
* @brief How many seconds are there per item?
|
||||
*
|
||||
* If this is less than zero, then we are not scrolling. */
|
||||
float m_fSecondsPerItem;
|
||||
float m_fSecondsPauseBetweenItems;
|
||||
float m_fNumItemsToDraw;
|
||||
int m_iFirstSubActorIndex;
|
||||
bool m_bLoop;
|
||||
bool m_bFastCatchup;
|
||||
bool m_bFunctionDependsOnPositionOffset;
|
||||
bool m_bFunctionDependsOnItemIndex;
|
||||
float m_fPauseCountdownSeconds;
|
||||
float m_fQuantizePixels;
|
||||
|
||||
Quad m_quadMask;
|
||||
float m_fMaskWidth, m_fMaskHeight;
|
||||
|
||||
LuaExpressionTransform m_exprTransformFunction; // params: self,offset,itemIndex,numItems
|
||||
};
|
||||
|
||||
class ActorScrollerAutoDeleteChildren : public ActorScroller
|
||||
{
|
||||
public:
|
||||
ActorScrollerAutoDeleteChildren() { DeleteChildrenWhenDone(true); }
|
||||
virtual bool AutoLoadChildren() const { return true; }
|
||||
virtual ActorScrollerAutoDeleteChildren *Copy() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2003-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 ActorScroller_H
|
||||
#define ActorScroller_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
#include "Quad.h"
|
||||
class XNode;
|
||||
#include "LuaExpressionTransform.h"
|
||||
/** @brief ActorFrame that moves its children. */
|
||||
class ActorScroller : public ActorFrame
|
||||
{
|
||||
public:
|
||||
ActorScroller();
|
||||
|
||||
void SetTransformFromReference( const LuaReference &ref );
|
||||
void SetTransformFromExpression( const RString &sTransformFunction );
|
||||
void SetTransformFromWidth( float fItemWidth );
|
||||
void SetTransformFromHeight( float fItemHeight );
|
||||
|
||||
void Load2();
|
||||
|
||||
void EnableMask( float fWidth, float fHeight );
|
||||
void DisableMask();
|
||||
|
||||
virtual void UpdateInternal( float fDelta );
|
||||
virtual void DrawPrimitives(); // handles drawing and doesn't call ActorFrame::DrawPrimitives
|
||||
|
||||
void PositionItems();
|
||||
|
||||
void LoadFromNode( const XNode *pNode );
|
||||
virtual ActorScroller *Copy() const;
|
||||
|
||||
void SetLoop( bool bLoop ) { m_bLoop = bLoop; }
|
||||
void SetNumItemsToDraw( float fNumItemsToDraw ) { m_fNumItemsToDraw = fNumItemsToDraw; }
|
||||
void SetDestinationItem( float fItemIndex ) { m_fDestinationItem = fItemIndex; }
|
||||
void SetCurrentAndDestinationItem( float fItemIndex ) { m_fCurrentItem = m_fDestinationItem = fItemIndex; }
|
||||
float GetCurrentItem() const { return m_fCurrentItem; }
|
||||
float GetDestinationItem() const { return m_fDestinationItem; }
|
||||
void ScrollThroughAllItems();
|
||||
void ScrollWithPadding( float fItemPaddingStart, float fItemPaddingEnd );
|
||||
void SetPauseCountdownSeconds( float fSecs ) { m_fPauseCountdownSeconds = fSecs; }
|
||||
void SetFastCatchup( bool bOn ) { m_bFastCatchup = bOn; }
|
||||
void SetSecondsPerItem( float fSeconds ) { m_fSecondsPerItem = fSeconds; }
|
||||
void SetSecondsPauseBetweenItems( float fSeconds ) { m_fSecondsPauseBetweenItems = fSeconds; }
|
||||
void SetNumSubdivisions( int iNumSubdivisions ) { m_exprTransformFunction.SetNumSubdivisions( iNumSubdivisions ); }
|
||||
float GetSecondsForCompleteScrollThrough() const;
|
||||
float GetSecondsToDestination() const;
|
||||
int GetNumItems() const { return m_iNumItems; }
|
||||
|
||||
// Commands
|
||||
void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
void PositionItemsAndDrawPrimitives( bool bDrawPrimitives );
|
||||
virtual void ShiftSubActors( int iDist );
|
||||
|
||||
int m_iNumItems;
|
||||
/**
|
||||
* @brief the current item we are focused on.
|
||||
*
|
||||
* An item at the center of the list, usually between 0 and m_SubActors.size(),
|
||||
* will approach its destination.
|
||||
*
|
||||
* The above comment was paraphrased from what was here previously. It could use
|
||||
* some clearing up. -Wolfman2000 */
|
||||
float m_fCurrentItem;
|
||||
float m_fDestinationItem;
|
||||
/**
|
||||
* @brief How many seconds are there per item?
|
||||
*
|
||||
* If this is less than zero, then we are not scrolling. */
|
||||
float m_fSecondsPerItem;
|
||||
float m_fSecondsPauseBetweenItems;
|
||||
float m_fNumItemsToDraw;
|
||||
int m_iFirstSubActorIndex;
|
||||
bool m_bLoop;
|
||||
bool m_bFastCatchup;
|
||||
bool m_bFunctionDependsOnPositionOffset;
|
||||
bool m_bFunctionDependsOnItemIndex;
|
||||
float m_fPauseCountdownSeconds;
|
||||
float m_fQuantizePixels;
|
||||
|
||||
Quad m_quadMask;
|
||||
float m_fMaskWidth, m_fMaskHeight;
|
||||
|
||||
LuaExpressionTransform m_exprTransformFunction; // params: self,offset,itemIndex,numItems
|
||||
};
|
||||
|
||||
class ActorScrollerAutoDeleteChildren : public ActorScroller
|
||||
{
|
||||
public:
|
||||
ActorScrollerAutoDeleteChildren() { DeleteChildrenWhenDone(true); }
|
||||
virtual bool AutoLoadChildren() const { return true; }
|
||||
virtual ActorScrollerAutoDeleteChildren *Copy() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2003-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.
|
||||
*/
|
||||
|
||||
+103
-103
@@ -1,103 +1,103 @@
|
||||
#include "global.h"
|
||||
#include "ActorSound.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "LuaManager.h"
|
||||
#include "XmlFile.h"
|
||||
#include "RageUtil.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS_WITH_NAME( ActorSound, Sound );
|
||||
|
||||
void ActorSound::Load( const RString &sPath )
|
||||
{
|
||||
m_Sound.Load( sPath, true );
|
||||
}
|
||||
|
||||
void ActorSound::Play()
|
||||
{
|
||||
// This fix makes it possible to stop and pause ActorSounds. (Also,
|
||||
// sometimes stacking sounds is annoying.) -DaisuMaster
|
||||
if( m_Sound.IsPlaying() )
|
||||
{
|
||||
m_Sound.PlayCopy();
|
||||
return;
|
||||
}
|
||||
m_Sound.StartPlaying();
|
||||
}
|
||||
|
||||
void ActorSound::Pause( bool bPause )
|
||||
{
|
||||
m_Sound.Pause(bPause);
|
||||
}
|
||||
|
||||
void ActorSound::Stop()
|
||||
{
|
||||
m_Sound.Stop();
|
||||
}
|
||||
|
||||
void ActorSound::LoadFromNode( const XNode* pNode )
|
||||
{
|
||||
RageSoundLoadParams params;
|
||||
pNode->GetAttrValue("SupportPan", params.m_bSupportPan);
|
||||
pNode->GetAttrValue("SupportRateChanging", params.m_bSupportRateChanging);
|
||||
|
||||
bool bPrecache = true;
|
||||
pNode->GetAttrValue( "Precache", bPrecache );
|
||||
|
||||
Actor::LoadFromNode( pNode );
|
||||
|
||||
RString sFile;
|
||||
if( ActorUtil::GetAttrPath(pNode, "File", sFile) )
|
||||
m_Sound.Load( sFile, bPrecache, ¶ms );
|
||||
}
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the ActorSound. */
|
||||
class LunaActorSound: public Luna<ActorSound>
|
||||
{
|
||||
public:
|
||||
static int load( T* p, lua_State *L ) { p->Load(SArg(1)); return 0; }
|
||||
static int play( T* p, lua_State *L ) { p->Play(); return 0; }
|
||||
static int pause( T* p, lua_State *L ) { p->Pause(BArg(1)); return 0; }
|
||||
static int stop( T* p, lua_State *L ) { p->Stop(); return 0; }
|
||||
static int get( T* p, lua_State *L ) { p->PushSound( L ); return 1; }
|
||||
|
||||
LunaActorSound()
|
||||
{
|
||||
ADD_METHOD( load );
|
||||
ADD_METHOD( play );
|
||||
ADD_METHOD( pause );
|
||||
ADD_METHOD( stop );
|
||||
ADD_METHOD( get );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( ActorSound, Actor )
|
||||
// lua end
|
||||
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
#include "global.h"
|
||||
#include "ActorSound.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "LuaManager.h"
|
||||
#include "XmlFile.h"
|
||||
#include "RageUtil.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS_WITH_NAME( ActorSound, Sound );
|
||||
|
||||
void ActorSound::Load( const RString &sPath )
|
||||
{
|
||||
m_Sound.Load( sPath, true );
|
||||
}
|
||||
|
||||
void ActorSound::Play()
|
||||
{
|
||||
// This fix makes it possible to stop and pause ActorSounds. (Also,
|
||||
// sometimes stacking sounds is annoying.) -DaisuMaster
|
||||
if( m_Sound.IsPlaying() )
|
||||
{
|
||||
m_Sound.PlayCopy();
|
||||
return;
|
||||
}
|
||||
m_Sound.StartPlaying();
|
||||
}
|
||||
|
||||
void ActorSound::Pause( bool bPause )
|
||||
{
|
||||
m_Sound.Pause(bPause);
|
||||
}
|
||||
|
||||
void ActorSound::Stop()
|
||||
{
|
||||
m_Sound.Stop();
|
||||
}
|
||||
|
||||
void ActorSound::LoadFromNode( const XNode* pNode )
|
||||
{
|
||||
RageSoundLoadParams params;
|
||||
pNode->GetAttrValue("SupportPan", params.m_bSupportPan);
|
||||
pNode->GetAttrValue("SupportRateChanging", params.m_bSupportRateChanging);
|
||||
|
||||
bool bPrecache = true;
|
||||
pNode->GetAttrValue( "Precache", bPrecache );
|
||||
|
||||
Actor::LoadFromNode( pNode );
|
||||
|
||||
RString sFile;
|
||||
if( ActorUtil::GetAttrPath(pNode, "File", sFile) )
|
||||
m_Sound.Load( sFile, bPrecache, ¶ms );
|
||||
}
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the ActorSound. */
|
||||
class LunaActorSound: public Luna<ActorSound>
|
||||
{
|
||||
public:
|
||||
static int load( T* p, lua_State *L ) { p->Load(SArg(1)); return 0; }
|
||||
static int play( T* p, lua_State *L ) { p->Play(); return 0; }
|
||||
static int pause( T* p, lua_State *L ) { p->Pause(BArg(1)); return 0; }
|
||||
static int stop( T* p, lua_State *L ) { p->Stop(); return 0; }
|
||||
static int get( T* p, lua_State *L ) { p->PushSound( L ); return 1; }
|
||||
|
||||
LunaActorSound()
|
||||
{
|
||||
ADD_METHOD( load );
|
||||
ADD_METHOD( play );
|
||||
ADD_METHOD( pause );
|
||||
ADD_METHOD( stop );
|
||||
ADD_METHOD( get );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( ActorSound, Actor )
|
||||
// lua end
|
||||
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
+56
-56
@@ -1,56 +1,56 @@
|
||||
#ifndef ACTOR_SOUND_H
|
||||
#define ACTOR_SOUND_H
|
||||
|
||||
#include "Actor.h"
|
||||
#include "RageSound.h"
|
||||
/** @brief RageSound Actor interface. */
|
||||
class ActorSound: public Actor
|
||||
{
|
||||
public:
|
||||
virtual ~ActorSound() { }
|
||||
virtual ActorSound *Copy() const;
|
||||
|
||||
void Load( const RString &sPath );
|
||||
void Play();
|
||||
void Pause( bool bPause );
|
||||
void Stop();
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
void PushSound( lua_State *L ) { m_Sound.PushSelf( L ); }
|
||||
|
||||
//
|
||||
// Lua
|
||||
//
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
private:
|
||||
RageSound m_Sound;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Glenn Maynard (c) 2005
|
||||
* @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 ACTOR_SOUND_H
|
||||
#define ACTOR_SOUND_H
|
||||
|
||||
#include "Actor.h"
|
||||
#include "RageSound.h"
|
||||
/** @brief RageSound Actor interface. */
|
||||
class ActorSound: public Actor
|
||||
{
|
||||
public:
|
||||
virtual ~ActorSound() { }
|
||||
virtual ActorSound *Copy() const;
|
||||
|
||||
void Load( const RString &sPath );
|
||||
void Play();
|
||||
void Pause( bool bPause );
|
||||
void Stop();
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
void PushSound( lua_State *L ) { m_Sound.PushSelf( L ); }
|
||||
|
||||
//
|
||||
// Lua
|
||||
//
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
private:
|
||||
RageSound m_Sound;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Glenn Maynard (c) 2005
|
||||
* @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.
|
||||
*/
|
||||
|
||||
+484
-484
@@ -1,484 +1,484 @@
|
||||
#include "global.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "ThemeManager.h"
|
||||
#include "RageFileManager.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageUtil.h"
|
||||
#include "EnumHelper.h"
|
||||
#include "XmlFile.h"
|
||||
#include "XmlFileUtil.h"
|
||||
#include "LuaManager.h"
|
||||
#include "Foreach.h"
|
||||
|
||||
#include "arch/Dialog/Dialog.h"
|
||||
|
||||
|
||||
// Actor registration
|
||||
static map<RString,CreateActorFn> *g_pmapRegistrees = NULL;
|
||||
|
||||
static bool IsRegistered( const RString& sClassName )
|
||||
{
|
||||
return g_pmapRegistrees->find( sClassName ) != g_pmapRegistrees->end();
|
||||
}
|
||||
|
||||
void ActorUtil::Register( const RString& sClassName, CreateActorFn pfn )
|
||||
{
|
||||
if( g_pmapRegistrees == NULL )
|
||||
g_pmapRegistrees = new map<RString,CreateActorFn>;
|
||||
|
||||
map<RString,CreateActorFn>::iterator iter = g_pmapRegistrees->find( sClassName );
|
||||
ASSERT_M( iter == g_pmapRegistrees->end(), ssprintf("Actor class '%s' already registered.", sClassName.c_str()) );
|
||||
|
||||
(*g_pmapRegistrees)[sClassName] = pfn;
|
||||
}
|
||||
|
||||
bool ActorUtil::ResolvePath( RString &sPath, const RString &sName )
|
||||
{
|
||||
retry:
|
||||
CollapsePath( sPath );
|
||||
|
||||
// If we know this is an exact match, don't bother with the GetDirListing,
|
||||
// so "foo" doesn't partial match "foobar" if "foo" exists.
|
||||
RageFileManager::FileType ft = FILEMAN->GetFileType( sPath );
|
||||
if( ft != RageFileManager::TYPE_FILE && ft != RageFileManager::TYPE_DIR )
|
||||
{
|
||||
vector<RString> asPaths;
|
||||
GetDirListing( sPath + "*", asPaths, false, true ); // return path too
|
||||
|
||||
if( asPaths.empty() )
|
||||
{
|
||||
RString sError = ssprintf( "%s: references a file \"%s\" which doesn't exist", sName.c_str(), sPath.c_str() );
|
||||
switch( Dialog::AbortRetryIgnore( sError, "BROKEN_FILE_REFERENCE" ) )
|
||||
{
|
||||
case Dialog::abort:
|
||||
RageException::Throw( "%s", sError.c_str() );
|
||||
break;
|
||||
case Dialog::retry:
|
||||
FILEMAN->FlushDirCache();
|
||||
goto retry;
|
||||
case Dialog::ignore:
|
||||
return false;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
THEME->FilterFileLanguages( asPaths );
|
||||
|
||||
if( asPaths.size() > 1 )
|
||||
{
|
||||
RString sError = ssprintf( "%s: references a file \"%s\" which has multiple matches", sName.c_str(), sPath.c_str() );
|
||||
sError += "\n" + join( "\n", asPaths );
|
||||
switch( Dialog::AbortRetryIgnore( sError, "BROKEN_FILE_REFERENCE" ) )
|
||||
{
|
||||
case Dialog::abort:
|
||||
RageException::Throw( "%s", sError.c_str() );
|
||||
break;
|
||||
case Dialog::retry:
|
||||
FILEMAN->FlushDirCache();
|
||||
goto retry;
|
||||
case Dialog::ignore:
|
||||
asPaths.erase( asPaths.begin()+1, asPaths.end() );
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
sPath = asPaths[0];
|
||||
}
|
||||
|
||||
if( ft == RageFileManager::TYPE_DIR )
|
||||
{
|
||||
RString sLuaPath = sPath + "/default.lua";
|
||||
if( DoesFileExist(sLuaPath) )
|
||||
{
|
||||
sPath = sLuaPath;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
sPath = DerefRedir( sPath );
|
||||
return true;
|
||||
}
|
||||
|
||||
Actor* ActorUtil::LoadFromNode( const XNode* pNode, Actor *pParentActor )
|
||||
{
|
||||
ASSERT( pNode );
|
||||
|
||||
// Remove this in favor of using conditionals in Lua. -Chris
|
||||
// There are a number of themes out there that depend on this (including
|
||||
// sm-ssc default). Probably for the best to leave this in. -aj
|
||||
{
|
||||
bool bCond;
|
||||
if( pNode->GetAttrValue("Condition", bCond) && !bCond )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RString sClass;
|
||||
pNode->GetAttrValue( "Class", sClass );
|
||||
|
||||
map<RString,CreateActorFn>::iterator iter = g_pmapRegistrees->find( sClass );
|
||||
if( iter == g_pmapRegistrees->end() )
|
||||
{
|
||||
// sClass is invalid
|
||||
RString sError = ssprintf( "%s: invalid Class \"%s\"",
|
||||
ActorUtil::GetWhere(pNode).c_str(), sClass.c_str() );
|
||||
Dialog::OK( sError );
|
||||
return new Actor; // Return a dummy object so that we don't crash in AutoActor later.
|
||||
}
|
||||
|
||||
const CreateActorFn &pfn = iter->second;
|
||||
Actor *pRet = pfn();
|
||||
|
||||
if( pParentActor )
|
||||
pRet->SetParent( pParentActor );
|
||||
|
||||
pRet->LoadFromNode( pNode );
|
||||
return pRet;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
XNode *LoadXNodeFromLuaShowErrors( const RString &sFile )
|
||||
{
|
||||
RString sScript;
|
||||
if( !GetFileContents(sFile, sScript) )
|
||||
return NULL;
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
|
||||
RString sError;
|
||||
if( !LuaHelpers::LoadScript(L, sScript, "@" + sFile, sError) )
|
||||
{
|
||||
LUA->Release( L );
|
||||
sError = ssprintf( "Lua runtime error: %s", sError.c_str() );
|
||||
Dialog::OK( sError, "LUA_ERROR" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XNode *pRet = NULL;
|
||||
if( ActorUtil::LoadTableFromStackShowErrors(L) )
|
||||
pRet = XmlFileUtil::XNodeFromTable( L );
|
||||
|
||||
LUA->Release( L );
|
||||
return pRet;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run the function at the top of the stack, which returns an actor description
|
||||
* table. If the table was returned, return true and leave it on the stack.
|
||||
* If not, display an error, return false, and leave nothing on the stack. */
|
||||
bool ActorUtil::LoadTableFromStackShowErrors( Lua *L )
|
||||
{
|
||||
LuaReference func;
|
||||
lua_pushvalue( L, -1 );
|
||||
func.SetFromStack( L );
|
||||
|
||||
RString sError;
|
||||
if( !LuaHelpers::RunScriptOnStack(L, sError, 0, 1) )
|
||||
{
|
||||
lua_pop( L, 1 );
|
||||
sError = ssprintf( "Lua runtime error: %s", sError.c_str() );
|
||||
Dialog::OK( sError, "LUA_ERROR" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( lua_type(L, -1) != LUA_TTABLE )
|
||||
{
|
||||
lua_pop( L, 1 );
|
||||
|
||||
func.PushSelf( L );
|
||||
lua_Debug debug;
|
||||
lua_getinfo( L, ">nS", &debug );
|
||||
|
||||
sError = ssprintf( "%s: must return a table", debug.short_src );
|
||||
|
||||
Dialog::OK( sError, "LUA_ERROR" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Actor* ActorUtil::MakeActor( const RString &sPath_, Actor *pParentActor )
|
||||
{
|
||||
RString sPath( sPath_ );
|
||||
|
||||
FileType ft = GetFileType( sPath );
|
||||
switch( ft )
|
||||
{
|
||||
case FT_Lua:
|
||||
{
|
||||
auto_ptr<XNode> pNode( LoadXNodeFromLuaShowErrors(sPath) );
|
||||
if( pNode.get() == NULL )
|
||||
{
|
||||
// XNode will warn about the error
|
||||
return new Actor;
|
||||
}
|
||||
|
||||
Actor *pRet = ActorUtil::LoadFromNode( pNode.get(), pParentActor );
|
||||
return pRet;
|
||||
}
|
||||
case FT_Directory:
|
||||
{
|
||||
if( sPath.Right(1) != "/" )
|
||||
sPath += '/';
|
||||
XNode xml;
|
||||
xml.AppendAttr( "Class", "BGAnimation" );
|
||||
xml.AppendAttr( "AniDir", sPath );
|
||||
|
||||
return ActorUtil::LoadFromNode( &xml, pParentActor );
|
||||
}
|
||||
case FT_Bitmap:
|
||||
case FT_Movie:
|
||||
{
|
||||
XNode xml;
|
||||
xml.AppendAttr( "Class", "Sprite" );
|
||||
xml.AppendAttr( "Texture", sPath );
|
||||
|
||||
return ActorUtil::LoadFromNode( &xml, pParentActor );
|
||||
}
|
||||
case FT_Model:
|
||||
{
|
||||
XNode xml;
|
||||
xml.AppendAttr( "Class", "Model" );
|
||||
xml.AppendAttr( "Meshes", sPath );
|
||||
xml.AppendAttr( "Materials", sPath );
|
||||
xml.AppendAttr( "Bones", sPath );
|
||||
|
||||
return ActorUtil::LoadFromNode( &xml, pParentActor );
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG->Warn( "File \"%s\" has unknown type, \"%s\".", sPath.c_str(), FileTypeToString(ft).c_str() );
|
||||
|
||||
XNode xml;
|
||||
xml.AppendAttr( "Class", "Actor" );
|
||||
return ActorUtil::LoadFromNode( &xml, pParentActor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RString ActorUtil::GetSourcePath( const XNode *pNode )
|
||||
{
|
||||
RString sRet;
|
||||
pNode->GetAttrValue( "_Source", sRet );
|
||||
if( sRet.substr(0, 1) == "@" )
|
||||
sRet.erase( 0, 1 );
|
||||
|
||||
return sRet;
|
||||
}
|
||||
|
||||
RString ActorUtil::GetWhere( const XNode *pNode )
|
||||
{
|
||||
RString sPath = GetSourcePath( pNode );
|
||||
|
||||
int iLine;
|
||||
if( pNode->GetAttrValue("_Line", iLine) )
|
||||
sPath += ssprintf( ":%i", iLine );
|
||||
return sPath;
|
||||
}
|
||||
|
||||
bool ActorUtil::GetAttrPath( const XNode *pNode, const RString &sName, RString &sOut )
|
||||
{
|
||||
if( !pNode->GetAttrValue(sName, sOut) )
|
||||
return false;
|
||||
|
||||
bool bIsRelativePath = sOut.Left(1) != "/";
|
||||
if( bIsRelativePath )
|
||||
{
|
||||
RString sDir;
|
||||
if( !pNode->GetAttrValue("_Dir", sDir) )
|
||||
{
|
||||
LOG->Warn( "Relative path \"%s\", but path is unknown", sOut.c_str() );
|
||||
return false;
|
||||
}
|
||||
sOut = sDir+sOut;
|
||||
}
|
||||
|
||||
return ActorUtil::ResolvePath( sOut, ActorUtil::GetWhere(pNode) );
|
||||
}
|
||||
|
||||
apActorCommands ActorUtil::ParseActorCommands( const RString &sCommands, const RString &sName )
|
||||
{
|
||||
Lua *L = LUA->Get();
|
||||
LuaHelpers::ParseCommandList( L, sCommands, sName );
|
||||
LuaReference *pRet = new LuaReference;
|
||||
pRet->SetFromStack( L );
|
||||
LUA->Release( L );
|
||||
|
||||
return apActorCommands( pRet );
|
||||
}
|
||||
|
||||
void ActorUtil::SetXY( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
ASSERT( !actor.GetName().empty() );
|
||||
|
||||
/*
|
||||
* Hack: This is run after InitCommand, and InitCommand might set X/Y. If
|
||||
* these are both 0, leave the actor where it is. If InitCommand doesn't,
|
||||
* then 0,0 is the default, anyway.
|
||||
*/
|
||||
float fX = THEME->GetMetricF(sMetricsGroup,actor.GetName()+"X");
|
||||
float fY = THEME->GetMetricF(sMetricsGroup,actor.GetName()+"Y");
|
||||
if( fX != 0 || fY != 0 )
|
||||
actor.SetXY( fX, fY );
|
||||
}
|
||||
|
||||
void ActorUtil::LoadCommand( Actor& actor, const RString &sMetricsGroup, const RString &sCommandName )
|
||||
{
|
||||
ActorUtil::LoadCommandFromName( actor, sMetricsGroup, sCommandName, actor.GetName() );
|
||||
}
|
||||
|
||||
void ActorUtil::LoadCommandFromName( Actor& actor, const RString &sMetricsGroup, const RString &sCommandName, const RString &sName )
|
||||
{
|
||||
actor.AddCommand( sCommandName, THEME->GetMetricA(sMetricsGroup,sName+sCommandName+"Command") );
|
||||
}
|
||||
|
||||
void ActorUtil::LoadAllCommands( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
LoadAllCommandsFromName( actor, sMetricsGroup, actor.GetName() );
|
||||
}
|
||||
|
||||
void ActorUtil::LoadAllCommandsFromName( Actor& actor, const RString &sMetricsGroup, const RString &sName )
|
||||
{
|
||||
set<RString> vsValueNames;
|
||||
THEME->GetMetricsThatBeginWith( sMetricsGroup, sName, vsValueNames );
|
||||
|
||||
FOREACHS_CONST( RString, vsValueNames, v )
|
||||
{
|
||||
const RString &sv = *v;
|
||||
static const RString sEnding = "Command";
|
||||
if( EndsWith(sv,sEnding) )
|
||||
{
|
||||
RString sCommandName( sv.begin()+sName.size(), sv.end()-sEnding.size() );
|
||||
LoadCommandFromName( actor, sMetricsGroup, sCommandName, sName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool CompareActorsByZPosition(const Actor *p1, const Actor *p2)
|
||||
{
|
||||
return p1->GetZ() < p2->GetZ();
|
||||
}
|
||||
|
||||
void ActorUtil::SortByZPosition( vector<Actor*> &vActors )
|
||||
{
|
||||
// Preserve ordering of Actors with equal Z positions.
|
||||
stable_sort( vActors.begin(), vActors.end(), CompareActorsByZPosition );
|
||||
}
|
||||
|
||||
static const char *FileTypeNames[] = {
|
||||
"Bitmap",
|
||||
"Sound",
|
||||
"Movie",
|
||||
"Directory",
|
||||
"Lua",
|
||||
"Model",
|
||||
};
|
||||
XToString( FileType );
|
||||
LuaXType( FileType );
|
||||
|
||||
FileType ActorUtil::GetFileType( const RString &sPath )
|
||||
{
|
||||
RString sExt = GetExtension( sPath );
|
||||
sExt.MakeLower();
|
||||
|
||||
if( sExt=="lua" ) return FT_Lua;
|
||||
else if(
|
||||
sExt=="png" ||
|
||||
sExt=="jpg" ||
|
||||
sExt=="gif" ||
|
||||
sExt=="bmp" ) return FT_Bitmap;
|
||||
else if(
|
||||
sExt=="ogg" ||
|
||||
sExt=="oga" ||
|
||||
sExt=="wav" ||
|
||||
sExt=="mp3" ) return FT_Sound;
|
||||
else if(
|
||||
sExt=="ogv" ||
|
||||
sExt=="avi" ||
|
||||
sExt=="mpeg" ||
|
||||
sExt=="mpg" ) return FT_Movie;
|
||||
else if(
|
||||
sExt=="txt" ) return FT_Model;
|
||||
else if( sPath.size() > 0 && sPath[sPath.size()-1] == '/' )
|
||||
return FT_Directory;
|
||||
/* Do this last, to avoid the IsADirectory in most cases. */
|
||||
else if( IsADirectory(sPath) ) return FT_Directory;
|
||||
else return FileType_Invalid;
|
||||
}
|
||||
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
int GetFileType( lua_State *L ) { Enum::Push( L, ActorUtil::GetFileType(SArg(1)) ); return 1; }
|
||||
int ResolvePath( lua_State *L )
|
||||
{
|
||||
RString sPath( SArg(1) );
|
||||
int iLevel = IArg(2);
|
||||
luaL_where( L, iLevel );
|
||||
RString sWhere = lua_tostring( L, -1 );
|
||||
if( sWhere.size() > 2 && sWhere.substr(sWhere.size()-2, 2) == ": " )
|
||||
sWhere = sWhere.substr( 0, sWhere.size()-2 ); // remove trailing ": "
|
||||
|
||||
LUA->YieldLua();
|
||||
bool bRet = ActorUtil::ResolvePath( sPath, sWhere );
|
||||
LUA->UnyieldLua();
|
||||
|
||||
if( !bRet )
|
||||
return 0;
|
||||
LuaHelpers::Push( L, sPath );
|
||||
return 1;
|
||||
}
|
||||
int IsRegisteredClass( lua_State *L )
|
||||
{
|
||||
lua_pushboolean( L, IsRegistered(SArg(1)) );
|
||||
return 1;
|
||||
}
|
||||
static int LoadAllCommandsAndSetXY( lua_State *L )
|
||||
{
|
||||
Actor *p = Luna<Actor>::check( L, 1 );
|
||||
ActorUtil::LoadAllCommandsAndSetXY( p, SArg(2) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg ActorUtilTable[] =
|
||||
{
|
||||
LIST_METHOD( GetFileType ),
|
||||
LIST_METHOD( ResolvePath ),
|
||||
LIST_METHOD( IsRegisteredClass ),
|
||||
LIST_METHOD( LoadAllCommandsAndSetXY ),
|
||||
{ NULL, NULL }
|
||||
};
|
||||
}
|
||||
|
||||
LUA_REGISTER_NAMESPACE( ActorUtil )
|
||||
|
||||
/*
|
||||
* (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 "ActorUtil.h"
|
||||
#include "ThemeManager.h"
|
||||
#include "RageFileManager.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageUtil.h"
|
||||
#include "EnumHelper.h"
|
||||
#include "XmlFile.h"
|
||||
#include "XmlFileUtil.h"
|
||||
#include "LuaManager.h"
|
||||
#include "Foreach.h"
|
||||
|
||||
#include "arch/Dialog/Dialog.h"
|
||||
|
||||
|
||||
// Actor registration
|
||||
static map<RString,CreateActorFn> *g_pmapRegistrees = NULL;
|
||||
|
||||
static bool IsRegistered( const RString& sClassName )
|
||||
{
|
||||
return g_pmapRegistrees->find( sClassName ) != g_pmapRegistrees->end();
|
||||
}
|
||||
|
||||
void ActorUtil::Register( const RString& sClassName, CreateActorFn pfn )
|
||||
{
|
||||
if( g_pmapRegistrees == NULL )
|
||||
g_pmapRegistrees = new map<RString,CreateActorFn>;
|
||||
|
||||
map<RString,CreateActorFn>::iterator iter = g_pmapRegistrees->find( sClassName );
|
||||
ASSERT_M( iter == g_pmapRegistrees->end(), ssprintf("Actor class '%s' already registered.", sClassName.c_str()) );
|
||||
|
||||
(*g_pmapRegistrees)[sClassName] = pfn;
|
||||
}
|
||||
|
||||
bool ActorUtil::ResolvePath( RString &sPath, const RString &sName )
|
||||
{
|
||||
retry:
|
||||
CollapsePath( sPath );
|
||||
|
||||
// If we know this is an exact match, don't bother with the GetDirListing,
|
||||
// so "foo" doesn't partial match "foobar" if "foo" exists.
|
||||
RageFileManager::FileType ft = FILEMAN->GetFileType( sPath );
|
||||
if( ft != RageFileManager::TYPE_FILE && ft != RageFileManager::TYPE_DIR )
|
||||
{
|
||||
vector<RString> asPaths;
|
||||
GetDirListing( sPath + "*", asPaths, false, true ); // return path too
|
||||
|
||||
if( asPaths.empty() )
|
||||
{
|
||||
RString sError = ssprintf( "%s: references a file \"%s\" which doesn't exist", sName.c_str(), sPath.c_str() );
|
||||
switch( Dialog::AbortRetryIgnore( sError, "BROKEN_FILE_REFERENCE" ) )
|
||||
{
|
||||
case Dialog::abort:
|
||||
RageException::Throw( "%s", sError.c_str() );
|
||||
break;
|
||||
case Dialog::retry:
|
||||
FILEMAN->FlushDirCache();
|
||||
goto retry;
|
||||
case Dialog::ignore:
|
||||
return false;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
THEME->FilterFileLanguages( asPaths );
|
||||
|
||||
if( asPaths.size() > 1 )
|
||||
{
|
||||
RString sError = ssprintf( "%s: references a file \"%s\" which has multiple matches", sName.c_str(), sPath.c_str() );
|
||||
sError += "\n" + join( "\n", asPaths );
|
||||
switch( Dialog::AbortRetryIgnore( sError, "BROKEN_FILE_REFERENCE" ) )
|
||||
{
|
||||
case Dialog::abort:
|
||||
RageException::Throw( "%s", sError.c_str() );
|
||||
break;
|
||||
case Dialog::retry:
|
||||
FILEMAN->FlushDirCache();
|
||||
goto retry;
|
||||
case Dialog::ignore:
|
||||
asPaths.erase( asPaths.begin()+1, asPaths.end() );
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
sPath = asPaths[0];
|
||||
}
|
||||
|
||||
if( ft == RageFileManager::TYPE_DIR )
|
||||
{
|
||||
RString sLuaPath = sPath + "/default.lua";
|
||||
if( DoesFileExist(sLuaPath) )
|
||||
{
|
||||
sPath = sLuaPath;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
sPath = DerefRedir( sPath );
|
||||
return true;
|
||||
}
|
||||
|
||||
Actor* ActorUtil::LoadFromNode( const XNode* pNode, Actor *pParentActor )
|
||||
{
|
||||
ASSERT( pNode );
|
||||
|
||||
// Remove this in favor of using conditionals in Lua. -Chris
|
||||
// There are a number of themes out there that depend on this (including
|
||||
// sm-ssc default). Probably for the best to leave this in. -aj
|
||||
{
|
||||
bool bCond;
|
||||
if( pNode->GetAttrValue("Condition", bCond) && !bCond )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RString sClass;
|
||||
pNode->GetAttrValue( "Class", sClass );
|
||||
|
||||
map<RString,CreateActorFn>::iterator iter = g_pmapRegistrees->find( sClass );
|
||||
if( iter == g_pmapRegistrees->end() )
|
||||
{
|
||||
// sClass is invalid
|
||||
RString sError = ssprintf( "%s: invalid Class \"%s\"",
|
||||
ActorUtil::GetWhere(pNode).c_str(), sClass.c_str() );
|
||||
Dialog::OK( sError );
|
||||
return new Actor; // Return a dummy object so that we don't crash in AutoActor later.
|
||||
}
|
||||
|
||||
const CreateActorFn &pfn = iter->second;
|
||||
Actor *pRet = pfn();
|
||||
|
||||
if( pParentActor )
|
||||
pRet->SetParent( pParentActor );
|
||||
|
||||
pRet->LoadFromNode( pNode );
|
||||
return pRet;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
XNode *LoadXNodeFromLuaShowErrors( const RString &sFile )
|
||||
{
|
||||
RString sScript;
|
||||
if( !GetFileContents(sFile, sScript) )
|
||||
return NULL;
|
||||
|
||||
Lua *L = LUA->Get();
|
||||
|
||||
RString sError;
|
||||
if( !LuaHelpers::LoadScript(L, sScript, "@" + sFile, sError) )
|
||||
{
|
||||
LUA->Release( L );
|
||||
sError = ssprintf( "Lua runtime error: %s", sError.c_str() );
|
||||
Dialog::OK( sError, "LUA_ERROR" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XNode *pRet = NULL;
|
||||
if( ActorUtil::LoadTableFromStackShowErrors(L) )
|
||||
pRet = XmlFileUtil::XNodeFromTable( L );
|
||||
|
||||
LUA->Release( L );
|
||||
return pRet;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run the function at the top of the stack, which returns an actor description
|
||||
* table. If the table was returned, return true and leave it on the stack.
|
||||
* If not, display an error, return false, and leave nothing on the stack. */
|
||||
bool ActorUtil::LoadTableFromStackShowErrors( Lua *L )
|
||||
{
|
||||
LuaReference func;
|
||||
lua_pushvalue( L, -1 );
|
||||
func.SetFromStack( L );
|
||||
|
||||
RString sError;
|
||||
if( !LuaHelpers::RunScriptOnStack(L, sError, 0, 1) )
|
||||
{
|
||||
lua_pop( L, 1 );
|
||||
sError = ssprintf( "Lua runtime error: %s", sError.c_str() );
|
||||
Dialog::OK( sError, "LUA_ERROR" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( lua_type(L, -1) != LUA_TTABLE )
|
||||
{
|
||||
lua_pop( L, 1 );
|
||||
|
||||
func.PushSelf( L );
|
||||
lua_Debug debug;
|
||||
lua_getinfo( L, ">nS", &debug );
|
||||
|
||||
sError = ssprintf( "%s: must return a table", debug.short_src );
|
||||
|
||||
Dialog::OK( sError, "LUA_ERROR" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Actor* ActorUtil::MakeActor( const RString &sPath_, Actor *pParentActor )
|
||||
{
|
||||
RString sPath( sPath_ );
|
||||
|
||||
FileType ft = GetFileType( sPath );
|
||||
switch( ft )
|
||||
{
|
||||
case FT_Lua:
|
||||
{
|
||||
auto_ptr<XNode> pNode( LoadXNodeFromLuaShowErrors(sPath) );
|
||||
if( pNode.get() == NULL )
|
||||
{
|
||||
// XNode will warn about the error
|
||||
return new Actor;
|
||||
}
|
||||
|
||||
Actor *pRet = ActorUtil::LoadFromNode( pNode.get(), pParentActor );
|
||||
return pRet;
|
||||
}
|
||||
case FT_Directory:
|
||||
{
|
||||
if( sPath.Right(1) != "/" )
|
||||
sPath += '/';
|
||||
XNode xml;
|
||||
xml.AppendAttr( "Class", "BGAnimation" );
|
||||
xml.AppendAttr( "AniDir", sPath );
|
||||
|
||||
return ActorUtil::LoadFromNode( &xml, pParentActor );
|
||||
}
|
||||
case FT_Bitmap:
|
||||
case FT_Movie:
|
||||
{
|
||||
XNode xml;
|
||||
xml.AppendAttr( "Class", "Sprite" );
|
||||
xml.AppendAttr( "Texture", sPath );
|
||||
|
||||
return ActorUtil::LoadFromNode( &xml, pParentActor );
|
||||
}
|
||||
case FT_Model:
|
||||
{
|
||||
XNode xml;
|
||||
xml.AppendAttr( "Class", "Model" );
|
||||
xml.AppendAttr( "Meshes", sPath );
|
||||
xml.AppendAttr( "Materials", sPath );
|
||||
xml.AppendAttr( "Bones", sPath );
|
||||
|
||||
return ActorUtil::LoadFromNode( &xml, pParentActor );
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG->Warn( "File \"%s\" has unknown type, \"%s\".", sPath.c_str(), FileTypeToString(ft).c_str() );
|
||||
|
||||
XNode xml;
|
||||
xml.AppendAttr( "Class", "Actor" );
|
||||
return ActorUtil::LoadFromNode( &xml, pParentActor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RString ActorUtil::GetSourcePath( const XNode *pNode )
|
||||
{
|
||||
RString sRet;
|
||||
pNode->GetAttrValue( "_Source", sRet );
|
||||
if( sRet.substr(0, 1) == "@" )
|
||||
sRet.erase( 0, 1 );
|
||||
|
||||
return sRet;
|
||||
}
|
||||
|
||||
RString ActorUtil::GetWhere( const XNode *pNode )
|
||||
{
|
||||
RString sPath = GetSourcePath( pNode );
|
||||
|
||||
int iLine;
|
||||
if( pNode->GetAttrValue("_Line", iLine) )
|
||||
sPath += ssprintf( ":%i", iLine );
|
||||
return sPath;
|
||||
}
|
||||
|
||||
bool ActorUtil::GetAttrPath( const XNode *pNode, const RString &sName, RString &sOut )
|
||||
{
|
||||
if( !pNode->GetAttrValue(sName, sOut) )
|
||||
return false;
|
||||
|
||||
bool bIsRelativePath = sOut.Left(1) != "/";
|
||||
if( bIsRelativePath )
|
||||
{
|
||||
RString sDir;
|
||||
if( !pNode->GetAttrValue("_Dir", sDir) )
|
||||
{
|
||||
LOG->Warn( "Relative path \"%s\", but path is unknown", sOut.c_str() );
|
||||
return false;
|
||||
}
|
||||
sOut = sDir+sOut;
|
||||
}
|
||||
|
||||
return ActorUtil::ResolvePath( sOut, ActorUtil::GetWhere(pNode) );
|
||||
}
|
||||
|
||||
apActorCommands ActorUtil::ParseActorCommands( const RString &sCommands, const RString &sName )
|
||||
{
|
||||
Lua *L = LUA->Get();
|
||||
LuaHelpers::ParseCommandList( L, sCommands, sName );
|
||||
LuaReference *pRet = new LuaReference;
|
||||
pRet->SetFromStack( L );
|
||||
LUA->Release( L );
|
||||
|
||||
return apActorCommands( pRet );
|
||||
}
|
||||
|
||||
void ActorUtil::SetXY( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
ASSERT( !actor.GetName().empty() );
|
||||
|
||||
/*
|
||||
* Hack: This is run after InitCommand, and InitCommand might set X/Y. If
|
||||
* these are both 0, leave the actor where it is. If InitCommand doesn't,
|
||||
* then 0,0 is the default, anyway.
|
||||
*/
|
||||
float fX = THEME->GetMetricF(sMetricsGroup,actor.GetName()+"X");
|
||||
float fY = THEME->GetMetricF(sMetricsGroup,actor.GetName()+"Y");
|
||||
if( fX != 0 || fY != 0 )
|
||||
actor.SetXY( fX, fY );
|
||||
}
|
||||
|
||||
void ActorUtil::LoadCommand( Actor& actor, const RString &sMetricsGroup, const RString &sCommandName )
|
||||
{
|
||||
ActorUtil::LoadCommandFromName( actor, sMetricsGroup, sCommandName, actor.GetName() );
|
||||
}
|
||||
|
||||
void ActorUtil::LoadCommandFromName( Actor& actor, const RString &sMetricsGroup, const RString &sCommandName, const RString &sName )
|
||||
{
|
||||
actor.AddCommand( sCommandName, THEME->GetMetricA(sMetricsGroup,sName+sCommandName+"Command") );
|
||||
}
|
||||
|
||||
void ActorUtil::LoadAllCommands( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
LoadAllCommandsFromName( actor, sMetricsGroup, actor.GetName() );
|
||||
}
|
||||
|
||||
void ActorUtil::LoadAllCommandsFromName( Actor& actor, const RString &sMetricsGroup, const RString &sName )
|
||||
{
|
||||
set<RString> vsValueNames;
|
||||
THEME->GetMetricsThatBeginWith( sMetricsGroup, sName, vsValueNames );
|
||||
|
||||
FOREACHS_CONST( RString, vsValueNames, v )
|
||||
{
|
||||
const RString &sv = *v;
|
||||
static const RString sEnding = "Command";
|
||||
if( EndsWith(sv,sEnding) )
|
||||
{
|
||||
RString sCommandName( sv.begin()+sName.size(), sv.end()-sEnding.size() );
|
||||
LoadCommandFromName( actor, sMetricsGroup, sCommandName, sName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool CompareActorsByZPosition(const Actor *p1, const Actor *p2)
|
||||
{
|
||||
return p1->GetZ() < p2->GetZ();
|
||||
}
|
||||
|
||||
void ActorUtil::SortByZPosition( vector<Actor*> &vActors )
|
||||
{
|
||||
// Preserve ordering of Actors with equal Z positions.
|
||||
stable_sort( vActors.begin(), vActors.end(), CompareActorsByZPosition );
|
||||
}
|
||||
|
||||
static const char *FileTypeNames[] = {
|
||||
"Bitmap",
|
||||
"Sound",
|
||||
"Movie",
|
||||
"Directory",
|
||||
"Lua",
|
||||
"Model",
|
||||
};
|
||||
XToString( FileType );
|
||||
LuaXType( FileType );
|
||||
|
||||
FileType ActorUtil::GetFileType( const RString &sPath )
|
||||
{
|
||||
RString sExt = GetExtension( sPath );
|
||||
sExt.MakeLower();
|
||||
|
||||
if( sExt=="lua" ) return FT_Lua;
|
||||
else if(
|
||||
sExt=="png" ||
|
||||
sExt=="jpg" ||
|
||||
sExt=="gif" ||
|
||||
sExt=="bmp" ) return FT_Bitmap;
|
||||
else if(
|
||||
sExt=="ogg" ||
|
||||
sExt=="oga" ||
|
||||
sExt=="wav" ||
|
||||
sExt=="mp3" ) return FT_Sound;
|
||||
else if(
|
||||
sExt=="ogv" ||
|
||||
sExt=="avi" ||
|
||||
sExt=="mpeg" ||
|
||||
sExt=="mpg" ) return FT_Movie;
|
||||
else if(
|
||||
sExt=="txt" ) return FT_Model;
|
||||
else if( sPath.size() > 0 && sPath[sPath.size()-1] == '/' )
|
||||
return FT_Directory;
|
||||
/* Do this last, to avoid the IsADirectory in most cases. */
|
||||
else if( IsADirectory(sPath) ) return FT_Directory;
|
||||
else return FileType_Invalid;
|
||||
}
|
||||
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
int GetFileType( lua_State *L ) { Enum::Push( L, ActorUtil::GetFileType(SArg(1)) ); return 1; }
|
||||
int ResolvePath( lua_State *L )
|
||||
{
|
||||
RString sPath( SArg(1) );
|
||||
int iLevel = IArg(2);
|
||||
luaL_where( L, iLevel );
|
||||
RString sWhere = lua_tostring( L, -1 );
|
||||
if( sWhere.size() > 2 && sWhere.substr(sWhere.size()-2, 2) == ": " )
|
||||
sWhere = sWhere.substr( 0, sWhere.size()-2 ); // remove trailing ": "
|
||||
|
||||
LUA->YieldLua();
|
||||
bool bRet = ActorUtil::ResolvePath( sPath, sWhere );
|
||||
LUA->UnyieldLua();
|
||||
|
||||
if( !bRet )
|
||||
return 0;
|
||||
LuaHelpers::Push( L, sPath );
|
||||
return 1;
|
||||
}
|
||||
int IsRegisteredClass( lua_State *L )
|
||||
{
|
||||
lua_pushboolean( L, IsRegistered(SArg(1)) );
|
||||
return 1;
|
||||
}
|
||||
static int LoadAllCommandsAndSetXY( lua_State *L )
|
||||
{
|
||||
Actor *p = Luna<Actor>::check( L, 1 );
|
||||
ActorUtil::LoadAllCommandsAndSetXY( p, SArg(2) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg ActorUtilTable[] =
|
||||
{
|
||||
LIST_METHOD( GetFileType ),
|
||||
LIST_METHOD( ResolvePath ),
|
||||
LIST_METHOD( IsRegisteredClass ),
|
||||
LIST_METHOD( LoadAllCommandsAndSetXY ),
|
||||
{ NULL, NULL }
|
||||
};
|
||||
}
|
||||
|
||||
LUA_REGISTER_NAMESPACE( ActorUtil )
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
+161
-161
@@ -1,161 +1,161 @@
|
||||
#ifndef ActorUtil_H
|
||||
#define ActorUtil_H
|
||||
|
||||
#include "Actor.h"
|
||||
#include "RageTexture.h"
|
||||
|
||||
class XNode;
|
||||
|
||||
typedef Actor* (*CreateActorFn)();
|
||||
|
||||
template<typename T>
|
||||
Actor *CreateActor() { return new T; }
|
||||
|
||||
/**
|
||||
* @brief Register the requested Actor with the specified external name.
|
||||
*
|
||||
* This should be called manually only if needed. */
|
||||
#define REGISTER_ACTOR_CLASS_WITH_NAME( className, externalClassName ) \
|
||||
struct Register##className { \
|
||||
Register##className() { ActorUtil::Register(#externalClassName, CreateActor<className>); } \
|
||||
}; \
|
||||
className *className::Copy() const { return new className(*this); } \
|
||||
static Register##className register##className
|
||||
|
||||
/**
|
||||
* @brief Register the requested Actor so that it's more accessible.
|
||||
*
|
||||
* Each Actor class should have a REGISTER_ACTOR_CLASS in its CPP file. */
|
||||
#define REGISTER_ACTOR_CLASS( className ) REGISTER_ACTOR_CLASS_WITH_NAME( className, className )
|
||||
|
||||
enum FileType
|
||||
{
|
||||
FT_Bitmap,
|
||||
FT_Sound,
|
||||
FT_Movie,
|
||||
FT_Directory,
|
||||
FT_Lua,
|
||||
FT_Model,
|
||||
NUM_FileType,
|
||||
FileType_Invalid
|
||||
};
|
||||
const RString& FileTypeToString( FileType ft );
|
||||
|
||||
/** @brief Utility functions for creating and manipulating Actors. */
|
||||
namespace ActorUtil
|
||||
{
|
||||
// Every screen should register its class at program initialization.
|
||||
void Register( const RString& sClassName, CreateActorFn pfn );
|
||||
|
||||
apActorCommands ParseActorCommands( const RString &sCommands, const RString &sName = "" );
|
||||
void SetXY( Actor& actor, const RString &sMetricsGroup );
|
||||
inline void PlayCommand( Actor& actor, const RString &sCommandName ) { actor.PlayCommand( sCommandName ); }
|
||||
inline void OnCommand( Actor& actor )
|
||||
{
|
||||
ASSERT_M( actor.HasCommand("On"), ssprintf("%s is missing an OnCommand.", actor.GetLineage().c_str()) );
|
||||
actor.PlayCommand("On");
|
||||
}
|
||||
inline void OffCommand( Actor& actor )
|
||||
{
|
||||
// HACK: It's very often that we command things to TweenOffScreen
|
||||
// that we aren't drawing. We know that an Actor is not being
|
||||
// used if its name is blank. So, do nothing on Actors with a blank name.
|
||||
// (Do "playcommand" anyway; BGAs often have no name.)
|
||||
if( actor.GetName().empty() )
|
||||
return;
|
||||
ASSERT_M( actor.HasCommand("Off"), ssprintf("Actor %s is missing an OffCommand.", actor.GetLineage().c_str()) );
|
||||
actor.PlayCommand("Off");
|
||||
}
|
||||
|
||||
void LoadCommand( Actor& actor, const RString &sMetricsGroup, const RString &sCommandName );
|
||||
void LoadCommandFromName( Actor& actor, const RString &sMetricsGroup, const RString &sCommandName, const RString &sName );
|
||||
void LoadAllCommands( Actor& actor, const RString &sMetricsGroup );
|
||||
void LoadAllCommandsFromName( Actor& actor, const RString &sMetricsGroup, const RString &sName );
|
||||
|
||||
inline void LoadAllCommandsAndSetXY( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
LoadAllCommands( actor, sMetricsGroup );
|
||||
SetXY( actor, sMetricsGroup );
|
||||
}
|
||||
inline void LoadAllCommandsAndOnCommand( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
LoadAllCommands( actor, sMetricsGroup );
|
||||
OnCommand( actor );
|
||||
}
|
||||
inline void SetXYAndOnCommand( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
SetXY( actor, sMetricsGroup );
|
||||
OnCommand( actor );
|
||||
}
|
||||
inline void LoadAllCommandsAndSetXYAndOnCommand( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
LoadAllCommands( actor, sMetricsGroup );
|
||||
SetXY( actor, sMetricsGroup );
|
||||
OnCommand( actor );
|
||||
}
|
||||
|
||||
/* convenience */
|
||||
inline void SetXY( Actor* pActor, const RString &sMetricsGroup ) { SetXY( *pActor, sMetricsGroup ); }
|
||||
inline void PlayCommand( Actor* pActor, const RString &sCommandName ) { if(pActor) pActor->PlayCommand( sCommandName ); }
|
||||
inline void OnCommand( Actor* pActor ) { if(pActor) ActorUtil::OnCommand( *pActor ); }
|
||||
inline void OffCommand( Actor* pActor ) { if(pActor) ActorUtil::OffCommand( *pActor ); }
|
||||
|
||||
inline void LoadAllCommands( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) LoadAllCommands( *pActor, sMetricsGroup ); }
|
||||
|
||||
inline void LoadAllCommandsAndSetXY( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) LoadAllCommandsAndSetXY( *pActor, sMetricsGroup ); }
|
||||
inline void LoadAllCommandsAndOnCommand( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) LoadAllCommandsAndOnCommand( *pActor, sMetricsGroup ); }
|
||||
inline void SetXYAndOnCommand( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) SetXYAndOnCommand( *pActor, sMetricsGroup ); }
|
||||
inline void LoadAllCommandsAndSetXYAndOnCommand( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) LoadAllCommandsAndSetXYAndOnCommand( *pActor, sMetricsGroup ); }
|
||||
|
||||
// Return a Sprite, BitmapText, or Model depending on the file type
|
||||
Actor* LoadFromNode( const XNode* pNode, Actor *pParentActor = NULL );
|
||||
Actor* MakeActor( const RString &sPath, Actor *pParentActor = NULL );
|
||||
RString GetSourcePath( const XNode *pNode );
|
||||
RString GetWhere( const XNode *pNode );
|
||||
bool GetAttrPath( const XNode *pNode, const RString &sName, RString &sOut );
|
||||
bool LoadTableFromStackShowErrors( Lua *L );
|
||||
|
||||
bool ResolvePath( RString &sPath, const RString &sName );
|
||||
|
||||
void SortByZPosition( vector<Actor*> &vActors );
|
||||
|
||||
FileType GetFileType( const RString &sPath );
|
||||
};
|
||||
|
||||
#define SET_XY( actor ) ActorUtil::SetXY( actor, m_sName )
|
||||
#define ON_COMMAND( actor ) ActorUtil::OnCommand( actor )
|
||||
#define OFF_COMMAND( actor ) ActorUtil::OffCommand( actor )
|
||||
#define SET_XY_AND_ON_COMMAND( actor ) ActorUtil::SetXYAndOnCommand( actor, m_sName )
|
||||
#define COMMAND( actor, command_name ) ActorUtil::PlayCommand( actor, command_name )
|
||||
#define LOAD_ALL_COMMANDS( actor ) ActorUtil::LoadAllCommands( actor, m_sName )
|
||||
#define LOAD_ALL_COMMANDS_AND_SET_XY( actor ) ActorUtil::LoadAllCommandsAndSetXY( actor, m_sName )
|
||||
#define LOAD_ALL_COMMANDS_AND_ON_COMMAND( actor ) ActorUtil::LoadAllCommandsAndOnCommand( actor, m_sName )
|
||||
#define LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( actor ) ActorUtil::LoadAllCommandsAndSetXYAndOnCommand( actor, m_sName )
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
#ifndef ActorUtil_H
|
||||
#define ActorUtil_H
|
||||
|
||||
#include "Actor.h"
|
||||
#include "RageTexture.h"
|
||||
|
||||
class XNode;
|
||||
|
||||
typedef Actor* (*CreateActorFn)();
|
||||
|
||||
template<typename T>
|
||||
Actor *CreateActor() { return new T; }
|
||||
|
||||
/**
|
||||
* @brief Register the requested Actor with the specified external name.
|
||||
*
|
||||
* This should be called manually only if needed. */
|
||||
#define REGISTER_ACTOR_CLASS_WITH_NAME( className, externalClassName ) \
|
||||
struct Register##className { \
|
||||
Register##className() { ActorUtil::Register(#externalClassName, CreateActor<className>); } \
|
||||
}; \
|
||||
className *className::Copy() const { return new className(*this); } \
|
||||
static Register##className register##className
|
||||
|
||||
/**
|
||||
* @brief Register the requested Actor so that it's more accessible.
|
||||
*
|
||||
* Each Actor class should have a REGISTER_ACTOR_CLASS in its CPP file. */
|
||||
#define REGISTER_ACTOR_CLASS( className ) REGISTER_ACTOR_CLASS_WITH_NAME( className, className )
|
||||
|
||||
enum FileType
|
||||
{
|
||||
FT_Bitmap,
|
||||
FT_Sound,
|
||||
FT_Movie,
|
||||
FT_Directory,
|
||||
FT_Lua,
|
||||
FT_Model,
|
||||
NUM_FileType,
|
||||
FileType_Invalid
|
||||
};
|
||||
const RString& FileTypeToString( FileType ft );
|
||||
|
||||
/** @brief Utility functions for creating and manipulating Actors. */
|
||||
namespace ActorUtil
|
||||
{
|
||||
// Every screen should register its class at program initialization.
|
||||
void Register( const RString& sClassName, CreateActorFn pfn );
|
||||
|
||||
apActorCommands ParseActorCommands( const RString &sCommands, const RString &sName = "" );
|
||||
void SetXY( Actor& actor, const RString &sMetricsGroup );
|
||||
inline void PlayCommand( Actor& actor, const RString &sCommandName ) { actor.PlayCommand( sCommandName ); }
|
||||
inline void OnCommand( Actor& actor )
|
||||
{
|
||||
ASSERT_M( actor.HasCommand("On"), ssprintf("%s is missing an OnCommand.", actor.GetLineage().c_str()) );
|
||||
actor.PlayCommand("On");
|
||||
}
|
||||
inline void OffCommand( Actor& actor )
|
||||
{
|
||||
// HACK: It's very often that we command things to TweenOffScreen
|
||||
// that we aren't drawing. We know that an Actor is not being
|
||||
// used if its name is blank. So, do nothing on Actors with a blank name.
|
||||
// (Do "playcommand" anyway; BGAs often have no name.)
|
||||
if( actor.GetName().empty() )
|
||||
return;
|
||||
ASSERT_M( actor.HasCommand("Off"), ssprintf("Actor %s is missing an OffCommand.", actor.GetLineage().c_str()) );
|
||||
actor.PlayCommand("Off");
|
||||
}
|
||||
|
||||
void LoadCommand( Actor& actor, const RString &sMetricsGroup, const RString &sCommandName );
|
||||
void LoadCommandFromName( Actor& actor, const RString &sMetricsGroup, const RString &sCommandName, const RString &sName );
|
||||
void LoadAllCommands( Actor& actor, const RString &sMetricsGroup );
|
||||
void LoadAllCommandsFromName( Actor& actor, const RString &sMetricsGroup, const RString &sName );
|
||||
|
||||
inline void LoadAllCommandsAndSetXY( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
LoadAllCommands( actor, sMetricsGroup );
|
||||
SetXY( actor, sMetricsGroup );
|
||||
}
|
||||
inline void LoadAllCommandsAndOnCommand( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
LoadAllCommands( actor, sMetricsGroup );
|
||||
OnCommand( actor );
|
||||
}
|
||||
inline void SetXYAndOnCommand( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
SetXY( actor, sMetricsGroup );
|
||||
OnCommand( actor );
|
||||
}
|
||||
inline void LoadAllCommandsAndSetXYAndOnCommand( Actor& actor, const RString &sMetricsGroup )
|
||||
{
|
||||
LoadAllCommands( actor, sMetricsGroup );
|
||||
SetXY( actor, sMetricsGroup );
|
||||
OnCommand( actor );
|
||||
}
|
||||
|
||||
/* convenience */
|
||||
inline void SetXY( Actor* pActor, const RString &sMetricsGroup ) { SetXY( *pActor, sMetricsGroup ); }
|
||||
inline void PlayCommand( Actor* pActor, const RString &sCommandName ) { if(pActor) pActor->PlayCommand( sCommandName ); }
|
||||
inline void OnCommand( Actor* pActor ) { if(pActor) ActorUtil::OnCommand( *pActor ); }
|
||||
inline void OffCommand( Actor* pActor ) { if(pActor) ActorUtil::OffCommand( *pActor ); }
|
||||
|
||||
inline void LoadAllCommands( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) LoadAllCommands( *pActor, sMetricsGroup ); }
|
||||
|
||||
inline void LoadAllCommandsAndSetXY( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) LoadAllCommandsAndSetXY( *pActor, sMetricsGroup ); }
|
||||
inline void LoadAllCommandsAndOnCommand( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) LoadAllCommandsAndOnCommand( *pActor, sMetricsGroup ); }
|
||||
inline void SetXYAndOnCommand( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) SetXYAndOnCommand( *pActor, sMetricsGroup ); }
|
||||
inline void LoadAllCommandsAndSetXYAndOnCommand( Actor* pActor, const RString &sMetricsGroup ) { if(pActor) LoadAllCommandsAndSetXYAndOnCommand( *pActor, sMetricsGroup ); }
|
||||
|
||||
// Return a Sprite, BitmapText, or Model depending on the file type
|
||||
Actor* LoadFromNode( const XNode* pNode, Actor *pParentActor = NULL );
|
||||
Actor* MakeActor( const RString &sPath, Actor *pParentActor = NULL );
|
||||
RString GetSourcePath( const XNode *pNode );
|
||||
RString GetWhere( const XNode *pNode );
|
||||
bool GetAttrPath( const XNode *pNode, const RString &sName, RString &sOut );
|
||||
bool LoadTableFromStackShowErrors( Lua *L );
|
||||
|
||||
bool ResolvePath( RString &sPath, const RString &sName );
|
||||
|
||||
void SortByZPosition( vector<Actor*> &vActors );
|
||||
|
||||
FileType GetFileType( const RString &sPath );
|
||||
};
|
||||
|
||||
#define SET_XY( actor ) ActorUtil::SetXY( actor, m_sName )
|
||||
#define ON_COMMAND( actor ) ActorUtil::OnCommand( actor )
|
||||
#define OFF_COMMAND( actor ) ActorUtil::OffCommand( actor )
|
||||
#define SET_XY_AND_ON_COMMAND( actor ) ActorUtil::SetXYAndOnCommand( actor, m_sName )
|
||||
#define COMMAND( actor, command_name ) ActorUtil::PlayCommand( actor, command_name )
|
||||
#define LOAD_ALL_COMMANDS( actor ) ActorUtil::LoadAllCommands( actor, m_sName )
|
||||
#define LOAD_ALL_COMMANDS_AND_SET_XY( actor ) ActorUtil::LoadAllCommandsAndSetXY( actor, m_sName )
|
||||
#define LOAD_ALL_COMMANDS_AND_ON_COMMAND( actor ) ActorUtil::LoadAllCommandsAndOnCommand( actor, m_sName )
|
||||
#define LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( actor ) ActorUtil::LoadAllCommandsAndSetXYAndOnCommand( actor, m_sName )
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
+388
-388
@@ -1,388 +1,388 @@
|
||||
/*
|
||||
* AdjustSync defines two methods for fixing the sync.
|
||||
*
|
||||
* The first method adjusts either the song or the machine by the
|
||||
* average offset of the user's steps. In other words, if the user
|
||||
* averages to step early by 10 ms, either the song or the global
|
||||
* offset is adjusted by 10 ms to compensate for that. These
|
||||
* adjustments only require a small set of data, so this method
|
||||
* updates the offset while the song is playing.
|
||||
*
|
||||
* The second method adjusts both the offset and the tempo of an
|
||||
* individual song. It records all of the steps during a play of
|
||||
* the song and uses linear least squares regression to minimize the
|
||||
* error of those steps. It makes one adjustment for the tempo of
|
||||
* the entire song, rather than adding many different tempo segments
|
||||
* to match the steps. If there are already several tempo segments
|
||||
* in the stepfile, this method makes a proportional change to each
|
||||
* of them. For example, if it changes 100 bpm to 101 bpm, it will
|
||||
* also change 200 bpm to 202 bpm. This method also adjusts the stops.
|
||||
* It assumes that a given stop is measured in terms of beats and makes
|
||||
* the appropriate change.
|
||||
*
|
||||
* If we use this method on a small set of data late in the song, it
|
||||
* can have very chaotic effects on the early settings. For example,
|
||||
* it may change the offset by several hundred milliseconds and make a
|
||||
* large change to the BPM to compensate if that would minimize the
|
||||
* error. This problem occurs especially when the user makes a couple
|
||||
* steps that are significantly off beat. The way to avoid this is to
|
||||
* perform the least squares regression once on all of the data
|
||||
* collected, rather than adjusting the sync every time we get another
|
||||
* 50 or so data points. In fact, if we are playing in edit mode and
|
||||
* the user loops through the song more than once, we use all of the
|
||||
* steps made.
|
||||
*/
|
||||
|
||||
#include "global.h"
|
||||
#include "Song.h"
|
||||
#include "AdjustSync.h"
|
||||
#include "GameState.h"
|
||||
#include "LocalizedString.h"
|
||||
#include "PrefsManager.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Foreach.h"
|
||||
|
||||
TimingData *AdjustSync::s_pTimingDataOriginal = NULL;
|
||||
float AdjustSync::s_fGlobalOffsetSecondsOriginal = 0.0f;
|
||||
int AdjustSync::s_iAutosyncOffsetSample = 0;
|
||||
float AdjustSync::s_fAutosyncOffset[AdjustSync::OFFSET_SAMPLE_COUNT];
|
||||
float AdjustSync::s_fStandardDeviation = 0.0f;
|
||||
vector< pair<float, float> > AdjustSync::s_vAutosyncTempoData;
|
||||
float AdjustSync::s_fAverageError = 0.0f;
|
||||
const float AdjustSync::ERROR_TOO_HIGH = 0.025f;
|
||||
int AdjustSync::s_iStepsFiltered = 0;
|
||||
|
||||
void AdjustSync::ResetOriginalSyncData()
|
||||
{
|
||||
if( s_pTimingDataOriginal == NULL )
|
||||
s_pTimingDataOriginal = new TimingData;
|
||||
|
||||
if( GAMESTATE->m_pCurSong )
|
||||
*s_pTimingDataOriginal = GAMESTATE->m_pCurSong->m_Timing;
|
||||
else
|
||||
*s_pTimingDataOriginal = TimingData();
|
||||
s_fGlobalOffsetSecondsOriginal = PREFSMAN->m_fGlobalOffsetSeconds;
|
||||
|
||||
ResetAutosync();
|
||||
}
|
||||
|
||||
void AdjustSync::ResetAutosync()
|
||||
{
|
||||
s_iAutosyncOffsetSample = 0;
|
||||
s_vAutosyncTempoData.clear();
|
||||
}
|
||||
|
||||
bool AdjustSync::IsSyncDataChanged()
|
||||
{
|
||||
// Can't sync in course modes
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return false;
|
||||
vector<RString> vs;
|
||||
AdjustSync::GetSyncChangeTextGlobal( vs );
|
||||
AdjustSync::GetSyncChangeTextSong( vs );
|
||||
return !vs.empty();
|
||||
}
|
||||
|
||||
void AdjustSync::SaveSyncChanges()
|
||||
{
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return;
|
||||
if( GAMESTATE->m_pCurSong && *s_pTimingDataOriginal != GAMESTATE->m_pCurSong->m_Timing )
|
||||
{
|
||||
if( GAMESTATE->IsEditing() )
|
||||
{
|
||||
MESSAGEMAN->Broadcast( Message_SongModified );
|
||||
}
|
||||
else
|
||||
{
|
||||
GAMESTATE->m_pCurSong->Save();
|
||||
}
|
||||
}
|
||||
if( s_fGlobalOffsetSecondsOriginal != PREFSMAN->m_fGlobalOffsetSeconds )
|
||||
PREFSMAN->SavePrefsToDisk();
|
||||
ResetOriginalSyncData();
|
||||
s_fStandardDeviation = 0.0f;
|
||||
s_fAverageError = 0.0f;
|
||||
}
|
||||
|
||||
void AdjustSync::RevertSyncChanges()
|
||||
{
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return;
|
||||
PREFSMAN->m_fGlobalOffsetSeconds.Set( s_fGlobalOffsetSecondsOriginal );
|
||||
GAMESTATE->m_pCurSong->m_Timing = *s_pTimingDataOriginal;
|
||||
ResetOriginalSyncData();
|
||||
s_fStandardDeviation = 0.0f;
|
||||
s_fAverageError = 0.0f;
|
||||
}
|
||||
|
||||
static LocalizedString AUTOSYNC_CORRECTION_APPLIED ( "AdjustSync", "Autosync: Correction applied." );
|
||||
static LocalizedString AUTOSYNC_CORRECTION_NOT_APPLIED ( "AdjustSync", "Autosync: Correction NOT applied. Deviation too high." );
|
||||
static LocalizedString AUTOSYNC_SONG ( "AdjustSync", "Autosync Song" );
|
||||
static LocalizedString AUTOSYNC_MACHINE ( "AdjustSync", "Autosync Machine" );
|
||||
static LocalizedString AUTOSYNC_TEMPO ( "AdjustSync", "Autosync Tempo" );
|
||||
void AdjustSync::HandleAutosync( float fNoteOffBySeconds, float fStepTime )
|
||||
{
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return;
|
||||
switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType ) {
|
||||
case SongOptions::AUTOSYNC_OFF:
|
||||
return;
|
||||
case SongOptions::AUTOSYNC_TEMPO:
|
||||
{
|
||||
// We collect all of the data and process it at the end
|
||||
s_vAutosyncTempoData.push_back( make_pair(fStepTime, fNoteOffBySeconds) );
|
||||
break;
|
||||
}
|
||||
case SongOptions::AUTOSYNC_MACHINE:
|
||||
case SongOptions::AUTOSYNC_SONG:
|
||||
{
|
||||
s_fAutosyncOffset[s_iAutosyncOffsetSample] = fNoteOffBySeconds;
|
||||
++s_iAutosyncOffsetSample;
|
||||
|
||||
if( s_iAutosyncOffsetSample < OFFSET_SAMPLE_COUNT )
|
||||
break; // need more
|
||||
|
||||
AutosyncOffset();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AdjustSync::HandleSongEnd()
|
||||
{
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return;
|
||||
if( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType == SongOptions::AUTOSYNC_TEMPO )
|
||||
{
|
||||
AutosyncTempo();
|
||||
}
|
||||
|
||||
// all other states don't care
|
||||
}
|
||||
|
||||
void AdjustSync::AutosyncOffset()
|
||||
{
|
||||
const float mean = calc_mean( s_fAutosyncOffset, s_fAutosyncOffset+OFFSET_SAMPLE_COUNT );
|
||||
const float stddev = calc_stddev( s_fAutosyncOffset, s_fAutosyncOffset+OFFSET_SAMPLE_COUNT );
|
||||
|
||||
RString sAutosyncType;
|
||||
switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType )
|
||||
{
|
||||
case SongOptions::AUTOSYNC_SONG:
|
||||
sAutosyncType = AUTOSYNC_SONG;
|
||||
break;
|
||||
case SongOptions::AUTOSYNC_MACHINE:
|
||||
sAutosyncType = AUTOSYNC_MACHINE;
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
if( stddev < .03f ) // If they stepped with less than .03 error
|
||||
{
|
||||
switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType )
|
||||
{
|
||||
case SongOptions::AUTOSYNC_SONG:
|
||||
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += mean;
|
||||
break;
|
||||
case SongOptions::AUTOSYNC_MACHINE:
|
||||
PREFSMAN->m_fGlobalOffsetSeconds.Set( PREFSMAN->m_fGlobalOffsetSeconds + mean );
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_APPLIED.GetValue() );
|
||||
}
|
||||
else
|
||||
{
|
||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_NOT_APPLIED.GetValue() );
|
||||
}
|
||||
|
||||
s_iAutosyncOffsetSample = 0;
|
||||
s_fStandardDeviation = stddev;
|
||||
}
|
||||
|
||||
void AdjustSync::AutosyncTempo()
|
||||
{
|
||||
float fSlope = 0.0f;
|
||||
float fIntercept = 0.0f;
|
||||
if( !CalcLeastSquares( s_vAutosyncTempoData, fSlope, fIntercept, s_fAverageError ) )
|
||||
{
|
||||
s_vAutosyncTempoData.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if( s_fAverageError < ERROR_TOO_HIGH )
|
||||
{
|
||||
// Here we filter out any steps that are too far off.
|
||||
//
|
||||
// If it turns out that we want to be even more selective, we can
|
||||
// keep only a fraction of the data, such as the 80% with the lowest
|
||||
// error. However, throwing away the ones with high error should
|
||||
// be enough in most cases.
|
||||
float fFilteredError = 0.0;
|
||||
s_iStepsFiltered = s_vAutosyncTempoData.size();
|
||||
FilterHighErrorPoints( s_vAutosyncTempoData, fSlope, fIntercept, ERROR_TOO_HIGH );
|
||||
s_iStepsFiltered -= s_vAutosyncTempoData.size();
|
||||
|
||||
if( !CalcLeastSquares( s_vAutosyncTempoData, fSlope, fIntercept, fFilteredError ) )
|
||||
return;
|
||||
|
||||
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += fIntercept;
|
||||
const float fScaleBPM = 1.0f/(1.0f - fSlope);
|
||||
FOREACH( BPMSegment, GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments, i )
|
||||
i->SetBPM( i->GetBPM() * fScaleBPM );
|
||||
|
||||
// We assume that the stops were measured as a number of beats.
|
||||
// Therefore, if we change the bpms, we need to make a similar
|
||||
// change to the stops.
|
||||
FOREACH( StopSegment, GAMESTATE->m_pCurSong->m_Timing.m_StopSegments, i )
|
||||
i->m_fStopSeconds *= 1.0f - fSlope;
|
||||
|
||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_APPLIED.GetValue() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// deviation... error... close enough for an error message
|
||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_NOT_APPLIED.GetValue() );
|
||||
}
|
||||
|
||||
s_vAutosyncTempoData.clear();
|
||||
}
|
||||
|
||||
|
||||
static LocalizedString EARLIER ("AdjustSync","earlier");
|
||||
static LocalizedString LATER ("AdjustSync","later");
|
||||
static LocalizedString GLOBAL_OFFSET_FROM ( "AdjustSync", "Global Offset from %+.3f to %+.3f (notes %s)" );
|
||||
// We need to limit the length of lines so each one fits on one line of the SM console.
|
||||
// The tempo and stop change message can get very long in a complicated song, and at
|
||||
// a low resolution, the keep/revert menu would be pushed off the bottom of the screen
|
||||
// if we didn't limit the length of the message. Keeping the lines short lets us fit
|
||||
// more information on the screen.
|
||||
static LocalizedString SONG_OFFSET_FROM ( "AdjustSync", "Song offset from %+.3f to %+.3f (notes %s)" );
|
||||
static LocalizedString TEMPO_SEGMENT_FROM ( "AdjustSync", "%s BPM from %.3f BPM to %.3f BPM." );
|
||||
static LocalizedString CHANGED_STOP ("AdjustSync","The stop segment #%d changed from %+.3fs to %+.3fs (change of %+.3f).");
|
||||
static LocalizedString ERROR ("AdjustSync", "Average Error %.5fs");
|
||||
static LocalizedString ETC ("AdjustSync", "Etc.");
|
||||
static LocalizedString TAPS_IGNORED ("AdjustSync", "%d taps ignored.");
|
||||
|
||||
void AdjustSync::GetSyncChangeTextGlobal( vector<RString> &vsAddTo )
|
||||
{
|
||||
{
|
||||
float fOld = Quantize( AdjustSync::s_fGlobalOffsetSecondsOriginal, 0.001f );
|
||||
float fNew = Quantize( PREFSMAN->m_fGlobalOffsetSeconds, 0.001f ) ;
|
||||
float fDelta = fNew - fOld;
|
||||
|
||||
if( fabsf(fDelta) > 0.0001f )
|
||||
{
|
||||
vsAddTo.push_back( ssprintf(
|
||||
GLOBAL_OFFSET_FROM.GetValue(),
|
||||
fOld,
|
||||
fNew,
|
||||
(fDelta > 0 ? EARLIER:LATER).GetValue().c_str() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdjustSync::GetSyncChangeTextSong( vector<RString> &vsAddTo )
|
||||
{
|
||||
if( GAMESTATE->m_pCurSong.Get() )
|
||||
{
|
||||
unsigned int iOriginalSize = vsAddTo.size();
|
||||
|
||||
{
|
||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_fBeat0OffsetInSeconds, 0.001f );
|
||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds, 0.001f );
|
||||
float fDelta = fNew - fOld;
|
||||
|
||||
if( fabsf(fDelta) > 0.0001f )
|
||||
{
|
||||
vsAddTo.push_back( ssprintf(
|
||||
SONG_OFFSET_FROM.GetValue(),
|
||||
fOld,
|
||||
fNew,
|
||||
(fDelta > 0 ? EARLIER:LATER).GetValue().c_str() ) );
|
||||
}
|
||||
}
|
||||
|
||||
for( unsigned i=0; i<GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments.size(); i++ )
|
||||
{
|
||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_BPMSegments[i].GetBPM(), 0.001f );
|
||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments[i].GetBPM(), 0.001f );
|
||||
float fDelta = fNew - fOld;
|
||||
|
||||
if( fabsf(fDelta) > 0.0001f )
|
||||
{
|
||||
if ( i >= 4 )
|
||||
{
|
||||
vsAddTo.push_back(ETC.GetValue());
|
||||
break;
|
||||
}
|
||||
vsAddTo.push_back( ssprintf(
|
||||
TEMPO_SEGMENT_FROM.GetValue(),
|
||||
FormatNumberAndSuffix(i+1).c_str(),
|
||||
fOld,
|
||||
fNew ) );
|
||||
}
|
||||
}
|
||||
|
||||
for( unsigned i=0; i<GAMESTATE->m_pCurSong->m_Timing.m_StopSegments.size(); i++ )
|
||||
{
|
||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_StopSegments[i].m_fStopSeconds, 0.001f );
|
||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_StopSegments[i].m_fStopSeconds, 0.001f );
|
||||
float fDelta = fNew - fOld;
|
||||
|
||||
if( fabsf(fDelta) > 0.0001f )
|
||||
{
|
||||
if ( i >= 4 )
|
||||
{
|
||||
vsAddTo.push_back(ETC.GetValue());
|
||||
break;
|
||||
}
|
||||
vsAddTo.push_back( ssprintf(
|
||||
CHANGED_STOP.GetValue(),
|
||||
i+1,
|
||||
fOld,
|
||||
fNew ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( vsAddTo.size() > iOriginalSize && s_fAverageError > 0.0f )
|
||||
{
|
||||
vsAddTo.push_back( ssprintf(ERROR.GetValue(), s_fAverageError) );
|
||||
}
|
||||
if( vsAddTo.size() > iOriginalSize && s_iStepsFiltered > 0 )
|
||||
{
|
||||
vsAddTo.push_back( ssprintf(TAPS_IGNORED.GetValue(), s_iStepsFiltered) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2003-2006 Chris Danford, John Bauer
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* AdjustSync defines two methods for fixing the sync.
|
||||
*
|
||||
* The first method adjusts either the song or the machine by the
|
||||
* average offset of the user's steps. In other words, if the user
|
||||
* averages to step early by 10 ms, either the song or the global
|
||||
* offset is adjusted by 10 ms to compensate for that. These
|
||||
* adjustments only require a small set of data, so this method
|
||||
* updates the offset while the song is playing.
|
||||
*
|
||||
* The second method adjusts both the offset and the tempo of an
|
||||
* individual song. It records all of the steps during a play of
|
||||
* the song and uses linear least squares regression to minimize the
|
||||
* error of those steps. It makes one adjustment for the tempo of
|
||||
* the entire song, rather than adding many different tempo segments
|
||||
* to match the steps. If there are already several tempo segments
|
||||
* in the stepfile, this method makes a proportional change to each
|
||||
* of them. For example, if it changes 100 bpm to 101 bpm, it will
|
||||
* also change 200 bpm to 202 bpm. This method also adjusts the stops.
|
||||
* It assumes that a given stop is measured in terms of beats and makes
|
||||
* the appropriate change.
|
||||
*
|
||||
* If we use this method on a small set of data late in the song, it
|
||||
* can have very chaotic effects on the early settings. For example,
|
||||
* it may change the offset by several hundred milliseconds and make a
|
||||
* large change to the BPM to compensate if that would minimize the
|
||||
* error. This problem occurs especially when the user makes a couple
|
||||
* steps that are significantly off beat. The way to avoid this is to
|
||||
* perform the least squares regression once on all of the data
|
||||
* collected, rather than adjusting the sync every time we get another
|
||||
* 50 or so data points. In fact, if we are playing in edit mode and
|
||||
* the user loops through the song more than once, we use all of the
|
||||
* steps made.
|
||||
*/
|
||||
|
||||
#include "global.h"
|
||||
#include "Song.h"
|
||||
#include "AdjustSync.h"
|
||||
#include "GameState.h"
|
||||
#include "LocalizedString.h"
|
||||
#include "PrefsManager.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "Foreach.h"
|
||||
|
||||
TimingData *AdjustSync::s_pTimingDataOriginal = NULL;
|
||||
float AdjustSync::s_fGlobalOffsetSecondsOriginal = 0.0f;
|
||||
int AdjustSync::s_iAutosyncOffsetSample = 0;
|
||||
float AdjustSync::s_fAutosyncOffset[AdjustSync::OFFSET_SAMPLE_COUNT];
|
||||
float AdjustSync::s_fStandardDeviation = 0.0f;
|
||||
vector< pair<float, float> > AdjustSync::s_vAutosyncTempoData;
|
||||
float AdjustSync::s_fAverageError = 0.0f;
|
||||
const float AdjustSync::ERROR_TOO_HIGH = 0.025f;
|
||||
int AdjustSync::s_iStepsFiltered = 0;
|
||||
|
||||
void AdjustSync::ResetOriginalSyncData()
|
||||
{
|
||||
if( s_pTimingDataOriginal == NULL )
|
||||
s_pTimingDataOriginal = new TimingData;
|
||||
|
||||
if( GAMESTATE->m_pCurSong )
|
||||
*s_pTimingDataOriginal = GAMESTATE->m_pCurSong->m_Timing;
|
||||
else
|
||||
*s_pTimingDataOriginal = TimingData();
|
||||
s_fGlobalOffsetSecondsOriginal = PREFSMAN->m_fGlobalOffsetSeconds;
|
||||
|
||||
ResetAutosync();
|
||||
}
|
||||
|
||||
void AdjustSync::ResetAutosync()
|
||||
{
|
||||
s_iAutosyncOffsetSample = 0;
|
||||
s_vAutosyncTempoData.clear();
|
||||
}
|
||||
|
||||
bool AdjustSync::IsSyncDataChanged()
|
||||
{
|
||||
// Can't sync in course modes
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return false;
|
||||
vector<RString> vs;
|
||||
AdjustSync::GetSyncChangeTextGlobal( vs );
|
||||
AdjustSync::GetSyncChangeTextSong( vs );
|
||||
return !vs.empty();
|
||||
}
|
||||
|
||||
void AdjustSync::SaveSyncChanges()
|
||||
{
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return;
|
||||
if( GAMESTATE->m_pCurSong && *s_pTimingDataOriginal != GAMESTATE->m_pCurSong->m_Timing )
|
||||
{
|
||||
if( GAMESTATE->IsEditing() )
|
||||
{
|
||||
MESSAGEMAN->Broadcast( Message_SongModified );
|
||||
}
|
||||
else
|
||||
{
|
||||
GAMESTATE->m_pCurSong->Save();
|
||||
}
|
||||
}
|
||||
if( s_fGlobalOffsetSecondsOriginal != PREFSMAN->m_fGlobalOffsetSeconds )
|
||||
PREFSMAN->SavePrefsToDisk();
|
||||
ResetOriginalSyncData();
|
||||
s_fStandardDeviation = 0.0f;
|
||||
s_fAverageError = 0.0f;
|
||||
}
|
||||
|
||||
void AdjustSync::RevertSyncChanges()
|
||||
{
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return;
|
||||
PREFSMAN->m_fGlobalOffsetSeconds.Set( s_fGlobalOffsetSecondsOriginal );
|
||||
GAMESTATE->m_pCurSong->m_Timing = *s_pTimingDataOriginal;
|
||||
ResetOriginalSyncData();
|
||||
s_fStandardDeviation = 0.0f;
|
||||
s_fAverageError = 0.0f;
|
||||
}
|
||||
|
||||
static LocalizedString AUTOSYNC_CORRECTION_APPLIED ( "AdjustSync", "Autosync: Correction applied." );
|
||||
static LocalizedString AUTOSYNC_CORRECTION_NOT_APPLIED ( "AdjustSync", "Autosync: Correction NOT applied. Deviation too high." );
|
||||
static LocalizedString AUTOSYNC_SONG ( "AdjustSync", "Autosync Song" );
|
||||
static LocalizedString AUTOSYNC_MACHINE ( "AdjustSync", "Autosync Machine" );
|
||||
static LocalizedString AUTOSYNC_TEMPO ( "AdjustSync", "Autosync Tempo" );
|
||||
void AdjustSync::HandleAutosync( float fNoteOffBySeconds, float fStepTime )
|
||||
{
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return;
|
||||
switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType ) {
|
||||
case SongOptions::AUTOSYNC_OFF:
|
||||
return;
|
||||
case SongOptions::AUTOSYNC_TEMPO:
|
||||
{
|
||||
// We collect all of the data and process it at the end
|
||||
s_vAutosyncTempoData.push_back( make_pair(fStepTime, fNoteOffBySeconds) );
|
||||
break;
|
||||
}
|
||||
case SongOptions::AUTOSYNC_MACHINE:
|
||||
case SongOptions::AUTOSYNC_SONG:
|
||||
{
|
||||
s_fAutosyncOffset[s_iAutosyncOffsetSample] = fNoteOffBySeconds;
|
||||
++s_iAutosyncOffsetSample;
|
||||
|
||||
if( s_iAutosyncOffsetSample < OFFSET_SAMPLE_COUNT )
|
||||
break; // need more
|
||||
|
||||
AutosyncOffset();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AdjustSync::HandleSongEnd()
|
||||
{
|
||||
if( GAMESTATE->IsCourseMode() )
|
||||
return;
|
||||
if( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType == SongOptions::AUTOSYNC_TEMPO )
|
||||
{
|
||||
AutosyncTempo();
|
||||
}
|
||||
|
||||
// all other states don't care
|
||||
}
|
||||
|
||||
void AdjustSync::AutosyncOffset()
|
||||
{
|
||||
const float mean = calc_mean( s_fAutosyncOffset, s_fAutosyncOffset+OFFSET_SAMPLE_COUNT );
|
||||
const float stddev = calc_stddev( s_fAutosyncOffset, s_fAutosyncOffset+OFFSET_SAMPLE_COUNT );
|
||||
|
||||
RString sAutosyncType;
|
||||
switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType )
|
||||
{
|
||||
case SongOptions::AUTOSYNC_SONG:
|
||||
sAutosyncType = AUTOSYNC_SONG;
|
||||
break;
|
||||
case SongOptions::AUTOSYNC_MACHINE:
|
||||
sAutosyncType = AUTOSYNC_MACHINE;
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
if( stddev < .03f ) // If they stepped with less than .03 error
|
||||
{
|
||||
switch( GAMESTATE->m_SongOptions.GetCurrent().m_AutosyncType )
|
||||
{
|
||||
case SongOptions::AUTOSYNC_SONG:
|
||||
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += mean;
|
||||
break;
|
||||
case SongOptions::AUTOSYNC_MACHINE:
|
||||
PREFSMAN->m_fGlobalOffsetSeconds.Set( PREFSMAN->m_fGlobalOffsetSeconds + mean );
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_APPLIED.GetValue() );
|
||||
}
|
||||
else
|
||||
{
|
||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_NOT_APPLIED.GetValue() );
|
||||
}
|
||||
|
||||
s_iAutosyncOffsetSample = 0;
|
||||
s_fStandardDeviation = stddev;
|
||||
}
|
||||
|
||||
void AdjustSync::AutosyncTempo()
|
||||
{
|
||||
float fSlope = 0.0f;
|
||||
float fIntercept = 0.0f;
|
||||
if( !CalcLeastSquares( s_vAutosyncTempoData, fSlope, fIntercept, s_fAverageError ) )
|
||||
{
|
||||
s_vAutosyncTempoData.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if( s_fAverageError < ERROR_TOO_HIGH )
|
||||
{
|
||||
// Here we filter out any steps that are too far off.
|
||||
//
|
||||
// If it turns out that we want to be even more selective, we can
|
||||
// keep only a fraction of the data, such as the 80% with the lowest
|
||||
// error. However, throwing away the ones with high error should
|
||||
// be enough in most cases.
|
||||
float fFilteredError = 0.0;
|
||||
s_iStepsFiltered = s_vAutosyncTempoData.size();
|
||||
FilterHighErrorPoints( s_vAutosyncTempoData, fSlope, fIntercept, ERROR_TOO_HIGH );
|
||||
s_iStepsFiltered -= s_vAutosyncTempoData.size();
|
||||
|
||||
if( !CalcLeastSquares( s_vAutosyncTempoData, fSlope, fIntercept, fFilteredError ) )
|
||||
return;
|
||||
|
||||
GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds += fIntercept;
|
||||
const float fScaleBPM = 1.0f/(1.0f - fSlope);
|
||||
FOREACH( BPMSegment, GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments, i )
|
||||
i->SetBPM( i->GetBPM() * fScaleBPM );
|
||||
|
||||
// We assume that the stops were measured as a number of beats.
|
||||
// Therefore, if we change the bpms, we need to make a similar
|
||||
// change to the stops.
|
||||
FOREACH( StopSegment, GAMESTATE->m_pCurSong->m_Timing.m_StopSegments, i )
|
||||
i->m_fStopSeconds *= 1.0f - fSlope;
|
||||
|
||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_APPLIED.GetValue() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// deviation... error... close enough for an error message
|
||||
SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_NOT_APPLIED.GetValue() );
|
||||
}
|
||||
|
||||
s_vAutosyncTempoData.clear();
|
||||
}
|
||||
|
||||
|
||||
static LocalizedString EARLIER ("AdjustSync","earlier");
|
||||
static LocalizedString LATER ("AdjustSync","later");
|
||||
static LocalizedString GLOBAL_OFFSET_FROM ( "AdjustSync", "Global Offset from %+.3f to %+.3f (notes %s)" );
|
||||
// We need to limit the length of lines so each one fits on one line of the SM console.
|
||||
// The tempo and stop change message can get very long in a complicated song, and at
|
||||
// a low resolution, the keep/revert menu would be pushed off the bottom of the screen
|
||||
// if we didn't limit the length of the message. Keeping the lines short lets us fit
|
||||
// more information on the screen.
|
||||
static LocalizedString SONG_OFFSET_FROM ( "AdjustSync", "Song offset from %+.3f to %+.3f (notes %s)" );
|
||||
static LocalizedString TEMPO_SEGMENT_FROM ( "AdjustSync", "%s BPM from %.3f BPM to %.3f BPM." );
|
||||
static LocalizedString CHANGED_STOP ("AdjustSync","The stop segment #%d changed from %+.3fs to %+.3fs (change of %+.3f).");
|
||||
static LocalizedString ERROR ("AdjustSync", "Average Error %.5fs");
|
||||
static LocalizedString ETC ("AdjustSync", "Etc.");
|
||||
static LocalizedString TAPS_IGNORED ("AdjustSync", "%d taps ignored.");
|
||||
|
||||
void AdjustSync::GetSyncChangeTextGlobal( vector<RString> &vsAddTo )
|
||||
{
|
||||
{
|
||||
float fOld = Quantize( AdjustSync::s_fGlobalOffsetSecondsOriginal, 0.001f );
|
||||
float fNew = Quantize( PREFSMAN->m_fGlobalOffsetSeconds, 0.001f ) ;
|
||||
float fDelta = fNew - fOld;
|
||||
|
||||
if( fabsf(fDelta) > 0.0001f )
|
||||
{
|
||||
vsAddTo.push_back( ssprintf(
|
||||
GLOBAL_OFFSET_FROM.GetValue(),
|
||||
fOld,
|
||||
fNew,
|
||||
(fDelta > 0 ? EARLIER:LATER).GetValue().c_str() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdjustSync::GetSyncChangeTextSong( vector<RString> &vsAddTo )
|
||||
{
|
||||
if( GAMESTATE->m_pCurSong.Get() )
|
||||
{
|
||||
unsigned int iOriginalSize = vsAddTo.size();
|
||||
|
||||
{
|
||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_fBeat0OffsetInSeconds, 0.001f );
|
||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_fBeat0OffsetInSeconds, 0.001f );
|
||||
float fDelta = fNew - fOld;
|
||||
|
||||
if( fabsf(fDelta) > 0.0001f )
|
||||
{
|
||||
vsAddTo.push_back( ssprintf(
|
||||
SONG_OFFSET_FROM.GetValue(),
|
||||
fOld,
|
||||
fNew,
|
||||
(fDelta > 0 ? EARLIER:LATER).GetValue().c_str() ) );
|
||||
}
|
||||
}
|
||||
|
||||
for( unsigned i=0; i<GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments.size(); i++ )
|
||||
{
|
||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_BPMSegments[i].GetBPM(), 0.001f );
|
||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_BPMSegments[i].GetBPM(), 0.001f );
|
||||
float fDelta = fNew - fOld;
|
||||
|
||||
if( fabsf(fDelta) > 0.0001f )
|
||||
{
|
||||
if ( i >= 4 )
|
||||
{
|
||||
vsAddTo.push_back(ETC.GetValue());
|
||||
break;
|
||||
}
|
||||
vsAddTo.push_back( ssprintf(
|
||||
TEMPO_SEGMENT_FROM.GetValue(),
|
||||
FormatNumberAndSuffix(i+1).c_str(),
|
||||
fOld,
|
||||
fNew ) );
|
||||
}
|
||||
}
|
||||
|
||||
for( unsigned i=0; i<GAMESTATE->m_pCurSong->m_Timing.m_StopSegments.size(); i++ )
|
||||
{
|
||||
float fOld = Quantize( AdjustSync::s_pTimingDataOriginal->m_StopSegments[i].m_fStopSeconds, 0.001f );
|
||||
float fNew = Quantize( GAMESTATE->m_pCurSong->m_Timing.m_StopSegments[i].m_fStopSeconds, 0.001f );
|
||||
float fDelta = fNew - fOld;
|
||||
|
||||
if( fabsf(fDelta) > 0.0001f )
|
||||
{
|
||||
if ( i >= 4 )
|
||||
{
|
||||
vsAddTo.push_back(ETC.GetValue());
|
||||
break;
|
||||
}
|
||||
vsAddTo.push_back( ssprintf(
|
||||
CHANGED_STOP.GetValue(),
|
||||
i+1,
|
||||
fOld,
|
||||
fNew ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( vsAddTo.size() > iOriginalSize && s_fAverageError > 0.0f )
|
||||
{
|
||||
vsAddTo.push_back( ssprintf(ERROR.GetValue(), s_fAverageError) );
|
||||
}
|
||||
if( vsAddTo.size() > iOriginalSize && s_iStepsFiltered > 0 )
|
||||
{
|
||||
vsAddTo.push_back( ssprintf(TAPS_IGNORED.GetValue(), s_iStepsFiltered) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2003-2006 Chris Danford, John Bauer
|
||||
* 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.
|
||||
*/
|
||||
|
||||
+79
-79
@@ -1,79 +1,79 @@
|
||||
#ifndef AdjustSync_H
|
||||
#define AdjustSync_H
|
||||
|
||||
class TimingData;
|
||||
/**
|
||||
* @brief Allows for adjusting the sync of a song.
|
||||
*
|
||||
* This class defines two ways of adjusting the sync of a song.
|
||||
* The first adjusts only the offset, "on the fly". It can adjust either the
|
||||
* song itself or the machine. The other style adjusts both the BPM and the
|
||||
* offset of the song, but it needs more data.
|
||||
*/
|
||||
class AdjustSync
|
||||
{
|
||||
public:
|
||||
static TimingData *s_pTimingDataOriginal;
|
||||
static float s_fGlobalOffsetSecondsOriginal;
|
||||
/* We only want to call the Reset methods before a song, not immediately after
|
||||
* a song. If we reset it at the end of a song, we have to carefully check
|
||||
* the logic to make sure we never reset it before the user gets a chance to
|
||||
* save or revert the change. Resetting at the start of the song is
|
||||
* sufficient. */
|
||||
static void ResetOriginalSyncData();
|
||||
static void ResetAutosync();
|
||||
static bool IsSyncDataChanged();
|
||||
|
||||
static void SaveSyncChanges();
|
||||
static void RevertSyncChanges();
|
||||
static void HandleAutosync( float fNoteOffBySeconds, float fStepTime );
|
||||
static void HandleSongEnd();
|
||||
static void AutosyncOffset();
|
||||
static void AutosyncTempo();
|
||||
static void GetSyncChangeTextGlobal( vector<RString> &vsAddTo );
|
||||
static void GetSyncChangeTextSong( vector<RString> &vsAddTo );
|
||||
|
||||
/** @brief The minimum number of steps to hit for syncing purposes. */
|
||||
static const int OFFSET_SAMPLE_COUNT = 56;
|
||||
|
||||
static float s_fAutosyncOffset[OFFSET_SAMPLE_COUNT];
|
||||
static int s_iAutosyncOffsetSample;
|
||||
static float s_fStandardDeviation;
|
||||
|
||||
// Measured in seconds. If the average error is too high, we
|
||||
// reject the recorded data for the Least Squares Regression.
|
||||
static const float ERROR_TOO_HIGH;
|
||||
|
||||
static vector< pair<float, float> > s_vAutosyncTempoData;
|
||||
static float s_fAverageError;
|
||||
static int s_iStepsFiltered;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford, John Bauer (c) 2003-2006
|
||||
* @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 AdjustSync_H
|
||||
#define AdjustSync_H
|
||||
|
||||
class TimingData;
|
||||
/**
|
||||
* @brief Allows for adjusting the sync of a song.
|
||||
*
|
||||
* This class defines two ways of adjusting the sync of a song.
|
||||
* The first adjusts only the offset, "on the fly". It can adjust either the
|
||||
* song itself or the machine. The other style adjusts both the BPM and the
|
||||
* offset of the song, but it needs more data.
|
||||
*/
|
||||
class AdjustSync
|
||||
{
|
||||
public:
|
||||
static TimingData *s_pTimingDataOriginal;
|
||||
static float s_fGlobalOffsetSecondsOriginal;
|
||||
/* We only want to call the Reset methods before a song, not immediately after
|
||||
* a song. If we reset it at the end of a song, we have to carefully check
|
||||
* the logic to make sure we never reset it before the user gets a chance to
|
||||
* save or revert the change. Resetting at the start of the song is
|
||||
* sufficient. */
|
||||
static void ResetOriginalSyncData();
|
||||
static void ResetAutosync();
|
||||
static bool IsSyncDataChanged();
|
||||
|
||||
static void SaveSyncChanges();
|
||||
static void RevertSyncChanges();
|
||||
static void HandleAutosync( float fNoteOffBySeconds, float fStepTime );
|
||||
static void HandleSongEnd();
|
||||
static void AutosyncOffset();
|
||||
static void AutosyncTempo();
|
||||
static void GetSyncChangeTextGlobal( vector<RString> &vsAddTo );
|
||||
static void GetSyncChangeTextSong( vector<RString> &vsAddTo );
|
||||
|
||||
/** @brief The minimum number of steps to hit for syncing purposes. */
|
||||
static const int OFFSET_SAMPLE_COUNT = 56;
|
||||
|
||||
static float s_fAutosyncOffset[OFFSET_SAMPLE_COUNT];
|
||||
static int s_iAutosyncOffsetSample;
|
||||
static float s_fStandardDeviation;
|
||||
|
||||
// Measured in seconds. If the average error is too high, we
|
||||
// reject the recorded data for the Least Squares Regression.
|
||||
static const float ERROR_TOO_HIGH;
|
||||
|
||||
static vector< pair<float, float> > s_vAutosyncTempoData;
|
||||
static float s_fAverageError;
|
||||
static int s_iStepsFiltered;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford, John Bauer (c) 2003-2006
|
||||
* @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.
|
||||
*/
|
||||
|
||||
+233
-233
@@ -1,233 +1,233 @@
|
||||
#include "global.h"
|
||||
#include "AnnouncerManager.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageFile.h"
|
||||
|
||||
AnnouncerManager* ANNOUNCER = NULL; // global object accessable from anywhere in the program
|
||||
|
||||
|
||||
const RString EMPTY_ANNOUNCER_NAME = "Empty";
|
||||
const RString ANNOUNCERS_DIR = "Announcers/";
|
||||
|
||||
AnnouncerManager::AnnouncerManager()
|
||||
{
|
||||
// Register with Lua.
|
||||
{
|
||||
Lua *L = LUA->Get();
|
||||
lua_pushstring( L, "ANNOUNCER" );
|
||||
this->PushSelf( L );
|
||||
lua_settable( L, LUA_GLOBALSINDEX );
|
||||
LUA->Release( L );
|
||||
}
|
||||
}
|
||||
|
||||
AnnouncerManager::~AnnouncerManager()
|
||||
{
|
||||
// Unregister with Lua.
|
||||
LUA->UnsetGlobal( "ANNOUNCER" );
|
||||
}
|
||||
|
||||
void AnnouncerManager::GetAnnouncerNames( vector<RString>& AddTo )
|
||||
{
|
||||
GetDirListing( ANNOUNCERS_DIR+"*", AddTo, true );
|
||||
|
||||
StripCvsAndSvn( AddTo );
|
||||
StripMacResourceForks( AddTo );
|
||||
|
||||
// strip out the empty announcer folder
|
||||
for( int i=AddTo.size()-1; i>=0; i-- )
|
||||
if( !stricmp( AddTo[i], EMPTY_ANNOUNCER_NAME ) )
|
||||
AddTo.erase(AddTo.begin()+i, AddTo.begin()+i+1 );
|
||||
}
|
||||
|
||||
bool AnnouncerManager::DoesAnnouncerExist( RString sAnnouncerName )
|
||||
{
|
||||
if( sAnnouncerName == "" )
|
||||
return true;
|
||||
|
||||
vector<RString> asAnnouncerNames;
|
||||
GetAnnouncerNames( asAnnouncerNames );
|
||||
for( unsigned i=0; i<asAnnouncerNames.size(); i++ )
|
||||
if( 0==stricmp(sAnnouncerName, asAnnouncerNames[i]) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
RString AnnouncerManager::GetAnnouncerDirFromName( RString sAnnouncerName )
|
||||
{
|
||||
return ANNOUNCERS_DIR + sAnnouncerName + "/";
|
||||
}
|
||||
|
||||
void AnnouncerManager::SwitchAnnouncer( RString sNewAnnouncerName )
|
||||
{
|
||||
if( !DoesAnnouncerExist(sNewAnnouncerName) )
|
||||
m_sCurAnnouncerName = "";
|
||||
else
|
||||
m_sCurAnnouncerName = sNewAnnouncerName;
|
||||
}
|
||||
|
||||
/* Aliases for announcer paths. This is for compatibility, so we don't force
|
||||
* announcer changes along with everything else. We could use it to support
|
||||
* DWI announcers transparently, too. */
|
||||
static const char *aliases[][2] = {
|
||||
/* ScreenSelectDifficulty compatibility: */
|
||||
{ "ScreenSelectDifficulty comment beginner", "select difficulty comment beginner" },
|
||||
{ "ScreenSelectDifficulty comment easy", "select difficulty comment easy" },
|
||||
{ "ScreenSelectDifficulty comment medium", "select difficulty comment medium" },
|
||||
{ "ScreenSelectDifficulty comment hard", "select difficulty comment hard" },
|
||||
{ "ScreenSelectDifficulty comment oni", "select difficulty comment oni" },
|
||||
{ "ScreenSelectDifficulty comment nonstop", "select difficulty comment nonstop" },
|
||||
{ "ScreenSelectDifficulty comment endless", "select difficulty comment endless" },
|
||||
{ "ScreenSelectDifficulty intro", "select difficulty intro" },
|
||||
|
||||
/* ScreenSelectStyle compatibility: */
|
||||
{ "ScreenSelectStyle intro", "select style intro" },
|
||||
{ "ScreenSelectStyle comment single", "select style comment single" },
|
||||
{ "ScreenSelectStyle comment double", "select style comment double" },
|
||||
{ "ScreenSelectStyle comment solo", "select style comment solo" },
|
||||
{ "ScreenSelectStyle comment versus", "select style comment versus" },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* Find an announcer directory with sounds in it. First search sFolderName,
|
||||
* then all aliases above. Ignore directories that are empty, since we might
|
||||
* have "select difficulty intro" with sounds and an empty "ScreenSelectDifficulty
|
||||
* intro". */
|
||||
RString AnnouncerManager::GetPathTo( RString sAnnouncerName, RString sFolderName )
|
||||
{
|
||||
if(sAnnouncerName == "")
|
||||
return RString(); /* announcer disabled */
|
||||
|
||||
const RString AnnouncerPath = GetAnnouncerDirFromName(sAnnouncerName);
|
||||
|
||||
if( !DirectoryIsEmpty(AnnouncerPath+sFolderName+"/") )
|
||||
return AnnouncerPath+sFolderName+"/";
|
||||
|
||||
/* Search for the announcer folder in the list of aliases. */
|
||||
int i;
|
||||
for(i = 0; aliases[i][0] != NULL; ++i)
|
||||
{
|
||||
if(!sFolderName.EqualsNoCase(aliases[i][0]))
|
||||
continue; /* no match */
|
||||
|
||||
if( !DirectoryIsEmpty(AnnouncerPath+aliases[i][1]+"/") )
|
||||
return AnnouncerPath+aliases[i][1]+"/";
|
||||
}
|
||||
|
||||
/* No announcer directory matched. In debug, create the directory by
|
||||
* its preferred name. */
|
||||
#ifdef DEBUG
|
||||
LOG->Trace( "The announcer in '%s' is missing the folder '%s'.",
|
||||
AnnouncerPath.c_str(), sFolderName.c_str() );
|
||||
// MessageBeep( MB_OK );
|
||||
RageFile temp;
|
||||
temp.Open( AnnouncerPath+sFolderName + "/announcer files go here.txt", RageFile::WRITE );
|
||||
#endif
|
||||
|
||||
return RString();
|
||||
}
|
||||
|
||||
RString AnnouncerManager::GetPathTo( RString sFolderName )
|
||||
{
|
||||
return GetPathTo(m_sCurAnnouncerName, sFolderName);
|
||||
}
|
||||
|
||||
bool AnnouncerManager::HasSoundsFor( RString sFolderName )
|
||||
{
|
||||
return !DirectoryIsEmpty( GetPathTo(sFolderName) );
|
||||
}
|
||||
|
||||
void AnnouncerManager::NextAnnouncer()
|
||||
{
|
||||
vector<RString> as;
|
||||
GetAnnouncerNames( as );
|
||||
if( as.size()==0 )
|
||||
return;
|
||||
|
||||
if( m_sCurAnnouncerName == "" )
|
||||
SwitchAnnouncer( as[0] );
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
for( i=0; i<as.size(); i++ )
|
||||
if( as[i].EqualsNoCase(m_sCurAnnouncerName) )
|
||||
break;
|
||||
if( i==as.size()-1 )
|
||||
SwitchAnnouncer( "" );
|
||||
else
|
||||
{
|
||||
int iNewIndex = (i+1)%as.size();
|
||||
SwitchAnnouncer( as[iNewIndex] );
|
||||
}
|
||||
}
|
||||
}
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the AnnouncerManager. */
|
||||
class LunaAnnouncerManager: public Luna<AnnouncerManager>
|
||||
{
|
||||
public:
|
||||
static int DoesAnnouncerExist( T* p, lua_State *L ) { lua_pushboolean(L, p->DoesAnnouncerExist( SArg(1) )); return 1; }
|
||||
static int GetAnnouncerNames( T* p, lua_State *L )
|
||||
{
|
||||
vector<RString> vAnnouncers;
|
||||
p->GetAnnouncerNames( vAnnouncers );
|
||||
LuaHelpers::CreateTableFromArray(vAnnouncers, L);
|
||||
return 1;
|
||||
}
|
||||
static int GetCurrentAnnouncer( T* p, lua_State *L )
|
||||
{
|
||||
RString s = p->GetCurAnnouncerName();
|
||||
if( s.empty() )
|
||||
return 0;
|
||||
lua_pushstring(L, s );
|
||||
return 1;
|
||||
}
|
||||
static int SetCurrentAnnouncer( T* p, lua_State *L )
|
||||
{
|
||||
RString s = SArg(1);
|
||||
// only bother switching if the announcer exists. -aj
|
||||
if(p->DoesAnnouncerExist(s))
|
||||
p->SwitchAnnouncer(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LunaAnnouncerManager()
|
||||
{
|
||||
ADD_METHOD( DoesAnnouncerExist );
|
||||
ADD_METHOD( GetAnnouncerNames );
|
||||
ADD_METHOD( GetCurrentAnnouncer );
|
||||
ADD_METHOD( SetCurrentAnnouncer );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_CLASS( AnnouncerManager )
|
||||
// lua end
|
||||
|
||||
/*
|
||||
* (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 "AnnouncerManager.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageFile.h"
|
||||
|
||||
AnnouncerManager* ANNOUNCER = NULL; // global object accessable from anywhere in the program
|
||||
|
||||
|
||||
const RString EMPTY_ANNOUNCER_NAME = "Empty";
|
||||
const RString ANNOUNCERS_DIR = "Announcers/";
|
||||
|
||||
AnnouncerManager::AnnouncerManager()
|
||||
{
|
||||
// Register with Lua.
|
||||
{
|
||||
Lua *L = LUA->Get();
|
||||
lua_pushstring( L, "ANNOUNCER" );
|
||||
this->PushSelf( L );
|
||||
lua_settable( L, LUA_GLOBALSINDEX );
|
||||
LUA->Release( L );
|
||||
}
|
||||
}
|
||||
|
||||
AnnouncerManager::~AnnouncerManager()
|
||||
{
|
||||
// Unregister with Lua.
|
||||
LUA->UnsetGlobal( "ANNOUNCER" );
|
||||
}
|
||||
|
||||
void AnnouncerManager::GetAnnouncerNames( vector<RString>& AddTo )
|
||||
{
|
||||
GetDirListing( ANNOUNCERS_DIR+"*", AddTo, true );
|
||||
|
||||
StripCvsAndSvn( AddTo );
|
||||
StripMacResourceForks( AddTo );
|
||||
|
||||
// strip out the empty announcer folder
|
||||
for( int i=AddTo.size()-1; i>=0; i-- )
|
||||
if( !stricmp( AddTo[i], EMPTY_ANNOUNCER_NAME ) )
|
||||
AddTo.erase(AddTo.begin()+i, AddTo.begin()+i+1 );
|
||||
}
|
||||
|
||||
bool AnnouncerManager::DoesAnnouncerExist( RString sAnnouncerName )
|
||||
{
|
||||
if( sAnnouncerName == "" )
|
||||
return true;
|
||||
|
||||
vector<RString> asAnnouncerNames;
|
||||
GetAnnouncerNames( asAnnouncerNames );
|
||||
for( unsigned i=0; i<asAnnouncerNames.size(); i++ )
|
||||
if( 0==stricmp(sAnnouncerName, asAnnouncerNames[i]) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
RString AnnouncerManager::GetAnnouncerDirFromName( RString sAnnouncerName )
|
||||
{
|
||||
return ANNOUNCERS_DIR + sAnnouncerName + "/";
|
||||
}
|
||||
|
||||
void AnnouncerManager::SwitchAnnouncer( RString sNewAnnouncerName )
|
||||
{
|
||||
if( !DoesAnnouncerExist(sNewAnnouncerName) )
|
||||
m_sCurAnnouncerName = "";
|
||||
else
|
||||
m_sCurAnnouncerName = sNewAnnouncerName;
|
||||
}
|
||||
|
||||
/* Aliases for announcer paths. This is for compatibility, so we don't force
|
||||
* announcer changes along with everything else. We could use it to support
|
||||
* DWI announcers transparently, too. */
|
||||
static const char *aliases[][2] = {
|
||||
/* ScreenSelectDifficulty compatibility: */
|
||||
{ "ScreenSelectDifficulty comment beginner", "select difficulty comment beginner" },
|
||||
{ "ScreenSelectDifficulty comment easy", "select difficulty comment easy" },
|
||||
{ "ScreenSelectDifficulty comment medium", "select difficulty comment medium" },
|
||||
{ "ScreenSelectDifficulty comment hard", "select difficulty comment hard" },
|
||||
{ "ScreenSelectDifficulty comment oni", "select difficulty comment oni" },
|
||||
{ "ScreenSelectDifficulty comment nonstop", "select difficulty comment nonstop" },
|
||||
{ "ScreenSelectDifficulty comment endless", "select difficulty comment endless" },
|
||||
{ "ScreenSelectDifficulty intro", "select difficulty intro" },
|
||||
|
||||
/* ScreenSelectStyle compatibility: */
|
||||
{ "ScreenSelectStyle intro", "select style intro" },
|
||||
{ "ScreenSelectStyle comment single", "select style comment single" },
|
||||
{ "ScreenSelectStyle comment double", "select style comment double" },
|
||||
{ "ScreenSelectStyle comment solo", "select style comment solo" },
|
||||
{ "ScreenSelectStyle comment versus", "select style comment versus" },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* Find an announcer directory with sounds in it. First search sFolderName,
|
||||
* then all aliases above. Ignore directories that are empty, since we might
|
||||
* have "select difficulty intro" with sounds and an empty "ScreenSelectDifficulty
|
||||
* intro". */
|
||||
RString AnnouncerManager::GetPathTo( RString sAnnouncerName, RString sFolderName )
|
||||
{
|
||||
if(sAnnouncerName == "")
|
||||
return RString(); /* announcer disabled */
|
||||
|
||||
const RString AnnouncerPath = GetAnnouncerDirFromName(sAnnouncerName);
|
||||
|
||||
if( !DirectoryIsEmpty(AnnouncerPath+sFolderName+"/") )
|
||||
return AnnouncerPath+sFolderName+"/";
|
||||
|
||||
/* Search for the announcer folder in the list of aliases. */
|
||||
int i;
|
||||
for(i = 0; aliases[i][0] != NULL; ++i)
|
||||
{
|
||||
if(!sFolderName.EqualsNoCase(aliases[i][0]))
|
||||
continue; /* no match */
|
||||
|
||||
if( !DirectoryIsEmpty(AnnouncerPath+aliases[i][1]+"/") )
|
||||
return AnnouncerPath+aliases[i][1]+"/";
|
||||
}
|
||||
|
||||
/* No announcer directory matched. In debug, create the directory by
|
||||
* its preferred name. */
|
||||
#ifdef DEBUG
|
||||
LOG->Trace( "The announcer in '%s' is missing the folder '%s'.",
|
||||
AnnouncerPath.c_str(), sFolderName.c_str() );
|
||||
// MessageBeep( MB_OK );
|
||||
RageFile temp;
|
||||
temp.Open( AnnouncerPath+sFolderName + "/announcer files go here.txt", RageFile::WRITE );
|
||||
#endif
|
||||
|
||||
return RString();
|
||||
}
|
||||
|
||||
RString AnnouncerManager::GetPathTo( RString sFolderName )
|
||||
{
|
||||
return GetPathTo(m_sCurAnnouncerName, sFolderName);
|
||||
}
|
||||
|
||||
bool AnnouncerManager::HasSoundsFor( RString sFolderName )
|
||||
{
|
||||
return !DirectoryIsEmpty( GetPathTo(sFolderName) );
|
||||
}
|
||||
|
||||
void AnnouncerManager::NextAnnouncer()
|
||||
{
|
||||
vector<RString> as;
|
||||
GetAnnouncerNames( as );
|
||||
if( as.size()==0 )
|
||||
return;
|
||||
|
||||
if( m_sCurAnnouncerName == "" )
|
||||
SwitchAnnouncer( as[0] );
|
||||
else
|
||||
{
|
||||
unsigned i;
|
||||
for( i=0; i<as.size(); i++ )
|
||||
if( as[i].EqualsNoCase(m_sCurAnnouncerName) )
|
||||
break;
|
||||
if( i==as.size()-1 )
|
||||
SwitchAnnouncer( "" );
|
||||
else
|
||||
{
|
||||
int iNewIndex = (i+1)%as.size();
|
||||
SwitchAnnouncer( as[iNewIndex] );
|
||||
}
|
||||
}
|
||||
}
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the AnnouncerManager. */
|
||||
class LunaAnnouncerManager: public Luna<AnnouncerManager>
|
||||
{
|
||||
public:
|
||||
static int DoesAnnouncerExist( T* p, lua_State *L ) { lua_pushboolean(L, p->DoesAnnouncerExist( SArg(1) )); return 1; }
|
||||
static int GetAnnouncerNames( T* p, lua_State *L )
|
||||
{
|
||||
vector<RString> vAnnouncers;
|
||||
p->GetAnnouncerNames( vAnnouncers );
|
||||
LuaHelpers::CreateTableFromArray(vAnnouncers, L);
|
||||
return 1;
|
||||
}
|
||||
static int GetCurrentAnnouncer( T* p, lua_State *L )
|
||||
{
|
||||
RString s = p->GetCurAnnouncerName();
|
||||
if( s.empty() )
|
||||
return 0;
|
||||
lua_pushstring(L, s );
|
||||
return 1;
|
||||
}
|
||||
static int SetCurrentAnnouncer( T* p, lua_State *L )
|
||||
{
|
||||
RString s = SArg(1);
|
||||
// only bother switching if the announcer exists. -aj
|
||||
if(p->DoesAnnouncerExist(s))
|
||||
p->SwitchAnnouncer(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LunaAnnouncerManager()
|
||||
{
|
||||
ADD_METHOD( DoesAnnouncerExist );
|
||||
ADD_METHOD( GetAnnouncerNames );
|
||||
ADD_METHOD( GetCurrentAnnouncer );
|
||||
ADD_METHOD( SetCurrentAnnouncer );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_CLASS( AnnouncerManager )
|
||||
// lua end
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
+74
-74
@@ -1,74 +1,74 @@
|
||||
#ifndef ANNOUNCER_MANAGER_H
|
||||
#define ANNOUNCER_MANAGER_H
|
||||
|
||||
#include "RageTypes.h"
|
||||
/** @brief The commentators who say seemlingly random things during gameplay. */
|
||||
class AnnouncerManager
|
||||
{
|
||||
public:
|
||||
AnnouncerManager();
|
||||
~AnnouncerManager();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the announcer names.
|
||||
* @param AddTo the list of announcer names. */
|
||||
void GetAnnouncerNames( vector<RString>& AddTo );
|
||||
/**
|
||||
* @brief Determine if the specified announcer exists.
|
||||
* @param sAnnouncerName the announcer we're checking for.
|
||||
* @return true if it exists, false otherwise. */
|
||||
bool DoesAnnouncerExist( RString sAnnouncerName );
|
||||
/**
|
||||
* @brief Switch to a new specified announcer.
|
||||
* @param sNewAnnouncerName the new announcer the Player will be listening to. */
|
||||
void SwitchAnnouncer( RString sNewAnnouncerName );
|
||||
/**
|
||||
* @brief Retrieve the current announcer's name.
|
||||
* @return the current announcer's name. */
|
||||
RString GetCurAnnouncerName() const { return m_sCurAnnouncerName; };
|
||||
void NextAnnouncer();
|
||||
|
||||
RString GetPathTo( RString sFolderName );
|
||||
bool HasSoundsFor( RString sFolderName );
|
||||
|
||||
// Lua
|
||||
void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
static RString GetAnnouncerDirFromName( RString sAnnouncerName );
|
||||
RString GetPathTo( RString AnnouncerPath, RString sFolderName );
|
||||
/** @brief the current announcer's name. */
|
||||
RString m_sCurAnnouncerName;
|
||||
};
|
||||
|
||||
|
||||
extern AnnouncerManager* ANNOUNCER; // global and accessable from anywhere in our program
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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 ANNOUNCER_MANAGER_H
|
||||
#define ANNOUNCER_MANAGER_H
|
||||
|
||||
#include "RageTypes.h"
|
||||
/** @brief The commentators who say seemlingly random things during gameplay. */
|
||||
class AnnouncerManager
|
||||
{
|
||||
public:
|
||||
AnnouncerManager();
|
||||
~AnnouncerManager();
|
||||
|
||||
/**
|
||||
* @brief Retrieve the announcer names.
|
||||
* @param AddTo the list of announcer names. */
|
||||
void GetAnnouncerNames( vector<RString>& AddTo );
|
||||
/**
|
||||
* @brief Determine if the specified announcer exists.
|
||||
* @param sAnnouncerName the announcer we're checking for.
|
||||
* @return true if it exists, false otherwise. */
|
||||
bool DoesAnnouncerExist( RString sAnnouncerName );
|
||||
/**
|
||||
* @brief Switch to a new specified announcer.
|
||||
* @param sNewAnnouncerName the new announcer the Player will be listening to. */
|
||||
void SwitchAnnouncer( RString sNewAnnouncerName );
|
||||
/**
|
||||
* @brief Retrieve the current announcer's name.
|
||||
* @return the current announcer's name. */
|
||||
RString GetCurAnnouncerName() const { return m_sCurAnnouncerName; };
|
||||
void NextAnnouncer();
|
||||
|
||||
RString GetPathTo( RString sFolderName );
|
||||
bool HasSoundsFor( RString sFolderName );
|
||||
|
||||
// Lua
|
||||
void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
static RString GetAnnouncerDirFromName( RString sAnnouncerName );
|
||||
RString GetPathTo( RString AnnouncerPath, RString sFolderName );
|
||||
/** @brief the current announcer's name. */
|
||||
RString m_sCurAnnouncerName;
|
||||
};
|
||||
|
||||
|
||||
extern AnnouncerManager* ANNOUNCER; // global and accessable from anywhere in our program
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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.
|
||||
*/
|
||||
|
||||
+787
-787
File diff suppressed because it is too large
Load Diff
+116
-116
@@ -1,116 +1,116 @@
|
||||
#ifndef ARROWEFFECTS_H
|
||||
#define ARROWEFFECTS_H
|
||||
|
||||
class PlayerState;
|
||||
/** @brief Functions that return properties of arrows based on Style and PlayerOptions. */
|
||||
class ArrowEffects
|
||||
{
|
||||
public:
|
||||
static void Update();
|
||||
|
||||
// fYOffset is a vertical position in pixels relative to the center
|
||||
// (positive if has not yet been stepped on, negative if has already passed).
|
||||
// The ArrowEffect and ScrollSpeed is applied in this stage.
|
||||
static float GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, float &fPeakYOffsetOut, bool &bIsPastPeakYOffset, bool bAbsolute=false );
|
||||
static float GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, bool bAbsolute=false )
|
||||
{
|
||||
float fThrowAway;
|
||||
bool bThrowAway;
|
||||
return GetYOffset( pPlayerState, iCol, fNoteBeat, fThrowAway, bThrowAway, bAbsolute );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve the actual display position.
|
||||
*
|
||||
* In this case, reverse and post-reverse-effects are factored in (fYOffset -> YPos).
|
||||
* @param pPlayerState the Player's state in question, including mods.
|
||||
* @param iCol the specific arrow column.
|
||||
* @param fYOffset the original display position.
|
||||
* @param fYReverseOffsetPixels the amount offset due to reverse.
|
||||
* @param WithReverse a flag to see if the Reverse mod is on.
|
||||
* @return the actual display position. */
|
||||
static float GetYPos( const PlayerState* pPlayerState, int iCol, float fYOffset, float fYReverseOffsetPixels, bool WithReverse = true );
|
||||
|
||||
// Inverse of ArrowGetYPos (YPos -> fYOffset).
|
||||
static float GetYOffsetFromYPos( const PlayerState* pPlayerState, int iCol, float YPos, float fYReverseOffsetPixels );
|
||||
|
||||
// fRotation is Z rotation of an arrow. This will depend on the column of
|
||||
// the arrow and possibly the Arrow effect and the fYOffset (in the case of
|
||||
// EFFECT_DIZZY).
|
||||
static float GetRotationZ( const PlayerState* pPlayerState, float fNoteBeat, bool bIsHoldHead );
|
||||
static float ReceptorGetRotationZ( const PlayerState* pPlayerState );
|
||||
|
||||
// Due to the handling logic for holds on Twirl, we need to use an offset instead.
|
||||
// It's more intuitive for Roll to be based off offset, so use an offset there too.
|
||||
static float GetRotationX( const PlayerState* pPlayerState, float fYOffset );
|
||||
static float GetRotationY( const PlayerState* pPlayerState, float fYOffset );
|
||||
|
||||
// fXPos is a horizontal position in pixels relative to the center of the field.
|
||||
// This depends on the column of the arrow and possibly the Arrow effect and
|
||||
// fYPos (in the case of EFFECT_DRUNK).
|
||||
static float GetXPos( const PlayerState* pPlayerState, int iCol, float fYOffset );
|
||||
|
||||
/**
|
||||
* @brief Retrieve the Z position.
|
||||
*
|
||||
* This is normally 0. This is only visible with perspective modes.
|
||||
* @param pPlayerState the Player's state, including the mods.
|
||||
* @param iCol the specific arrow column.
|
||||
* @param fYPos the Y position of the arrow.
|
||||
* @return the Z position. */
|
||||
static float GetZPos( const PlayerState* pPlayerState, int iCol, float fYPos );
|
||||
|
||||
// Enable this if any ZPos effects are enabled.
|
||||
static bool NeedZBuffer( const PlayerState* pPlayerState );
|
||||
|
||||
// fAlpha is the transparency of the arrow. It depends on fYPos and the
|
||||
// AppearanceType.
|
||||
static float GetAlpha( const PlayerState* pPlayerState, int iCol, float fYPos, float fPercentFadeToFail, float fYReverseOffsetPixels, float fDrawDistanceBeforeTargetsPixels, float fFadeInPercentOfDrawFar );
|
||||
|
||||
// fAlpha is the transparency of the arrow. It depends on fYPos and the
|
||||
// AppearanceType.
|
||||
static float GetGlow( const PlayerState* pPlayerState, int iCol, float fYPos, float fPercentFadeToFail, float fYReverseOffsetPixels, float fDrawDistanceBeforeTargetsPixels, float fFadeInPercentOfDrawFar );
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current brightness.
|
||||
*
|
||||
* Note that this depends on fYOffset.
|
||||
* @param pPlayerState the present PlayerState.
|
||||
* @param fNoteBeat the current beat.
|
||||
* @return the current brightness. */
|
||||
static float GetBrightness( const PlayerState* pPlayerState, float fNoteBeat );
|
||||
|
||||
// This is the zoom of the individual tracks, not of the whole Player.
|
||||
static float GetZoom( const PlayerState* pPlayerState );
|
||||
|
||||
static float GetFrameWidthScale( const PlayerState* pPlayerState, float fYOffset, float fOverlappedTime );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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 ARROWEFFECTS_H
|
||||
#define ARROWEFFECTS_H
|
||||
|
||||
class PlayerState;
|
||||
/** @brief Functions that return properties of arrows based on Style and PlayerOptions. */
|
||||
class ArrowEffects
|
||||
{
|
||||
public:
|
||||
static void Update();
|
||||
|
||||
// fYOffset is a vertical position in pixels relative to the center
|
||||
// (positive if has not yet been stepped on, negative if has already passed).
|
||||
// The ArrowEffect and ScrollSpeed is applied in this stage.
|
||||
static float GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, float &fPeakYOffsetOut, bool &bIsPastPeakYOffset, bool bAbsolute=false );
|
||||
static float GetYOffset( const PlayerState* pPlayerState, int iCol, float fNoteBeat, bool bAbsolute=false )
|
||||
{
|
||||
float fThrowAway;
|
||||
bool bThrowAway;
|
||||
return GetYOffset( pPlayerState, iCol, fNoteBeat, fThrowAway, bThrowAway, bAbsolute );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieve the actual display position.
|
||||
*
|
||||
* In this case, reverse and post-reverse-effects are factored in (fYOffset -> YPos).
|
||||
* @param pPlayerState the Player's state in question, including mods.
|
||||
* @param iCol the specific arrow column.
|
||||
* @param fYOffset the original display position.
|
||||
* @param fYReverseOffsetPixels the amount offset due to reverse.
|
||||
* @param WithReverse a flag to see if the Reverse mod is on.
|
||||
* @return the actual display position. */
|
||||
static float GetYPos( const PlayerState* pPlayerState, int iCol, float fYOffset, float fYReverseOffsetPixels, bool WithReverse = true );
|
||||
|
||||
// Inverse of ArrowGetYPos (YPos -> fYOffset).
|
||||
static float GetYOffsetFromYPos( const PlayerState* pPlayerState, int iCol, float YPos, float fYReverseOffsetPixels );
|
||||
|
||||
// fRotation is Z rotation of an arrow. This will depend on the column of
|
||||
// the arrow and possibly the Arrow effect and the fYOffset (in the case of
|
||||
// EFFECT_DIZZY).
|
||||
static float GetRotationZ( const PlayerState* pPlayerState, float fNoteBeat, bool bIsHoldHead );
|
||||
static float ReceptorGetRotationZ( const PlayerState* pPlayerState );
|
||||
|
||||
// Due to the handling logic for holds on Twirl, we need to use an offset instead.
|
||||
// It's more intuitive for Roll to be based off offset, so use an offset there too.
|
||||
static float GetRotationX( const PlayerState* pPlayerState, float fYOffset );
|
||||
static float GetRotationY( const PlayerState* pPlayerState, float fYOffset );
|
||||
|
||||
// fXPos is a horizontal position in pixels relative to the center of the field.
|
||||
// This depends on the column of the arrow and possibly the Arrow effect and
|
||||
// fYPos (in the case of EFFECT_DRUNK).
|
||||
static float GetXPos( const PlayerState* pPlayerState, int iCol, float fYOffset );
|
||||
|
||||
/**
|
||||
* @brief Retrieve the Z position.
|
||||
*
|
||||
* This is normally 0. This is only visible with perspective modes.
|
||||
* @param pPlayerState the Player's state, including the mods.
|
||||
* @param iCol the specific arrow column.
|
||||
* @param fYPos the Y position of the arrow.
|
||||
* @return the Z position. */
|
||||
static float GetZPos( const PlayerState* pPlayerState, int iCol, float fYPos );
|
||||
|
||||
// Enable this if any ZPos effects are enabled.
|
||||
static bool NeedZBuffer( const PlayerState* pPlayerState );
|
||||
|
||||
// fAlpha is the transparency of the arrow. It depends on fYPos and the
|
||||
// AppearanceType.
|
||||
static float GetAlpha( const PlayerState* pPlayerState, int iCol, float fYPos, float fPercentFadeToFail, float fYReverseOffsetPixels, float fDrawDistanceBeforeTargetsPixels, float fFadeInPercentOfDrawFar );
|
||||
|
||||
// fAlpha is the transparency of the arrow. It depends on fYPos and the
|
||||
// AppearanceType.
|
||||
static float GetGlow( const PlayerState* pPlayerState, int iCol, float fYPos, float fPercentFadeToFail, float fYReverseOffsetPixels, float fDrawDistanceBeforeTargetsPixels, float fFadeInPercentOfDrawFar );
|
||||
|
||||
/**
|
||||
* @brief Retrieve the current brightness.
|
||||
*
|
||||
* Note that this depends on fYOffset.
|
||||
* @param pPlayerState the present PlayerState.
|
||||
* @param fNoteBeat the current beat.
|
||||
* @return the current brightness. */
|
||||
static float GetBrightness( const PlayerState* pPlayerState, float fNoteBeat );
|
||||
|
||||
// This is the zoom of the individual tracks, not of the whole Player.
|
||||
static float GetZoom( const PlayerState* pPlayerState );
|
||||
|
||||
static float GetFrameWidthScale( const PlayerState* pPlayerState, float fYOffset, float fOverlappedTime );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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.
|
||||
*/
|
||||
|
||||
+115
-115
@@ -1,115 +1,115 @@
|
||||
#include "global.h"
|
||||
#include "Attack.h"
|
||||
#include "GameState.h"
|
||||
#include "RageUtil.h"
|
||||
#include "Song.h"
|
||||
#include "Foreach.h"
|
||||
#include "PlayerOptions.h"
|
||||
#include "PlayerState.h"
|
||||
|
||||
void Attack::GetAttackBeats( const Song *pSong, float &fStartBeat, float &fEndBeat ) const
|
||||
{
|
||||
ASSERT( pSong );
|
||||
ASSERT_M( fStartSecond >= 0, ssprintf("StartSecond: %f",fStartSecond) );
|
||||
|
||||
fStartBeat = pSong->GetBeatFromElapsedTime( fStartSecond );
|
||||
fEndBeat = pSong->GetBeatFromElapsedTime( fStartSecond+fSecsRemaining );
|
||||
}
|
||||
|
||||
/* Get the range for an attack that's being applied in realtime, eg. during battle
|
||||
* mode. We need a PlayerState for this, so we can push the region off-screen to
|
||||
* prevent popping when the attack has note modifers. */
|
||||
void Attack::GetRealtimeAttackBeats( const Song *pSong, const PlayerState* pPlayerState, float &fStartBeat, float &fEndBeat ) const
|
||||
{
|
||||
if( fStartSecond >= 0 )
|
||||
{
|
||||
GetAttackBeats( pSong, fStartBeat, fEndBeat );
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT( pPlayerState );
|
||||
ASSERT( pSong );
|
||||
|
||||
/* If reasonable, push the attack forward 8 beats so that notes on screen don't change suddenly. */
|
||||
fStartBeat = min( GAMESTATE->m_fSongBeat+8, pPlayerState->m_fLastDrawnBeat );
|
||||
fStartBeat = truncf(fStartBeat)+1;
|
||||
|
||||
const float lStartSecond = pSong->GetElapsedTimeFromBeat( fStartBeat );
|
||||
const float fEndSecond = lStartSecond + fSecsRemaining;
|
||||
fEndBeat = pSong->GetBeatFromElapsedTime( fEndSecond );
|
||||
fEndBeat = truncf(fEndBeat)+1;
|
||||
|
||||
// loading the course should have caught this.
|
||||
ASSERT_M( fEndBeat >= fStartBeat, ssprintf("EndBeat %f >= StartBeat %f", fEndBeat, fStartBeat) );
|
||||
}
|
||||
|
||||
bool Attack::operator== ( const Attack &rhs ) const
|
||||
{
|
||||
#define EQUAL(a) (a==rhs.a)
|
||||
return
|
||||
EQUAL(level) &&
|
||||
EQUAL(fStartSecond) &&
|
||||
EQUAL(fSecsRemaining) &&
|
||||
EQUAL(sModifiers) &&
|
||||
EQUAL(bOn) &&
|
||||
EQUAL(bGlobal);
|
||||
}
|
||||
|
||||
bool Attack::ContainsTransformOrTurn() const
|
||||
{
|
||||
PlayerOptions po;
|
||||
po.FromString( sModifiers );
|
||||
return po.ContainsTransformOrTurn();
|
||||
}
|
||||
|
||||
Attack Attack::FromGlobalCourseModifier( const RString &sModifiers )
|
||||
{
|
||||
Attack a;
|
||||
a.fStartSecond = 0;
|
||||
a.fSecsRemaining = 10000; /* whole song */
|
||||
a.level = ATTACK_LEVEL_1;
|
||||
a.sModifiers = sModifiers;
|
||||
a.bGlobal = true;
|
||||
return a;
|
||||
}
|
||||
|
||||
RString Attack::GetTextDescription() const
|
||||
{
|
||||
RString s = sModifiers + " " + ssprintf("(%.2f seconds)", fSecsRemaining);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool AttackArray::ContainsTransformOrTurn() const
|
||||
{
|
||||
FOREACH_CONST( Attack, *this, a )
|
||||
{
|
||||
if( a->ContainsTransformOrTurn() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (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 "Attack.h"
|
||||
#include "GameState.h"
|
||||
#include "RageUtil.h"
|
||||
#include "Song.h"
|
||||
#include "Foreach.h"
|
||||
#include "PlayerOptions.h"
|
||||
#include "PlayerState.h"
|
||||
|
||||
void Attack::GetAttackBeats( const Song *pSong, float &fStartBeat, float &fEndBeat ) const
|
||||
{
|
||||
ASSERT( pSong );
|
||||
ASSERT_M( fStartSecond >= 0, ssprintf("StartSecond: %f",fStartSecond) );
|
||||
|
||||
fStartBeat = pSong->GetBeatFromElapsedTime( fStartSecond );
|
||||
fEndBeat = pSong->GetBeatFromElapsedTime( fStartSecond+fSecsRemaining );
|
||||
}
|
||||
|
||||
/* Get the range for an attack that's being applied in realtime, eg. during battle
|
||||
* mode. We need a PlayerState for this, so we can push the region off-screen to
|
||||
* prevent popping when the attack has note modifers. */
|
||||
void Attack::GetRealtimeAttackBeats( const Song *pSong, const PlayerState* pPlayerState, float &fStartBeat, float &fEndBeat ) const
|
||||
{
|
||||
if( fStartSecond >= 0 )
|
||||
{
|
||||
GetAttackBeats( pSong, fStartBeat, fEndBeat );
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT( pPlayerState );
|
||||
ASSERT( pSong );
|
||||
|
||||
/* If reasonable, push the attack forward 8 beats so that notes on screen don't change suddenly. */
|
||||
fStartBeat = min( GAMESTATE->m_fSongBeat+8, pPlayerState->m_fLastDrawnBeat );
|
||||
fStartBeat = truncf(fStartBeat)+1;
|
||||
|
||||
const float lStartSecond = pSong->GetElapsedTimeFromBeat( fStartBeat );
|
||||
const float fEndSecond = lStartSecond + fSecsRemaining;
|
||||
fEndBeat = pSong->GetBeatFromElapsedTime( fEndSecond );
|
||||
fEndBeat = truncf(fEndBeat)+1;
|
||||
|
||||
// loading the course should have caught this.
|
||||
ASSERT_M( fEndBeat >= fStartBeat, ssprintf("EndBeat %f >= StartBeat %f", fEndBeat, fStartBeat) );
|
||||
}
|
||||
|
||||
bool Attack::operator== ( const Attack &rhs ) const
|
||||
{
|
||||
#define EQUAL(a) (a==rhs.a)
|
||||
return
|
||||
EQUAL(level) &&
|
||||
EQUAL(fStartSecond) &&
|
||||
EQUAL(fSecsRemaining) &&
|
||||
EQUAL(sModifiers) &&
|
||||
EQUAL(bOn) &&
|
||||
EQUAL(bGlobal);
|
||||
}
|
||||
|
||||
bool Attack::ContainsTransformOrTurn() const
|
||||
{
|
||||
PlayerOptions po;
|
||||
po.FromString( sModifiers );
|
||||
return po.ContainsTransformOrTurn();
|
||||
}
|
||||
|
||||
Attack Attack::FromGlobalCourseModifier( const RString &sModifiers )
|
||||
{
|
||||
Attack a;
|
||||
a.fStartSecond = 0;
|
||||
a.fSecsRemaining = 10000; /* whole song */
|
||||
a.level = ATTACK_LEVEL_1;
|
||||
a.sModifiers = sModifiers;
|
||||
a.bGlobal = true;
|
||||
return a;
|
||||
}
|
||||
|
||||
RString Attack::GetTextDescription() const
|
||||
{
|
||||
RString s = sModifiers + " " + ssprintf("(%.2f seconds)", fSecsRemaining);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool AttackArray::ContainsTransformOrTurn() const
|
||||
{
|
||||
FOREACH_CONST( Attack, *this, a )
|
||||
{
|
||||
if( a->ContainsTransformOrTurn() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
+103
-103
@@ -1,103 +1,103 @@
|
||||
#ifndef ATTACK_H
|
||||
#define ATTACK_H
|
||||
|
||||
#include "GameConstantsAndTypes.h"
|
||||
#include "PlayerNumber.h"
|
||||
class Song;
|
||||
class PlayerState;
|
||||
/** @brief An action made against a Player to make things more difficult. */
|
||||
struct Attack
|
||||
{
|
||||
AttackLevel level;
|
||||
/**
|
||||
* @brief the starting point of this attack.
|
||||
*
|
||||
* If this is -1, then the attack starts now. */
|
||||
float fStartSecond;
|
||||
/** @brief How long does this attack last? */
|
||||
float fSecsRemaining;
|
||||
/** @brief The modifiers used for this attack. */
|
||||
RString sModifiers;
|
||||
bool bOn; // set and used by GAMESTATE
|
||||
bool bGlobal; // true for song-wide course mods
|
||||
bool bShowInAttackList;
|
||||
|
||||
void MakeBlank()
|
||||
{
|
||||
level = ATTACK_LEVEL_1;
|
||||
fStartSecond = -1;
|
||||
fSecsRemaining = 0;
|
||||
sModifiers = RString();
|
||||
bOn = false;
|
||||
bGlobal = false;
|
||||
bShowInAttackList = true;
|
||||
}
|
||||
Attack(): level(ATTACK_LEVEL_1), fStartSecond(-1),
|
||||
fSecsRemaining(0), sModifiers(RString()),
|
||||
bOn(false), bGlobal(false), bShowInAttackList(true)
|
||||
{} // MakeBlank() is effectively called here.
|
||||
Attack(
|
||||
AttackLevel level_,
|
||||
float fStartSecond_,
|
||||
float fSecsRemaining_,
|
||||
RString sModifiers_,
|
||||
bool bOn_,
|
||||
bool bGlobal_,
|
||||
bool bShowInAttackList_ = true ):
|
||||
level(level_), fStartSecond(fStartSecond_),
|
||||
fSecsRemaining(fSecsRemaining_), sModifiers(sModifiers_),
|
||||
bOn(bOn_), bGlobal(bGlobal_),
|
||||
bShowInAttackList(bShowInAttackList_) {}
|
||||
|
||||
void GetAttackBeats( const Song *pSong, float &fStartBeat, float &fEndBeat ) const;
|
||||
void GetRealtimeAttackBeats( const Song *pSong, const PlayerState* pPlayerState, float &fStartBeat, float &fEndBeat ) const;
|
||||
/**
|
||||
* @brief Determine if this attack has no modifiers, and is thus blank or empty.
|
||||
* @return true if it is blank/empty, or false otherwise. */
|
||||
bool IsBlank() const { return sModifiers.empty(); }
|
||||
/**
|
||||
* @brief Determine if two Attacks are equal to each other.
|
||||
* @param rhs the other Attack in question.
|
||||
* @return true if the two Attacks are equal, or false otherwise. */
|
||||
bool operator== ( const Attack &rhs ) const;
|
||||
bool ContainsTransformOrTurn() const;
|
||||
static Attack FromGlobalCourseModifier( const RString &sModifiers );
|
||||
RString GetTextDescription() const;
|
||||
};
|
||||
|
||||
struct AttackArray : public vector<Attack>
|
||||
{
|
||||
/**
|
||||
* @brief Determine if the list of attacks contains a transform or turn mod.
|
||||
* @return true if it does, or false otherwise. */
|
||||
bool ContainsTransformOrTurn() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2003-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 ATTACK_H
|
||||
#define ATTACK_H
|
||||
|
||||
#include "GameConstantsAndTypes.h"
|
||||
#include "PlayerNumber.h"
|
||||
class Song;
|
||||
class PlayerState;
|
||||
/** @brief An action made against a Player to make things more difficult. */
|
||||
struct Attack
|
||||
{
|
||||
AttackLevel level;
|
||||
/**
|
||||
* @brief the starting point of this attack.
|
||||
*
|
||||
* If this is -1, then the attack starts now. */
|
||||
float fStartSecond;
|
||||
/** @brief How long does this attack last? */
|
||||
float fSecsRemaining;
|
||||
/** @brief The modifiers used for this attack. */
|
||||
RString sModifiers;
|
||||
bool bOn; // set and used by GAMESTATE
|
||||
bool bGlobal; // true for song-wide course mods
|
||||
bool bShowInAttackList;
|
||||
|
||||
void MakeBlank()
|
||||
{
|
||||
level = ATTACK_LEVEL_1;
|
||||
fStartSecond = -1;
|
||||
fSecsRemaining = 0;
|
||||
sModifiers = RString();
|
||||
bOn = false;
|
||||
bGlobal = false;
|
||||
bShowInAttackList = true;
|
||||
}
|
||||
Attack(): level(ATTACK_LEVEL_1), fStartSecond(-1),
|
||||
fSecsRemaining(0), sModifiers(RString()),
|
||||
bOn(false), bGlobal(false), bShowInAttackList(true)
|
||||
{} // MakeBlank() is effectively called here.
|
||||
Attack(
|
||||
AttackLevel level_,
|
||||
float fStartSecond_,
|
||||
float fSecsRemaining_,
|
||||
RString sModifiers_,
|
||||
bool bOn_,
|
||||
bool bGlobal_,
|
||||
bool bShowInAttackList_ = true ):
|
||||
level(level_), fStartSecond(fStartSecond_),
|
||||
fSecsRemaining(fSecsRemaining_), sModifiers(sModifiers_),
|
||||
bOn(bOn_), bGlobal(bGlobal_),
|
||||
bShowInAttackList(bShowInAttackList_) {}
|
||||
|
||||
void GetAttackBeats( const Song *pSong, float &fStartBeat, float &fEndBeat ) const;
|
||||
void GetRealtimeAttackBeats( const Song *pSong, const PlayerState* pPlayerState, float &fStartBeat, float &fEndBeat ) const;
|
||||
/**
|
||||
* @brief Determine if this attack has no modifiers, and is thus blank or empty.
|
||||
* @return true if it is blank/empty, or false otherwise. */
|
||||
bool IsBlank() const { return sModifiers.empty(); }
|
||||
/**
|
||||
* @brief Determine if two Attacks are equal to each other.
|
||||
* @param rhs the other Attack in question.
|
||||
* @return true if the two Attacks are equal, or false otherwise. */
|
||||
bool operator== ( const Attack &rhs ) const;
|
||||
bool ContainsTransformOrTurn() const;
|
||||
static Attack FromGlobalCourseModifier( const RString &sModifiers );
|
||||
RString GetTextDescription() const;
|
||||
};
|
||||
|
||||
struct AttackArray : public vector<Attack>
|
||||
{
|
||||
/**
|
||||
* @brief Determine if the list of attacks contains a transform or turn mod.
|
||||
* @return true if it does, or false otherwise. */
|
||||
bool ContainsTransformOrTurn() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2003-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.
|
||||
*/
|
||||
|
||||
+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 );
|
||||
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 );
|
||||
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.
|
||||
*/
|
||||
|
||||
+56
-56
@@ -1,56 +1,56 @@
|
||||
#ifndef AttackDisplay_H
|
||||
#define AttackDisplay_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
#include "Sprite.h"
|
||||
#include "GameConstantsAndTypes.h" // for TapNoteScore
|
||||
#include "RageTexturePreloader.h"
|
||||
|
||||
class PlayerState;
|
||||
/** @brief A graphical display for attacks. */
|
||||
class AttackDisplay : public ActorFrame
|
||||
{
|
||||
public:
|
||||
AttackDisplay();
|
||||
|
||||
void Init( const PlayerState* pPlayerState );
|
||||
void SetAttack( const RString &mod );
|
||||
|
||||
virtual void Update( float fDelta );
|
||||
|
||||
protected:
|
||||
const PlayerState* m_pPlayerState;
|
||||
|
||||
Sprite m_sprAttack;
|
||||
|
||||
RageTexturePreloader m_TexturePreload;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2003
|
||||
* @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 AttackDisplay_H
|
||||
#define AttackDisplay_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
#include "Sprite.h"
|
||||
#include "GameConstantsAndTypes.h" // for TapNoteScore
|
||||
#include "RageTexturePreloader.h"
|
||||
|
||||
class PlayerState;
|
||||
/** @brief A graphical display for attacks. */
|
||||
class AttackDisplay : public ActorFrame
|
||||
{
|
||||
public:
|
||||
AttackDisplay();
|
||||
|
||||
void Init( const PlayerState* pPlayerState );
|
||||
void SetAttack( const RString &mod );
|
||||
|
||||
virtual void Update( float fDelta );
|
||||
|
||||
protected:
|
||||
const PlayerState* m_pPlayerState;
|
||||
|
||||
Sprite m_sprAttack;
|
||||
|
||||
RageTexturePreloader m_TexturePreload;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2003
|
||||
* @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.
|
||||
*/
|
||||
|
||||
+95
-95
@@ -1,95 +1,95 @@
|
||||
#include "global.h"
|
||||
#include "AutoActor.h"
|
||||
#include "ThemeManager.h"
|
||||
#include "Actor.h"
|
||||
#include "ActorUtil.h"
|
||||
|
||||
void AutoActor::Unload()
|
||||
{
|
||||
delete m_pActor;
|
||||
m_pActor=NULL;
|
||||
}
|
||||
|
||||
AutoActor::AutoActor( const AutoActor &cpy )
|
||||
{
|
||||
if( cpy.m_pActor == NULL )
|
||||
m_pActor = NULL;
|
||||
else
|
||||
m_pActor = cpy.m_pActor->Copy();
|
||||
}
|
||||
|
||||
AutoActor &AutoActor::operator=( const AutoActor &cpy )
|
||||
{
|
||||
Unload();
|
||||
|
||||
if( cpy.m_pActor == NULL )
|
||||
m_pActor = NULL;
|
||||
else
|
||||
m_pActor = cpy.m_pActor->Copy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void AutoActor::Load( Actor *pActor )
|
||||
{
|
||||
Unload();
|
||||
m_pActor = pActor;
|
||||
}
|
||||
|
||||
void AutoActor::Load( const RString &sPath )
|
||||
{
|
||||
Unload();
|
||||
m_pActor = ActorUtil::MakeActor( sPath );
|
||||
|
||||
// If a Condition is false, MakeActor will return NULL.
|
||||
if( m_pActor == NULL )
|
||||
m_pActor = new Actor;
|
||||
}
|
||||
|
||||
void AutoActor::LoadB( const RString &sMetricsGroup, const RString &sElement )
|
||||
{
|
||||
ThemeManager::PathInfo pi;
|
||||
bool b = THEME->GetPathInfo( pi, EC_BGANIMATIONS, sMetricsGroup, sElement );
|
||||
ASSERT( b );
|
||||
LuaThreadVariable var1( "MatchingMetricsGroup", pi.sMatchingMetricsGroup );
|
||||
LuaThreadVariable var2( "MatchingElement", pi.sMatchingElement );
|
||||
Load( pi.sResolvedPath );
|
||||
}
|
||||
|
||||
void AutoActor::LoadActorFromNode( const XNode* pNode, Actor *pParent )
|
||||
{
|
||||
Unload();
|
||||
|
||||
m_pActor = ActorUtil::LoadFromNode( pNode, pParent );
|
||||
}
|
||||
|
||||
void AutoActor::LoadAndSetName( const RString &sScreenName, const RString &sActorName )
|
||||
{
|
||||
Load( THEME->GetPathG(sScreenName,sActorName) );
|
||||
m_pActor->SetName( sActorName );
|
||||
ActorUtil::LoadAllCommands( *m_pActor, sScreenName );
|
||||
}
|
||||
|
||||
/*
|
||||
* (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 "AutoActor.h"
|
||||
#include "ThemeManager.h"
|
||||
#include "Actor.h"
|
||||
#include "ActorUtil.h"
|
||||
|
||||
void AutoActor::Unload()
|
||||
{
|
||||
delete m_pActor;
|
||||
m_pActor=NULL;
|
||||
}
|
||||
|
||||
AutoActor::AutoActor( const AutoActor &cpy )
|
||||
{
|
||||
if( cpy.m_pActor == NULL )
|
||||
m_pActor = NULL;
|
||||
else
|
||||
m_pActor = cpy.m_pActor->Copy();
|
||||
}
|
||||
|
||||
AutoActor &AutoActor::operator=( const AutoActor &cpy )
|
||||
{
|
||||
Unload();
|
||||
|
||||
if( cpy.m_pActor == NULL )
|
||||
m_pActor = NULL;
|
||||
else
|
||||
m_pActor = cpy.m_pActor->Copy();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void AutoActor::Load( Actor *pActor )
|
||||
{
|
||||
Unload();
|
||||
m_pActor = pActor;
|
||||
}
|
||||
|
||||
void AutoActor::Load( const RString &sPath )
|
||||
{
|
||||
Unload();
|
||||
m_pActor = ActorUtil::MakeActor( sPath );
|
||||
|
||||
// If a Condition is false, MakeActor will return NULL.
|
||||
if( m_pActor == NULL )
|
||||
m_pActor = new Actor;
|
||||
}
|
||||
|
||||
void AutoActor::LoadB( const RString &sMetricsGroup, const RString &sElement )
|
||||
{
|
||||
ThemeManager::PathInfo pi;
|
||||
bool b = THEME->GetPathInfo( pi, EC_BGANIMATIONS, sMetricsGroup, sElement );
|
||||
ASSERT( b );
|
||||
LuaThreadVariable var1( "MatchingMetricsGroup", pi.sMatchingMetricsGroup );
|
||||
LuaThreadVariable var2( "MatchingElement", pi.sMatchingElement );
|
||||
Load( pi.sResolvedPath );
|
||||
}
|
||||
|
||||
void AutoActor::LoadActorFromNode( const XNode* pNode, Actor *pParent )
|
||||
{
|
||||
Unload();
|
||||
|
||||
m_pActor = ActorUtil::LoadFromNode( pNode, pParent );
|
||||
}
|
||||
|
||||
void AutoActor::LoadAndSetName( const RString &sScreenName, const RString &sActorName )
|
||||
{
|
||||
Load( THEME->GetPathG(sScreenName,sActorName) );
|
||||
m_pActor->SetName( sActorName );
|
||||
ActorUtil::LoadAllCommands( *m_pActor, sScreenName );
|
||||
}
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
+66
-66
@@ -1,66 +1,66 @@
|
||||
#ifndef AutoActor_H
|
||||
#define AutoActor_H
|
||||
|
||||
class Actor;
|
||||
class XNode;
|
||||
|
||||
/**
|
||||
* @brief A smart pointer for Actor.
|
||||
*
|
||||
* This creates the appropriate Actor derivative on load and
|
||||
* automatically deletes the Actor on deconstruction. */
|
||||
class AutoActor
|
||||
{
|
||||
public:
|
||||
AutoActor() { m_pActor = NULL; }
|
||||
~AutoActor() { Unload(); }
|
||||
AutoActor( const AutoActor &cpy );
|
||||
AutoActor &operator =( const AutoActor &cpy );
|
||||
operator const Actor* () const { return m_pActor; }
|
||||
operator Actor* () { return m_pActor; }
|
||||
const Actor *operator->() const { return m_pActor; }
|
||||
Actor *operator->() { return m_pActor; }
|
||||
void Unload();
|
||||
/**
|
||||
* @brief Determine if this actor is presently loaded.
|
||||
* @return true if it is loaded, or false otherwise. */
|
||||
bool IsLoaded() const { return m_pActor != NULL; }
|
||||
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
|
||||
void LoadActorFromNode( const XNode *pNode, Actor *pParent );
|
||||
void LoadAndSetName( const RString &sScreenName, const RString &sActorName );
|
||||
|
||||
protected:
|
||||
/** @brief the Actor for which there is a smart pointer to. */
|
||||
Actor* m_pActor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2003-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 AutoActor_H
|
||||
#define AutoActor_H
|
||||
|
||||
class Actor;
|
||||
class XNode;
|
||||
|
||||
/**
|
||||
* @brief A smart pointer for Actor.
|
||||
*
|
||||
* This creates the appropriate Actor derivative on load and
|
||||
* automatically deletes the Actor on deconstruction. */
|
||||
class AutoActor
|
||||
{
|
||||
public:
|
||||
AutoActor() { m_pActor = NULL; }
|
||||
~AutoActor() { Unload(); }
|
||||
AutoActor( const AutoActor &cpy );
|
||||
AutoActor &operator =( const AutoActor &cpy );
|
||||
operator const Actor* () const { return m_pActor; }
|
||||
operator Actor* () { return m_pActor; }
|
||||
const Actor *operator->() const { return m_pActor; }
|
||||
Actor *operator->() { return m_pActor; }
|
||||
void Unload();
|
||||
/**
|
||||
* @brief Determine if this actor is presently loaded.
|
||||
* @return true if it is loaded, or false otherwise. */
|
||||
bool IsLoaded() const { return m_pActor != NULL; }
|
||||
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
|
||||
void LoadActorFromNode( const XNode *pNode, Actor *pParent );
|
||||
void LoadAndSetName( const RString &sScreenName, const RString &sActorName );
|
||||
|
||||
protected:
|
||||
/** @brief the Actor for which there is a smart pointer to. */
|
||||
Actor* m_pActor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2003-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.
|
||||
*/
|
||||
|
||||
+385
-385
@@ -1,385 +1,385 @@
|
||||
/*
|
||||
* This class handles two things: auto-play preload, and runtime auto-play sounds.
|
||||
*
|
||||
* On song start, all autoplay sounds and the main BGM track (if any) are combined
|
||||
* into a single chain, which is used as the song background. Sounds added this way
|
||||
* are removed from the NoteData.
|
||||
*
|
||||
* Any sounds not added to the sound chain and any autoplay sounds added to the NoteData
|
||||
* during play (usually due to battle mode mods) are played dynamically, via Update().
|
||||
*
|
||||
* Note that autoplay sounds which are played before the BGM starts will never be
|
||||
* placed in the sound chain, since the sound chain becomes the BGM; the BGM can't
|
||||
* play sound before it starts. These sounds will be left in the NoteData, and played
|
||||
* as dynamic sounds; this means that they don't get robust sync. This isn't a problem
|
||||
* for imported BMS files, which don't have an offset value, but it's annoying.
|
||||
*/
|
||||
|
||||
#include "global.h"
|
||||
#include "AutoKeysounds.h"
|
||||
#include "GameState.h"
|
||||
#include "Song.h"
|
||||
#include "RageSoundReader_Chain.h"
|
||||
#include "RageSoundReader_ChannelSplit.h"
|
||||
#include "RageSoundReader_Extend.h"
|
||||
#include "RageSoundReader_Merge.h"
|
||||
#include "RageSoundReader_Pan.h"
|
||||
#include "RageSoundReader_PitchChange.h"
|
||||
#include "RageSoundReader_PostBuffering.h"
|
||||
#include "RageSoundReader_ThreadedBuffer.h"
|
||||
#include "RageSoundManager.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageSoundReader_FileReader.h"
|
||||
#include "Foreach.h"
|
||||
|
||||
void AutoKeysounds::Load( PlayerNumber pn, const NoteData& ndAutoKeysoundsOnly )
|
||||
{
|
||||
m_ndAutoKeysoundsOnly[pn] = ndAutoKeysoundsOnly;
|
||||
}
|
||||
|
||||
void AutoKeysounds::LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain )
|
||||
{
|
||||
//
|
||||
// Load sounds.
|
||||
//
|
||||
Song* pSong = GAMESTATE->m_pCurSong;
|
||||
RString sSongDir = pSong->GetSongDir();
|
||||
|
||||
/*
|
||||
* Add all current autoplay sounds in both players to the chain. If a sound is
|
||||
* common to both players, don't pan it; otherwise pan it to that player's side.
|
||||
*/
|
||||
int iNumTracks = m_ndAutoKeysoundsOnly[GAMESTATE->m_MasterPlayerNumber].GetNumTracks();
|
||||
for( int t = 0; t < iNumTracks; t++ )
|
||||
{
|
||||
int iRow = -1;
|
||||
while(1)
|
||||
{
|
||||
/* Find the next row that either player has a note on. */
|
||||
int iNextRow = INT_MAX;
|
||||
FOREACH_EnabledPlayer(pn)
|
||||
{
|
||||
// XXX Hack. Enabled players need not have their own note data.
|
||||
if( t >= m_ndAutoKeysoundsOnly[pn].GetNumTracks() )
|
||||
continue;
|
||||
int iNextRowForPlayer = iRow;
|
||||
if( m_ndAutoKeysoundsOnly[pn].GetNextTapNoteRowForTrack( t, iNextRowForPlayer ) )
|
||||
iNextRow = min( iNextRow, iNextRowForPlayer );
|
||||
}
|
||||
|
||||
if( iNextRow == INT_MAX )
|
||||
break;
|
||||
iRow = iNextRow;
|
||||
|
||||
TapNote tn[NUM_PLAYERS];
|
||||
FOREACH_EnabledPlayer(pn)
|
||||
tn[pn] = m_ndAutoKeysoundsOnly[pn].GetTapNote( t, iRow );
|
||||
|
||||
/* Do all enabled players have the same note here? (Having no note at all
|
||||
* counts as having a different note.) */
|
||||
bool bSoundIsGlobal = true;
|
||||
{
|
||||
PlayerNumber pn = GetNextEnabledPlayer((PlayerNumber)-1);
|
||||
const TapNote &tap = tn[pn];
|
||||
pn = GetNextEnabledPlayer(pn);
|
||||
while( pn != PLAYER_INVALID )
|
||||
{
|
||||
if( tn[pn].type != TapNote::autoKeysound || tn[pn].iKeysoundIndex != tap.iKeysoundIndex )
|
||||
bSoundIsGlobal = false;
|
||||
pn = GetNextEnabledPlayer(pn);
|
||||
}
|
||||
}
|
||||
|
||||
FOREACH_EnabledPlayer(pn)
|
||||
{
|
||||
if( tn[pn] == TAP_EMPTY )
|
||||
continue;
|
||||
|
||||
ASSERT( tn[pn].type == TapNote::autoKeysound );
|
||||
if( tn[pn].iKeysoundIndex >= 0 )
|
||||
{
|
||||
RString sKeysoundFilePath = sSongDir + pSong->m_vsKeysoundFile[tn[pn].iKeysoundIndex];
|
||||
float fSeconds = pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(iRow) );
|
||||
|
||||
float fPan = 0;
|
||||
if( !bSoundIsGlobal )
|
||||
fPan = (pn == PLAYER_1)? -1.0f:+1.0f;
|
||||
int iIndex = pChain->LoadSound( sKeysoundFilePath );
|
||||
pChain->AddSound( iIndex, fSeconds, fPan );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoKeysounds::LoadTracks( const Song *pSong, RageSoundReader *&pShared, RageSoundReader *&pPlayer1, RageSoundReader *&pPlayer2 )
|
||||
{
|
||||
// If we have two players, prefer a three-track sound; otherwise prefer a
|
||||
// two-track sound.
|
||||
//bool bTwoPlayers = GAMESTATE->GetNumPlayersEnabled() == 2;
|
||||
|
||||
pPlayer1 = NULL;
|
||||
pPlayer2 = NULL;
|
||||
pShared = NULL;
|
||||
|
||||
vector<RString> vsMusicFile;
|
||||
const RString sMusicPath = pSong->GetMusicPath();
|
||||
|
||||
if( !sMusicPath.empty() )
|
||||
vsMusicFile.push_back( sMusicPath );
|
||||
|
||||
FOREACH_ENUM( InstrumentTrack, it )
|
||||
{
|
||||
if( it == InstrumentTrack_Guitar )
|
||||
continue;
|
||||
if( pSong->HasInstrumentTrack(it) )
|
||||
vsMusicFile.push_back( pSong->GetInstrumentTrackPath(it) );
|
||||
}
|
||||
|
||||
|
||||
vector<RageSoundReader *> vpSounds;
|
||||
FOREACH( RString, vsMusicFile, s )
|
||||
{
|
||||
RString sError;
|
||||
RageSoundReader *pSongReader = RageSoundReader_FileReader::OpenFile( *s, sError );
|
||||
vpSounds.push_back( pSongReader );
|
||||
}
|
||||
|
||||
if( vpSounds.size() == 1 )
|
||||
{
|
||||
RageSoundReader *pSongReader = vpSounds[0];
|
||||
|
||||
// Load the buffering filter before the effects filters, so effects aren't delayed.
|
||||
pSongReader = new RageSoundReader_Extend( pSongReader );
|
||||
pSongReader = new RageSoundReader_ThreadedBuffer( pSongReader );
|
||||
pShared = pSongReader;
|
||||
}
|
||||
else if( !vpSounds.empty() )
|
||||
{
|
||||
RageSoundReader_Merge *pMerge = new RageSoundReader_Merge;
|
||||
|
||||
FOREACH( RageSoundReader *, vpSounds, so )
|
||||
pMerge->AddSound( *so );
|
||||
pMerge->Finish( SOUNDMAN->GetDriverSampleRate() );
|
||||
|
||||
RageSoundReader *pSongReader = pMerge;
|
||||
|
||||
// Load the buffering filter before the effects filters, so effects aren't delayed.
|
||||
pSongReader = new RageSoundReader_Extend( pSongReader );
|
||||
pSongReader = new RageSoundReader_ThreadedBuffer( pSongReader );
|
||||
pShared = pSongReader;
|
||||
}
|
||||
|
||||
|
||||
if( pSong->HasInstrumentTrack(InstrumentTrack_Guitar) )
|
||||
{
|
||||
RString sError;
|
||||
RageSoundReader *pGuitarTrackReader = RageSoundReader_FileReader::OpenFile( pSong->GetInstrumentTrackPath(InstrumentTrack_Guitar), sError );
|
||||
// Load the buffering filter before the effects filters, so effects aren't delayed.
|
||||
pGuitarTrackReader = new RageSoundReader_Extend( pGuitarTrackReader );
|
||||
pGuitarTrackReader = new RageSoundReader_ThreadedBuffer( pGuitarTrackReader );
|
||||
pPlayer1 = pGuitarTrackReader;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
//if( pSongReader->GetNumChannels() <= 2 )
|
||||
//{
|
||||
// /* If we only have one track, return it as the shared track. */
|
||||
// pShared = pSongReader;
|
||||
// return;
|
||||
//}
|
||||
|
||||
// TODO: Make this work for player 2, and for 2 players
|
||||
|
||||
/* The code below is used to split the main sound stream into per-player
|
||||
* sounds. The results of this method doesn't seem interesting enough to
|
||||
* bother supporting this. */
|
||||
|
||||
//RageSoundSplitter Splitter( pSongReader );
|
||||
|
||||
//RageSoundReader_Split *pMainSound = Splitter.CreateSound();
|
||||
//pMainSound->AddSourceChannelToSound( 0, 0 );
|
||||
//if( pSongReader->GetNumChannels() >= 2 ) // stereo
|
||||
// pMainSound->AddSourceChannelToSound( 1, 1 );
|
||||
//pShared = pMainSound;
|
||||
|
||||
//RageSoundReader_Split *pLeadSound = Splitter.CreateSound();
|
||||
//pLeadSound->AddSourceChannelToSound( 2, 0 );
|
||||
//if( pSongReader->GetNumChannels() >= 4 ) // stereo
|
||||
// pLeadSound->AddSourceChannelToSound( 3, 1 );
|
||||
//pPlayer1 = pLeadSound;
|
||||
|
||||
//if( pSongReader->GetNumChannels() >= 5 )
|
||||
//{
|
||||
// if( bTwoPlayers )
|
||||
// {
|
||||
// RageSoundReader_Split *pSecondarySound = Splitter.CreateSound();
|
||||
// pSecondarySound->AddSourceChannelToSound( 4, 0 );
|
||||
// if( pSongReader->GetNumChannels() >= 6 )
|
||||
// pSecondarySound->AddSourceChannelToSound( 5, 1 ); // stereo
|
||||
// else
|
||||
// pSecondarySound->AddSourceChannelToSound( 4, 1 ); // mono
|
||||
// pPlayer2 = pSecondarySound;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// /* We have a secondary track, but we only have one player. Mix it into
|
||||
// * the background track. */
|
||||
// pMainSound->AddSourceChannelToSound( 4, 0 );
|
||||
// if( pSongReader->GetNumChannels() >= 6 )
|
||||
// pMainSound->AddSourceChannelToSound( 5, 1 ); // stereo
|
||||
// else
|
||||
// pMainSound->AddSourceChannelToSound( 4, 1 ); // mono
|
||||
// }
|
||||
|
||||
//}
|
||||
//else if( bTwoPlayers )
|
||||
//{
|
||||
// /* We have two players, but only two tracks. Use the same track for both
|
||||
// * players. */
|
||||
// pPlayer2 = pPlayer1->Copy();
|
||||
// pPlayer1->SetProperty( "Balance", -1.0f );
|
||||
// pPlayer2->SetProperty( "Balance", +1.0f );
|
||||
//}
|
||||
}
|
||||
|
||||
void AutoKeysounds::FinishLoading()
|
||||
{
|
||||
m_sSound.Unload();
|
||||
|
||||
Song* pSong = GAMESTATE->m_pCurSong;
|
||||
|
||||
vector<RageSoundReader *> apSounds;
|
||||
LoadTracks( pSong, m_pSharedSound, m_pPlayerSounds[0], m_pPlayerSounds[1] );
|
||||
|
||||
// Load autoplay sounds, if any.
|
||||
{
|
||||
RageSoundReader_Chain *pChain = new RageSoundReader_Chain;
|
||||
pChain->SetPreferredSampleRate( SOUNDMAN->GetDriverSampleRate() );
|
||||
LoadAutoplaySoundsInto( pChain );
|
||||
|
||||
if( pChain->GetNumSounds() > 0 )
|
||||
{
|
||||
if( m_pSharedSound )
|
||||
{
|
||||
int iIndex = pChain->LoadSound( m_pSharedSound );
|
||||
pChain->AddSound( iIndex, 0.0f, 0 );
|
||||
}
|
||||
pChain->Finish();
|
||||
m_pSharedSound = pChain;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pChain;
|
||||
}
|
||||
}
|
||||
ASSERT( m_pSharedSound );
|
||||
|
||||
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 )
|
||||
{
|
||||
m_pPlayerSounds[0] = new RageSoundReader_PitchChange( m_pPlayerSounds[0] );
|
||||
m_pPlayerSounds[0] = new RageSoundReader_PostBuffering( m_pPlayerSounds[0] );
|
||||
m_pPlayerSounds[0] = new RageSoundReader_Pan( m_pPlayerSounds[0] );
|
||||
apSounds.push_back( m_pPlayerSounds[0] );
|
||||
}
|
||||
|
||||
if( m_pPlayerSounds[1] != NULL )
|
||||
{
|
||||
m_pPlayerSounds[1] = new RageSoundReader_PitchChange( m_pPlayerSounds[1] );
|
||||
m_pPlayerSounds[1] = new RageSoundReader_PostBuffering( m_pPlayerSounds[1] );
|
||||
m_pPlayerSounds[1] = new RageSoundReader_Pan( m_pPlayerSounds[1] );
|
||||
apSounds.push_back( m_pPlayerSounds[1] );
|
||||
}
|
||||
|
||||
if( GAMESTATE->GetNumPlayersEnabled() == 1 && GAMESTATE->m_MasterPlayerNumber == PLAYER_2 )
|
||||
swap( m_pPlayerSounds[PLAYER_1], m_pPlayerSounds[PLAYER_2] );
|
||||
|
||||
if( apSounds.size() > 1 )
|
||||
{
|
||||
RageSoundReader_Merge *pMerge = new RageSoundReader_Merge;
|
||||
|
||||
FOREACH( RageSoundReader *, apSounds, ps )
|
||||
pMerge->AddSound( *ps );
|
||||
|
||||
pMerge->Finish( SOUNDMAN->GetDriverSampleRate() );
|
||||
|
||||
m_pChain = pMerge;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT( !apSounds.empty() );
|
||||
m_pChain = apSounds[0];
|
||||
}
|
||||
|
||||
m_sSound.LoadSoundReader( m_pChain );
|
||||
}
|
||||
|
||||
void AutoKeysounds::Update( float fDelta )
|
||||
{
|
||||
// Play keysounds for crossed rows.
|
||||
/*
|
||||
bool bCrossedABeat = false;
|
||||
{
|
||||
float fPositionSeconds = GAMESTATE->m_fMusicSeconds;
|
||||
float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds );
|
||||
|
||||
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
|
||||
iRowNow = max( 0, iRowNow );
|
||||
static int iRowLastCrossed = 0;
|
||||
|
||||
float fBeatLast = roundf(NoteRowToBeat(iRowLastCrossed));
|
||||
float fBeatNow = roundf(NoteRowToBeat(iRowNow));
|
||||
|
||||
bCrossedABeat = fBeatLast != fBeatNow;
|
||||
|
||||
FOREACH_EnabledPlayer( pn )
|
||||
{
|
||||
const NoteData &nd = m_ndAutoKeysoundsOnly[pn];
|
||||
|
||||
for( int t=0; t<nd.GetNumTracks(); t++ )
|
||||
{
|
||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( nd, t, r, iRowLastCrossed+1, iRowNow )
|
||||
{
|
||||
const TapNote &tn = nd.GetTapNote( t, r );
|
||||
ASSERT( tn.type == TapNote::autoKeysound );
|
||||
if( tn.bKeysound )
|
||||
m_vKeysounds[tn.iKeysoundIndex].Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iRowLastCrossed = iRowNow;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 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.
|
||||
*/
|
||||
/*
|
||||
* This class handles two things: auto-play preload, and runtime auto-play sounds.
|
||||
*
|
||||
* On song start, all autoplay sounds and the main BGM track (if any) are combined
|
||||
* into a single chain, which is used as the song background. Sounds added this way
|
||||
* are removed from the NoteData.
|
||||
*
|
||||
* Any sounds not added to the sound chain and any autoplay sounds added to the NoteData
|
||||
* during play (usually due to battle mode mods) are played dynamically, via Update().
|
||||
*
|
||||
* Note that autoplay sounds which are played before the BGM starts will never be
|
||||
* placed in the sound chain, since the sound chain becomes the BGM; the BGM can't
|
||||
* play sound before it starts. These sounds will be left in the NoteData, and played
|
||||
* as dynamic sounds; this means that they don't get robust sync. This isn't a problem
|
||||
* for imported BMS files, which don't have an offset value, but it's annoying.
|
||||
*/
|
||||
|
||||
#include "global.h"
|
||||
#include "AutoKeysounds.h"
|
||||
#include "GameState.h"
|
||||
#include "Song.h"
|
||||
#include "RageSoundReader_Chain.h"
|
||||
#include "RageSoundReader_ChannelSplit.h"
|
||||
#include "RageSoundReader_Extend.h"
|
||||
#include "RageSoundReader_Merge.h"
|
||||
#include "RageSoundReader_Pan.h"
|
||||
#include "RageSoundReader_PitchChange.h"
|
||||
#include "RageSoundReader_PostBuffering.h"
|
||||
#include "RageSoundReader_ThreadedBuffer.h"
|
||||
#include "RageSoundManager.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageSoundReader_FileReader.h"
|
||||
#include "Foreach.h"
|
||||
|
||||
void AutoKeysounds::Load( PlayerNumber pn, const NoteData& ndAutoKeysoundsOnly )
|
||||
{
|
||||
m_ndAutoKeysoundsOnly[pn] = ndAutoKeysoundsOnly;
|
||||
}
|
||||
|
||||
void AutoKeysounds::LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain )
|
||||
{
|
||||
//
|
||||
// Load sounds.
|
||||
//
|
||||
Song* pSong = GAMESTATE->m_pCurSong;
|
||||
RString sSongDir = pSong->GetSongDir();
|
||||
|
||||
/*
|
||||
* Add all current autoplay sounds in both players to the chain. If a sound is
|
||||
* common to both players, don't pan it; otherwise pan it to that player's side.
|
||||
*/
|
||||
int iNumTracks = m_ndAutoKeysoundsOnly[GAMESTATE->m_MasterPlayerNumber].GetNumTracks();
|
||||
for( int t = 0; t < iNumTracks; t++ )
|
||||
{
|
||||
int iRow = -1;
|
||||
while(1)
|
||||
{
|
||||
/* Find the next row that either player has a note on. */
|
||||
int iNextRow = INT_MAX;
|
||||
FOREACH_EnabledPlayer(pn)
|
||||
{
|
||||
// XXX Hack. Enabled players need not have their own note data.
|
||||
if( t >= m_ndAutoKeysoundsOnly[pn].GetNumTracks() )
|
||||
continue;
|
||||
int iNextRowForPlayer = iRow;
|
||||
if( m_ndAutoKeysoundsOnly[pn].GetNextTapNoteRowForTrack( t, iNextRowForPlayer ) )
|
||||
iNextRow = min( iNextRow, iNextRowForPlayer );
|
||||
}
|
||||
|
||||
if( iNextRow == INT_MAX )
|
||||
break;
|
||||
iRow = iNextRow;
|
||||
|
||||
TapNote tn[NUM_PLAYERS];
|
||||
FOREACH_EnabledPlayer(pn)
|
||||
tn[pn] = m_ndAutoKeysoundsOnly[pn].GetTapNote( t, iRow );
|
||||
|
||||
/* Do all enabled players have the same note here? (Having no note at all
|
||||
* counts as having a different note.) */
|
||||
bool bSoundIsGlobal = true;
|
||||
{
|
||||
PlayerNumber pn = GetNextEnabledPlayer((PlayerNumber)-1);
|
||||
const TapNote &tap = tn[pn];
|
||||
pn = GetNextEnabledPlayer(pn);
|
||||
while( pn != PLAYER_INVALID )
|
||||
{
|
||||
if( tn[pn].type != TapNote::autoKeysound || tn[pn].iKeysoundIndex != tap.iKeysoundIndex )
|
||||
bSoundIsGlobal = false;
|
||||
pn = GetNextEnabledPlayer(pn);
|
||||
}
|
||||
}
|
||||
|
||||
FOREACH_EnabledPlayer(pn)
|
||||
{
|
||||
if( tn[pn] == TAP_EMPTY )
|
||||
continue;
|
||||
|
||||
ASSERT( tn[pn].type == TapNote::autoKeysound );
|
||||
if( tn[pn].iKeysoundIndex >= 0 )
|
||||
{
|
||||
RString sKeysoundFilePath = sSongDir + pSong->m_vsKeysoundFile[tn[pn].iKeysoundIndex];
|
||||
float fSeconds = pSong->m_Timing.GetElapsedTimeFromBeat( NoteRowToBeat(iRow) );
|
||||
|
||||
float fPan = 0;
|
||||
if( !bSoundIsGlobal )
|
||||
fPan = (pn == PLAYER_1)? -1.0f:+1.0f;
|
||||
int iIndex = pChain->LoadSound( sKeysoundFilePath );
|
||||
pChain->AddSound( iIndex, fSeconds, fPan );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoKeysounds::LoadTracks( const Song *pSong, RageSoundReader *&pShared, RageSoundReader *&pPlayer1, RageSoundReader *&pPlayer2 )
|
||||
{
|
||||
// If we have two players, prefer a three-track sound; otherwise prefer a
|
||||
// two-track sound.
|
||||
//bool bTwoPlayers = GAMESTATE->GetNumPlayersEnabled() == 2;
|
||||
|
||||
pPlayer1 = NULL;
|
||||
pPlayer2 = NULL;
|
||||
pShared = NULL;
|
||||
|
||||
vector<RString> vsMusicFile;
|
||||
const RString sMusicPath = pSong->GetMusicPath();
|
||||
|
||||
if( !sMusicPath.empty() )
|
||||
vsMusicFile.push_back( sMusicPath );
|
||||
|
||||
FOREACH_ENUM( InstrumentTrack, it )
|
||||
{
|
||||
if( it == InstrumentTrack_Guitar )
|
||||
continue;
|
||||
if( pSong->HasInstrumentTrack(it) )
|
||||
vsMusicFile.push_back( pSong->GetInstrumentTrackPath(it) );
|
||||
}
|
||||
|
||||
|
||||
vector<RageSoundReader *> vpSounds;
|
||||
FOREACH( RString, vsMusicFile, s )
|
||||
{
|
||||
RString sError;
|
||||
RageSoundReader *pSongReader = RageSoundReader_FileReader::OpenFile( *s, sError );
|
||||
vpSounds.push_back( pSongReader );
|
||||
}
|
||||
|
||||
if( vpSounds.size() == 1 )
|
||||
{
|
||||
RageSoundReader *pSongReader = vpSounds[0];
|
||||
|
||||
// Load the buffering filter before the effects filters, so effects aren't delayed.
|
||||
pSongReader = new RageSoundReader_Extend( pSongReader );
|
||||
pSongReader = new RageSoundReader_ThreadedBuffer( pSongReader );
|
||||
pShared = pSongReader;
|
||||
}
|
||||
else if( !vpSounds.empty() )
|
||||
{
|
||||
RageSoundReader_Merge *pMerge = new RageSoundReader_Merge;
|
||||
|
||||
FOREACH( RageSoundReader *, vpSounds, so )
|
||||
pMerge->AddSound( *so );
|
||||
pMerge->Finish( SOUNDMAN->GetDriverSampleRate() );
|
||||
|
||||
RageSoundReader *pSongReader = pMerge;
|
||||
|
||||
// Load the buffering filter before the effects filters, so effects aren't delayed.
|
||||
pSongReader = new RageSoundReader_Extend( pSongReader );
|
||||
pSongReader = new RageSoundReader_ThreadedBuffer( pSongReader );
|
||||
pShared = pSongReader;
|
||||
}
|
||||
|
||||
|
||||
if( pSong->HasInstrumentTrack(InstrumentTrack_Guitar) )
|
||||
{
|
||||
RString sError;
|
||||
RageSoundReader *pGuitarTrackReader = RageSoundReader_FileReader::OpenFile( pSong->GetInstrumentTrackPath(InstrumentTrack_Guitar), sError );
|
||||
// Load the buffering filter before the effects filters, so effects aren't delayed.
|
||||
pGuitarTrackReader = new RageSoundReader_Extend( pGuitarTrackReader );
|
||||
pGuitarTrackReader = new RageSoundReader_ThreadedBuffer( pGuitarTrackReader );
|
||||
pPlayer1 = pGuitarTrackReader;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
//if( pSongReader->GetNumChannels() <= 2 )
|
||||
//{
|
||||
// /* If we only have one track, return it as the shared track. */
|
||||
// pShared = pSongReader;
|
||||
// return;
|
||||
//}
|
||||
|
||||
// TODO: Make this work for player 2, and for 2 players
|
||||
|
||||
/* The code below is used to split the main sound stream into per-player
|
||||
* sounds. The results of this method doesn't seem interesting enough to
|
||||
* bother supporting this. */
|
||||
|
||||
//RageSoundSplitter Splitter( pSongReader );
|
||||
|
||||
//RageSoundReader_Split *pMainSound = Splitter.CreateSound();
|
||||
//pMainSound->AddSourceChannelToSound( 0, 0 );
|
||||
//if( pSongReader->GetNumChannels() >= 2 ) // stereo
|
||||
// pMainSound->AddSourceChannelToSound( 1, 1 );
|
||||
//pShared = pMainSound;
|
||||
|
||||
//RageSoundReader_Split *pLeadSound = Splitter.CreateSound();
|
||||
//pLeadSound->AddSourceChannelToSound( 2, 0 );
|
||||
//if( pSongReader->GetNumChannels() >= 4 ) // stereo
|
||||
// pLeadSound->AddSourceChannelToSound( 3, 1 );
|
||||
//pPlayer1 = pLeadSound;
|
||||
|
||||
//if( pSongReader->GetNumChannels() >= 5 )
|
||||
//{
|
||||
// if( bTwoPlayers )
|
||||
// {
|
||||
// RageSoundReader_Split *pSecondarySound = Splitter.CreateSound();
|
||||
// pSecondarySound->AddSourceChannelToSound( 4, 0 );
|
||||
// if( pSongReader->GetNumChannels() >= 6 )
|
||||
// pSecondarySound->AddSourceChannelToSound( 5, 1 ); // stereo
|
||||
// else
|
||||
// pSecondarySound->AddSourceChannelToSound( 4, 1 ); // mono
|
||||
// pPlayer2 = pSecondarySound;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// /* We have a secondary track, but we only have one player. Mix it into
|
||||
// * the background track. */
|
||||
// pMainSound->AddSourceChannelToSound( 4, 0 );
|
||||
// if( pSongReader->GetNumChannels() >= 6 )
|
||||
// pMainSound->AddSourceChannelToSound( 5, 1 ); // stereo
|
||||
// else
|
||||
// pMainSound->AddSourceChannelToSound( 4, 1 ); // mono
|
||||
// }
|
||||
|
||||
//}
|
||||
//else if( bTwoPlayers )
|
||||
//{
|
||||
// /* We have two players, but only two tracks. Use the same track for both
|
||||
// * players. */
|
||||
// pPlayer2 = pPlayer1->Copy();
|
||||
// pPlayer1->SetProperty( "Balance", -1.0f );
|
||||
// pPlayer2->SetProperty( "Balance", +1.0f );
|
||||
//}
|
||||
}
|
||||
|
||||
void AutoKeysounds::FinishLoading()
|
||||
{
|
||||
m_sSound.Unload();
|
||||
|
||||
Song* pSong = GAMESTATE->m_pCurSong;
|
||||
|
||||
vector<RageSoundReader *> apSounds;
|
||||
LoadTracks( pSong, m_pSharedSound, m_pPlayerSounds[0], m_pPlayerSounds[1] );
|
||||
|
||||
// Load autoplay sounds, if any.
|
||||
{
|
||||
RageSoundReader_Chain *pChain = new RageSoundReader_Chain;
|
||||
pChain->SetPreferredSampleRate( SOUNDMAN->GetDriverSampleRate() );
|
||||
LoadAutoplaySoundsInto( pChain );
|
||||
|
||||
if( pChain->GetNumSounds() > 0 )
|
||||
{
|
||||
if( m_pSharedSound )
|
||||
{
|
||||
int iIndex = pChain->LoadSound( m_pSharedSound );
|
||||
pChain->AddSound( iIndex, 0.0f, 0 );
|
||||
}
|
||||
pChain->Finish();
|
||||
m_pSharedSound = pChain;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pChain;
|
||||
}
|
||||
}
|
||||
ASSERT( m_pSharedSound );
|
||||
|
||||
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 )
|
||||
{
|
||||
m_pPlayerSounds[0] = new RageSoundReader_PitchChange( m_pPlayerSounds[0] );
|
||||
m_pPlayerSounds[0] = new RageSoundReader_PostBuffering( m_pPlayerSounds[0] );
|
||||
m_pPlayerSounds[0] = new RageSoundReader_Pan( m_pPlayerSounds[0] );
|
||||
apSounds.push_back( m_pPlayerSounds[0] );
|
||||
}
|
||||
|
||||
if( m_pPlayerSounds[1] != NULL )
|
||||
{
|
||||
m_pPlayerSounds[1] = new RageSoundReader_PitchChange( m_pPlayerSounds[1] );
|
||||
m_pPlayerSounds[1] = new RageSoundReader_PostBuffering( m_pPlayerSounds[1] );
|
||||
m_pPlayerSounds[1] = new RageSoundReader_Pan( m_pPlayerSounds[1] );
|
||||
apSounds.push_back( m_pPlayerSounds[1] );
|
||||
}
|
||||
|
||||
if( GAMESTATE->GetNumPlayersEnabled() == 1 && GAMESTATE->m_MasterPlayerNumber == PLAYER_2 )
|
||||
swap( m_pPlayerSounds[PLAYER_1], m_pPlayerSounds[PLAYER_2] );
|
||||
|
||||
if( apSounds.size() > 1 )
|
||||
{
|
||||
RageSoundReader_Merge *pMerge = new RageSoundReader_Merge;
|
||||
|
||||
FOREACH( RageSoundReader *, apSounds, ps )
|
||||
pMerge->AddSound( *ps );
|
||||
|
||||
pMerge->Finish( SOUNDMAN->GetDriverSampleRate() );
|
||||
|
||||
m_pChain = pMerge;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT( !apSounds.empty() );
|
||||
m_pChain = apSounds[0];
|
||||
}
|
||||
|
||||
m_sSound.LoadSoundReader( m_pChain );
|
||||
}
|
||||
|
||||
void AutoKeysounds::Update( float fDelta )
|
||||
{
|
||||
// Play keysounds for crossed rows.
|
||||
/*
|
||||
bool bCrossedABeat = false;
|
||||
{
|
||||
float fPositionSeconds = GAMESTATE->m_fMusicSeconds;
|
||||
float fSongBeat = GAMESTATE->m_pCurSong->GetBeatFromElapsedTime( fPositionSeconds );
|
||||
|
||||
int iRowNow = BeatToNoteRowNotRounded( fSongBeat );
|
||||
iRowNow = max( 0, iRowNow );
|
||||
static int iRowLastCrossed = 0;
|
||||
|
||||
float fBeatLast = roundf(NoteRowToBeat(iRowLastCrossed));
|
||||
float fBeatNow = roundf(NoteRowToBeat(iRowNow));
|
||||
|
||||
bCrossedABeat = fBeatLast != fBeatNow;
|
||||
|
||||
FOREACH_EnabledPlayer( pn )
|
||||
{
|
||||
const NoteData &nd = m_ndAutoKeysoundsOnly[pn];
|
||||
|
||||
for( int t=0; t<nd.GetNumTracks(); t++ )
|
||||
{
|
||||
FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( nd, t, r, iRowLastCrossed+1, iRowNow )
|
||||
{
|
||||
const TapNote &tn = nd.GetTapNote( t, r );
|
||||
ASSERT( tn.type == TapNote::autoKeysound );
|
||||
if( tn.bKeysound )
|
||||
m_vKeysounds[tn.iKeysoundIndex].Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iRowLastCrossed = iRowNow;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 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.
|
||||
*/
|
||||
|
||||
+62
-62
@@ -1,62 +1,62 @@
|
||||
#ifndef AUTO_KEYSOUNDS_H
|
||||
#define AUTO_KEYSOUNDS_H
|
||||
|
||||
#include "NoteData.h"
|
||||
#include "PlayerNumber.h"
|
||||
#include "RageSound.h"
|
||||
|
||||
class RageSoundReader;
|
||||
class RageSoundReader_Chain;
|
||||
class Song;
|
||||
/** @brief Handle playback of auto keysound notes. */
|
||||
class AutoKeysounds
|
||||
{
|
||||
public:
|
||||
void Load( PlayerNumber pn, const NoteData& ndAutoKeysoundsOnly );
|
||||
void Update( float fDelta );
|
||||
/** @brief Finish loading the main sounds, and setup the auto keysounds if any. */
|
||||
void FinishLoading();
|
||||
RageSound *GetSound() { return &m_sSound; }
|
||||
RageSoundReader *GetSharedSound() { return m_pSharedSound; }
|
||||
RageSoundReader *GetPlayerSound( PlayerNumber pn ) { if( pn == PLAYER_INVALID ) return NULL; return m_pPlayerSounds[pn]; }
|
||||
|
||||
protected:
|
||||
void LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain );
|
||||
static void LoadTracks( const Song *pSong, RageSoundReader *&pGlobal, RageSoundReader *&pPlayer1, RageSoundReader *&pPlayer2 );
|
||||
|
||||
NoteData m_ndAutoKeysoundsOnly[NUM_PLAYERS];
|
||||
vector<RageSound> m_vKeysounds;
|
||||
RageSound m_sSound;
|
||||
RageSoundReader *m_pChain; // owned by m_sSound
|
||||
RageSoundReader *m_pPlayerSounds[NUM_PLAYERS]; // owned by m_sSound
|
||||
RageSoundReader *m_pSharedSound; // owned by m_sSound
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford, Glenn Maynard (c) 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 AUTO_KEYSOUNDS_H
|
||||
#define AUTO_KEYSOUNDS_H
|
||||
|
||||
#include "NoteData.h"
|
||||
#include "PlayerNumber.h"
|
||||
#include "RageSound.h"
|
||||
|
||||
class RageSoundReader;
|
||||
class RageSoundReader_Chain;
|
||||
class Song;
|
||||
/** @brief Handle playback of auto keysound notes. */
|
||||
class AutoKeysounds
|
||||
{
|
||||
public:
|
||||
void Load( PlayerNumber pn, const NoteData& ndAutoKeysoundsOnly );
|
||||
void Update( float fDelta );
|
||||
/** @brief Finish loading the main sounds, and setup the auto keysounds if any. */
|
||||
void FinishLoading();
|
||||
RageSound *GetSound() { return &m_sSound; }
|
||||
RageSoundReader *GetSharedSound() { return m_pSharedSound; }
|
||||
RageSoundReader *GetPlayerSound( PlayerNumber pn ) { if( pn == PLAYER_INVALID ) return NULL; return m_pPlayerSounds[pn]; }
|
||||
|
||||
protected:
|
||||
void LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain );
|
||||
static void LoadTracks( const Song *pSong, RageSoundReader *&pGlobal, RageSoundReader *&pPlayer1, RageSoundReader *&pPlayer2 );
|
||||
|
||||
NoteData m_ndAutoKeysoundsOnly[NUM_PLAYERS];
|
||||
vector<RageSound> m_vKeysounds;
|
||||
RageSound m_sSound;
|
||||
RageSoundReader *m_pChain; // owned by m_sSound
|
||||
RageSoundReader *m_pPlayerSounds[NUM_PLAYERS]; // owned by m_sSound
|
||||
RageSoundReader *m_pSharedSound; // owned by m_sSound
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford, Glenn Maynard (c) 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.
|
||||
*/
|
||||
|
||||
+193
-193
@@ -1,193 +1,193 @@
|
||||
#include "global.h"
|
||||
#include "BGAnimation.h"
|
||||
#include "IniFile.h"
|
||||
#include "BGAnimationLayer.h"
|
||||
#include "RageUtil.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "Foreach.h"
|
||||
#include "LuaManager.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS(BGAnimation);
|
||||
|
||||
BGAnimation::BGAnimation()
|
||||
{
|
||||
}
|
||||
|
||||
BGAnimation::~BGAnimation()
|
||||
{
|
||||
DeleteAllChildren();
|
||||
}
|
||||
|
||||
static bool CompareLayerNames( const RString& s1, const RString& s2 )
|
||||
{
|
||||
int i1, i2;
|
||||
int ret;
|
||||
|
||||
ret = sscanf( s1, "Layer%d", &i1 );
|
||||
ASSERT( ret == 1 );
|
||||
ret = sscanf( s2, "Layer%d", &i2 );
|
||||
ASSERT( ret == 1 );
|
||||
return i1 < i2;
|
||||
}
|
||||
|
||||
void BGAnimation::AddLayersFromAniDir( const RString &_sAniDir, const XNode *pNode )
|
||||
{
|
||||
const RString& sAniDir = _sAniDir;
|
||||
|
||||
{
|
||||
vector<RString> vsLayerNames;
|
||||
FOREACH_CONST_Child( pNode, pLayer )
|
||||
{
|
||||
if( strncmp(pLayer->GetName(), "Layer", 5) == 0 )
|
||||
vsLayerNames.push_back( pLayer->GetName() );
|
||||
}
|
||||
|
||||
sort( vsLayerNames.begin(), vsLayerNames.end(), CompareLayerNames );
|
||||
|
||||
|
||||
FOREACH_CONST( RString, vsLayerNames, s )
|
||||
{
|
||||
const RString &sLayer = *s;
|
||||
const XNode* pKey = pNode->GetChild( sLayer );
|
||||
ASSERT( pKey );
|
||||
|
||||
RString sImportDir;
|
||||
if( pKey->GetAttrValue("Import", sImportDir) )
|
||||
{
|
||||
bool bCond;
|
||||
if( pKey->GetAttrValue("Condition",bCond) && !bCond )
|
||||
continue;
|
||||
|
||||
// import a whole BGAnimation
|
||||
sImportDir = sAniDir + sImportDir;
|
||||
CollapsePath( sImportDir );
|
||||
|
||||
if( sImportDir.Right(1) != "/" )
|
||||
sImportDir += "/";
|
||||
|
||||
ASSERT_M( IsADirectory(sImportDir), sImportDir + " isn't a directory" );
|
||||
|
||||
RString sPathToIni = sImportDir + "BGAnimation.ini";
|
||||
|
||||
IniFile ini2;
|
||||
ini2.ReadFile( sPathToIni );
|
||||
|
||||
AddLayersFromAniDir( sImportDir, &ini2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// import as a single layer
|
||||
BGAnimationLayer* bgLayer = new BGAnimationLayer;
|
||||
bgLayer->LoadFromNode( pKey );
|
||||
this->AddChild( bgLayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BGAnimation::LoadFromAniDir( const RString &_sAniDir )
|
||||
{
|
||||
DeleteAllChildren();
|
||||
|
||||
if( _sAniDir.empty() )
|
||||
return;
|
||||
|
||||
RString sAniDir = _sAniDir;
|
||||
if( sAniDir.Right(1) != "/" )
|
||||
sAniDir += "/";
|
||||
|
||||
ASSERT_M( IsADirectory(sAniDir), sAniDir + " isn't a directory" );
|
||||
|
||||
RString sPathToIni = sAniDir + "BGAnimation.ini";
|
||||
|
||||
if( DoesFileExist(sPathToIni) )
|
||||
{
|
||||
// This is a 3.9-style BGAnimation (using .ini)
|
||||
IniFile ini;
|
||||
ini.ReadFile( sPathToIni );
|
||||
|
||||
AddLayersFromAniDir( sAniDir, &ini ); // TODO: Check for circular load
|
||||
|
||||
XNode* pBGAnimation = ini.GetChild( "BGAnimation" );
|
||||
XNode dummy( "BGAnimation" );
|
||||
if( pBGAnimation == NULL )
|
||||
pBGAnimation = &dummy;
|
||||
|
||||
LoadFromNode( pBGAnimation );
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is an 3.0 and before-style BGAnimation (not using .ini)
|
||||
|
||||
// loading a directory of layers
|
||||
vector<RString> asImagePaths;
|
||||
ASSERT( sAniDir != "" );
|
||||
|
||||
GetDirListing( sAniDir+"*.png", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.jpg", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.gif", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.ogv", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.avi", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.mpg", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.mpeg", asImagePaths, false, true );
|
||||
|
||||
SortRStringArray( asImagePaths );
|
||||
|
||||
for( unsigned i=0; i<asImagePaths.size(); i++ )
|
||||
{
|
||||
const RString sPath = asImagePaths[i];
|
||||
if( Basename(sPath).Left(1) == "_" )
|
||||
continue; // don't directly load files starting with an underscore
|
||||
BGAnimationLayer* pLayer = new BGAnimationLayer;
|
||||
pLayer->LoadFromAniLayerFile( asImagePaths[i] );
|
||||
AddChild( pLayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BGAnimation::LoadFromNode( const XNode* pNode )
|
||||
{
|
||||
RString sDir;
|
||||
if( pNode->GetAttrValue("AniDir", sDir) )
|
||||
LoadFromAniDir( sDir );
|
||||
|
||||
ActorFrame::LoadFromNode( pNode );
|
||||
|
||||
/* Backwards-compatibility: if a "LengthSeconds" value is present, create a dummy
|
||||
* actor that sleeps for the given length of time. This will extend GetTweenTimeLeft. */
|
||||
float fLengthSeconds = 0;
|
||||
if( pNode->GetAttrValue( "LengthSeconds", fLengthSeconds ) )
|
||||
{
|
||||
Actor *pActor = new Actor;
|
||||
pActor->SetName( "BGAnimation dummy" );
|
||||
pActor->SetVisible( false );
|
||||
apActorCommands ap = ActorUtil::ParseActorCommands( ssprintf("sleep,%f",fLengthSeconds) );
|
||||
pActor->AddCommand( "On", ap );
|
||||
AddChild( pActor );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2001-2004 Ben Nordstrom, 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 "BGAnimation.h"
|
||||
#include "IniFile.h"
|
||||
#include "BGAnimationLayer.h"
|
||||
#include "RageUtil.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "Foreach.h"
|
||||
#include "LuaManager.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS(BGAnimation);
|
||||
|
||||
BGAnimation::BGAnimation()
|
||||
{
|
||||
}
|
||||
|
||||
BGAnimation::~BGAnimation()
|
||||
{
|
||||
DeleteAllChildren();
|
||||
}
|
||||
|
||||
static bool CompareLayerNames( const RString& s1, const RString& s2 )
|
||||
{
|
||||
int i1, i2;
|
||||
int ret;
|
||||
|
||||
ret = sscanf( s1, "Layer%d", &i1 );
|
||||
ASSERT( ret == 1 );
|
||||
ret = sscanf( s2, "Layer%d", &i2 );
|
||||
ASSERT( ret == 1 );
|
||||
return i1 < i2;
|
||||
}
|
||||
|
||||
void BGAnimation::AddLayersFromAniDir( const RString &_sAniDir, const XNode *pNode )
|
||||
{
|
||||
const RString& sAniDir = _sAniDir;
|
||||
|
||||
{
|
||||
vector<RString> vsLayerNames;
|
||||
FOREACH_CONST_Child( pNode, pLayer )
|
||||
{
|
||||
if( strncmp(pLayer->GetName(), "Layer", 5) == 0 )
|
||||
vsLayerNames.push_back( pLayer->GetName() );
|
||||
}
|
||||
|
||||
sort( vsLayerNames.begin(), vsLayerNames.end(), CompareLayerNames );
|
||||
|
||||
|
||||
FOREACH_CONST( RString, vsLayerNames, s )
|
||||
{
|
||||
const RString &sLayer = *s;
|
||||
const XNode* pKey = pNode->GetChild( sLayer );
|
||||
ASSERT( pKey );
|
||||
|
||||
RString sImportDir;
|
||||
if( pKey->GetAttrValue("Import", sImportDir) )
|
||||
{
|
||||
bool bCond;
|
||||
if( pKey->GetAttrValue("Condition",bCond) && !bCond )
|
||||
continue;
|
||||
|
||||
// import a whole BGAnimation
|
||||
sImportDir = sAniDir + sImportDir;
|
||||
CollapsePath( sImportDir );
|
||||
|
||||
if( sImportDir.Right(1) != "/" )
|
||||
sImportDir += "/";
|
||||
|
||||
ASSERT_M( IsADirectory(sImportDir), sImportDir + " isn't a directory" );
|
||||
|
||||
RString sPathToIni = sImportDir + "BGAnimation.ini";
|
||||
|
||||
IniFile ini2;
|
||||
ini2.ReadFile( sPathToIni );
|
||||
|
||||
AddLayersFromAniDir( sImportDir, &ini2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// import as a single layer
|
||||
BGAnimationLayer* bgLayer = new BGAnimationLayer;
|
||||
bgLayer->LoadFromNode( pKey );
|
||||
this->AddChild( bgLayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BGAnimation::LoadFromAniDir( const RString &_sAniDir )
|
||||
{
|
||||
DeleteAllChildren();
|
||||
|
||||
if( _sAniDir.empty() )
|
||||
return;
|
||||
|
||||
RString sAniDir = _sAniDir;
|
||||
if( sAniDir.Right(1) != "/" )
|
||||
sAniDir += "/";
|
||||
|
||||
ASSERT_M( IsADirectory(sAniDir), sAniDir + " isn't a directory" );
|
||||
|
||||
RString sPathToIni = sAniDir + "BGAnimation.ini";
|
||||
|
||||
if( DoesFileExist(sPathToIni) )
|
||||
{
|
||||
// This is a 3.9-style BGAnimation (using .ini)
|
||||
IniFile ini;
|
||||
ini.ReadFile( sPathToIni );
|
||||
|
||||
AddLayersFromAniDir( sAniDir, &ini ); // TODO: Check for circular load
|
||||
|
||||
XNode* pBGAnimation = ini.GetChild( "BGAnimation" );
|
||||
XNode dummy( "BGAnimation" );
|
||||
if( pBGAnimation == NULL )
|
||||
pBGAnimation = &dummy;
|
||||
|
||||
LoadFromNode( pBGAnimation );
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is an 3.0 and before-style BGAnimation (not using .ini)
|
||||
|
||||
// loading a directory of layers
|
||||
vector<RString> asImagePaths;
|
||||
ASSERT( sAniDir != "" );
|
||||
|
||||
GetDirListing( sAniDir+"*.png", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.jpg", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.gif", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.ogv", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.avi", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.mpg", asImagePaths, false, true );
|
||||
GetDirListing( sAniDir+"*.mpeg", asImagePaths, false, true );
|
||||
|
||||
SortRStringArray( asImagePaths );
|
||||
|
||||
for( unsigned i=0; i<asImagePaths.size(); i++ )
|
||||
{
|
||||
const RString sPath = asImagePaths[i];
|
||||
if( Basename(sPath).Left(1) == "_" )
|
||||
continue; // don't directly load files starting with an underscore
|
||||
BGAnimationLayer* pLayer = new BGAnimationLayer;
|
||||
pLayer->LoadFromAniLayerFile( asImagePaths[i] );
|
||||
AddChild( pLayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BGAnimation::LoadFromNode( const XNode* pNode )
|
||||
{
|
||||
RString sDir;
|
||||
if( pNode->GetAttrValue("AniDir", sDir) )
|
||||
LoadFromAniDir( sDir );
|
||||
|
||||
ActorFrame::LoadFromNode( pNode );
|
||||
|
||||
/* Backwards-compatibility: if a "LengthSeconds" value is present, create a dummy
|
||||
* actor that sleeps for the given length of time. This will extend GetTweenTimeLeft. */
|
||||
float fLengthSeconds = 0;
|
||||
if( pNode->GetAttrValue( "LengthSeconds", fLengthSeconds ) )
|
||||
{
|
||||
Actor *pActor = new Actor;
|
||||
pActor->SetName( "BGAnimation dummy" );
|
||||
pActor->SetVisible( false );
|
||||
apActorCommands ap = ActorUtil::ParseActorCommands( ssprintf("sleep,%f",fLengthSeconds) );
|
||||
pActor->AddCommand( "On", ap );
|
||||
AddChild( pActor );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2001-2004 Ben Nordstrom, 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.
|
||||
*/
|
||||
|
||||
+51
-51
@@ -1,51 +1,51 @@
|
||||
#ifndef BGANIMATION_H
|
||||
#define BGANIMATION_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
|
||||
class XNode;
|
||||
|
||||
/** @brief An ActorFrame that loads itself. */
|
||||
class BGAnimation : public ActorFrameAutoDeleteChildren
|
||||
{
|
||||
public:
|
||||
BGAnimation();
|
||||
virtual ~BGAnimation();
|
||||
|
||||
void LoadFromAniDir( const RString &sAniDir );
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
|
||||
virtual BGAnimation *Copy() const;
|
||||
|
||||
protected:
|
||||
void AddLayersFromAniDir( const RString &_sAniDir, const XNode *pNode );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Ben Nordstrom, Chris Danford (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 BGANIMATION_H
|
||||
#define BGANIMATION_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
|
||||
class XNode;
|
||||
|
||||
/** @brief An ActorFrame that loads itself. */
|
||||
class BGAnimation : public ActorFrameAutoDeleteChildren
|
||||
{
|
||||
public:
|
||||
BGAnimation();
|
||||
virtual ~BGAnimation();
|
||||
|
||||
void LoadFromAniDir( const RString &sAniDir );
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
|
||||
virtual BGAnimation *Copy() const;
|
||||
|
||||
protected:
|
||||
void AddLayersFromAniDir( const RString &_sAniDir, const XNode *pNode );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Ben Nordstrom, Chris Danford (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.
|
||||
*/
|
||||
|
||||
+671
-671
File diff suppressed because it is too large
Load Diff
+80
-80
@@ -1,80 +1,80 @@
|
||||
#ifndef BGANIMATIONLAYER_H
|
||||
#define BGANIMATIONLAYER_H
|
||||
|
||||
#include "GameConstantsAndTypes.h"
|
||||
#include "ActorFrame.h"
|
||||
#include <map>
|
||||
|
||||
class XNode;
|
||||
|
||||
/** @brief Layer elements used by BGAnimation. */
|
||||
class BGAnimationLayer : public ActorFrame
|
||||
{
|
||||
public:
|
||||
BGAnimationLayer();
|
||||
~BGAnimationLayer();
|
||||
|
||||
void LoadFromAniLayerFile( const RString& sPath );
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
|
||||
void UpdateInternal( float fDeltaTime );
|
||||
|
||||
float GetMaxTweenTimeLeft() const;
|
||||
|
||||
protected:
|
||||
vector<RageVector3> m_vParticleVelocity;
|
||||
|
||||
enum Type
|
||||
{
|
||||
TYPE_SPRITE,
|
||||
TYPE_PARTICLES,
|
||||
TYPE_TILES,
|
||||
NUM_TYPES,
|
||||
} m_Type;
|
||||
|
||||
// stretch stuff
|
||||
float m_fTexCoordVelocityX;
|
||||
float m_fTexCoordVelocityY;
|
||||
|
||||
// particles stuff
|
||||
bool m_bParticlesBounce;
|
||||
|
||||
// tiles stuff
|
||||
int m_iNumTilesWide;
|
||||
int m_iNumTilesHigh;
|
||||
float m_fTilesStartX;
|
||||
float m_fTilesStartY;
|
||||
float m_fTilesSpacingX;
|
||||
float m_fTilesSpacingY;
|
||||
float m_fTileVelocityX;
|
||||
float m_fTileVelocityY;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Ben Nordstrom, Chris Danford, 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 BGANIMATIONLAYER_H
|
||||
#define BGANIMATIONLAYER_H
|
||||
|
||||
#include "GameConstantsAndTypes.h"
|
||||
#include "ActorFrame.h"
|
||||
#include <map>
|
||||
|
||||
class XNode;
|
||||
|
||||
/** @brief Layer elements used by BGAnimation. */
|
||||
class BGAnimationLayer : public ActorFrame
|
||||
{
|
||||
public:
|
||||
BGAnimationLayer();
|
||||
~BGAnimationLayer();
|
||||
|
||||
void LoadFromAniLayerFile( const RString& sPath );
|
||||
void LoadFromNode( const XNode* pNode );
|
||||
|
||||
void UpdateInternal( float fDeltaTime );
|
||||
|
||||
float GetMaxTweenTimeLeft() const;
|
||||
|
||||
protected:
|
||||
vector<RageVector3> m_vParticleVelocity;
|
||||
|
||||
enum Type
|
||||
{
|
||||
TYPE_SPRITE,
|
||||
TYPE_PARTICLES,
|
||||
TYPE_TILES,
|
||||
NUM_TYPES,
|
||||
} m_Type;
|
||||
|
||||
// stretch stuff
|
||||
float m_fTexCoordVelocityX;
|
||||
float m_fTexCoordVelocityY;
|
||||
|
||||
// particles stuff
|
||||
bool m_bParticlesBounce;
|
||||
|
||||
// tiles stuff
|
||||
int m_iNumTilesWide;
|
||||
int m_iNumTilesHigh;
|
||||
float m_fTilesStartX;
|
||||
float m_fTilesStartY;
|
||||
float m_fTilesSpacingX;
|
||||
float m_fTilesSpacingY;
|
||||
float m_fTileVelocityX;
|
||||
float m_fTileVelocityY;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Ben Nordstrom, Chris Danford, 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.
|
||||
*/
|
||||
|
||||
+331
-331
@@ -1,331 +1,331 @@
|
||||
#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 <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" );
|
||||
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 );
|
||||
switch( pSong->m_DisplayBPMType )
|
||||
{
|
||||
case Song::DISPLAY_ACTUAL:
|
||||
case Song::DISPLAY_SPECIFIED:
|
||||
{
|
||||
DisplayBpms bpms;
|
||||
pSong->GetDisplayBpms( bpms );
|
||||
SetBPMRange( bpms );
|
||||
m_fCycleTime = 1.0f;
|
||||
}
|
||||
break;
|
||||
case Song::DISPLAY_RANDOM:
|
||||
CycleRandomly();
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void BPMDisplay::SetBpmFromCourse( const Course* pCourse )
|
||||
{
|
||||
ASSERT( pCourse );
|
||||
ASSERT( GAMESTATE->GetCurrentStyle() );
|
||||
|
||||
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
|
||||
Trail *pTrail = pCourse->GetTrail( st );
|
||||
ASSERT( pTrail );
|
||||
|
||||
m_fCycleTime = 0.2f;
|
||||
|
||||
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_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 GetText( T* p, lua_State *L ) { lua_pushstring( L, p->GetText() ); return 1; }
|
||||
|
||||
LunaBPMDisplay()
|
||||
{
|
||||
ADD_METHOD( SetFromGameState );
|
||||
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 <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" );
|
||||
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 );
|
||||
switch( pSong->m_DisplayBPMType )
|
||||
{
|
||||
case Song::DISPLAY_ACTUAL:
|
||||
case Song::DISPLAY_SPECIFIED:
|
||||
{
|
||||
DisplayBpms bpms;
|
||||
pSong->GetDisplayBpms( bpms );
|
||||
SetBPMRange( bpms );
|
||||
m_fCycleTime = 1.0f;
|
||||
}
|
||||
break;
|
||||
case Song::DISPLAY_RANDOM:
|
||||
CycleRandomly();
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
void BPMDisplay::SetBpmFromCourse( const Course* pCourse )
|
||||
{
|
||||
ASSERT( pCourse );
|
||||
ASSERT( GAMESTATE->GetCurrentStyle() );
|
||||
|
||||
StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
|
||||
Trail *pTrail = pCourse->GetTrail( st );
|
||||
ASSERT( pTrail );
|
||||
|
||||
m_fCycleTime = 0.2f;
|
||||
|
||||
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_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 GetText( T* p, lua_State *L ) { lua_pushstring( L, p->GetText() ); return 1; }
|
||||
|
||||
LunaBPMDisplay()
|
||||
{
|
||||
ADD_METHOD( SetFromGameState );
|
||||
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.
|
||||
*/
|
||||
|
||||
+138
-138
@@ -1,138 +1,138 @@
|
||||
#ifndef BPM_DISPLAY_H
|
||||
#define BPM_DISPLAY_H
|
||||
|
||||
#include "BitmapText.h"
|
||||
#include "AutoActor.h"
|
||||
#include "ThemeMetric.h"
|
||||
#include "LocalizedString.h"
|
||||
class Song;
|
||||
class Course;
|
||||
struct DisplayBpms;
|
||||
|
||||
/** @brief Displays a BPM or a range of BPMs. */
|
||||
class BPMDisplay : public BitmapText
|
||||
{
|
||||
public:
|
||||
/** @brief Set up the BPM Display with default values. */
|
||||
BPMDisplay();
|
||||
/** @brief Copy the BPMDisplay to another. */
|
||||
virtual BPMDisplay *Copy() const;
|
||||
/** @brief Load the various metrics needed. */
|
||||
void Load();
|
||||
/**
|
||||
* @brief Update the display as required.
|
||||
* @param fDeltaTime the changed time.
|
||||
*/
|
||||
virtual void Update( float fDeltaTime );
|
||||
void LoadFromNode( const XNode *pNode );
|
||||
/**
|
||||
* @brief Use the BPM[s] from a song.
|
||||
* @param pSong the song in question.
|
||||
*/
|
||||
void SetBpmFromSong( const Song* pSong );
|
||||
/**
|
||||
* @brief Use the BPM[s] from a course.
|
||||
* @param pCourse the course in question.
|
||||
*/
|
||||
void SetBpmFromCourse( const Course* pCourse );
|
||||
/**
|
||||
* @brief Use a specified, constant BPM.
|
||||
* @param fBPM the constant BPM.
|
||||
*/
|
||||
void SetConstantBpm( float fBPM );
|
||||
/**
|
||||
* @brief Have the BPMDisplay cycle between various BPMs.
|
||||
*/
|
||||
void CycleRandomly();
|
||||
/** @brief Don't use a BPM at all. */
|
||||
void NoBPM();
|
||||
/** @brief Have the BPMDisplay use various BPMs. */
|
||||
void SetVarious();
|
||||
/** @brief Have the GameState determine which BPMs to display. */
|
||||
void SetFromGameState();
|
||||
|
||||
// Lua
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Retrieve the active BPM on display.
|
||||
* @return the active BPM on display.
|
||||
*/
|
||||
float GetActiveBPM() const;
|
||||
/**
|
||||
* @brief Set the range to be used for the display.
|
||||
* @param bpms the set of BPMs to be used.
|
||||
*/
|
||||
void SetBPMRange( const DisplayBpms &bpms );
|
||||
|
||||
/** @brief The commands to use when there is no BPM. */
|
||||
ThemeMetric<apActorCommands> SET_NO_BPM_COMMAND;
|
||||
/** @brief The commands to use when there is a normal BPM. */
|
||||
ThemeMetric<apActorCommands> SET_NORMAL_COMMAND;
|
||||
/** @brief The commands to use when the BPM can change between 2 or more values. */
|
||||
ThemeMetric<apActorCommands> SET_CHANGING_COMMAND;
|
||||
/** @brief The commands to use when the BPM is random. */
|
||||
ThemeMetric<apActorCommands> SET_RANDOM_COMMAND;
|
||||
/** @brief The commands to use if it is an extra stage. */
|
||||
ThemeMetric<apActorCommands> SET_EXTRA_COMMAND;
|
||||
/** @brief A flag to determine if the BPMs cycle from low to high or just display both. */
|
||||
ThemeMetric<bool> CYCLE;
|
||||
/** @brief A flag to determine if QUESTIONMARKS_TEXT is shown. */
|
||||
ThemeMetric<bool> SHOW_QMARKS;
|
||||
/** @brief How often the random BPMs cycle themselves. */
|
||||
ThemeMetric<float> RANDOM_CYCLE_SPEED;
|
||||
/** @brief The text used to separate the low and high BPMs. */
|
||||
ThemeMetric<RString> SEPARATOR;
|
||||
/** @brief The text used when there is no BPM. */
|
||||
ThemeMetric<RString> NO_BPM_TEXT;
|
||||
/** @brief The text used when there are various BPMs for the song. */
|
||||
ThemeMetric<RString> VARIOUS_TEXT;
|
||||
/** @brief The text used when it is a random BPM. */
|
||||
ThemeMetric<RString> RANDOM_TEXT;
|
||||
/** @brief The text used as one possible option for random BPM. */
|
||||
ThemeMetric<RString> QUESTIONMARKS_TEXT;
|
||||
/** @brief The format string used for the numbers. */
|
||||
ThemeMetric<RString> BPM_FORMAT_STRING;
|
||||
|
||||
/** @brief The lowest valued BPM. */
|
||||
float m_fBPMFrom;
|
||||
/** @brief The highest valued BPM. */
|
||||
float m_fBPMTo;
|
||||
/** @brief The current BPM index used. */
|
||||
int m_iCurrentBPM;
|
||||
/** @brief The list of BPMs. */
|
||||
vector<float> m_BPMS;
|
||||
float m_fPercentInState;
|
||||
/** @brief How long it takes to cycle the various BPMs. */
|
||||
float m_fCycleTime;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2001-2002
|
||||
* @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 BPM_DISPLAY_H
|
||||
#define BPM_DISPLAY_H
|
||||
|
||||
#include "BitmapText.h"
|
||||
#include "AutoActor.h"
|
||||
#include "ThemeMetric.h"
|
||||
#include "LocalizedString.h"
|
||||
class Song;
|
||||
class Course;
|
||||
struct DisplayBpms;
|
||||
|
||||
/** @brief Displays a BPM or a range of BPMs. */
|
||||
class BPMDisplay : public BitmapText
|
||||
{
|
||||
public:
|
||||
/** @brief Set up the BPM Display with default values. */
|
||||
BPMDisplay();
|
||||
/** @brief Copy the BPMDisplay to another. */
|
||||
virtual BPMDisplay *Copy() const;
|
||||
/** @brief Load the various metrics needed. */
|
||||
void Load();
|
||||
/**
|
||||
* @brief Update the display as required.
|
||||
* @param fDeltaTime the changed time.
|
||||
*/
|
||||
virtual void Update( float fDeltaTime );
|
||||
void LoadFromNode( const XNode *pNode );
|
||||
/**
|
||||
* @brief Use the BPM[s] from a song.
|
||||
* @param pSong the song in question.
|
||||
*/
|
||||
void SetBpmFromSong( const Song* pSong );
|
||||
/**
|
||||
* @brief Use the BPM[s] from a course.
|
||||
* @param pCourse the course in question.
|
||||
*/
|
||||
void SetBpmFromCourse( const Course* pCourse );
|
||||
/**
|
||||
* @brief Use a specified, constant BPM.
|
||||
* @param fBPM the constant BPM.
|
||||
*/
|
||||
void SetConstantBpm( float fBPM );
|
||||
/**
|
||||
* @brief Have the BPMDisplay cycle between various BPMs.
|
||||
*/
|
||||
void CycleRandomly();
|
||||
/** @brief Don't use a BPM at all. */
|
||||
void NoBPM();
|
||||
/** @brief Have the BPMDisplay use various BPMs. */
|
||||
void SetVarious();
|
||||
/** @brief Have the GameState determine which BPMs to display. */
|
||||
void SetFromGameState();
|
||||
|
||||
// Lua
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Retrieve the active BPM on display.
|
||||
* @return the active BPM on display.
|
||||
*/
|
||||
float GetActiveBPM() const;
|
||||
/**
|
||||
* @brief Set the range to be used for the display.
|
||||
* @param bpms the set of BPMs to be used.
|
||||
*/
|
||||
void SetBPMRange( const DisplayBpms &bpms );
|
||||
|
||||
/** @brief The commands to use when there is no BPM. */
|
||||
ThemeMetric<apActorCommands> SET_NO_BPM_COMMAND;
|
||||
/** @brief The commands to use when there is a normal BPM. */
|
||||
ThemeMetric<apActorCommands> SET_NORMAL_COMMAND;
|
||||
/** @brief The commands to use when the BPM can change between 2 or more values. */
|
||||
ThemeMetric<apActorCommands> SET_CHANGING_COMMAND;
|
||||
/** @brief The commands to use when the BPM is random. */
|
||||
ThemeMetric<apActorCommands> SET_RANDOM_COMMAND;
|
||||
/** @brief The commands to use if it is an extra stage. */
|
||||
ThemeMetric<apActorCommands> SET_EXTRA_COMMAND;
|
||||
/** @brief A flag to determine if the BPMs cycle from low to high or just display both. */
|
||||
ThemeMetric<bool> CYCLE;
|
||||
/** @brief A flag to determine if QUESTIONMARKS_TEXT is shown. */
|
||||
ThemeMetric<bool> SHOW_QMARKS;
|
||||
/** @brief How often the random BPMs cycle themselves. */
|
||||
ThemeMetric<float> RANDOM_CYCLE_SPEED;
|
||||
/** @brief The text used to separate the low and high BPMs. */
|
||||
ThemeMetric<RString> SEPARATOR;
|
||||
/** @brief The text used when there is no BPM. */
|
||||
ThemeMetric<RString> NO_BPM_TEXT;
|
||||
/** @brief The text used when there are various BPMs for the song. */
|
||||
ThemeMetric<RString> VARIOUS_TEXT;
|
||||
/** @brief The text used when it is a random BPM. */
|
||||
ThemeMetric<RString> RANDOM_TEXT;
|
||||
/** @brief The text used as one possible option for random BPM. */
|
||||
ThemeMetric<RString> QUESTIONMARKS_TEXT;
|
||||
/** @brief The format string used for the numbers. */
|
||||
ThemeMetric<RString> BPM_FORMAT_STRING;
|
||||
|
||||
/** @brief The lowest valued BPM. */
|
||||
float m_fBPMFrom;
|
||||
/** @brief The highest valued BPM. */
|
||||
float m_fBPMTo;
|
||||
/** @brief The current BPM index used. */
|
||||
int m_iCurrentBPM;
|
||||
/** @brief The list of BPMs. */
|
||||
vector<float> m_BPMS;
|
||||
float m_fPercentInState;
|
||||
/** @brief How long it takes to cycle the various BPMs. */
|
||||
float m_fCycleTime;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (c) 2001-2002
|
||||
* @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.
|
||||
*/
|
||||
|
||||
+972
-972
File diff suppressed because it is too large
Load Diff
+64
-64
@@ -1,64 +1,64 @@
|
||||
#ifndef BACKGROUND_H
|
||||
#define BACKGROUND_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
#include "Quad.h"
|
||||
#include "PlayerNumber.h"
|
||||
#include "BackgroundUtil.h"
|
||||
|
||||
class DancingCharacters;
|
||||
class Song;
|
||||
class BackgroundImpl;
|
||||
/** @brief the Background that is behind the notes while playing. */
|
||||
class Background : public ActorFrame
|
||||
{
|
||||
public:
|
||||
Background();
|
||||
~Background();
|
||||
void Init();
|
||||
|
||||
virtual void LoadFromSong( const Song *pSong );
|
||||
virtual void Unload();
|
||||
|
||||
void FadeToActualBrightness();
|
||||
void SetBrightness( float fBrightness ); // overrides pref and Cover
|
||||
|
||||
/**
|
||||
* @brief Retrieve whatever dancing characters are in use.
|
||||
* @return the dancing characters. */
|
||||
DancingCharacters* GetDancingCharacters();
|
||||
|
||||
void GetLoadedBackgroundChanges( vector<BackgroundChange> **pBackgroundChangesOut );
|
||||
|
||||
protected:
|
||||
BackgroundImpl *m_pImpl;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford, Ben Nordstrom (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 BACKGROUND_H
|
||||
#define BACKGROUND_H
|
||||
|
||||
#include "ActorFrame.h"
|
||||
#include "Quad.h"
|
||||
#include "PlayerNumber.h"
|
||||
#include "BackgroundUtil.h"
|
||||
|
||||
class DancingCharacters;
|
||||
class Song;
|
||||
class BackgroundImpl;
|
||||
/** @brief the Background that is behind the notes while playing. */
|
||||
class Background : public ActorFrame
|
||||
{
|
||||
public:
|
||||
Background();
|
||||
~Background();
|
||||
void Init();
|
||||
|
||||
virtual void LoadFromSong( const Song *pSong );
|
||||
virtual void Unload();
|
||||
|
||||
void FadeToActualBrightness();
|
||||
void SetBrightness( float fBrightness ); // overrides pref and Cover
|
||||
|
||||
/**
|
||||
* @brief Retrieve whatever dancing characters are in use.
|
||||
* @return the dancing characters. */
|
||||
DancingCharacters* GetDancingCharacters();
|
||||
|
||||
void GetLoadedBackgroundChanges( vector<BackgroundChange> **pBackgroundChangesOut );
|
||||
|
||||
protected:
|
||||
BackgroundImpl *m_pImpl;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford, Ben Nordstrom (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.
|
||||
*/
|
||||
|
||||
+363
-363
@@ -1,363 +1,363 @@
|
||||
#include "global.h"
|
||||
#include "BackgroundUtil.h"
|
||||
#include "RageUtil.h"
|
||||
#include "Song.h"
|
||||
#include "Foreach.h"
|
||||
#include "IniFile.h"
|
||||
#include "RageLog.h"
|
||||
#include <set>
|
||||
#include "Background.h"
|
||||
|
||||
|
||||
bool BackgroundDef::operator<( const BackgroundDef &other ) const
|
||||
{
|
||||
#define COMPARE(x) if( x < other.x ) return true; else if( x > other.x ) return false;
|
||||
COMPARE( m_sEffect );
|
||||
COMPARE( m_sFile1 );
|
||||
COMPARE( m_sFile2 );
|
||||
COMPARE( m_sColor1 );
|
||||
COMPARE( m_sColor2 );
|
||||
#undef COMPARE
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BackgroundDef::operator==( const BackgroundDef &other ) const
|
||||
{
|
||||
return
|
||||
m_sEffect == other.m_sEffect &&
|
||||
m_sFile1 == other.m_sFile1 &&
|
||||
m_sFile2 == other.m_sFile2 &&
|
||||
m_sColor1 == other.m_sColor1 &&
|
||||
m_sColor2 == other.m_sColor2;
|
||||
}
|
||||
|
||||
XNode *BackgroundDef::CreateNode() const
|
||||
{
|
||||
XNode* pNode = new XNode( "BackgroundDef" );
|
||||
|
||||
if( !m_sEffect.empty() )
|
||||
pNode->AppendAttr( "Effect", m_sEffect );
|
||||
if( !m_sFile1.empty() )
|
||||
pNode->AppendAttr( "File1", m_sFile1 );
|
||||
if( !m_sFile2.empty() )
|
||||
pNode->AppendAttr( "File2", m_sFile2 );
|
||||
if( !m_sColor1.empty() )
|
||||
pNode->AppendAttr( "Color1", m_sColor1 );
|
||||
if( !m_sColor2.empty() )
|
||||
pNode->AppendAttr( "Color2", m_sColor2 );
|
||||
|
||||
return pNode;
|
||||
}
|
||||
|
||||
|
||||
RString BackgroundChange::GetTextDescription() const
|
||||
{
|
||||
vector<RString> vsParts;
|
||||
if( !m_def.m_sFile1.empty() ) vsParts.push_back( m_def.m_sFile1 );
|
||||
if( !m_def.m_sFile2.empty() ) vsParts.push_back( m_def.m_sFile2 );
|
||||
if( m_fRate!=1.0f ) vsParts.push_back( ssprintf("%.2f%%",m_fRate*100) );
|
||||
if( !m_sTransition.empty() ) vsParts.push_back( m_sTransition );
|
||||
if( !m_def.m_sEffect.empty() ) vsParts.push_back( m_def.m_sEffect );
|
||||
if( !m_def.m_sColor1.empty() ) vsParts.push_back( m_def.m_sColor1 );
|
||||
if( !m_def.m_sColor2.empty() ) vsParts.push_back( m_def.m_sColor2 );
|
||||
|
||||
if( vsParts.empty() )
|
||||
vsParts.push_back( "(empty)" );
|
||||
|
||||
RString s = join( "\n", vsParts );
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
const RString BACKGROUND_EFFECTS_DIR = "BackgroundEffects/";
|
||||
const RString BACKGROUND_TRANSITIONS_DIR = "BackgroundTransitions/";
|
||||
const RString BG_ANIMS_DIR = "BGAnimations/";
|
||||
const RString VISUALIZATIONS_DIR = "Visualizations/";
|
||||
const RString RANDOMMOVIES_DIR = "RandomMovies/";
|
||||
const RString SONG_MOVIES_DIR = "SongMovies/";
|
||||
|
||||
const RString RANDOM_BACKGROUND_FILE = "-random-";
|
||||
const RString NO_SONG_BG_FILE = "-nosongbg-";
|
||||
const RString SONG_BACKGROUND_FILE = "songbackground";
|
||||
|
||||
const RString SBE_UpperLeft = "UpperLeft";
|
||||
const RString SBE_Centered = "Centered";
|
||||
const RString SBE_StretchNormal = "StretchNormal";
|
||||
const RString SBE_StretchNoLoop = "StretchNoLoop";
|
||||
const RString SBE_StretchRewind = "StretchRewind";
|
||||
const RString SBT_CrossFade = "CrossFade";
|
||||
|
||||
static void StripCvsAndSvn( vector<RString> &vsPathsToStrip, vector<RString> &vsNamesToStrip )
|
||||
{
|
||||
ASSERT( vsPathsToStrip.size() == vsNamesToStrip.size() );
|
||||
for( unsigned i=0; i<vsNamesToStrip.size(); i++ )
|
||||
{
|
||||
if( vsNamesToStrip[i].Right(3).CompareNoCase("CVS") == 0 || vsNamesToStrip[i] == ".svn" )
|
||||
{
|
||||
vsPathsToStrip.erase( vsPathsToStrip.begin()+i );
|
||||
vsNamesToStrip.erase( vsNamesToStrip.begin()+i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CompareBackgroundChanges(const BackgroundChange &seg1, const BackgroundChange &seg2)
|
||||
{
|
||||
return seg1.m_fStartBeat < seg2.m_fStartBeat;
|
||||
}
|
||||
|
||||
void BackgroundUtil::SortBackgroundChangesArray( vector<BackgroundChange> &vBackgroundChanges )
|
||||
{
|
||||
sort( vBackgroundChanges.begin(), vBackgroundChanges.end(), CompareBackgroundChanges );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetBackgroundEffects( const RString &_sName, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
RString sName = _sName;
|
||||
if( sName == "" )
|
||||
sName = "*";
|
||||
|
||||
vsPathsOut.clear();
|
||||
GetDirListing( BACKGROUND_EFFECTS_DIR+sName+".lua", vsPathsOut, false, true );
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( GetFileNameWithoutExtension(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetBackgroundTransitions( const RString &_sName, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
RString sName = _sName;
|
||||
if( sName == "" )
|
||||
sName = "*";
|
||||
|
||||
vsPathsOut.clear();
|
||||
GetDirListing( BACKGROUND_TRANSITIONS_DIR+sName+".xml", vsPathsOut, false, true );
|
||||
GetDirListing( BACKGROUND_TRANSITIONS_DIR+sName+".lua", vsPathsOut, false, true );
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( GetFileNameWithoutExtension(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetSongBGAnimations( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
if( sMatch.empty() )
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+"*", vsPathsOut, true, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch, vsPathsOut, true, true );
|
||||
}
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( Basename(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetSongMovies( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
if( sMatch.empty() )
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.ogv", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.avi", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.mpg", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.mpeg", vsPathsOut, false, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch, vsPathsOut, false, true );
|
||||
}
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( Basename(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetSongBitmaps( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
if( sMatch.empty() )
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.png", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.jpg", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.gif", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.bmp", vsPathsOut, false, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch, vsPathsOut, false, true );
|
||||
}
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( Basename(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
static void GetFilterToFileNames( const RString sBaseDir, const Song *pSong, set<RString> &vsPossibleFileNamesOut )
|
||||
{
|
||||
vsPossibleFileNamesOut.clear();
|
||||
|
||||
if( pSong->m_sGenre.empty() )
|
||||
return;
|
||||
|
||||
ASSERT( !pSong->m_sGroupName.empty() );
|
||||
IniFile ini;
|
||||
RString sPath = sBaseDir+pSong->m_sGroupName+"/"+"BackgroundMapping.ini";
|
||||
ini.ReadFile( sPath );
|
||||
|
||||
RString sSection;
|
||||
bool bSuccess = ini.GetValue( "GenreToSection", pSong->m_sGenre, sSection );
|
||||
if( !bSuccess )
|
||||
{
|
||||
LOG->Warn( "Genre '%s' isn't mapped", pSong->m_sGenre.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
XNode *pSection = ini.GetChild( sSection );
|
||||
if( pSection == NULL )
|
||||
{
|
||||
ASSERT_M( 0, ssprintf("File '%s' refers to a section '%s' that is missing.", sPath.c_str(), sSection.c_str()) );
|
||||
return;
|
||||
}
|
||||
|
||||
FOREACH_CONST_Attr( pSection, p )
|
||||
vsPossibleFileNamesOut.insert( p->first );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetGlobalBGAnimations( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
GetDirListing( BG_ANIMS_DIR+sMatch+"*", vsPathsOut, true, true );
|
||||
GetDirListing( BG_ANIMS_DIR+sMatch+"*.xml", vsPathsOut, false, true );
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( Basename(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetGlobalRandomMovies(
|
||||
const Song *pSong,
|
||||
const RString &sMatch,
|
||||
vector<RString> &vsPathsOut,
|
||||
vector<RString> &vsNamesOut,
|
||||
bool bTryInsideOfSongGroupAndGenreFirst,
|
||||
bool bTryInsideOfSongGroupFirst )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
vsNamesOut.clear();
|
||||
|
||||
// Check for an exact match
|
||||
if( !sMatch.empty() )
|
||||
{
|
||||
GetDirListing( SONG_MOVIES_DIR+pSong->m_sGroupName+"/"+sMatch, vsPathsOut, false, true ); // search in SongMovies/SongGroupName/ first
|
||||
GetDirListing( SONG_MOVIES_DIR+sMatch, vsPathsOut, false, true );
|
||||
GetDirListing( RANDOMMOVIES_DIR+sMatch, vsPathsOut, false, true );
|
||||
if( !vsPathsOut.empty() )
|
||||
goto found_files;
|
||||
|
||||
if( sMatch != NO_SONG_BG_FILE )
|
||||
LOG->Warn( "Background missing: %s", sMatch.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for the most appropriate background
|
||||
{
|
||||
set<RString> ssFileNameWhitelist;
|
||||
if( bTryInsideOfSongGroupAndGenreFirst && pSong && !pSong->m_sGenre.empty() )
|
||||
GetFilterToFileNames( RANDOMMOVIES_DIR, pSong, ssFileNameWhitelist );
|
||||
|
||||
vector<RString> vsDirsToTry;
|
||||
if( bTryInsideOfSongGroupFirst && pSong )
|
||||
{
|
||||
ASSERT( !pSong->m_sGroupName.empty() );
|
||||
vsDirsToTry.push_back( RANDOMMOVIES_DIR+pSong->m_sGroupName+"/" );
|
||||
}
|
||||
vsDirsToTry.push_back( RANDOMMOVIES_DIR );
|
||||
|
||||
FOREACH_CONST( RString, vsDirsToTry, sDir )
|
||||
{
|
||||
GetDirListing( *sDir+"*.ogv", vsPathsOut, false, true );
|
||||
GetDirListing( *sDir+"*.avi", vsPathsOut, false, true );
|
||||
GetDirListing( *sDir+"*.mpg", vsPathsOut, false, true );
|
||||
GetDirListing( *sDir+"*.mpeg", vsPathsOut, false, true );
|
||||
|
||||
if( !ssFileNameWhitelist.empty() )
|
||||
{
|
||||
vector<RString> vsMatches;
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
{
|
||||
RString sBasename = Basename( *s );
|
||||
bool bFound = ssFileNameWhitelist.find(sBasename) != ssFileNameWhitelist.end();
|
||||
if( bFound )
|
||||
vsMatches.push_back(*s);
|
||||
}
|
||||
// If we found any that match the whitelist, use only them.
|
||||
// If none match the whitelist, ignore the whitelist..
|
||||
if( !vsMatches.empty() )
|
||||
vsPathsOut = vsMatches;
|
||||
}
|
||||
|
||||
if( !vsPathsOut.empty() )
|
||||
goto found_files;
|
||||
}
|
||||
}
|
||||
|
||||
found_files:
|
||||
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
{
|
||||
RString sName = s->Right( s->size() - RANDOMMOVIES_DIR.size() - 1 );
|
||||
vsNamesOut.push_back( sName );
|
||||
}
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::BakeAllBackgroundChanges( Song *pSong )
|
||||
{
|
||||
Background bg;
|
||||
bg.LoadFromSong( pSong );
|
||||
vector<BackgroundChange> *vBGChanges[NUM_BackgroundLayer];
|
||||
FOREACH_BackgroundLayer( i )
|
||||
vBGChanges[i] = &pSong->GetBackgroundChanges(i);
|
||||
bg.GetLoadedBackgroundChanges( vBGChanges );
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2001-2004 Chris Danford, Ben Nordstrom
|
||||
* 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 "BackgroundUtil.h"
|
||||
#include "RageUtil.h"
|
||||
#include "Song.h"
|
||||
#include "Foreach.h"
|
||||
#include "IniFile.h"
|
||||
#include "RageLog.h"
|
||||
#include <set>
|
||||
#include "Background.h"
|
||||
|
||||
|
||||
bool BackgroundDef::operator<( const BackgroundDef &other ) const
|
||||
{
|
||||
#define COMPARE(x) if( x < other.x ) return true; else if( x > other.x ) return false;
|
||||
COMPARE( m_sEffect );
|
||||
COMPARE( m_sFile1 );
|
||||
COMPARE( m_sFile2 );
|
||||
COMPARE( m_sColor1 );
|
||||
COMPARE( m_sColor2 );
|
||||
#undef COMPARE
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BackgroundDef::operator==( const BackgroundDef &other ) const
|
||||
{
|
||||
return
|
||||
m_sEffect == other.m_sEffect &&
|
||||
m_sFile1 == other.m_sFile1 &&
|
||||
m_sFile2 == other.m_sFile2 &&
|
||||
m_sColor1 == other.m_sColor1 &&
|
||||
m_sColor2 == other.m_sColor2;
|
||||
}
|
||||
|
||||
XNode *BackgroundDef::CreateNode() const
|
||||
{
|
||||
XNode* pNode = new XNode( "BackgroundDef" );
|
||||
|
||||
if( !m_sEffect.empty() )
|
||||
pNode->AppendAttr( "Effect", m_sEffect );
|
||||
if( !m_sFile1.empty() )
|
||||
pNode->AppendAttr( "File1", m_sFile1 );
|
||||
if( !m_sFile2.empty() )
|
||||
pNode->AppendAttr( "File2", m_sFile2 );
|
||||
if( !m_sColor1.empty() )
|
||||
pNode->AppendAttr( "Color1", m_sColor1 );
|
||||
if( !m_sColor2.empty() )
|
||||
pNode->AppendAttr( "Color2", m_sColor2 );
|
||||
|
||||
return pNode;
|
||||
}
|
||||
|
||||
|
||||
RString BackgroundChange::GetTextDescription() const
|
||||
{
|
||||
vector<RString> vsParts;
|
||||
if( !m_def.m_sFile1.empty() ) vsParts.push_back( m_def.m_sFile1 );
|
||||
if( !m_def.m_sFile2.empty() ) vsParts.push_back( m_def.m_sFile2 );
|
||||
if( m_fRate!=1.0f ) vsParts.push_back( ssprintf("%.2f%%",m_fRate*100) );
|
||||
if( !m_sTransition.empty() ) vsParts.push_back( m_sTransition );
|
||||
if( !m_def.m_sEffect.empty() ) vsParts.push_back( m_def.m_sEffect );
|
||||
if( !m_def.m_sColor1.empty() ) vsParts.push_back( m_def.m_sColor1 );
|
||||
if( !m_def.m_sColor2.empty() ) vsParts.push_back( m_def.m_sColor2 );
|
||||
|
||||
if( vsParts.empty() )
|
||||
vsParts.push_back( "(empty)" );
|
||||
|
||||
RString s = join( "\n", vsParts );
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
const RString BACKGROUND_EFFECTS_DIR = "BackgroundEffects/";
|
||||
const RString BACKGROUND_TRANSITIONS_DIR = "BackgroundTransitions/";
|
||||
const RString BG_ANIMS_DIR = "BGAnimations/";
|
||||
const RString VISUALIZATIONS_DIR = "Visualizations/";
|
||||
const RString RANDOMMOVIES_DIR = "RandomMovies/";
|
||||
const RString SONG_MOVIES_DIR = "SongMovies/";
|
||||
|
||||
const RString RANDOM_BACKGROUND_FILE = "-random-";
|
||||
const RString NO_SONG_BG_FILE = "-nosongbg-";
|
||||
const RString SONG_BACKGROUND_FILE = "songbackground";
|
||||
|
||||
const RString SBE_UpperLeft = "UpperLeft";
|
||||
const RString SBE_Centered = "Centered";
|
||||
const RString SBE_StretchNormal = "StretchNormal";
|
||||
const RString SBE_StretchNoLoop = "StretchNoLoop";
|
||||
const RString SBE_StretchRewind = "StretchRewind";
|
||||
const RString SBT_CrossFade = "CrossFade";
|
||||
|
||||
static void StripCvsAndSvn( vector<RString> &vsPathsToStrip, vector<RString> &vsNamesToStrip )
|
||||
{
|
||||
ASSERT( vsPathsToStrip.size() == vsNamesToStrip.size() );
|
||||
for( unsigned i=0; i<vsNamesToStrip.size(); i++ )
|
||||
{
|
||||
if( vsNamesToStrip[i].Right(3).CompareNoCase("CVS") == 0 || vsNamesToStrip[i] == ".svn" )
|
||||
{
|
||||
vsPathsToStrip.erase( vsPathsToStrip.begin()+i );
|
||||
vsNamesToStrip.erase( vsNamesToStrip.begin()+i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CompareBackgroundChanges(const BackgroundChange &seg1, const BackgroundChange &seg2)
|
||||
{
|
||||
return seg1.m_fStartBeat < seg2.m_fStartBeat;
|
||||
}
|
||||
|
||||
void BackgroundUtil::SortBackgroundChangesArray( vector<BackgroundChange> &vBackgroundChanges )
|
||||
{
|
||||
sort( vBackgroundChanges.begin(), vBackgroundChanges.end(), CompareBackgroundChanges );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetBackgroundEffects( const RString &_sName, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
RString sName = _sName;
|
||||
if( sName == "" )
|
||||
sName = "*";
|
||||
|
||||
vsPathsOut.clear();
|
||||
GetDirListing( BACKGROUND_EFFECTS_DIR+sName+".lua", vsPathsOut, false, true );
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( GetFileNameWithoutExtension(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetBackgroundTransitions( const RString &_sName, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
RString sName = _sName;
|
||||
if( sName == "" )
|
||||
sName = "*";
|
||||
|
||||
vsPathsOut.clear();
|
||||
GetDirListing( BACKGROUND_TRANSITIONS_DIR+sName+".xml", vsPathsOut, false, true );
|
||||
GetDirListing( BACKGROUND_TRANSITIONS_DIR+sName+".lua", vsPathsOut, false, true );
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( GetFileNameWithoutExtension(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetSongBGAnimations( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
if( sMatch.empty() )
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+"*", vsPathsOut, true, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch, vsPathsOut, true, true );
|
||||
}
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( Basename(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetSongMovies( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
if( sMatch.empty() )
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.ogv", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.avi", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.mpg", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.mpeg", vsPathsOut, false, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch, vsPathsOut, false, true );
|
||||
}
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( Basename(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetSongBitmaps( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
if( sMatch.empty() )
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.png", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.jpg", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.gif", vsPathsOut, false, true );
|
||||
GetDirListing( pSong->GetSongDir()+sMatch+"*.bmp", vsPathsOut, false, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetDirListing( pSong->GetSongDir()+sMatch, vsPathsOut, false, true );
|
||||
}
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( Basename(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
static void GetFilterToFileNames( const RString sBaseDir, const Song *pSong, set<RString> &vsPossibleFileNamesOut )
|
||||
{
|
||||
vsPossibleFileNamesOut.clear();
|
||||
|
||||
if( pSong->m_sGenre.empty() )
|
||||
return;
|
||||
|
||||
ASSERT( !pSong->m_sGroupName.empty() );
|
||||
IniFile ini;
|
||||
RString sPath = sBaseDir+pSong->m_sGroupName+"/"+"BackgroundMapping.ini";
|
||||
ini.ReadFile( sPath );
|
||||
|
||||
RString sSection;
|
||||
bool bSuccess = ini.GetValue( "GenreToSection", pSong->m_sGenre, sSection );
|
||||
if( !bSuccess )
|
||||
{
|
||||
LOG->Warn( "Genre '%s' isn't mapped", pSong->m_sGenre.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
XNode *pSection = ini.GetChild( sSection );
|
||||
if( pSection == NULL )
|
||||
{
|
||||
ASSERT_M( 0, ssprintf("File '%s' refers to a section '%s' that is missing.", sPath.c_str(), sSection.c_str()) );
|
||||
return;
|
||||
}
|
||||
|
||||
FOREACH_CONST_Attr( pSection, p )
|
||||
vsPossibleFileNamesOut.insert( p->first );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetGlobalBGAnimations( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
GetDirListing( BG_ANIMS_DIR+sMatch+"*", vsPathsOut, true, true );
|
||||
GetDirListing( BG_ANIMS_DIR+sMatch+"*.xml", vsPathsOut, false, true );
|
||||
|
||||
vsNamesOut.clear();
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
vsNamesOut.push_back( Basename(*s) );
|
||||
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::GetGlobalRandomMovies(
|
||||
const Song *pSong,
|
||||
const RString &sMatch,
|
||||
vector<RString> &vsPathsOut,
|
||||
vector<RString> &vsNamesOut,
|
||||
bool bTryInsideOfSongGroupAndGenreFirst,
|
||||
bool bTryInsideOfSongGroupFirst )
|
||||
{
|
||||
vsPathsOut.clear();
|
||||
vsNamesOut.clear();
|
||||
|
||||
// Check for an exact match
|
||||
if( !sMatch.empty() )
|
||||
{
|
||||
GetDirListing( SONG_MOVIES_DIR+pSong->m_sGroupName+"/"+sMatch, vsPathsOut, false, true ); // search in SongMovies/SongGroupName/ first
|
||||
GetDirListing( SONG_MOVIES_DIR+sMatch, vsPathsOut, false, true );
|
||||
GetDirListing( RANDOMMOVIES_DIR+sMatch, vsPathsOut, false, true );
|
||||
if( !vsPathsOut.empty() )
|
||||
goto found_files;
|
||||
|
||||
if( sMatch != NO_SONG_BG_FILE )
|
||||
LOG->Warn( "Background missing: %s", sMatch.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for the most appropriate background
|
||||
{
|
||||
set<RString> ssFileNameWhitelist;
|
||||
if( bTryInsideOfSongGroupAndGenreFirst && pSong && !pSong->m_sGenre.empty() )
|
||||
GetFilterToFileNames( RANDOMMOVIES_DIR, pSong, ssFileNameWhitelist );
|
||||
|
||||
vector<RString> vsDirsToTry;
|
||||
if( bTryInsideOfSongGroupFirst && pSong )
|
||||
{
|
||||
ASSERT( !pSong->m_sGroupName.empty() );
|
||||
vsDirsToTry.push_back( RANDOMMOVIES_DIR+pSong->m_sGroupName+"/" );
|
||||
}
|
||||
vsDirsToTry.push_back( RANDOMMOVIES_DIR );
|
||||
|
||||
FOREACH_CONST( RString, vsDirsToTry, sDir )
|
||||
{
|
||||
GetDirListing( *sDir+"*.ogv", vsPathsOut, false, true );
|
||||
GetDirListing( *sDir+"*.avi", vsPathsOut, false, true );
|
||||
GetDirListing( *sDir+"*.mpg", vsPathsOut, false, true );
|
||||
GetDirListing( *sDir+"*.mpeg", vsPathsOut, false, true );
|
||||
|
||||
if( !ssFileNameWhitelist.empty() )
|
||||
{
|
||||
vector<RString> vsMatches;
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
{
|
||||
RString sBasename = Basename( *s );
|
||||
bool bFound = ssFileNameWhitelist.find(sBasename) != ssFileNameWhitelist.end();
|
||||
if( bFound )
|
||||
vsMatches.push_back(*s);
|
||||
}
|
||||
// If we found any that match the whitelist, use only them.
|
||||
// If none match the whitelist, ignore the whitelist..
|
||||
if( !vsMatches.empty() )
|
||||
vsPathsOut = vsMatches;
|
||||
}
|
||||
|
||||
if( !vsPathsOut.empty() )
|
||||
goto found_files;
|
||||
}
|
||||
}
|
||||
|
||||
found_files:
|
||||
|
||||
FOREACH_CONST( RString, vsPathsOut, s )
|
||||
{
|
||||
RString sName = s->Right( s->size() - RANDOMMOVIES_DIR.size() - 1 );
|
||||
vsNamesOut.push_back( sName );
|
||||
}
|
||||
StripCvsAndSvn( vsPathsOut, vsNamesOut );
|
||||
}
|
||||
|
||||
void BackgroundUtil::BakeAllBackgroundChanges( Song *pSong )
|
||||
{
|
||||
Background bg;
|
||||
bg.LoadFromSong( pSong );
|
||||
vector<BackgroundChange> *vBGChanges[NUM_BackgroundLayer];
|
||||
FOREACH_BackgroundLayer( i )
|
||||
vBGChanges[i] = &pSong->GetBackgroundChanges(i);
|
||||
bg.GetLoadedBackgroundChanges( vBGChanges );
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2001-2004 Chris Danford, Ben Nordstrom
|
||||
* 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.
|
||||
*/
|
||||
|
||||
+105
-105
@@ -1,105 +1,105 @@
|
||||
#ifndef BackgroundUtil_H
|
||||
#define BackgroundUtil_H
|
||||
|
||||
class Song;
|
||||
class XNode;
|
||||
|
||||
extern const RString RANDOM_BACKGROUND_FILE;
|
||||
extern const RString NO_SONG_BG_FILE;
|
||||
extern const RString SONG_BACKGROUND_FILE;
|
||||
|
||||
extern const RString SBE_UpperLeft;
|
||||
extern const RString SBE_Centered;
|
||||
extern const RString SBE_StretchNormal;
|
||||
extern const RString SBE_StretchNoLoop;
|
||||
extern const RString SBE_StretchRewind;
|
||||
extern const RString SBT_CrossFade;
|
||||
|
||||
struct BackgroundDef
|
||||
{
|
||||
bool operator<( const BackgroundDef &other ) const;
|
||||
bool operator==( const BackgroundDef &other ) const;
|
||||
bool IsEmpty() const { return m_sFile1.empty() && m_sFile2.empty(); }
|
||||
RString m_sEffect; // "" == automatically choose
|
||||
RString m_sFile1; // must not be ""
|
||||
RString m_sFile2; // may be ""
|
||||
RString m_sColor1; // "" == use default
|
||||
RString m_sColor2; // "" == use default
|
||||
|
||||
XNode *CreateNode() const;
|
||||
};
|
||||
|
||||
struct BackgroundChange
|
||||
{
|
||||
BackgroundChange()
|
||||
{
|
||||
m_fStartBeat=-1;
|
||||
m_fRate=1;
|
||||
}
|
||||
BackgroundChange(
|
||||
float s,
|
||||
RString f1,
|
||||
RString f2=RString(),
|
||||
float r=1.f,
|
||||
RString e=SBE_Centered,
|
||||
RString t=RString()
|
||||
)
|
||||
{
|
||||
m_fStartBeat=s;
|
||||
m_def.m_sFile1=f1;
|
||||
m_def.m_sFile2=f2;
|
||||
m_fRate=r;
|
||||
m_def.m_sEffect=e;
|
||||
m_sTransition=t;
|
||||
}
|
||||
BackgroundDef m_def;
|
||||
float m_fStartBeat;
|
||||
float m_fRate;
|
||||
RString m_sTransition;
|
||||
|
||||
RString GetTextDescription() const;
|
||||
};
|
||||
/** @brief Shared background-related routines. */
|
||||
namespace BackgroundUtil
|
||||
{
|
||||
void SortBackgroundChangesArray( vector<BackgroundChange> &vBackgroundChanges );
|
||||
|
||||
void GetBackgroundEffects( const RString &sName, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetBackgroundTransitions( const RString &sName, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
|
||||
void GetSongBGAnimations( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetSongMovies( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetSongBitmaps( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetGlobalBGAnimations( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetGlobalRandomMovies( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut, bool bTryInsideOfSongGroupAndGenreFirst = true, bool bTryInsideOfSongGroupFirst = true );
|
||||
|
||||
void BakeAllBackgroundChanges( Song *pSong );
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (c) 2001-2004 Chris Danford, Ben Nordstrom
|
||||
* 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 BackgroundUtil_H
|
||||
#define BackgroundUtil_H
|
||||
|
||||
class Song;
|
||||
class XNode;
|
||||
|
||||
extern const RString RANDOM_BACKGROUND_FILE;
|
||||
extern const RString NO_SONG_BG_FILE;
|
||||
extern const RString SONG_BACKGROUND_FILE;
|
||||
|
||||
extern const RString SBE_UpperLeft;
|
||||
extern const RString SBE_Centered;
|
||||
extern const RString SBE_StretchNormal;
|
||||
extern const RString SBE_StretchNoLoop;
|
||||
extern const RString SBE_StretchRewind;
|
||||
extern const RString SBT_CrossFade;
|
||||
|
||||
struct BackgroundDef
|
||||
{
|
||||
bool operator<( const BackgroundDef &other ) const;
|
||||
bool operator==( const BackgroundDef &other ) const;
|
||||
bool IsEmpty() const { return m_sFile1.empty() && m_sFile2.empty(); }
|
||||
RString m_sEffect; // "" == automatically choose
|
||||
RString m_sFile1; // must not be ""
|
||||
RString m_sFile2; // may be ""
|
||||
RString m_sColor1; // "" == use default
|
||||
RString m_sColor2; // "" == use default
|
||||
|
||||
XNode *CreateNode() const;
|
||||
};
|
||||
|
||||
struct BackgroundChange
|
||||
{
|
||||
BackgroundChange()
|
||||
{
|
||||
m_fStartBeat=-1;
|
||||
m_fRate=1;
|
||||
}
|
||||
BackgroundChange(
|
||||
float s,
|
||||
RString f1,
|
||||
RString f2=RString(),
|
||||
float r=1.f,
|
||||
RString e=SBE_Centered,
|
||||
RString t=RString()
|
||||
)
|
||||
{
|
||||
m_fStartBeat=s;
|
||||
m_def.m_sFile1=f1;
|
||||
m_def.m_sFile2=f2;
|
||||
m_fRate=r;
|
||||
m_def.m_sEffect=e;
|
||||
m_sTransition=t;
|
||||
}
|
||||
BackgroundDef m_def;
|
||||
float m_fStartBeat;
|
||||
float m_fRate;
|
||||
RString m_sTransition;
|
||||
|
||||
RString GetTextDescription() const;
|
||||
};
|
||||
/** @brief Shared background-related routines. */
|
||||
namespace BackgroundUtil
|
||||
{
|
||||
void SortBackgroundChangesArray( vector<BackgroundChange> &vBackgroundChanges );
|
||||
|
||||
void GetBackgroundEffects( const RString &sName, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetBackgroundTransitions( const RString &sName, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
|
||||
void GetSongBGAnimations( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetSongMovies( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetSongBitmaps( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetGlobalBGAnimations( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut );
|
||||
void GetGlobalRandomMovies( const Song *pSong, const RString &sMatch, vector<RString> &vsPathsOut, vector<RString> &vsNamesOut, bool bTryInsideOfSongGroupAndGenreFirst = true, bool bTryInsideOfSongGroupFirst = true );
|
||||
|
||||
void BakeAllBackgroundChanges( Song *pSong );
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (c) 2001-2004 Chris Danford, Ben Nordstrom
|
||||
* 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.
|
||||
*/
|
||||
|
||||
+347
-347
@@ -1,347 +1,347 @@
|
||||
#include "global.h"
|
||||
#include "Banner.h"
|
||||
#include "BannerCache.h"
|
||||
#include "SongManager.h"
|
||||
#include "RageUtil.h"
|
||||
#include "Song.h"
|
||||
#include "RageTextureManager.h"
|
||||
#include "Course.h"
|
||||
#include "Character.h"
|
||||
#include "ThemeMetric.h"
|
||||
#include "CharacterManager.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "UnlockManager.h"
|
||||
#include "PrefsManager.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS( Banner );
|
||||
|
||||
ThemeMetric<bool> SCROLL_RANDOM ("Banner","ScrollRandom");
|
||||
ThemeMetric<bool> SCROLL_ROULETTE ("Banner","ScrollRoulette");
|
||||
|
||||
Banner::Banner()
|
||||
{
|
||||
m_bScrolling = false;
|
||||
m_fPercentScrolling = 0;
|
||||
}
|
||||
|
||||
// Ugly: if sIsBanner is false, we're actually loading something other than a banner.
|
||||
void Banner::Load( RageTextureID ID, bool bIsBanner )
|
||||
{
|
||||
if( ID.filename == "" )
|
||||
{
|
||||
LoadFallback();
|
||||
return;
|
||||
}
|
||||
|
||||
if( bIsBanner )
|
||||
ID = SongBannerTexture(ID);
|
||||
|
||||
m_fPercentScrolling = 0;
|
||||
m_bScrolling = false;
|
||||
|
||||
TEXTUREMAN->DisableOddDimensionWarning();
|
||||
TEXTUREMAN->VolatileTexture( ID );
|
||||
Sprite::Load( ID );
|
||||
TEXTUREMAN->EnableOddDimensionWarning();
|
||||
};
|
||||
|
||||
void Banner::LoadFromCachedBanner( const RString &sPath )
|
||||
{
|
||||
if( sPath.empty() )
|
||||
{
|
||||
LoadFallback();
|
||||
return;
|
||||
}
|
||||
|
||||
RageTextureID ID;
|
||||
bool bLowRes = (PREFSMAN->m_BannerCache != BNCACHE_FULL);
|
||||
if( !bLowRes )
|
||||
{
|
||||
ID = Sprite::SongBannerTexture( sPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to load the low quality version.
|
||||
ID = BANNERCACHE->LoadCachedBanner( sPath );
|
||||
}
|
||||
|
||||
if( TEXTUREMAN->IsTextureRegistered(ID) )
|
||||
Load( ID );
|
||||
else if( IsAFile(sPath) )
|
||||
Load( sPath );
|
||||
else
|
||||
LoadFallback();
|
||||
}
|
||||
|
||||
void Banner::Update( float fDeltaTime )
|
||||
{
|
||||
Sprite::Update( fDeltaTime );
|
||||
|
||||
if( m_bScrolling )
|
||||
{
|
||||
m_fPercentScrolling += fDeltaTime/2;
|
||||
m_fPercentScrolling -= (int)m_fPercentScrolling;
|
||||
|
||||
const RectF *pTextureRect = GetCurrentTextureCoordRect();
|
||||
|
||||
float fTexCoords[8] =
|
||||
{
|
||||
0+m_fPercentScrolling, pTextureRect->top, // top left
|
||||
0+m_fPercentScrolling, pTextureRect->bottom, // bottom left
|
||||
1+m_fPercentScrolling, pTextureRect->bottom, // bottom right
|
||||
1+m_fPercentScrolling, pTextureRect->top, // top right
|
||||
};
|
||||
Sprite::SetCustomTextureCoords( fTexCoords );
|
||||
}
|
||||
}
|
||||
|
||||
void Banner::SetScrolling( bool bScroll, float Percent)
|
||||
{
|
||||
m_bScrolling = bScroll;
|
||||
m_fPercentScrolling = Percent;
|
||||
|
||||
// Set up the texture coord rects for the current state.
|
||||
Update(0);
|
||||
}
|
||||
|
||||
void Banner::LoadFromSong( Song* pSong ) // NULL means no song
|
||||
{
|
||||
if( pSong == NULL ) LoadFallback();
|
||||
else if( pSong->HasBanner() ) Load( pSong->GetBannerPath() );
|
||||
else LoadFallback();
|
||||
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadMode()
|
||||
{
|
||||
Load( THEME->GetPathG("Banner","Mode") );
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadFromSongGroup( RString sSongGroup )
|
||||
{
|
||||
RString sGroupBannerPath = SONGMAN->GetSongGroupBannerPath( sSongGroup );
|
||||
if( sGroupBannerPath != "" ) Load( sGroupBannerPath );
|
||||
else LoadFallback();
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadFromCourse( const Course *pCourse ) // NULL means no course
|
||||
{
|
||||
if( pCourse == NULL ) LoadFallback();
|
||||
else if( pCourse->GetBannerPath() != "" ) Load( pCourse->GetBannerPath() );
|
||||
else LoadCourseFallback();
|
||||
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadCardFromCharacter( const Character *pCharacter )
|
||||
{
|
||||
if( pCharacter == NULL ) LoadFallback();
|
||||
else if( pCharacter->GetCardPath() != "" ) Load( pCharacter->GetCardPath() );
|
||||
else LoadFallback();
|
||||
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadIconFromCharacter( const Character *pCharacter )
|
||||
{
|
||||
if( pCharacter == NULL ) LoadFallbackCharacterIcon();
|
||||
else if( pCharacter->GetIconPath() != "" ) Load( pCharacter->GetIconPath(), false );
|
||||
else LoadFallbackCharacterIcon();
|
||||
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadBannerFromUnlockEntry( const UnlockEntry* pUE )
|
||||
{
|
||||
if( pUE == NULL )
|
||||
LoadFallback();
|
||||
else
|
||||
{
|
||||
RString sFile = pUE->GetBannerFile();
|
||||
Load( sFile );
|
||||
m_bScrolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Banner::LoadBackgroundFromUnlockEntry( const UnlockEntry* pUE )
|
||||
{
|
||||
if( pUE == NULL )
|
||||
LoadFallback();
|
||||
else
|
||||
{
|
||||
RString sFile = pUE->GetBackgroundFile();
|
||||
Load( sFile );
|
||||
m_bScrolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Banner::LoadFallback()
|
||||
{
|
||||
Load( THEME->GetPathG("Common","fallback banner") );
|
||||
}
|
||||
|
||||
void Banner::LoadFallbackBG()
|
||||
{
|
||||
Load( THEME->GetPathG("Common","fallback background") );
|
||||
}
|
||||
|
||||
void Banner::LoadCourseFallback()
|
||||
{
|
||||
Load( THEME->GetPathG("Banner","course fallback") );
|
||||
}
|
||||
|
||||
void Banner::LoadFallbackCharacterIcon()
|
||||
{
|
||||
Character *pCharacter = CHARMAN->GetDefaultCharacter();
|
||||
if( pCharacter && !pCharacter->GetIconPath().empty() )
|
||||
Load( pCharacter->GetIconPath(), false );
|
||||
else
|
||||
LoadFallback();
|
||||
}
|
||||
|
||||
void Banner::LoadRoulette()
|
||||
{
|
||||
Load( THEME->GetPathG("Banner","roulette") );
|
||||
m_bScrolling = (bool)SCROLL_ROULETTE;
|
||||
}
|
||||
|
||||
void Banner::LoadRandom()
|
||||
{
|
||||
Load( THEME->GetPathG("Banner","random") );
|
||||
m_bScrolling = (bool)SCROLL_RANDOM;
|
||||
}
|
||||
|
||||
void Banner::LoadFromSortOrder( SortOrder so )
|
||||
{
|
||||
// TODO: See if the check for NULL/PREFERRED(?) is needed.
|
||||
if( so == SortOrder_Invalid )
|
||||
{
|
||||
LoadFallback();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( so != SORT_GROUP && so != SORT_RECENT )
|
||||
Load( THEME->GetPathG("Banner",ssprintf("%s",SortOrderToString(so).c_str())) );
|
||||
}
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the Banner. */
|
||||
class LunaBanner: public Luna<Banner>
|
||||
{
|
||||
public:
|
||||
static int scaletoclipped( T* p, lua_State *L ) { p->ScaleToClipped(FArg(1),FArg(2)); return 0; }
|
||||
static int ScaleToClipped( T* p, lua_State *L ) { p->ScaleToClipped(FArg(1),FArg(2)); return 0; }
|
||||
static int LoadFromSong( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadFromSong( NULL ); }
|
||||
else { Song *pS = Luna<Song>::check(L,1); p->LoadFromSong( pS ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadFromCourse( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadFromCourse( NULL ); }
|
||||
else { Course *pC = Luna<Course>::check(L,1); p->LoadFromCourse( pC ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadFromCachedBanner( T* p, lua_State *L )
|
||||
{
|
||||
p->LoadFromCachedBanner( SArg(1) );
|
||||
return 0;
|
||||
}
|
||||
static int LoadIconFromCharacter( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadIconFromCharacter( NULL ); }
|
||||
else { Character *pC = Luna<Character>::check(L,1); p->LoadIconFromCharacter( pC ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadCardFromCharacter( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadIconFromCharacter( NULL ); }
|
||||
else { Character *pC = Luna<Character>::check(L,1); p->LoadIconFromCharacter( pC ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadBannerFromUnlockEntry( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadBannerFromUnlockEntry( NULL ); }
|
||||
else { UnlockEntry *pUE = Luna<UnlockEntry>::check(L,1); p->LoadBannerFromUnlockEntry( pUE ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadBackgroundFromUnlockEntry( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadBackgroundFromUnlockEntry( NULL ); }
|
||||
else { UnlockEntry *pUE = Luna<UnlockEntry>::check(L,1); p->LoadBackgroundFromUnlockEntry( pUE ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadFromSongGroup( T* p, lua_State *L )
|
||||
{
|
||||
p->LoadFromSongGroup( SArg(1) );
|
||||
return 0;
|
||||
}
|
||||
static int LoadFromSortOrder( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadFromSortOrder( SortOrder_Invalid ); }
|
||||
else
|
||||
{
|
||||
SortOrder so = Enum::Check<SortOrder>(L, 1);
|
||||
p->LoadFromSortOrder( so );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int GetScrolling( T* p, lua_State *L ){ lua_pushboolean( L, p->GetScrolling() ); return 1; }
|
||||
static int SetScrolling( T* p, lua_State *L ){ p->SetScrolling( BArg(1), FArg(2) ); return 0; }
|
||||
static int GetPercentScrolling( T* p, lua_State *L ){ lua_pushnumber( L, p->ScrollingPercent() ); return 1; }
|
||||
|
||||
LunaBanner()
|
||||
{
|
||||
ADD_METHOD( scaletoclipped );
|
||||
ADD_METHOD( ScaleToClipped );
|
||||
ADD_METHOD( LoadFromSong );
|
||||
ADD_METHOD( LoadFromCourse );
|
||||
ADD_METHOD( LoadFromCachedBanner );
|
||||
ADD_METHOD( LoadIconFromCharacter );
|
||||
ADD_METHOD( LoadCardFromCharacter );
|
||||
ADD_METHOD( LoadBannerFromUnlockEntry );
|
||||
ADD_METHOD( LoadBackgroundFromUnlockEntry );
|
||||
ADD_METHOD( LoadFromSongGroup );
|
||||
ADD_METHOD( LoadFromSortOrder );
|
||||
ADD_METHOD( GetScrolling );
|
||||
ADD_METHOD( SetScrolling );
|
||||
ADD_METHOD( GetPercentScrolling );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( Banner, Sprite )
|
||||
// lua end
|
||||
|
||||
|
||||
/*
|
||||
* (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 "Banner.h"
|
||||
#include "BannerCache.h"
|
||||
#include "SongManager.h"
|
||||
#include "RageUtil.h"
|
||||
#include "Song.h"
|
||||
#include "RageTextureManager.h"
|
||||
#include "Course.h"
|
||||
#include "Character.h"
|
||||
#include "ThemeMetric.h"
|
||||
#include "CharacterManager.h"
|
||||
#include "ActorUtil.h"
|
||||
#include "UnlockManager.h"
|
||||
#include "PrefsManager.h"
|
||||
|
||||
REGISTER_ACTOR_CLASS( Banner );
|
||||
|
||||
ThemeMetric<bool> SCROLL_RANDOM ("Banner","ScrollRandom");
|
||||
ThemeMetric<bool> SCROLL_ROULETTE ("Banner","ScrollRoulette");
|
||||
|
||||
Banner::Banner()
|
||||
{
|
||||
m_bScrolling = false;
|
||||
m_fPercentScrolling = 0;
|
||||
}
|
||||
|
||||
// Ugly: if sIsBanner is false, we're actually loading something other than a banner.
|
||||
void Banner::Load( RageTextureID ID, bool bIsBanner )
|
||||
{
|
||||
if( ID.filename == "" )
|
||||
{
|
||||
LoadFallback();
|
||||
return;
|
||||
}
|
||||
|
||||
if( bIsBanner )
|
||||
ID = SongBannerTexture(ID);
|
||||
|
||||
m_fPercentScrolling = 0;
|
||||
m_bScrolling = false;
|
||||
|
||||
TEXTUREMAN->DisableOddDimensionWarning();
|
||||
TEXTUREMAN->VolatileTexture( ID );
|
||||
Sprite::Load( ID );
|
||||
TEXTUREMAN->EnableOddDimensionWarning();
|
||||
};
|
||||
|
||||
void Banner::LoadFromCachedBanner( const RString &sPath )
|
||||
{
|
||||
if( sPath.empty() )
|
||||
{
|
||||
LoadFallback();
|
||||
return;
|
||||
}
|
||||
|
||||
RageTextureID ID;
|
||||
bool bLowRes = (PREFSMAN->m_BannerCache != BNCACHE_FULL);
|
||||
if( !bLowRes )
|
||||
{
|
||||
ID = Sprite::SongBannerTexture( sPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to load the low quality version.
|
||||
ID = BANNERCACHE->LoadCachedBanner( sPath );
|
||||
}
|
||||
|
||||
if( TEXTUREMAN->IsTextureRegistered(ID) )
|
||||
Load( ID );
|
||||
else if( IsAFile(sPath) )
|
||||
Load( sPath );
|
||||
else
|
||||
LoadFallback();
|
||||
}
|
||||
|
||||
void Banner::Update( float fDeltaTime )
|
||||
{
|
||||
Sprite::Update( fDeltaTime );
|
||||
|
||||
if( m_bScrolling )
|
||||
{
|
||||
m_fPercentScrolling += fDeltaTime/2;
|
||||
m_fPercentScrolling -= (int)m_fPercentScrolling;
|
||||
|
||||
const RectF *pTextureRect = GetCurrentTextureCoordRect();
|
||||
|
||||
float fTexCoords[8] =
|
||||
{
|
||||
0+m_fPercentScrolling, pTextureRect->top, // top left
|
||||
0+m_fPercentScrolling, pTextureRect->bottom, // bottom left
|
||||
1+m_fPercentScrolling, pTextureRect->bottom, // bottom right
|
||||
1+m_fPercentScrolling, pTextureRect->top, // top right
|
||||
};
|
||||
Sprite::SetCustomTextureCoords( fTexCoords );
|
||||
}
|
||||
}
|
||||
|
||||
void Banner::SetScrolling( bool bScroll, float Percent)
|
||||
{
|
||||
m_bScrolling = bScroll;
|
||||
m_fPercentScrolling = Percent;
|
||||
|
||||
// Set up the texture coord rects for the current state.
|
||||
Update(0);
|
||||
}
|
||||
|
||||
void Banner::LoadFromSong( Song* pSong ) // NULL means no song
|
||||
{
|
||||
if( pSong == NULL ) LoadFallback();
|
||||
else if( pSong->HasBanner() ) Load( pSong->GetBannerPath() );
|
||||
else LoadFallback();
|
||||
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadMode()
|
||||
{
|
||||
Load( THEME->GetPathG("Banner","Mode") );
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadFromSongGroup( RString sSongGroup )
|
||||
{
|
||||
RString sGroupBannerPath = SONGMAN->GetSongGroupBannerPath( sSongGroup );
|
||||
if( sGroupBannerPath != "" ) Load( sGroupBannerPath );
|
||||
else LoadFallback();
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadFromCourse( const Course *pCourse ) // NULL means no course
|
||||
{
|
||||
if( pCourse == NULL ) LoadFallback();
|
||||
else if( pCourse->GetBannerPath() != "" ) Load( pCourse->GetBannerPath() );
|
||||
else LoadCourseFallback();
|
||||
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadCardFromCharacter( const Character *pCharacter )
|
||||
{
|
||||
if( pCharacter == NULL ) LoadFallback();
|
||||
else if( pCharacter->GetCardPath() != "" ) Load( pCharacter->GetCardPath() );
|
||||
else LoadFallback();
|
||||
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadIconFromCharacter( const Character *pCharacter )
|
||||
{
|
||||
if( pCharacter == NULL ) LoadFallbackCharacterIcon();
|
||||
else if( pCharacter->GetIconPath() != "" ) Load( pCharacter->GetIconPath(), false );
|
||||
else LoadFallbackCharacterIcon();
|
||||
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
void Banner::LoadBannerFromUnlockEntry( const UnlockEntry* pUE )
|
||||
{
|
||||
if( pUE == NULL )
|
||||
LoadFallback();
|
||||
else
|
||||
{
|
||||
RString sFile = pUE->GetBannerFile();
|
||||
Load( sFile );
|
||||
m_bScrolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Banner::LoadBackgroundFromUnlockEntry( const UnlockEntry* pUE )
|
||||
{
|
||||
if( pUE == NULL )
|
||||
LoadFallback();
|
||||
else
|
||||
{
|
||||
RString sFile = pUE->GetBackgroundFile();
|
||||
Load( sFile );
|
||||
m_bScrolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Banner::LoadFallback()
|
||||
{
|
||||
Load( THEME->GetPathG("Common","fallback banner") );
|
||||
}
|
||||
|
||||
void Banner::LoadFallbackBG()
|
||||
{
|
||||
Load( THEME->GetPathG("Common","fallback background") );
|
||||
}
|
||||
|
||||
void Banner::LoadCourseFallback()
|
||||
{
|
||||
Load( THEME->GetPathG("Banner","course fallback") );
|
||||
}
|
||||
|
||||
void Banner::LoadFallbackCharacterIcon()
|
||||
{
|
||||
Character *pCharacter = CHARMAN->GetDefaultCharacter();
|
||||
if( pCharacter && !pCharacter->GetIconPath().empty() )
|
||||
Load( pCharacter->GetIconPath(), false );
|
||||
else
|
||||
LoadFallback();
|
||||
}
|
||||
|
||||
void Banner::LoadRoulette()
|
||||
{
|
||||
Load( THEME->GetPathG("Banner","roulette") );
|
||||
m_bScrolling = (bool)SCROLL_ROULETTE;
|
||||
}
|
||||
|
||||
void Banner::LoadRandom()
|
||||
{
|
||||
Load( THEME->GetPathG("Banner","random") );
|
||||
m_bScrolling = (bool)SCROLL_RANDOM;
|
||||
}
|
||||
|
||||
void Banner::LoadFromSortOrder( SortOrder so )
|
||||
{
|
||||
// TODO: See if the check for NULL/PREFERRED(?) is needed.
|
||||
if( so == SortOrder_Invalid )
|
||||
{
|
||||
LoadFallback();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( so != SORT_GROUP && so != SORT_RECENT )
|
||||
Load( THEME->GetPathG("Banner",ssprintf("%s",SortOrderToString(so).c_str())) );
|
||||
}
|
||||
m_bScrolling = false;
|
||||
}
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
/** @brief Allow Lua to have access to the Banner. */
|
||||
class LunaBanner: public Luna<Banner>
|
||||
{
|
||||
public:
|
||||
static int scaletoclipped( T* p, lua_State *L ) { p->ScaleToClipped(FArg(1),FArg(2)); return 0; }
|
||||
static int ScaleToClipped( T* p, lua_State *L ) { p->ScaleToClipped(FArg(1),FArg(2)); return 0; }
|
||||
static int LoadFromSong( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadFromSong( NULL ); }
|
||||
else { Song *pS = Luna<Song>::check(L,1); p->LoadFromSong( pS ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadFromCourse( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadFromCourse( NULL ); }
|
||||
else { Course *pC = Luna<Course>::check(L,1); p->LoadFromCourse( pC ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadFromCachedBanner( T* p, lua_State *L )
|
||||
{
|
||||
p->LoadFromCachedBanner( SArg(1) );
|
||||
return 0;
|
||||
}
|
||||
static int LoadIconFromCharacter( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadIconFromCharacter( NULL ); }
|
||||
else { Character *pC = Luna<Character>::check(L,1); p->LoadIconFromCharacter( pC ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadCardFromCharacter( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadIconFromCharacter( NULL ); }
|
||||
else { Character *pC = Luna<Character>::check(L,1); p->LoadIconFromCharacter( pC ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadBannerFromUnlockEntry( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadBannerFromUnlockEntry( NULL ); }
|
||||
else { UnlockEntry *pUE = Luna<UnlockEntry>::check(L,1); p->LoadBannerFromUnlockEntry( pUE ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadBackgroundFromUnlockEntry( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadBackgroundFromUnlockEntry( NULL ); }
|
||||
else { UnlockEntry *pUE = Luna<UnlockEntry>::check(L,1); p->LoadBackgroundFromUnlockEntry( pUE ); }
|
||||
return 0;
|
||||
}
|
||||
static int LoadFromSongGroup( T* p, lua_State *L )
|
||||
{
|
||||
p->LoadFromSongGroup( SArg(1) );
|
||||
return 0;
|
||||
}
|
||||
static int LoadFromSortOrder( T* p, lua_State *L )
|
||||
{
|
||||
if( lua_isnil(L,1) ) { p->LoadFromSortOrder( SortOrder_Invalid ); }
|
||||
else
|
||||
{
|
||||
SortOrder so = Enum::Check<SortOrder>(L, 1);
|
||||
p->LoadFromSortOrder( so );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int GetScrolling( T* p, lua_State *L ){ lua_pushboolean( L, p->GetScrolling() ); return 1; }
|
||||
static int SetScrolling( T* p, lua_State *L ){ p->SetScrolling( BArg(1), FArg(2) ); return 0; }
|
||||
static int GetPercentScrolling( T* p, lua_State *L ){ lua_pushnumber( L, p->ScrollingPercent() ); return 1; }
|
||||
|
||||
LunaBanner()
|
||||
{
|
||||
ADD_METHOD( scaletoclipped );
|
||||
ADD_METHOD( ScaleToClipped );
|
||||
ADD_METHOD( LoadFromSong );
|
||||
ADD_METHOD( LoadFromCourse );
|
||||
ADD_METHOD( LoadFromCachedBanner );
|
||||
ADD_METHOD( LoadIconFromCharacter );
|
||||
ADD_METHOD( LoadCardFromCharacter );
|
||||
ADD_METHOD( LoadBannerFromUnlockEntry );
|
||||
ADD_METHOD( LoadBackgroundFromUnlockEntry );
|
||||
ADD_METHOD( LoadFromSongGroup );
|
||||
ADD_METHOD( LoadFromSortOrder );
|
||||
ADD_METHOD( GetScrolling );
|
||||
ADD_METHOD( SetScrolling );
|
||||
ADD_METHOD( GetPercentScrolling );
|
||||
}
|
||||
};
|
||||
|
||||
LUA_REGISTER_DERIVED_CLASS( Banner, Sprite )
|
||||
// lua end
|
||||
|
||||
|
||||
/*
|
||||
* (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.
|
||||
*/
|
||||
|
||||
+87
-87
@@ -1,87 +1,87 @@
|
||||
/** @brief Banner - The song/course's banner displayed in SelectMusic/Course. */
|
||||
|
||||
#ifndef BANNER_H
|
||||
#define BANNER_H
|
||||
|
||||
#include "Sprite.h"
|
||||
#include "RageTextureID.h"
|
||||
#include "GameConstantsAndTypes.h"
|
||||
class Song;
|
||||
class Course;
|
||||
class Character;
|
||||
class UnlockEntry;
|
||||
|
||||
/** @brief The characteristics of a Banner */
|
||||
class Banner : public Sprite
|
||||
{
|
||||
public:
|
||||
Banner();
|
||||
virtual ~Banner() { }
|
||||
virtual Banner *Copy() const;
|
||||
|
||||
void Load( RageTextureID ID, bool bIsBanner );
|
||||
virtual void Load( RageTextureID ID ) { Load( ID, true ); }
|
||||
void LoadFromCachedBanner( const RString &sPath );
|
||||
|
||||
virtual void Update( float fDeltaTime );
|
||||
|
||||
/**
|
||||
* @brief Attempt to load the banner from a song.
|
||||
* @param pSong the song in question. If NULL, there is no song.
|
||||
*/
|
||||
void LoadFromSong( Song* pSong );
|
||||
void LoadMode();
|
||||
void LoadFromSongGroup( RString sSongGroup );
|
||||
void LoadFromCourse( const Course *pCourse );
|
||||
void LoadCardFromCharacter( const Character *pCharacter );
|
||||
void LoadIconFromCharacter( const Character *pCharacter );
|
||||
void LoadBannerFromUnlockEntry( const UnlockEntry* pUE );
|
||||
void LoadBackgroundFromUnlockEntry( const UnlockEntry* pUE );
|
||||
void LoadRoulette();
|
||||
void LoadRandom();
|
||||
void LoadFromSortOrder( SortOrder so );
|
||||
void LoadFallback();
|
||||
void LoadFallbackBG();
|
||||
void LoadCourseFallback();
|
||||
void LoadFallbackCharacterIcon();
|
||||
|
||||
void SetScrolling( bool bScroll, float Percent = 0 );
|
||||
bool GetScrolling() const { return m_bScrolling; }
|
||||
float ScrollingPercent() const { return m_fPercentScrolling; }
|
||||
|
||||
// Lua
|
||||
void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
bool m_bScrolling;
|
||||
float m_fPercentScrolling;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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.
|
||||
*/
|
||||
/** @brief Banner - The song/course's banner displayed in SelectMusic/Course. */
|
||||
|
||||
#ifndef BANNER_H
|
||||
#define BANNER_H
|
||||
|
||||
#include "Sprite.h"
|
||||
#include "RageTextureID.h"
|
||||
#include "GameConstantsAndTypes.h"
|
||||
class Song;
|
||||
class Course;
|
||||
class Character;
|
||||
class UnlockEntry;
|
||||
|
||||
/** @brief The characteristics of a Banner */
|
||||
class Banner : public Sprite
|
||||
{
|
||||
public:
|
||||
Banner();
|
||||
virtual ~Banner() { }
|
||||
virtual Banner *Copy() const;
|
||||
|
||||
void Load( RageTextureID ID, bool bIsBanner );
|
||||
virtual void Load( RageTextureID ID ) { Load( ID, true ); }
|
||||
void LoadFromCachedBanner( const RString &sPath );
|
||||
|
||||
virtual void Update( float fDeltaTime );
|
||||
|
||||
/**
|
||||
* @brief Attempt to load the banner from a song.
|
||||
* @param pSong the song in question. If NULL, there is no song.
|
||||
*/
|
||||
void LoadFromSong( Song* pSong );
|
||||
void LoadMode();
|
||||
void LoadFromSongGroup( RString sSongGroup );
|
||||
void LoadFromCourse( const Course *pCourse );
|
||||
void LoadCardFromCharacter( const Character *pCharacter );
|
||||
void LoadIconFromCharacter( const Character *pCharacter );
|
||||
void LoadBannerFromUnlockEntry( const UnlockEntry* pUE );
|
||||
void LoadBackgroundFromUnlockEntry( const UnlockEntry* pUE );
|
||||
void LoadRoulette();
|
||||
void LoadRandom();
|
||||
void LoadFromSortOrder( SortOrder so );
|
||||
void LoadFallback();
|
||||
void LoadFallbackBG();
|
||||
void LoadCourseFallback();
|
||||
void LoadFallbackCharacterIcon();
|
||||
|
||||
void SetScrolling( bool bScroll, float Percent = 0 );
|
||||
bool GetScrolling() const { return m_bScrolling; }
|
||||
float ScrollingPercent() const { return m_fPercentScrolling; }
|
||||
|
||||
// Lua
|
||||
void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
bool m_bScrolling;
|
||||
float m_fPercentScrolling;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Chris Danford (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.
|
||||
*/
|
||||
|
||||
+539
-539
File diff suppressed because it is too large
Load Diff
+63
-63
@@ -1,63 +1,63 @@
|
||||
#ifndef BANNER_CACHE_H
|
||||
#define BANNER_CACHE_H
|
||||
|
||||
#include "IniFile.h"
|
||||
|
||||
#include "RageTexture.h"
|
||||
|
||||
class LoadingWindow;
|
||||
/** @brief Maintains a cache of reduced-quality banners. */
|
||||
class BannerCache
|
||||
{
|
||||
public:
|
||||
BannerCache();
|
||||
~BannerCache();
|
||||
void ReadFromDisk();
|
||||
|
||||
RageTextureID LoadCachedBanner( RString sBannerPath );
|
||||
void CacheBanner( RString sBannerPath );
|
||||
void LoadBanner( RString sBannerPath );
|
||||
|
||||
void Demand();
|
||||
void Undemand();
|
||||
|
||||
void OutputStats() const;
|
||||
|
||||
private:
|
||||
static RString GetBannerCachePath( RString sBannerPath );
|
||||
void UnloadAllBanners();
|
||||
void CacheBannerInternal( RString sBannerPath );
|
||||
|
||||
IniFile BannerData;
|
||||
};
|
||||
|
||||
extern BannerCache *BANNERCACHE; // global and accessable from anywhere in our program
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Glenn Maynard (c) 2003
|
||||
* @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 BANNER_CACHE_H
|
||||
#define BANNER_CACHE_H
|
||||
|
||||
#include "IniFile.h"
|
||||
|
||||
#include "RageTexture.h"
|
||||
|
||||
class LoadingWindow;
|
||||
/** @brief Maintains a cache of reduced-quality banners. */
|
||||
class BannerCache
|
||||
{
|
||||
public:
|
||||
BannerCache();
|
||||
~BannerCache();
|
||||
void ReadFromDisk();
|
||||
|
||||
RageTextureID LoadCachedBanner( RString sBannerPath );
|
||||
void CacheBanner( RString sBannerPath );
|
||||
void LoadBanner( RString sBannerPath );
|
||||
|
||||
void Demand();
|
||||
void Undemand();
|
||||
|
||||
void OutputStats() const;
|
||||
|
||||
private:
|
||||
static RString GetBannerCachePath( RString sBannerPath );
|
||||
void UnloadAllBanners();
|
||||
void CacheBannerInternal( RString sBannerPath );
|
||||
|
||||
IniFile BannerData;
|
||||
};
|
||||
|
||||
extern BannerCache *BANNERCACHE; // global and accessable from anywhere in our program
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @author Glenn Maynard (c) 2003
|
||||
* @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.
|
||||
*/
|
||||
|
||||
+111
-111
@@ -1,111 +1,111 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMExtra.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements CRenderedInputPin class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h> // DirectShow base class definitions
|
||||
#include <mmsystem.h> // Needed for definition of timeGetTime
|
||||
#include <limits.h> // Standard data type limit definitions
|
||||
#include <measure.h> // Used for time critical log functions
|
||||
|
||||
#include "amextra.h"
|
||||
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
// Implements CRenderedInputPin class
|
||||
|
||||
CRenderedInputPin::CRenderedInputPin(TCHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName) :
|
||||
CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
|
||||
m_bAtEndOfStream(FALSE),
|
||||
m_bCompleteNotified(FALSE)
|
||||
{
|
||||
}
|
||||
#ifdef UNICODE
|
||||
CRenderedInputPin::CRenderedInputPin(CHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName) :
|
||||
CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
|
||||
m_bAtEndOfStream(FALSE),
|
||||
m_bCompleteNotified(FALSE)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flush end of stream condition - caller should do any
|
||||
// necessary stream level locking before calling this
|
||||
|
||||
STDMETHODIMP CRenderedInputPin::EndOfStream()
|
||||
{
|
||||
HRESULT hr = CheckStreaming();
|
||||
|
||||
// Do EC_COMPLETE handling for rendered pins
|
||||
if (S_OK == hr && !m_bAtEndOfStream) {
|
||||
m_bAtEndOfStream = TRUE;
|
||||
FILTER_STATE fs;
|
||||
EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs)));
|
||||
if (fs == State_Running) {
|
||||
DoCompleteHandling();
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Called to complete the flush
|
||||
|
||||
STDMETHODIMP CRenderedInputPin::EndFlush()
|
||||
{
|
||||
CAutoLock lck(m_pLock);
|
||||
|
||||
// Clean up renderer state
|
||||
m_bAtEndOfStream = FALSE;
|
||||
m_bCompleteNotified = FALSE;
|
||||
|
||||
return CBaseInputPin::EndFlush();
|
||||
}
|
||||
|
||||
|
||||
// Notify of Run() from filter
|
||||
|
||||
HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(tStart);
|
||||
m_bCompleteNotified = FALSE;
|
||||
if (m_bAtEndOfStream) {
|
||||
DoCompleteHandling();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Clear status on going into paused state
|
||||
|
||||
HRESULT CRenderedInputPin::Active()
|
||||
{
|
||||
m_bAtEndOfStream = FALSE;
|
||||
m_bCompleteNotified = FALSE;
|
||||
return CBaseInputPin::Active();
|
||||
}
|
||||
|
||||
|
||||
// Do stuff to deliver end of stream
|
||||
|
||||
void CRenderedInputPin::DoCompleteHandling()
|
||||
{
|
||||
ASSERT(m_bAtEndOfStream);
|
||||
if (!m_bCompleteNotified) {
|
||||
m_bCompleteNotified = TRUE;
|
||||
m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMExtra.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements CRenderedInputPin class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h> // DirectShow base class definitions
|
||||
#include <mmsystem.h> // Needed for definition of timeGetTime
|
||||
#include <limits.h> // Standard data type limit definitions
|
||||
#include <measure.h> // Used for time critical log functions
|
||||
|
||||
#include "amextra.h"
|
||||
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
// Implements CRenderedInputPin class
|
||||
|
||||
CRenderedInputPin::CRenderedInputPin(TCHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName) :
|
||||
CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
|
||||
m_bAtEndOfStream(FALSE),
|
||||
m_bCompleteNotified(FALSE)
|
||||
{
|
||||
}
|
||||
#ifdef UNICODE
|
||||
CRenderedInputPin::CRenderedInputPin(CHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName) :
|
||||
CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
|
||||
m_bAtEndOfStream(FALSE),
|
||||
m_bCompleteNotified(FALSE)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flush end of stream condition - caller should do any
|
||||
// necessary stream level locking before calling this
|
||||
|
||||
STDMETHODIMP CRenderedInputPin::EndOfStream()
|
||||
{
|
||||
HRESULT hr = CheckStreaming();
|
||||
|
||||
// Do EC_COMPLETE handling for rendered pins
|
||||
if (S_OK == hr && !m_bAtEndOfStream) {
|
||||
m_bAtEndOfStream = TRUE;
|
||||
FILTER_STATE fs;
|
||||
EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs)));
|
||||
if (fs == State_Running) {
|
||||
DoCompleteHandling();
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Called to complete the flush
|
||||
|
||||
STDMETHODIMP CRenderedInputPin::EndFlush()
|
||||
{
|
||||
CAutoLock lck(m_pLock);
|
||||
|
||||
// Clean up renderer state
|
||||
m_bAtEndOfStream = FALSE;
|
||||
m_bCompleteNotified = FALSE;
|
||||
|
||||
return CBaseInputPin::EndFlush();
|
||||
}
|
||||
|
||||
|
||||
// Notify of Run() from filter
|
||||
|
||||
HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(tStart);
|
||||
m_bCompleteNotified = FALSE;
|
||||
if (m_bAtEndOfStream) {
|
||||
DoCompleteHandling();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Clear status on going into paused state
|
||||
|
||||
HRESULT CRenderedInputPin::Active()
|
||||
{
|
||||
m_bAtEndOfStream = FALSE;
|
||||
m_bCompleteNotified = FALSE;
|
||||
return CBaseInputPin::Active();
|
||||
}
|
||||
|
||||
|
||||
// Do stuff to deliver end of stream
|
||||
|
||||
void CRenderedInputPin::DoCompleteHandling()
|
||||
{
|
||||
ASSERT(m_bAtEndOfStream);
|
||||
if (!m_bCompleteNotified) {
|
||||
m_bCompleteNotified = TRUE;
|
||||
m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+56
-56
@@ -1,56 +1,56 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMExtra.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __AMEXTRA__
|
||||
#define __AMEXTRA__
|
||||
|
||||
// Simple rendered input pin
|
||||
//
|
||||
// NOTE if your filter queues stuff before rendering then it may not be
|
||||
// appropriate to use this class
|
||||
//
|
||||
// In that case queue the end of stream condition until the last sample
|
||||
// is actually rendered and flush the condition appropriately
|
||||
|
||||
class CRenderedInputPin : public CBaseInputPin
|
||||
{
|
||||
public:
|
||||
|
||||
CRenderedInputPin(TCHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CRenderedInputPin(CHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
|
||||
// Override methods to track end of stream state
|
||||
STDMETHODIMP EndOfStream();
|
||||
STDMETHODIMP EndFlush();
|
||||
|
||||
HRESULT Active();
|
||||
HRESULT Run(REFERENCE_TIME tStart);
|
||||
|
||||
protected:
|
||||
|
||||
// Member variables to track state
|
||||
BOOL m_bAtEndOfStream; // Set by EndOfStream
|
||||
BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE
|
||||
|
||||
private:
|
||||
void DoCompleteHandling();
|
||||
};
|
||||
|
||||
#endif // __AMEXTRA__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMExtra.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __AMEXTRA__
|
||||
#define __AMEXTRA__
|
||||
|
||||
// Simple rendered input pin
|
||||
//
|
||||
// NOTE if your filter queues stuff before rendering then it may not be
|
||||
// appropriate to use this class
|
||||
//
|
||||
// In that case queue the end of stream condition until the last sample
|
||||
// is actually rendered and flush the condition appropriately
|
||||
|
||||
class CRenderedInputPin : public CBaseInputPin
|
||||
{
|
||||
public:
|
||||
|
||||
CRenderedInputPin(TCHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CRenderedInputPin(CHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
|
||||
// Override methods to track end of stream state
|
||||
STDMETHODIMP EndOfStream();
|
||||
STDMETHODIMP EndFlush();
|
||||
|
||||
HRESULT Active();
|
||||
HRESULT Run(REFERENCE_TIME tStart);
|
||||
|
||||
protected:
|
||||
|
||||
// Member variables to track state
|
||||
BOOL m_bAtEndOfStream; // Set by EndOfStream
|
||||
BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE
|
||||
|
||||
private:
|
||||
void DoCompleteHandling();
|
||||
};
|
||||
|
||||
#endif // __AMEXTRA__
|
||||
|
||||
|
||||
+5207
-5207
File diff suppressed because it is too large
Load Diff
+1589
-1589
File diff suppressed because it is too large
Load Diff
+275
-275
@@ -1,275 +1,275 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMVideo.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements helper functions for
|
||||
// bitmap formats.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
// These are bit field masks for true colour devices
|
||||
|
||||
const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F};
|
||||
const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F};
|
||||
const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF};
|
||||
|
||||
// This maps bitmap subtypes into a bits per pixel value and also a
|
||||
// name. unicode and ansi versions are stored because we have to
|
||||
// return a pointer to a static string.
|
||||
const struct {
|
||||
const GUID *pSubtype;
|
||||
WORD BitCount;
|
||||
CHAR *pName;
|
||||
WCHAR *wszName;
|
||||
} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome",
|
||||
&MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA",
|
||||
&MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8",
|
||||
&MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)",
|
||||
&MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)",
|
||||
&MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24",
|
||||
&MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32",
|
||||
&MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32",
|
||||
&MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay",
|
||||
&GUID_NULL, 0, "UNKNOWN", L"UNKNOWN"
|
||||
};
|
||||
|
||||
// Return the size of the bitmap as defined by this header
|
||||
|
||||
STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader)
|
||||
{
|
||||
return DIBSIZE(*pHeader);
|
||||
}
|
||||
|
||||
|
||||
// This is called if the header has a 16 bit colour depth and needs to work
|
||||
// out the detailed type from the bit fields (either RGB 565 or RGB 555)
|
||||
|
||||
STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader)
|
||||
{
|
||||
BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader;
|
||||
ASSERT(pbmiHeader->biBitCount == 16);
|
||||
|
||||
// If its BI_RGB then it's RGB 555 by default
|
||||
|
||||
if (pbmiHeader->biCompression == BI_RGB) {
|
||||
return MEDIASUBTYPE_RGB555;
|
||||
}
|
||||
|
||||
// Compare the bit fields with RGB 555
|
||||
|
||||
DWORD *pMask = (DWORD *) pbmInfo->bmiColors;
|
||||
if (pMask[0] == bits555[0]) {
|
||||
if (pMask[1] == bits555[1]) {
|
||||
if (pMask[2] == bits555[2]) {
|
||||
return MEDIASUBTYPE_RGB555;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compare the bit fields with RGB 565
|
||||
|
||||
pMask = (DWORD *) pbmInfo->bmiColors;
|
||||
if (pMask[0] == bits565[0]) {
|
||||
if (pMask[1] == bits565[1]) {
|
||||
if (pMask[2] == bits565[2]) {
|
||||
return MEDIASUBTYPE_RGB565;
|
||||
}
|
||||
}
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
||||
|
||||
// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is
|
||||
// used to describe it in format negotiations. For example a video codec fills
|
||||
// in the format block with a VIDEOINFO structure, it also fills in the major
|
||||
// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit
|
||||
// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8
|
||||
|
||||
STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader)
|
||||
{
|
||||
ASSERT(pbmiHeader);
|
||||
|
||||
// If it's not RGB then create a GUID from the compression type
|
||||
|
||||
if (pbmiHeader->biCompression != BI_RGB) {
|
||||
if (pbmiHeader->biCompression != BI_BITFIELDS) {
|
||||
FOURCCMap FourCCMap(pbmiHeader->biCompression);
|
||||
return (const GUID) FourCCMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Map the RGB DIB bit depth to a image GUID
|
||||
|
||||
switch(pbmiHeader->biBitCount) {
|
||||
case 1 : return MEDIASUBTYPE_RGB1;
|
||||
case 4 : return MEDIASUBTYPE_RGB4;
|
||||
case 8 : return MEDIASUBTYPE_RGB8;
|
||||
case 16 : return GetTrueColorType(pbmiHeader);
|
||||
case 24 : return MEDIASUBTYPE_RGB24;
|
||||
case 32 : return MEDIASUBTYPE_RGB32;
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
||||
|
||||
// Given a video bitmap subtype we return the number of bits per pixel it uses
|
||||
// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the
|
||||
// GUID subtype is not found in the table we return an invalid USHRT_MAX
|
||||
|
||||
STDAPI_(WORD) GetBitCount(const GUID *pSubtype)
|
||||
{
|
||||
ASSERT(pSubtype);
|
||||
const GUID *pMediaSubtype;
|
||||
INT iPosition = 0;
|
||||
|
||||
// Scan the mapping list seeing if the source GUID matches any known
|
||||
// bitmap subtypes, the list is terminated by a GUID_NULL entry
|
||||
|
||||
while (TRUE) {
|
||||
pMediaSubtype = BitCountMap[iPosition].pSubtype;
|
||||
if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) {
|
||||
return USHRT_MAX;
|
||||
}
|
||||
if (IsEqualGUID(*pMediaSubtype,*pSubtype)) {
|
||||
return BitCountMap[iPosition].BitCount;
|
||||
}
|
||||
iPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Given a bitmap subtype we return a description name that can be used for
|
||||
// debug purposes. In a retail build this function still returns the names
|
||||
// If the subtype isn't found in the lookup table we return string UNKNOWN
|
||||
|
||||
int LocateSubtype(const GUID *pSubtype)
|
||||
{
|
||||
ASSERT(pSubtype);
|
||||
const GUID *pMediaSubtype;
|
||||
INT iPosition = 0;
|
||||
|
||||
// Scan the mapping list seeing if the source GUID matches any known
|
||||
// bitmap subtypes, the list is terminated by a GUID_NULL entry
|
||||
|
||||
while (TRUE) {
|
||||
pMediaSubtype = BitCountMap[iPosition].pSubtype;
|
||||
if (IsEqualGUID(*pMediaSubtype,*pSubtype) ||
|
||||
IsEqualGUID(*pMediaSubtype,GUID_NULL)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
iPosition++;
|
||||
}
|
||||
|
||||
return iPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype)
|
||||
{
|
||||
return BitCountMap[LocateSubtype(pSubtype)].wszName;
|
||||
}
|
||||
|
||||
STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype)
|
||||
{
|
||||
return BitCountMap[LocateSubtype(pSubtype)].pName;
|
||||
}
|
||||
|
||||
#ifndef GetSubtypeName
|
||||
#error wxutil.h should have defined GetSubtypeName
|
||||
#endif
|
||||
#undef GetSubtypeName
|
||||
|
||||
// this is here for people that linked to it directly; most people
|
||||
// would use the header file that picks the A or W version.
|
||||
STDAPI_(CHAR *) GetSubtypeName(const GUID *pSubtype)
|
||||
{
|
||||
return GetSubtypeNameA(pSubtype);
|
||||
}
|
||||
|
||||
|
||||
// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER
|
||||
// This is really messy to deal with because it invariably has fields that
|
||||
// follow it holding bit fields, palettes and the rest. This function gives
|
||||
// the number of bytes required to hold a VIDEOINFO that represents it. This
|
||||
// count includes the prefix information (like the rcSource rectangle) the
|
||||
// BITMAPINFOHEADER field, and any other colour information on the end.
|
||||
//
|
||||
// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make
|
||||
// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't
|
||||
// right at the start of the VIDEOINFO (there are a number of other fields),
|
||||
//
|
||||
// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER));
|
||||
//
|
||||
|
||||
STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader)
|
||||
{
|
||||
// Everyone has this to start with this
|
||||
LONG Size = SIZE_PREHEADER + pHeader->biSize;
|
||||
|
||||
ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER));
|
||||
|
||||
// Does this format use a palette, if the number of colours actually used
|
||||
// is zero then it is set to the maximum that are allowed for that colour
|
||||
// depth (an example is 256 for eight bits). Truecolour formats may also
|
||||
// pass a palette with them in which case the used count is non zero
|
||||
|
||||
// This would scare me.
|
||||
ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0);
|
||||
|
||||
if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) {
|
||||
LONG Entries = (DWORD) 1 << pHeader->biBitCount;
|
||||
if (pHeader->biClrUsed) {
|
||||
Entries = pHeader->biClrUsed;
|
||||
}
|
||||
Size += Entries * sizeof(RGBQUAD);
|
||||
}
|
||||
|
||||
// Truecolour formats may have a BI_BITFIELDS specifier for compression
|
||||
// type which means that room for three DWORDs should be allocated that
|
||||
// specify where in each pixel the RGB colour components may be found
|
||||
|
||||
if (pHeader->biCompression == BI_BITFIELDS) {
|
||||
Size += SIZE_MASKS;
|
||||
}
|
||||
|
||||
// A BITMAPINFO for a palettised image may also contain a palette map that
|
||||
// provides the information to map from a source palette to a destination
|
||||
// palette during a BitBlt for example, because this information is only
|
||||
// ever processed during drawing you don't normally store the palette map
|
||||
// nor have any way of knowing if it is present in the data structure
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
// Returns TRUE if the VIDEOINFO contains a palette
|
||||
|
||||
STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo)
|
||||
{
|
||||
if (PALETTISED(pVideoInfo) == FALSE) {
|
||||
if (pVideoInfo->bmiHeader.biClrUsed == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Return a pointer to the first entry in a palette
|
||||
|
||||
STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo)
|
||||
{
|
||||
if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) {
|
||||
return TRUECOLOR(pVideoInfo)->bmiColors;
|
||||
}
|
||||
return COLORS(pVideoInfo);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMVideo.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements helper functions for
|
||||
// bitmap formats.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
// These are bit field masks for true colour devices
|
||||
|
||||
const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F};
|
||||
const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F};
|
||||
const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF};
|
||||
|
||||
// This maps bitmap subtypes into a bits per pixel value and also a
|
||||
// name. unicode and ansi versions are stored because we have to
|
||||
// return a pointer to a static string.
|
||||
const struct {
|
||||
const GUID *pSubtype;
|
||||
WORD BitCount;
|
||||
CHAR *pName;
|
||||
WCHAR *wszName;
|
||||
} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome",
|
||||
&MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA",
|
||||
&MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8",
|
||||
&MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)",
|
||||
&MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)",
|
||||
&MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24",
|
||||
&MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32",
|
||||
&MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32",
|
||||
&MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay",
|
||||
&GUID_NULL, 0, "UNKNOWN", L"UNKNOWN"
|
||||
};
|
||||
|
||||
// Return the size of the bitmap as defined by this header
|
||||
|
||||
STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader)
|
||||
{
|
||||
return DIBSIZE(*pHeader);
|
||||
}
|
||||
|
||||
|
||||
// This is called if the header has a 16 bit colour depth and needs to work
|
||||
// out the detailed type from the bit fields (either RGB 565 or RGB 555)
|
||||
|
||||
STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader)
|
||||
{
|
||||
BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader;
|
||||
ASSERT(pbmiHeader->biBitCount == 16);
|
||||
|
||||
// If its BI_RGB then it's RGB 555 by default
|
||||
|
||||
if (pbmiHeader->biCompression == BI_RGB) {
|
||||
return MEDIASUBTYPE_RGB555;
|
||||
}
|
||||
|
||||
// Compare the bit fields with RGB 555
|
||||
|
||||
DWORD *pMask = (DWORD *) pbmInfo->bmiColors;
|
||||
if (pMask[0] == bits555[0]) {
|
||||
if (pMask[1] == bits555[1]) {
|
||||
if (pMask[2] == bits555[2]) {
|
||||
return MEDIASUBTYPE_RGB555;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compare the bit fields with RGB 565
|
||||
|
||||
pMask = (DWORD *) pbmInfo->bmiColors;
|
||||
if (pMask[0] == bits565[0]) {
|
||||
if (pMask[1] == bits565[1]) {
|
||||
if (pMask[2] == bits565[2]) {
|
||||
return MEDIASUBTYPE_RGB565;
|
||||
}
|
||||
}
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
||||
|
||||
// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is
|
||||
// used to describe it in format negotiations. For example a video codec fills
|
||||
// in the format block with a VIDEOINFO structure, it also fills in the major
|
||||
// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit
|
||||
// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8
|
||||
|
||||
STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader)
|
||||
{
|
||||
ASSERT(pbmiHeader);
|
||||
|
||||
// If it's not RGB then create a GUID from the compression type
|
||||
|
||||
if (pbmiHeader->biCompression != BI_RGB) {
|
||||
if (pbmiHeader->biCompression != BI_BITFIELDS) {
|
||||
FOURCCMap FourCCMap(pbmiHeader->biCompression);
|
||||
return (const GUID) FourCCMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Map the RGB DIB bit depth to a image GUID
|
||||
|
||||
switch(pbmiHeader->biBitCount) {
|
||||
case 1 : return MEDIASUBTYPE_RGB1;
|
||||
case 4 : return MEDIASUBTYPE_RGB4;
|
||||
case 8 : return MEDIASUBTYPE_RGB8;
|
||||
case 16 : return GetTrueColorType(pbmiHeader);
|
||||
case 24 : return MEDIASUBTYPE_RGB24;
|
||||
case 32 : return MEDIASUBTYPE_RGB32;
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
||||
|
||||
// Given a video bitmap subtype we return the number of bits per pixel it uses
|
||||
// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the
|
||||
// GUID subtype is not found in the table we return an invalid USHRT_MAX
|
||||
|
||||
STDAPI_(WORD) GetBitCount(const GUID *pSubtype)
|
||||
{
|
||||
ASSERT(pSubtype);
|
||||
const GUID *pMediaSubtype;
|
||||
INT iPosition = 0;
|
||||
|
||||
// Scan the mapping list seeing if the source GUID matches any known
|
||||
// bitmap subtypes, the list is terminated by a GUID_NULL entry
|
||||
|
||||
while (TRUE) {
|
||||
pMediaSubtype = BitCountMap[iPosition].pSubtype;
|
||||
if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) {
|
||||
return USHRT_MAX;
|
||||
}
|
||||
if (IsEqualGUID(*pMediaSubtype,*pSubtype)) {
|
||||
return BitCountMap[iPosition].BitCount;
|
||||
}
|
||||
iPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Given a bitmap subtype we return a description name that can be used for
|
||||
// debug purposes. In a retail build this function still returns the names
|
||||
// If the subtype isn't found in the lookup table we return string UNKNOWN
|
||||
|
||||
int LocateSubtype(const GUID *pSubtype)
|
||||
{
|
||||
ASSERT(pSubtype);
|
||||
const GUID *pMediaSubtype;
|
||||
INT iPosition = 0;
|
||||
|
||||
// Scan the mapping list seeing if the source GUID matches any known
|
||||
// bitmap subtypes, the list is terminated by a GUID_NULL entry
|
||||
|
||||
while (TRUE) {
|
||||
pMediaSubtype = BitCountMap[iPosition].pSubtype;
|
||||
if (IsEqualGUID(*pMediaSubtype,*pSubtype) ||
|
||||
IsEqualGUID(*pMediaSubtype,GUID_NULL)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
iPosition++;
|
||||
}
|
||||
|
||||
return iPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype)
|
||||
{
|
||||
return BitCountMap[LocateSubtype(pSubtype)].wszName;
|
||||
}
|
||||
|
||||
STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype)
|
||||
{
|
||||
return BitCountMap[LocateSubtype(pSubtype)].pName;
|
||||
}
|
||||
|
||||
#ifndef GetSubtypeName
|
||||
#error wxutil.h should have defined GetSubtypeName
|
||||
#endif
|
||||
#undef GetSubtypeName
|
||||
|
||||
// this is here for people that linked to it directly; most people
|
||||
// would use the header file that picks the A or W version.
|
||||
STDAPI_(CHAR *) GetSubtypeName(const GUID *pSubtype)
|
||||
{
|
||||
return GetSubtypeNameA(pSubtype);
|
||||
}
|
||||
|
||||
|
||||
// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER
|
||||
// This is really messy to deal with because it invariably has fields that
|
||||
// follow it holding bit fields, palettes and the rest. This function gives
|
||||
// the number of bytes required to hold a VIDEOINFO that represents it. This
|
||||
// count includes the prefix information (like the rcSource rectangle) the
|
||||
// BITMAPINFOHEADER field, and any other colour information on the end.
|
||||
//
|
||||
// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make
|
||||
// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't
|
||||
// right at the start of the VIDEOINFO (there are a number of other fields),
|
||||
//
|
||||
// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER));
|
||||
//
|
||||
|
||||
STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader)
|
||||
{
|
||||
// Everyone has this to start with this
|
||||
LONG Size = SIZE_PREHEADER + pHeader->biSize;
|
||||
|
||||
ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER));
|
||||
|
||||
// Does this format use a palette, if the number of colours actually used
|
||||
// is zero then it is set to the maximum that are allowed for that colour
|
||||
// depth (an example is 256 for eight bits). Truecolour formats may also
|
||||
// pass a palette with them in which case the used count is non zero
|
||||
|
||||
// This would scare me.
|
||||
ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0);
|
||||
|
||||
if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) {
|
||||
LONG Entries = (DWORD) 1 << pHeader->biBitCount;
|
||||
if (pHeader->biClrUsed) {
|
||||
Entries = pHeader->biClrUsed;
|
||||
}
|
||||
Size += Entries * sizeof(RGBQUAD);
|
||||
}
|
||||
|
||||
// Truecolour formats may have a BI_BITFIELDS specifier for compression
|
||||
// type which means that room for three DWORDs should be allocated that
|
||||
// specify where in each pixel the RGB colour components may be found
|
||||
|
||||
if (pHeader->biCompression == BI_BITFIELDS) {
|
||||
Size += SIZE_MASKS;
|
||||
}
|
||||
|
||||
// A BITMAPINFO for a palettised image may also contain a palette map that
|
||||
// provides the information to map from a source palette to a destination
|
||||
// palette during a BitBlt for example, because this information is only
|
||||
// ever processed during drawing you don't normally store the palette map
|
||||
// nor have any way of knowing if it is present in the data structure
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
// Returns TRUE if the VIDEOINFO contains a palette
|
||||
|
||||
STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo)
|
||||
{
|
||||
if (PALETTISED(pVideoInfo) == FALSE) {
|
||||
if (pVideoInfo->bmiHeader.biClrUsed == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Return a pointer to the first entry in a palette
|
||||
|
||||
STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo)
|
||||
{
|
||||
if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) {
|
||||
return TRUECOLOR(pVideoInfo)->bmiColors;
|
||||
}
|
||||
return COLORS(pVideoInfo);
|
||||
}
|
||||
|
||||
+74
-74
@@ -1,74 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Cache.h
|
||||
//
|
||||
// Desc: DirectShow base classes - efines a non-MFC generic cache class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/* This class implements a simple cache. A cache object is instantiated
|
||||
with the number of items it is to hold. An item is a pointer to an
|
||||
object derived from CBaseObject (helps reduce memory leaks). The cache
|
||||
can then have objects added to it and removed from it. The cache size
|
||||
is fixed at construction time and may therefore run out or be flooded.
|
||||
If it runs out it returns a NULL pointer, if it fills up it also returns
|
||||
a NULL pointer instead of a pointer to the object just inserted */
|
||||
|
||||
/* Making these classes inherit from CBaseObject does nothing for their
|
||||
functionality but it allows us to check there are no memory leaks */
|
||||
|
||||
/* WARNING Be very careful when using this class, what it lets you do is
|
||||
store and retrieve objects so that you can minimise object creation
|
||||
which in turns improves efficiency. However the object you store is
|
||||
exactly the same as the object you get back which means that it short
|
||||
circuits the constructor initialisation phase. This means any class
|
||||
variables the object has (eg pointers) are highly likely to be invalid.
|
||||
Therefore ensure you reinitialise the object before using it again */
|
||||
|
||||
|
||||
#ifndef __CACHE__
|
||||
#define __CACHE__
|
||||
|
||||
|
||||
class CCache : CBaseObject {
|
||||
|
||||
/* Make copy constructor and assignment operator inaccessible */
|
||||
|
||||
CCache(const CCache &refCache);
|
||||
CCache &operator=(const CCache &refCache);
|
||||
|
||||
private:
|
||||
|
||||
/* These are initialised in the constructor. The first variable points to
|
||||
an array of pointers, each of which points to a CBaseObject derived
|
||||
object. The m_iCacheSize is the static fixed size for the cache and the
|
||||
m_iUsed defines the number of places filled with objects at any time.
|
||||
We fill the array of pointers from the start (ie m_ppObjects[0] first)
|
||||
and then only add and remove objects from the end position, so in this
|
||||
respect the array of object pointers should be treated as a stack */
|
||||
|
||||
CBaseObject **m_ppObjects;
|
||||
const INT m_iCacheSize;
|
||||
INT m_iUsed;
|
||||
|
||||
public:
|
||||
|
||||
CCache(TCHAR *pName,INT iItems);
|
||||
virtual ~CCache();
|
||||
|
||||
/* Add an item to the cache */
|
||||
CBaseObject *AddToCache(CBaseObject *pObject);
|
||||
|
||||
/* Remove an item from the cache */
|
||||
CBaseObject *RemoveFromCache();
|
||||
|
||||
/* Delete all the objects held in the cache */
|
||||
void RemoveAll(void);
|
||||
|
||||
/* Return the cache size which is set during construction */
|
||||
INT GetCacheSize(void) const {return m_iCacheSize;};
|
||||
};
|
||||
|
||||
#endif /* __CACHE__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Cache.h
|
||||
//
|
||||
// Desc: DirectShow base classes - efines a non-MFC generic cache class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/* This class implements a simple cache. A cache object is instantiated
|
||||
with the number of items it is to hold. An item is a pointer to an
|
||||
object derived from CBaseObject (helps reduce memory leaks). The cache
|
||||
can then have objects added to it and removed from it. The cache size
|
||||
is fixed at construction time and may therefore run out or be flooded.
|
||||
If it runs out it returns a NULL pointer, if it fills up it also returns
|
||||
a NULL pointer instead of a pointer to the object just inserted */
|
||||
|
||||
/* Making these classes inherit from CBaseObject does nothing for their
|
||||
functionality but it allows us to check there are no memory leaks */
|
||||
|
||||
/* WARNING Be very careful when using this class, what it lets you do is
|
||||
store and retrieve objects so that you can minimise object creation
|
||||
which in turns improves efficiency. However the object you store is
|
||||
exactly the same as the object you get back which means that it short
|
||||
circuits the constructor initialisation phase. This means any class
|
||||
variables the object has (eg pointers) are highly likely to be invalid.
|
||||
Therefore ensure you reinitialise the object before using it again */
|
||||
|
||||
|
||||
#ifndef __CACHE__
|
||||
#define __CACHE__
|
||||
|
||||
|
||||
class CCache : CBaseObject {
|
||||
|
||||
/* Make copy constructor and assignment operator inaccessible */
|
||||
|
||||
CCache(const CCache &refCache);
|
||||
CCache &operator=(const CCache &refCache);
|
||||
|
||||
private:
|
||||
|
||||
/* These are initialised in the constructor. The first variable points to
|
||||
an array of pointers, each of which points to a CBaseObject derived
|
||||
object. The m_iCacheSize is the static fixed size for the cache and the
|
||||
m_iUsed defines the number of places filled with objects at any time.
|
||||
We fill the array of pointers from the start (ie m_ppObjects[0] first)
|
||||
and then only add and remove objects from the end position, so in this
|
||||
respect the array of object pointers should be treated as a stack */
|
||||
|
||||
CBaseObject **m_ppObjects;
|
||||
const INT m_iCacheSize;
|
||||
INT m_iUsed;
|
||||
|
||||
public:
|
||||
|
||||
CCache(TCHAR *pName,INT iItems);
|
||||
virtual ~CCache();
|
||||
|
||||
/* Add an item to the cache */
|
||||
CBaseObject *AddToCache(CBaseObject *pObject);
|
||||
|
||||
/* Remove an item from the cache */
|
||||
CBaseObject *RemoveFromCache();
|
||||
|
||||
/* Delete all the objects held in the cache */
|
||||
void RemoveAll(void);
|
||||
|
||||
/* Return the cache size which is set during construction */
|
||||
INT GetCacheSize(void) const {return m_iCacheSize;};
|
||||
};
|
||||
|
||||
#endif /* __CACHE__ */
|
||||
|
||||
|
||||
+254
-254
@@ -1,254 +1,254 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: ComBase.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements class hierarchy for creating
|
||||
// COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions
|
||||
|
||||
|
||||
/* Define the static member variable */
|
||||
|
||||
LONG CBaseObject::m_cObjects = 0;
|
||||
|
||||
|
||||
/* Constructor */
|
||||
|
||||
CBaseObject::CBaseObject(const TCHAR *pName)
|
||||
{
|
||||
/* Increment the number of active objects */
|
||||
InterlockedIncrement(&m_cObjects);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifdef UNICODE
|
||||
m_dwCookie = DbgRegisterObjectCreation(0, pName);
|
||||
#else
|
||||
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CBaseObject::CBaseObject(const char *pName)
|
||||
{
|
||||
/* Increment the number of active objects */
|
||||
InterlockedIncrement(&m_cObjects);
|
||||
|
||||
#ifdef DEBUG
|
||||
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
HINSTANCE hlibOLEAut32;
|
||||
|
||||
/* Destructor */
|
||||
|
||||
CBaseObject::~CBaseObject()
|
||||
{
|
||||
/* Decrement the number of objects active */
|
||||
if (InterlockedDecrement(&m_cObjects) == 0) {
|
||||
if (hlibOLEAut32) {
|
||||
FreeLibrary(hlibOLEAut32);
|
||||
hlibOLEAut32 = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
DbgRegisterObjectDestruction(m_dwCookie);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll");
|
||||
|
||||
HINSTANCE LoadOLEAut32()
|
||||
{
|
||||
if (hlibOLEAut32 == 0) {
|
||||
hlibOLEAut32 = LoadLibrary(szOle32Aut);
|
||||
}
|
||||
|
||||
return hlibOLEAut32;
|
||||
}
|
||||
|
||||
|
||||
/* Constructor */
|
||||
|
||||
// We know we use "this" in the initialization list, we also know we don't modify *phr.
|
||||
#pragma warning( disable : 4355 4100 )
|
||||
CUnknown::CUnknown(const TCHAR *pName, LPUNKNOWN pUnk)
|
||||
: CBaseObject(pName)
|
||||
/* Start the object with a reference count of zero - when the */
|
||||
/* object is queried for it's first interface this may be */
|
||||
/* incremented depending on whether or not this object is */
|
||||
/* currently being aggregated upon */
|
||||
, m_cRef(0)
|
||||
/* Set our pointer to our IUnknown interface. */
|
||||
/* If we have an outer, use its, otherwise use ours. */
|
||||
/* This pointer effectivly points to the owner of */
|
||||
/* this object and can be accessed by the GetOwner() method. */
|
||||
, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
/* Why the double cast? Well, the inner cast is a type-safe cast */
|
||||
/* to pointer to a type from which we inherit. The second is */
|
||||
/* type-unsafe but works because INonDelegatingUnknown "behaves */
|
||||
/* like" IUnknown. (Only the names on the methods change.) */
|
||||
{
|
||||
// Everything we need to do has been done in the initializer list
|
||||
}
|
||||
|
||||
// This does the same as above except it has a useless HRESULT argument
|
||||
// use the previous constructor, this is just left for compatibility...
|
||||
CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseObject(pName),
|
||||
m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CUnknown::CUnknown(const CHAR *pName, LPUNKNOWN pUnk)
|
||||
: CBaseObject(pName), m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{ }
|
||||
|
||||
CUnknown::CUnknown(CHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseObject(pName), m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{ }
|
||||
|
||||
#endif
|
||||
|
||||
#pragma warning( default : 4355 4100 )
|
||||
|
||||
|
||||
/* QueryInterface */
|
||||
|
||||
STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
CheckPointer(ppv,E_POINTER);
|
||||
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
||||
|
||||
/* We know only about IUnknown */
|
||||
|
||||
if (riid == IID_IUnknown) {
|
||||
GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv);
|
||||
return NOERROR;
|
||||
} else {
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have to ensure that we DON'T use a max macro, since these will typically */
|
||||
/* lead to one of the parameters being evaluated twice. Since we are worried */
|
||||
/* about concurrency, we can't afford to access the m_cRef twice since we can't */
|
||||
/* afford to run the risk that its value having changed between accesses. */
|
||||
|
||||
template<class T> inline static T ourmax( const T & a, const T & b )
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/* AddRef */
|
||||
|
||||
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement( &m_cRef );
|
||||
ASSERT(lRef > 0);
|
||||
DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"),
|
||||
m_dwCookie, m_cRef));
|
||||
return ourmax(ULONG(m_cRef), 1ul);
|
||||
}
|
||||
|
||||
|
||||
/* Release */
|
||||
|
||||
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease()
|
||||
{
|
||||
/* If the reference count drops to zero delete ourselves */
|
||||
|
||||
LONG lRef = InterlockedDecrement( &m_cRef );
|
||||
ASSERT(lRef >= 0);
|
||||
|
||||
DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"),
|
||||
m_dwCookie, m_cRef));
|
||||
if (lRef == 0) {
|
||||
|
||||
// COM rules say we must protect against re-entrancy.
|
||||
// If we are an aggregator and we hold our own interfaces
|
||||
// on the aggregatee, the QI for these interfaces will
|
||||
// addref ourselves. So after doing the QI we must release
|
||||
// a ref count on ourselves. Then, before releasing the
|
||||
// private interface, we must addref ourselves. When we do
|
||||
// this from the destructor here it will result in the ref
|
||||
// count going to 1 and then back to 0 causing us to
|
||||
// re-enter the destructor. Hence we add an extra refcount here
|
||||
// once we know we will delete the object.
|
||||
// for an example aggregator see filgraph\distrib.cpp.
|
||||
|
||||
m_cRef++;
|
||||
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
} else {
|
||||
return ourmax(ULONG(m_cRef), 1ul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return an interface pointer to a requesting client
|
||||
performing a thread safe AddRef as necessary */
|
||||
|
||||
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv)
|
||||
{
|
||||
CheckPointer(ppv, E_POINTER);
|
||||
*ppv = pUnk;
|
||||
pUnk->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Compares two interfaces and returns TRUE if they are on the same object */
|
||||
|
||||
BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond)
|
||||
{
|
||||
/* Different objects can't have the same interface pointer for
|
||||
any interface
|
||||
*/
|
||||
if (pFirst == pSecond) {
|
||||
return TRUE;
|
||||
}
|
||||
/* OK - do it the hard way - check if they have the same
|
||||
IUnknown pointers - a single object can only have one of these
|
||||
*/
|
||||
LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface
|
||||
LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface
|
||||
HRESULT hr; // General OLE return code
|
||||
|
||||
ASSERT(pFirst);
|
||||
ASSERT(pSecond);
|
||||
|
||||
/* See if the IUnknown pointers match */
|
||||
|
||||
hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1);
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
ASSERT(pUnknown1);
|
||||
|
||||
hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2);
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
ASSERT(pUnknown2);
|
||||
|
||||
/* Release the extra interfaces we hold */
|
||||
|
||||
pUnknown1->Release();
|
||||
pUnknown2->Release();
|
||||
return (pUnknown1 == pUnknown2);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: ComBase.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements class hierarchy for creating
|
||||
// COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions
|
||||
|
||||
|
||||
/* Define the static member variable */
|
||||
|
||||
LONG CBaseObject::m_cObjects = 0;
|
||||
|
||||
|
||||
/* Constructor */
|
||||
|
||||
CBaseObject::CBaseObject(const TCHAR *pName)
|
||||
{
|
||||
/* Increment the number of active objects */
|
||||
InterlockedIncrement(&m_cObjects);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifdef UNICODE
|
||||
m_dwCookie = DbgRegisterObjectCreation(0, pName);
|
||||
#else
|
||||
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CBaseObject::CBaseObject(const char *pName)
|
||||
{
|
||||
/* Increment the number of active objects */
|
||||
InterlockedIncrement(&m_cObjects);
|
||||
|
||||
#ifdef DEBUG
|
||||
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
HINSTANCE hlibOLEAut32;
|
||||
|
||||
/* Destructor */
|
||||
|
||||
CBaseObject::~CBaseObject()
|
||||
{
|
||||
/* Decrement the number of objects active */
|
||||
if (InterlockedDecrement(&m_cObjects) == 0) {
|
||||
if (hlibOLEAut32) {
|
||||
FreeLibrary(hlibOLEAut32);
|
||||
hlibOLEAut32 = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
DbgRegisterObjectDestruction(m_dwCookie);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll");
|
||||
|
||||
HINSTANCE LoadOLEAut32()
|
||||
{
|
||||
if (hlibOLEAut32 == 0) {
|
||||
hlibOLEAut32 = LoadLibrary(szOle32Aut);
|
||||
}
|
||||
|
||||
return hlibOLEAut32;
|
||||
}
|
||||
|
||||
|
||||
/* Constructor */
|
||||
|
||||
// We know we use "this" in the initialization list, we also know we don't modify *phr.
|
||||
#pragma warning( disable : 4355 4100 )
|
||||
CUnknown::CUnknown(const TCHAR *pName, LPUNKNOWN pUnk)
|
||||
: CBaseObject(pName)
|
||||
/* Start the object with a reference count of zero - when the */
|
||||
/* object is queried for it's first interface this may be */
|
||||
/* incremented depending on whether or not this object is */
|
||||
/* currently being aggregated upon */
|
||||
, m_cRef(0)
|
||||
/* Set our pointer to our IUnknown interface. */
|
||||
/* If we have an outer, use its, otherwise use ours. */
|
||||
/* This pointer effectivly points to the owner of */
|
||||
/* this object and can be accessed by the GetOwner() method. */
|
||||
, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
/* Why the double cast? Well, the inner cast is a type-safe cast */
|
||||
/* to pointer to a type from which we inherit. The second is */
|
||||
/* type-unsafe but works because INonDelegatingUnknown "behaves */
|
||||
/* like" IUnknown. (Only the names on the methods change.) */
|
||||
{
|
||||
// Everything we need to do has been done in the initializer list
|
||||
}
|
||||
|
||||
// This does the same as above except it has a useless HRESULT argument
|
||||
// use the previous constructor, this is just left for compatibility...
|
||||
CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseObject(pName),
|
||||
m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CUnknown::CUnknown(const CHAR *pName, LPUNKNOWN pUnk)
|
||||
: CBaseObject(pName), m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{ }
|
||||
|
||||
CUnknown::CUnknown(CHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseObject(pName), m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{ }
|
||||
|
||||
#endif
|
||||
|
||||
#pragma warning( default : 4355 4100 )
|
||||
|
||||
|
||||
/* QueryInterface */
|
||||
|
||||
STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
CheckPointer(ppv,E_POINTER);
|
||||
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
||||
|
||||
/* We know only about IUnknown */
|
||||
|
||||
if (riid == IID_IUnknown) {
|
||||
GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv);
|
||||
return NOERROR;
|
||||
} else {
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have to ensure that we DON'T use a max macro, since these will typically */
|
||||
/* lead to one of the parameters being evaluated twice. Since we are worried */
|
||||
/* about concurrency, we can't afford to access the m_cRef twice since we can't */
|
||||
/* afford to run the risk that its value having changed between accesses. */
|
||||
|
||||
template<class T> inline static T ourmax( const T & a, const T & b )
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/* AddRef */
|
||||
|
||||
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement( &m_cRef );
|
||||
ASSERT(lRef > 0);
|
||||
DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"),
|
||||
m_dwCookie, m_cRef));
|
||||
return ourmax(ULONG(m_cRef), 1ul);
|
||||
}
|
||||
|
||||
|
||||
/* Release */
|
||||
|
||||
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease()
|
||||
{
|
||||
/* If the reference count drops to zero delete ourselves */
|
||||
|
||||
LONG lRef = InterlockedDecrement( &m_cRef );
|
||||
ASSERT(lRef >= 0);
|
||||
|
||||
DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"),
|
||||
m_dwCookie, m_cRef));
|
||||
if (lRef == 0) {
|
||||
|
||||
// COM rules say we must protect against re-entrancy.
|
||||
// If we are an aggregator and we hold our own interfaces
|
||||
// on the aggregatee, the QI for these interfaces will
|
||||
// addref ourselves. So after doing the QI we must release
|
||||
// a ref count on ourselves. Then, before releasing the
|
||||
// private interface, we must addref ourselves. When we do
|
||||
// this from the destructor here it will result in the ref
|
||||
// count going to 1 and then back to 0 causing us to
|
||||
// re-enter the destructor. Hence we add an extra refcount here
|
||||
// once we know we will delete the object.
|
||||
// for an example aggregator see filgraph\distrib.cpp.
|
||||
|
||||
m_cRef++;
|
||||
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
} else {
|
||||
return ourmax(ULONG(m_cRef), 1ul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return an interface pointer to a requesting client
|
||||
performing a thread safe AddRef as necessary */
|
||||
|
||||
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv)
|
||||
{
|
||||
CheckPointer(ppv, E_POINTER);
|
||||
*ppv = pUnk;
|
||||
pUnk->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Compares two interfaces and returns TRUE if they are on the same object */
|
||||
|
||||
BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond)
|
||||
{
|
||||
/* Different objects can't have the same interface pointer for
|
||||
any interface
|
||||
*/
|
||||
if (pFirst == pSecond) {
|
||||
return TRUE;
|
||||
}
|
||||
/* OK - do it the hard way - check if they have the same
|
||||
IUnknown pointers - a single object can only have one of these
|
||||
*/
|
||||
LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface
|
||||
LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface
|
||||
HRESULT hr; // General OLE return code
|
||||
|
||||
ASSERT(pFirst);
|
||||
ASSERT(pSecond);
|
||||
|
||||
/* See if the IUnknown pointers match */
|
||||
|
||||
hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1);
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
ASSERT(pUnknown1);
|
||||
|
||||
hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2);
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
ASSERT(pUnknown2);
|
||||
|
||||
/* Release the extra interfaces we hold */
|
||||
|
||||
pUnknown1->Release();
|
||||
pUnknown2->Release();
|
||||
return (pUnknown1 == pUnknown2);
|
||||
}
|
||||
|
||||
|
||||
+319
-319
@@ -1,319 +1,319 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: ComBase.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class hierarchy for creating
|
||||
// COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
|
||||
a. Derive your COM object from CUnknown
|
||||
|
||||
b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT *
|
||||
and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls
|
||||
to. The HRESULT * allows error codes to be passed around constructors and
|
||||
the TCHAR * is a descriptive name that can be printed on the debugger.
|
||||
|
||||
It is important that constructors only change the HRESULT * if they have
|
||||
to set an ERROR code, if it was successful then leave it alone or you may
|
||||
overwrite an error code from an object previously created.
|
||||
|
||||
When you call a constructor the descriptive name should be in static store
|
||||
as we do not copy the string. To stop large amounts of memory being used
|
||||
in retail builds by all these static strings use the NAME macro,
|
||||
|
||||
CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class
|
||||
knows not to do anything with objects that don't have a name.
|
||||
|
||||
c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and
|
||||
TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an
|
||||
error, or just simply pass it through to the constructor.
|
||||
|
||||
The object creation will fail in the class factory if the HRESULT indicates
|
||||
an error (ie FAILED(HRESULT) == TRUE)
|
||||
|
||||
d. Create a FactoryTemplate with your object's class id and CreateInstance
|
||||
function.
|
||||
|
||||
Then (for each interface) either
|
||||
|
||||
Multiple inheritance
|
||||
|
||||
1. Also derive it from ISomeInterface
|
||||
2. Include DECLARE_IUNKNOWN in your class definition to declare
|
||||
implementations of QueryInterface, AddRef and Release that
|
||||
call the outer unknown
|
||||
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
|
||||
code something like
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return GetInterface((ISomeInterface *) this, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
4. Declare and implement the member functions of ISomeInterface.
|
||||
|
||||
or: Nested interfaces
|
||||
|
||||
1. Declare a class derived from CUnknown
|
||||
2. Include DECLARE_IUNKNOWN in your class definition
|
||||
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
|
||||
code something like
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return GetInterface((ISomeInterface *) this, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
4. Implement the member functions of ISomeInterface. Use GetOwner() to
|
||||
access the COM object class.
|
||||
|
||||
And in your COM object class:
|
||||
|
||||
5. Make the nested class a friend of the COM object class, and declare
|
||||
an instance of the nested class as a member of the COM object class.
|
||||
|
||||
NOTE that because you must always pass the outer unknown and an hResult
|
||||
to the CUnknown constructor you cannot use a default constructor, in
|
||||
other words you will have to make the member variable a pointer to the
|
||||
class and make a NEW call in your constructor to actually create it.
|
||||
|
||||
6. override the NonDelegatingQueryInterface with code like this:
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return m_pImplFilter->
|
||||
NonDelegatingQueryInterface(IID_ISomeInterface, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
You can have mixed classes which support some interfaces via multiple
|
||||
inheritance and some via nested classes
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __COMBASE__
|
||||
#define __COMBASE__
|
||||
|
||||
// Filter Setup data structures no defined in axextend.idl
|
||||
|
||||
typedef REGPINTYPES
|
||||
AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE;
|
||||
|
||||
typedef REGFILTERPINS
|
||||
AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN;
|
||||
|
||||
typedef struct _AMOVIESETUP_FILTER
|
||||
{
|
||||
const CLSID * clsID;
|
||||
const WCHAR * strName;
|
||||
DWORD dwMerit;
|
||||
UINT nPins;
|
||||
const AMOVIESETUP_PIN * lpPin;
|
||||
}
|
||||
AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER;
|
||||
|
||||
/* The DLLENTRY module initialises the module handle on loading */
|
||||
|
||||
extern HINSTANCE g_hInst;
|
||||
|
||||
/* On DLL load remember which platform we are running on */
|
||||
|
||||
extern DWORD g_amPlatform;
|
||||
extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx
|
||||
|
||||
/* Version of IUnknown that is renamed to allow a class to support both
|
||||
non delegating and delegating IUnknowns in the same COM object */
|
||||
|
||||
#ifndef INONDELEGATINGUNKNOWN_DEFINED
|
||||
DECLARE_INTERFACE(INonDelegatingUnknown)
|
||||
{
|
||||
STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
|
||||
STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE;
|
||||
};
|
||||
#define INONDELEGATINGUNKNOWN_DEFINED
|
||||
#endif
|
||||
|
||||
typedef INonDelegatingUnknown *PNDUNKNOWN;
|
||||
|
||||
|
||||
/* This is the base object class that supports active object counting. As
|
||||
part of the debug facilities we trace every time a C++ object is created
|
||||
or destroyed. The name of the object has to be passed up through the class
|
||||
derivation list during construction as you cannot call virtual functions
|
||||
in the constructor. The downside of all this is that every single object
|
||||
constructor has to take an object name parameter that describes it */
|
||||
|
||||
class CBaseObject
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// Disable the copy constructor and assignment by default so you will get
|
||||
// compiler errors instead of unexpected behaviour if you pass objects
|
||||
// by value or assign objects.
|
||||
CBaseObject(const CBaseObject& objectSrc); // no implementation
|
||||
void operator=(const CBaseObject& objectSrc); // no implementation
|
||||
|
||||
private:
|
||||
static LONG m_cObjects; /* Total number of objects active */
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
DWORD m_dwCookie; /* Cookie identifying this object */
|
||||
#endif
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* These increment and decrement the number of active objects */
|
||||
|
||||
CBaseObject(const TCHAR *pName);
|
||||
#ifdef UNICODE
|
||||
CBaseObject(const char *pName);
|
||||
#endif
|
||||
~CBaseObject();
|
||||
|
||||
/* Call this to find if there are any CUnknown derived objects active */
|
||||
|
||||
static LONG ObjectsActive() {
|
||||
return m_cObjects;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* An object that supports one or more COM interfaces will be based on
|
||||
this class. It supports counting of total objects for DLLCanUnloadNow
|
||||
support, and an implementation of the core non delegating IUnknown */
|
||||
|
||||
class AM_NOVTABLE CUnknown : public INonDelegatingUnknown,
|
||||
public CBaseObject
|
||||
{
|
||||
private:
|
||||
const LPUNKNOWN m_pUnknown; /* Owner of this object */
|
||||
|
||||
protected: /* So we can override NonDelegatingRelease() */
|
||||
volatile LONG m_cRef; /* Number of reference counts */
|
||||
|
||||
public:
|
||||
|
||||
CUnknown(const TCHAR *pName, LPUNKNOWN pUnk);
|
||||
virtual ~CUnknown() {};
|
||||
|
||||
// This is redundant, just use the other constructor
|
||||
// as we never touch the HRESULT in this anyway
|
||||
CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr);
|
||||
#ifdef UNICODE
|
||||
CUnknown(const char *pName, LPUNKNOWN pUnk);
|
||||
CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr);
|
||||
#endif
|
||||
|
||||
/* Return the owner of this object */
|
||||
|
||||
LPUNKNOWN GetOwner() const {
|
||||
return m_pUnknown;
|
||||
};
|
||||
|
||||
/* Called from the class factory to create a new instance, it is
|
||||
pure virtual so it must be overriden in your derived class */
|
||||
|
||||
/* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */
|
||||
|
||||
/* Non delegating unknown implementation */
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
};
|
||||
|
||||
#if (_MSC_VER <= 1200)
|
||||
#pragma warning(disable:4211)
|
||||
|
||||
/* The standard InterlockedXXX functions won't take volatiles */
|
||||
static inline LONG WINAPI InterlockedIncrement( volatile LONG * plong )
|
||||
{ return InterlockedIncrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
static inline LONG WINAPI InterlockedDecrement( volatile LONG * plong )
|
||||
{ return InterlockedDecrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
#pragma warning(default:4211)
|
||||
#endif
|
||||
|
||||
|
||||
/* Return an interface pointer to a requesting client
|
||||
performing a thread safe AddRef as necessary */
|
||||
|
||||
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv);
|
||||
|
||||
/* A function that can create a new COM object */
|
||||
|
||||
typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
|
||||
|
||||
/* A function (can be NULL) which is called from the DLL entrypoint
|
||||
routine for each factory template:
|
||||
|
||||
bLoading - TRUE on DLL load, FALSE on DLL unload
|
||||
rclsid - the m_ClsID of the entry
|
||||
*/
|
||||
typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
|
||||
|
||||
/* Create one of these per object class in an array so that
|
||||
the default class factory code can create new instances */
|
||||
|
||||
class CFactoryTemplate {
|
||||
|
||||
public:
|
||||
|
||||
const WCHAR * m_Name;
|
||||
const CLSID * m_ClsID;
|
||||
LPFNNewCOMObject m_lpfnNew;
|
||||
LPFNInitRoutine m_lpfnInit;
|
||||
const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter;
|
||||
|
||||
BOOL IsClassID(REFCLSID rclsid) const {
|
||||
return (IsEqualCLSID(*m_ClsID,rclsid));
|
||||
};
|
||||
|
||||
CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const {
|
||||
CheckPointer(phr,NULL);
|
||||
return m_lpfnNew(pUnk, phr);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* You must override the (pure virtual) NonDelegatingQueryInterface to return
|
||||
interface pointers (using GetInterface) to the interfaces your derived
|
||||
class supports (the default implementation only supports IUnknown) */
|
||||
|
||||
#define DECLARE_IUNKNOWN \
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \
|
||||
return GetOwner()->QueryInterface(riid,ppv); \
|
||||
}; \
|
||||
STDMETHODIMP_(ULONG) AddRef() { \
|
||||
return GetOwner()->AddRef(); \
|
||||
}; \
|
||||
STDMETHODIMP_(ULONG) Release() { \
|
||||
return GetOwner()->Release(); \
|
||||
};
|
||||
|
||||
|
||||
|
||||
HINSTANCE LoadOLEAut32();
|
||||
|
||||
|
||||
#endif /* __COMBASE__ */
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: ComBase.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class hierarchy for creating
|
||||
// COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
|
||||
a. Derive your COM object from CUnknown
|
||||
|
||||
b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT *
|
||||
and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls
|
||||
to. The HRESULT * allows error codes to be passed around constructors and
|
||||
the TCHAR * is a descriptive name that can be printed on the debugger.
|
||||
|
||||
It is important that constructors only change the HRESULT * if they have
|
||||
to set an ERROR code, if it was successful then leave it alone or you may
|
||||
overwrite an error code from an object previously created.
|
||||
|
||||
When you call a constructor the descriptive name should be in static store
|
||||
as we do not copy the string. To stop large amounts of memory being used
|
||||
in retail builds by all these static strings use the NAME macro,
|
||||
|
||||
CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class
|
||||
knows not to do anything with objects that don't have a name.
|
||||
|
||||
c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and
|
||||
TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an
|
||||
error, or just simply pass it through to the constructor.
|
||||
|
||||
The object creation will fail in the class factory if the HRESULT indicates
|
||||
an error (ie FAILED(HRESULT) == TRUE)
|
||||
|
||||
d. Create a FactoryTemplate with your object's class id and CreateInstance
|
||||
function.
|
||||
|
||||
Then (for each interface) either
|
||||
|
||||
Multiple inheritance
|
||||
|
||||
1. Also derive it from ISomeInterface
|
||||
2. Include DECLARE_IUNKNOWN in your class definition to declare
|
||||
implementations of QueryInterface, AddRef and Release that
|
||||
call the outer unknown
|
||||
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
|
||||
code something like
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return GetInterface((ISomeInterface *) this, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
4. Declare and implement the member functions of ISomeInterface.
|
||||
|
||||
or: Nested interfaces
|
||||
|
||||
1. Declare a class derived from CUnknown
|
||||
2. Include DECLARE_IUNKNOWN in your class definition
|
||||
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
|
||||
code something like
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return GetInterface((ISomeInterface *) this, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
4. Implement the member functions of ISomeInterface. Use GetOwner() to
|
||||
access the COM object class.
|
||||
|
||||
And in your COM object class:
|
||||
|
||||
5. Make the nested class a friend of the COM object class, and declare
|
||||
an instance of the nested class as a member of the COM object class.
|
||||
|
||||
NOTE that because you must always pass the outer unknown and an hResult
|
||||
to the CUnknown constructor you cannot use a default constructor, in
|
||||
other words you will have to make the member variable a pointer to the
|
||||
class and make a NEW call in your constructor to actually create it.
|
||||
|
||||
6. override the NonDelegatingQueryInterface with code like this:
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return m_pImplFilter->
|
||||
NonDelegatingQueryInterface(IID_ISomeInterface, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
You can have mixed classes which support some interfaces via multiple
|
||||
inheritance and some via nested classes
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __COMBASE__
|
||||
#define __COMBASE__
|
||||
|
||||
// Filter Setup data structures no defined in axextend.idl
|
||||
|
||||
typedef REGPINTYPES
|
||||
AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE;
|
||||
|
||||
typedef REGFILTERPINS
|
||||
AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN;
|
||||
|
||||
typedef struct _AMOVIESETUP_FILTER
|
||||
{
|
||||
const CLSID * clsID;
|
||||
const WCHAR * strName;
|
||||
DWORD dwMerit;
|
||||
UINT nPins;
|
||||
const AMOVIESETUP_PIN * lpPin;
|
||||
}
|
||||
AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER;
|
||||
|
||||
/* The DLLENTRY module initialises the module handle on loading */
|
||||
|
||||
extern HINSTANCE g_hInst;
|
||||
|
||||
/* On DLL load remember which platform we are running on */
|
||||
|
||||
extern DWORD g_amPlatform;
|
||||
extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx
|
||||
|
||||
/* Version of IUnknown that is renamed to allow a class to support both
|
||||
non delegating and delegating IUnknowns in the same COM object */
|
||||
|
||||
#ifndef INONDELEGATINGUNKNOWN_DEFINED
|
||||
DECLARE_INTERFACE(INonDelegatingUnknown)
|
||||
{
|
||||
STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
|
||||
STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE;
|
||||
};
|
||||
#define INONDELEGATINGUNKNOWN_DEFINED
|
||||
#endif
|
||||
|
||||
typedef INonDelegatingUnknown *PNDUNKNOWN;
|
||||
|
||||
|
||||
/* This is the base object class that supports active object counting. As
|
||||
part of the debug facilities we trace every time a C++ object is created
|
||||
or destroyed. The name of the object has to be passed up through the class
|
||||
derivation list during construction as you cannot call virtual functions
|
||||
in the constructor. The downside of all this is that every single object
|
||||
constructor has to take an object name parameter that describes it */
|
||||
|
||||
class CBaseObject
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// Disable the copy constructor and assignment by default so you will get
|
||||
// compiler errors instead of unexpected behaviour if you pass objects
|
||||
// by value or assign objects.
|
||||
CBaseObject(const CBaseObject& objectSrc); // no implementation
|
||||
void operator=(const CBaseObject& objectSrc); // no implementation
|
||||
|
||||
private:
|
||||
static LONG m_cObjects; /* Total number of objects active */
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
DWORD m_dwCookie; /* Cookie identifying this object */
|
||||
#endif
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* These increment and decrement the number of active objects */
|
||||
|
||||
CBaseObject(const TCHAR *pName);
|
||||
#ifdef UNICODE
|
||||
CBaseObject(const char *pName);
|
||||
#endif
|
||||
~CBaseObject();
|
||||
|
||||
/* Call this to find if there are any CUnknown derived objects active */
|
||||
|
||||
static LONG ObjectsActive() {
|
||||
return m_cObjects;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* An object that supports one or more COM interfaces will be based on
|
||||
this class. It supports counting of total objects for DLLCanUnloadNow
|
||||
support, and an implementation of the core non delegating IUnknown */
|
||||
|
||||
class AM_NOVTABLE CUnknown : public INonDelegatingUnknown,
|
||||
public CBaseObject
|
||||
{
|
||||
private:
|
||||
const LPUNKNOWN m_pUnknown; /* Owner of this object */
|
||||
|
||||
protected: /* So we can override NonDelegatingRelease() */
|
||||
volatile LONG m_cRef; /* Number of reference counts */
|
||||
|
||||
public:
|
||||
|
||||
CUnknown(const TCHAR *pName, LPUNKNOWN pUnk);
|
||||
virtual ~CUnknown() {};
|
||||
|
||||
// This is redundant, just use the other constructor
|
||||
// as we never touch the HRESULT in this anyway
|
||||
CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr);
|
||||
#ifdef UNICODE
|
||||
CUnknown(const char *pName, LPUNKNOWN pUnk);
|
||||
CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr);
|
||||
#endif
|
||||
|
||||
/* Return the owner of this object */
|
||||
|
||||
LPUNKNOWN GetOwner() const {
|
||||
return m_pUnknown;
|
||||
};
|
||||
|
||||
/* Called from the class factory to create a new instance, it is
|
||||
pure virtual so it must be overriden in your derived class */
|
||||
|
||||
/* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */
|
||||
|
||||
/* Non delegating unknown implementation */
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
};
|
||||
|
||||
#if (_MSC_VER <= 1200)
|
||||
#pragma warning(disable:4211)
|
||||
|
||||
/* The standard InterlockedXXX functions won't take volatiles */
|
||||
static inline LONG WINAPI InterlockedIncrement( volatile LONG * plong )
|
||||
{ return InterlockedIncrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
static inline LONG WINAPI InterlockedDecrement( volatile LONG * plong )
|
||||
{ return InterlockedDecrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
#pragma warning(default:4211)
|
||||
#endif
|
||||
|
||||
|
||||
/* Return an interface pointer to a requesting client
|
||||
performing a thread safe AddRef as necessary */
|
||||
|
||||
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv);
|
||||
|
||||
/* A function that can create a new COM object */
|
||||
|
||||
typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
|
||||
|
||||
/* A function (can be NULL) which is called from the DLL entrypoint
|
||||
routine for each factory template:
|
||||
|
||||
bLoading - TRUE on DLL load, FALSE on DLL unload
|
||||
rclsid - the m_ClsID of the entry
|
||||
*/
|
||||
typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
|
||||
|
||||
/* Create one of these per object class in an array so that
|
||||
the default class factory code can create new instances */
|
||||
|
||||
class CFactoryTemplate {
|
||||
|
||||
public:
|
||||
|
||||
const WCHAR * m_Name;
|
||||
const CLSID * m_ClsID;
|
||||
LPFNNewCOMObject m_lpfnNew;
|
||||
LPFNInitRoutine m_lpfnInit;
|
||||
const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter;
|
||||
|
||||
BOOL IsClassID(REFCLSID rclsid) const {
|
||||
return (IsEqualCLSID(*m_ClsID,rclsid));
|
||||
};
|
||||
|
||||
CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const {
|
||||
CheckPointer(phr,NULL);
|
||||
return m_lpfnNew(pUnk, phr);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* You must override the (pure virtual) NonDelegatingQueryInterface to return
|
||||
interface pointers (using GetInterface) to the interfaces your derived
|
||||
class supports (the default implementation only supports IUnknown) */
|
||||
|
||||
#define DECLARE_IUNKNOWN \
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \
|
||||
return GetOwner()->QueryInterface(riid,ppv); \
|
||||
}; \
|
||||
STDMETHODIMP_(ULONG) AddRef() { \
|
||||
return GetOwner()->AddRef(); \
|
||||
}; \
|
||||
STDMETHODIMP_(ULONG) Release() { \
|
||||
return GetOwner()->Release(); \
|
||||
};
|
||||
|
||||
|
||||
|
||||
HINSTANCE LoadOLEAut32();
|
||||
|
||||
|
||||
#endif /* __COMBASE__ */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+380
-380
@@ -1,380 +1,380 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: CProp.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements CBasePropertyPage class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
// Constructor for the base property page class. As described in the header
|
||||
// file we must be initialised with dialog and title resource identifiers.
|
||||
// The class supports IPropertyPage and overrides AddRef and Release calls
|
||||
// to keep track of the reference counts. When the last count is released
|
||||
// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces
|
||||
// previously obtained by the property page when it had SetObjects called
|
||||
|
||||
CBasePropertyPage::CBasePropertyPage(TCHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId) : // To get tital
|
||||
CUnknown(pName,pUnk),
|
||||
m_DialogId(DialogId),
|
||||
m_TitleId(TitleId),
|
||||
m_hwnd(NULL),
|
||||
m_Dlg(NULL),
|
||||
m_pPageSite(NULL),
|
||||
m_bObjectSet(FALSE),
|
||||
m_bDirty(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CBasePropertyPage::CBasePropertyPage(CHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId) : // To get tital
|
||||
CUnknown(pName,pUnk),
|
||||
m_DialogId(DialogId),
|
||||
m_TitleId(TitleId),
|
||||
m_hwnd(NULL),
|
||||
m_Dlg(NULL),
|
||||
m_pPageSite(NULL),
|
||||
m_bObjectSet(FALSE),
|
||||
m_bDirty(FALSE)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// Increment our reference count
|
||||
|
||||
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement(&m_cRef);
|
||||
ASSERT(lRef > 0);
|
||||
return max(ULONG(m_cRef),1ul);
|
||||
}
|
||||
|
||||
|
||||
// Release a reference count and protect against reentrancy
|
||||
|
||||
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease()
|
||||
{
|
||||
// If the reference count drops to zero delete ourselves
|
||||
|
||||
if (InterlockedDecrement(&m_cRef) == 0) {
|
||||
m_cRef++;
|
||||
SetPageSite(NULL);
|
||||
SetObjects(0,NULL);
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
} else {
|
||||
return max(ULONG(m_cRef),1ul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Expose our IPropertyPage interface
|
||||
|
||||
STDMETHODIMP
|
||||
CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,void **ppv)
|
||||
{
|
||||
if (riid == IID_IPropertyPage) {
|
||||
return GetInterface((IPropertyPage *)this,ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid,ppv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the page info so that the page site can size itself
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::GetPageInfo(LPPROPPAGEINFO pPageInfo)
|
||||
{
|
||||
CheckPointer(pPageInfo,E_POINTER);
|
||||
WCHAR wszTitle[STR_MAX_LENGTH];
|
||||
WideStringFromResource(wszTitle,m_TitleId);
|
||||
|
||||
// Allocate dynamic memory for the property page title
|
||||
|
||||
LPOLESTR pszTitle;
|
||||
HRESULT hr = AMGetWideString(wszTitle, &pszTitle);
|
||||
if (FAILED(hr)) {
|
||||
NOTE("No caption memory");
|
||||
return hr;
|
||||
}
|
||||
|
||||
pPageInfo->cb = sizeof(PROPPAGEINFO);
|
||||
pPageInfo->pszTitle = pszTitle;
|
||||
pPageInfo->pszDocString = NULL;
|
||||
pPageInfo->pszHelpFile = NULL;
|
||||
pPageInfo->dwHelpContext = 0;
|
||||
|
||||
// Set defaults in case GetDialogSize fails
|
||||
pPageInfo->size.cx = 340;
|
||||
pPageInfo->size.cy = 150;
|
||||
|
||||
GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Handles the messages for our property window
|
||||
|
||||
INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
CBasePropertyPage *pPropertyPage;
|
||||
|
||||
switch (uMsg) {
|
||||
|
||||
case WM_INITDIALOG:
|
||||
|
||||
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
|
||||
|
||||
// This pointer may be NULL when calculating size
|
||||
|
||||
pPropertyPage = (CBasePropertyPage *) lParam;
|
||||
if (pPropertyPage == NULL) {
|
||||
return (LRESULT) 1;
|
||||
}
|
||||
pPropertyPage->m_Dlg = hwnd;
|
||||
}
|
||||
|
||||
// This pointer may be NULL when calculating size
|
||||
|
||||
pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
|
||||
if (pPropertyPage == NULL) {
|
||||
return (LRESULT) 1;
|
||||
}
|
||||
return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
|
||||
// Tells us the object that should be informed of the property changes
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,LPUNKNOWN *ppUnk)
|
||||
{
|
||||
if (cObjects == 1) {
|
||||
|
||||
if ((ppUnk == NULL) || (*ppUnk == NULL)) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// Set a flag to say that we have set the Object
|
||||
m_bObjectSet = TRUE ;
|
||||
return OnConnect(*ppUnk);
|
||||
|
||||
} else if (cObjects == 0) {
|
||||
|
||||
// Set a flag to say that we have not set the Object for the page
|
||||
m_bObjectSet = FALSE ;
|
||||
return OnDisconnect();
|
||||
}
|
||||
|
||||
DbgBreak("No support for more than one object");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
// Create the window we will use to edit properties
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent,
|
||||
LPCRECT pRect,
|
||||
BOOL fModal)
|
||||
{
|
||||
CheckPointer(pRect,E_POINTER);
|
||||
|
||||
// Return failure if SetObject has not been called.
|
||||
if (m_bObjectSet == FALSE) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (m_hwnd) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_hwnd = CreateDialogParam(g_hInst,
|
||||
MAKEINTRESOURCE(m_DialogId),
|
||||
hwndParent,
|
||||
DialogProc,
|
||||
(LPARAM) this);
|
||||
if (m_hwnd == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
OnActivate();
|
||||
Move(pRect);
|
||||
return Show(SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
|
||||
// Set the position of the property page
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect)
|
||||
{
|
||||
CheckPointer(pRect,E_POINTER);
|
||||
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
MoveWindow(m_hwnd, // Property page handle
|
||||
pRect->left, // x coordinate
|
||||
pRect->top, // y coordinate
|
||||
WIDTH(pRect), // Overall window width
|
||||
HEIGHT(pRect), // And likewise height
|
||||
TRUE); // Should we repaint it
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Display the property dialog
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow)
|
||||
{
|
||||
// Have we been activated yet
|
||||
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Ignore wrong show flags
|
||||
|
||||
if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
ShowWindow(m_hwnd,nCmdShow);
|
||||
InvalidateRect(m_hwnd,NULL,TRUE);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Destroy the property page dialog
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Deactivate(void)
|
||||
{
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Remove WS_EX_CONTROLPARENT before DestroyWindow call
|
||||
|
||||
DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE);
|
||||
dwStyle = dwStyle & (~WS_EX_CONTROLPARENT);
|
||||
|
||||
// Set m_hwnd to be NULL temporarily so the message handler
|
||||
// for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT
|
||||
// style back in
|
||||
HWND hwnd = m_hwnd;
|
||||
m_hwnd = NULL;
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle);
|
||||
m_hwnd = hwnd;
|
||||
|
||||
OnDeactivate();
|
||||
|
||||
// Destroy the dialog window
|
||||
|
||||
DestroyWindow(m_hwnd);
|
||||
m_hwnd = NULL;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Tells the application property page site
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::SetPageSite(LPPROPERTYPAGESITE pPageSite)
|
||||
{
|
||||
if (pPageSite) {
|
||||
|
||||
if (m_pPageSite) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_pPageSite = pPageSite;
|
||||
m_pPageSite->AddRef();
|
||||
|
||||
} else {
|
||||
|
||||
if (m_pPageSite == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_pPageSite->Release();
|
||||
m_pPageSite = NULL;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Apply any changes so far made
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Apply()
|
||||
{
|
||||
// In ActiveMovie 1.0 we used to check whether we had been activated or
|
||||
// not. This is too constrictive. Apply should be allowed as long as
|
||||
// SetObject was called to set an object. So we will no longer check to
|
||||
// see if we have been activated (ie., m_hWnd != NULL), but instead
|
||||
// make sure that m_bObjectSet is TRUE (ie., SetObject has been called).
|
||||
|
||||
if (m_bObjectSet == FALSE) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Must have had a site set
|
||||
|
||||
if (m_pPageSite == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Has anything changed
|
||||
|
||||
if (m_bDirty == FALSE) {
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Commit derived class changes
|
||||
|
||||
HRESULT hr = OnApplyChanges();
|
||||
if (SUCCEEDED(hr)) {
|
||||
m_bDirty = FALSE;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Base class definition for message handling
|
||||
|
||||
INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
// we would like the TAB key to move around the tab stops in our property
|
||||
// page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT
|
||||
// style behind our back, so we need to switch it back on now behind its
|
||||
// back. Otherwise the tab key will be useless in every page.
|
||||
//
|
||||
|
||||
CBasePropertyPage *pPropertyPage;
|
||||
{
|
||||
pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
|
||||
if (pPropertyPage->m_hwnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
switch (uMsg) {
|
||||
case WM_STYLECHANGING:
|
||||
if (wParam == GWL_EXSTYLE) {
|
||||
LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam;
|
||||
lpss->styleNew |= WS_EX_CONTROLPARENT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: CProp.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements CBasePropertyPage class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
// Constructor for the base property page class. As described in the header
|
||||
// file we must be initialised with dialog and title resource identifiers.
|
||||
// The class supports IPropertyPage and overrides AddRef and Release calls
|
||||
// to keep track of the reference counts. When the last count is released
|
||||
// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces
|
||||
// previously obtained by the property page when it had SetObjects called
|
||||
|
||||
CBasePropertyPage::CBasePropertyPage(TCHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId) : // To get tital
|
||||
CUnknown(pName,pUnk),
|
||||
m_DialogId(DialogId),
|
||||
m_TitleId(TitleId),
|
||||
m_hwnd(NULL),
|
||||
m_Dlg(NULL),
|
||||
m_pPageSite(NULL),
|
||||
m_bObjectSet(FALSE),
|
||||
m_bDirty(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CBasePropertyPage::CBasePropertyPage(CHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId) : // To get tital
|
||||
CUnknown(pName,pUnk),
|
||||
m_DialogId(DialogId),
|
||||
m_TitleId(TitleId),
|
||||
m_hwnd(NULL),
|
||||
m_Dlg(NULL),
|
||||
m_pPageSite(NULL),
|
||||
m_bObjectSet(FALSE),
|
||||
m_bDirty(FALSE)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// Increment our reference count
|
||||
|
||||
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement(&m_cRef);
|
||||
ASSERT(lRef > 0);
|
||||
return max(ULONG(m_cRef),1ul);
|
||||
}
|
||||
|
||||
|
||||
// Release a reference count and protect against reentrancy
|
||||
|
||||
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease()
|
||||
{
|
||||
// If the reference count drops to zero delete ourselves
|
||||
|
||||
if (InterlockedDecrement(&m_cRef) == 0) {
|
||||
m_cRef++;
|
||||
SetPageSite(NULL);
|
||||
SetObjects(0,NULL);
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
} else {
|
||||
return max(ULONG(m_cRef),1ul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Expose our IPropertyPage interface
|
||||
|
||||
STDMETHODIMP
|
||||
CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,void **ppv)
|
||||
{
|
||||
if (riid == IID_IPropertyPage) {
|
||||
return GetInterface((IPropertyPage *)this,ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid,ppv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the page info so that the page site can size itself
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::GetPageInfo(LPPROPPAGEINFO pPageInfo)
|
||||
{
|
||||
CheckPointer(pPageInfo,E_POINTER);
|
||||
WCHAR wszTitle[STR_MAX_LENGTH];
|
||||
WideStringFromResource(wszTitle,m_TitleId);
|
||||
|
||||
// Allocate dynamic memory for the property page title
|
||||
|
||||
LPOLESTR pszTitle;
|
||||
HRESULT hr = AMGetWideString(wszTitle, &pszTitle);
|
||||
if (FAILED(hr)) {
|
||||
NOTE("No caption memory");
|
||||
return hr;
|
||||
}
|
||||
|
||||
pPageInfo->cb = sizeof(PROPPAGEINFO);
|
||||
pPageInfo->pszTitle = pszTitle;
|
||||
pPageInfo->pszDocString = NULL;
|
||||
pPageInfo->pszHelpFile = NULL;
|
||||
pPageInfo->dwHelpContext = 0;
|
||||
|
||||
// Set defaults in case GetDialogSize fails
|
||||
pPageInfo->size.cx = 340;
|
||||
pPageInfo->size.cy = 150;
|
||||
|
||||
GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Handles the messages for our property window
|
||||
|
||||
INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
CBasePropertyPage *pPropertyPage;
|
||||
|
||||
switch (uMsg) {
|
||||
|
||||
case WM_INITDIALOG:
|
||||
|
||||
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
|
||||
|
||||
// This pointer may be NULL when calculating size
|
||||
|
||||
pPropertyPage = (CBasePropertyPage *) lParam;
|
||||
if (pPropertyPage == NULL) {
|
||||
return (LRESULT) 1;
|
||||
}
|
||||
pPropertyPage->m_Dlg = hwnd;
|
||||
}
|
||||
|
||||
// This pointer may be NULL when calculating size
|
||||
|
||||
pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
|
||||
if (pPropertyPage == NULL) {
|
||||
return (LRESULT) 1;
|
||||
}
|
||||
return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
|
||||
// Tells us the object that should be informed of the property changes
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,LPUNKNOWN *ppUnk)
|
||||
{
|
||||
if (cObjects == 1) {
|
||||
|
||||
if ((ppUnk == NULL) || (*ppUnk == NULL)) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// Set a flag to say that we have set the Object
|
||||
m_bObjectSet = TRUE ;
|
||||
return OnConnect(*ppUnk);
|
||||
|
||||
} else if (cObjects == 0) {
|
||||
|
||||
// Set a flag to say that we have not set the Object for the page
|
||||
m_bObjectSet = FALSE ;
|
||||
return OnDisconnect();
|
||||
}
|
||||
|
||||
DbgBreak("No support for more than one object");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
// Create the window we will use to edit properties
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent,
|
||||
LPCRECT pRect,
|
||||
BOOL fModal)
|
||||
{
|
||||
CheckPointer(pRect,E_POINTER);
|
||||
|
||||
// Return failure if SetObject has not been called.
|
||||
if (m_bObjectSet == FALSE) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (m_hwnd) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_hwnd = CreateDialogParam(g_hInst,
|
||||
MAKEINTRESOURCE(m_DialogId),
|
||||
hwndParent,
|
||||
DialogProc,
|
||||
(LPARAM) this);
|
||||
if (m_hwnd == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
OnActivate();
|
||||
Move(pRect);
|
||||
return Show(SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
|
||||
// Set the position of the property page
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect)
|
||||
{
|
||||
CheckPointer(pRect,E_POINTER);
|
||||
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
MoveWindow(m_hwnd, // Property page handle
|
||||
pRect->left, // x coordinate
|
||||
pRect->top, // y coordinate
|
||||
WIDTH(pRect), // Overall window width
|
||||
HEIGHT(pRect), // And likewise height
|
||||
TRUE); // Should we repaint it
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Display the property dialog
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow)
|
||||
{
|
||||
// Have we been activated yet
|
||||
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Ignore wrong show flags
|
||||
|
||||
if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
ShowWindow(m_hwnd,nCmdShow);
|
||||
InvalidateRect(m_hwnd,NULL,TRUE);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Destroy the property page dialog
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Deactivate(void)
|
||||
{
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Remove WS_EX_CONTROLPARENT before DestroyWindow call
|
||||
|
||||
DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE);
|
||||
dwStyle = dwStyle & (~WS_EX_CONTROLPARENT);
|
||||
|
||||
// Set m_hwnd to be NULL temporarily so the message handler
|
||||
// for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT
|
||||
// style back in
|
||||
HWND hwnd = m_hwnd;
|
||||
m_hwnd = NULL;
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle);
|
||||
m_hwnd = hwnd;
|
||||
|
||||
OnDeactivate();
|
||||
|
||||
// Destroy the dialog window
|
||||
|
||||
DestroyWindow(m_hwnd);
|
||||
m_hwnd = NULL;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Tells the application property page site
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::SetPageSite(LPPROPERTYPAGESITE pPageSite)
|
||||
{
|
||||
if (pPageSite) {
|
||||
|
||||
if (m_pPageSite) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_pPageSite = pPageSite;
|
||||
m_pPageSite->AddRef();
|
||||
|
||||
} else {
|
||||
|
||||
if (m_pPageSite == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_pPageSite->Release();
|
||||
m_pPageSite = NULL;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Apply any changes so far made
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Apply()
|
||||
{
|
||||
// In ActiveMovie 1.0 we used to check whether we had been activated or
|
||||
// not. This is too constrictive. Apply should be allowed as long as
|
||||
// SetObject was called to set an object. So we will no longer check to
|
||||
// see if we have been activated (ie., m_hWnd != NULL), but instead
|
||||
// make sure that m_bObjectSet is TRUE (ie., SetObject has been called).
|
||||
|
||||
if (m_bObjectSet == FALSE) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Must have had a site set
|
||||
|
||||
if (m_pPageSite == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Has anything changed
|
||||
|
||||
if (m_bDirty == FALSE) {
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Commit derived class changes
|
||||
|
||||
HRESULT hr = OnApplyChanges();
|
||||
if (SUCCEEDED(hr)) {
|
||||
m_bDirty = FALSE;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Base class definition for message handling
|
||||
|
||||
INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
// we would like the TAB key to move around the tab stops in our property
|
||||
// page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT
|
||||
// style behind our back, so we need to switch it back on now behind its
|
||||
// back. Otherwise the tab key will be useless in every page.
|
||||
//
|
||||
|
||||
CBasePropertyPage *pPropertyPage;
|
||||
{
|
||||
pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
|
||||
if (pPropertyPage->m_hwnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
switch (uMsg) {
|
||||
case WM_STYLECHANGING:
|
||||
if (wParam == GWL_EXSTYLE) {
|
||||
LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam;
|
||||
lpss->styleNew |= WS_EX_CONTROLPARENT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
|
||||
+95
-95
@@ -1,95 +1,95 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: CProp.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __CPROP__
|
||||
#define __CPROP__
|
||||
|
||||
// Base property page class. Filters typically expose custom properties by
|
||||
// implementing special control interfaces, examples are IDirectDrawVideo
|
||||
// and IQualProp on renderers. This allows property pages to be built that
|
||||
// use the given interface. Applications such as the ActiveMovie OCX query
|
||||
// filters for the property pages they support and expose them to the user
|
||||
//
|
||||
// This class provides all the framework for a property page. A property
|
||||
// page is a COM object that supports IPropertyPage. We should be created
|
||||
// with a resource ID for the dialog which we will load when required. We
|
||||
// should also be given in the constructor a resource ID for a title string
|
||||
// we will load from the DLLs STRINGTABLE. The property page titles must be
|
||||
// stored in resource files so that they can be easily internationalised
|
||||
//
|
||||
// We have a number of virtual methods (not PURE) that may be overriden in
|
||||
// derived classes to query for interfaces and so on. These functions have
|
||||
// simple implementations here that just return NOERROR. Derived classes
|
||||
// will almost definately have to override the message handler method called
|
||||
// OnReceiveMessage. We have a static dialog procedure that calls the method
|
||||
// so that derived classes don't have to fiddle around with the this pointer
|
||||
|
||||
class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPPROPERTYPAGESITE m_pPageSite; // Details for our property site
|
||||
HWND m_hwnd; // Window handle for the page
|
||||
HWND m_Dlg; // Actual dialog window handle
|
||||
BOOL m_bDirty; // Has anything been changed
|
||||
int m_TitleId; // Resource identifier for title
|
||||
int m_DialogId; // Dialog resource identifier
|
||||
|
||||
static INT_PTR CALLBACK DialogProc(HWND hwnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
private:
|
||||
BOOL m_bObjectSet ; // SetObject has been called or not.
|
||||
public:
|
||||
|
||||
CBasePropertyPage(TCHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId); // To get tital
|
||||
|
||||
#ifdef UNICODE
|
||||
CBasePropertyPage(CHAR *pName,
|
||||
LPUNKNOWN pUnk,
|
||||
int DialogId,
|
||||
int TitleId);
|
||||
#endif
|
||||
virtual ~CBasePropertyPage() { };
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
// Override these virtual methods
|
||||
|
||||
virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; };
|
||||
virtual HRESULT OnDisconnect() { return NOERROR; };
|
||||
virtual HRESULT OnActivate() { return NOERROR; };
|
||||
virtual HRESULT OnDeactivate() { return NOERROR; };
|
||||
virtual HRESULT OnApplyChanges() { return NOERROR; };
|
||||
virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
||||
|
||||
// These implement an IPropertyPage interface
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP SetPageSite(LPPROPERTYPAGESITE pPageSite);
|
||||
STDMETHODIMP Activate(HWND hwndParent,LPCRECT prect,BOOL fModal);
|
||||
STDMETHODIMP Deactivate(void);
|
||||
STDMETHODIMP GetPageInfo(LPPROPPAGEINFO pPageInfo);
|
||||
STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN *ppUnk);
|
||||
STDMETHODIMP Show(UINT nCmdShow);
|
||||
STDMETHODIMP Move(LPCRECT prect);
|
||||
STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; }
|
||||
STDMETHODIMP Apply(void);
|
||||
STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; }
|
||||
STDMETHODIMP TranslateAccelerator(LPMSG lpMsg) { return E_NOTIMPL; }
|
||||
};
|
||||
|
||||
#endif // __CPROP__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: CProp.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __CPROP__
|
||||
#define __CPROP__
|
||||
|
||||
// Base property page class. Filters typically expose custom properties by
|
||||
// implementing special control interfaces, examples are IDirectDrawVideo
|
||||
// and IQualProp on renderers. This allows property pages to be built that
|
||||
// use the given interface. Applications such as the ActiveMovie OCX query
|
||||
// filters for the property pages they support and expose them to the user
|
||||
//
|
||||
// This class provides all the framework for a property page. A property
|
||||
// page is a COM object that supports IPropertyPage. We should be created
|
||||
// with a resource ID for the dialog which we will load when required. We
|
||||
// should also be given in the constructor a resource ID for a title string
|
||||
// we will load from the DLLs STRINGTABLE. The property page titles must be
|
||||
// stored in resource files so that they can be easily internationalised
|
||||
//
|
||||
// We have a number of virtual methods (not PURE) that may be overriden in
|
||||
// derived classes to query for interfaces and so on. These functions have
|
||||
// simple implementations here that just return NOERROR. Derived classes
|
||||
// will almost definately have to override the message handler method called
|
||||
// OnReceiveMessage. We have a static dialog procedure that calls the method
|
||||
// so that derived classes don't have to fiddle around with the this pointer
|
||||
|
||||
class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPPROPERTYPAGESITE m_pPageSite; // Details for our property site
|
||||
HWND m_hwnd; // Window handle for the page
|
||||
HWND m_Dlg; // Actual dialog window handle
|
||||
BOOL m_bDirty; // Has anything been changed
|
||||
int m_TitleId; // Resource identifier for title
|
||||
int m_DialogId; // Dialog resource identifier
|
||||
|
||||
static INT_PTR CALLBACK DialogProc(HWND hwnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
private:
|
||||
BOOL m_bObjectSet ; // SetObject has been called or not.
|
||||
public:
|
||||
|
||||
CBasePropertyPage(TCHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId); // To get tital
|
||||
|
||||
#ifdef UNICODE
|
||||
CBasePropertyPage(CHAR *pName,
|
||||
LPUNKNOWN pUnk,
|
||||
int DialogId,
|
||||
int TitleId);
|
||||
#endif
|
||||
virtual ~CBasePropertyPage() { };
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
// Override these virtual methods
|
||||
|
||||
virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; };
|
||||
virtual HRESULT OnDisconnect() { return NOERROR; };
|
||||
virtual HRESULT OnActivate() { return NOERROR; };
|
||||
virtual HRESULT OnDeactivate() { return NOERROR; };
|
||||
virtual HRESULT OnApplyChanges() { return NOERROR; };
|
||||
virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
||||
|
||||
// These implement an IPropertyPage interface
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP SetPageSite(LPPROPERTYPAGESITE pPageSite);
|
||||
STDMETHODIMP Activate(HWND hwndParent,LPCRECT prect,BOOL fModal);
|
||||
STDMETHODIMP Deactivate(void);
|
||||
STDMETHODIMP GetPageInfo(LPPROPPAGEINFO pPageInfo);
|
||||
STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN *ppUnk);
|
||||
STDMETHODIMP Show(UINT nCmdShow);
|
||||
STDMETHODIMP Move(LPCRECT prect);
|
||||
STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; }
|
||||
STDMETHODIMP Apply(void);
|
||||
STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; }
|
||||
STDMETHODIMP TranslateAccelerator(LPMSG lpMsg) { return E_NOTIMPL; }
|
||||
};
|
||||
|
||||
#endif // __CPROP__
|
||||
|
||||
|
||||
+2378
-2378
File diff suppressed because it is too large
Load Diff
+919
-919
File diff suppressed because it is too large
Load Diff
+126
-126
@@ -1,126 +1,126 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDMM.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements routines for using DirectDraw
|
||||
// on a multimonitor system.
|
||||
//
|
||||
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <ddraw.h>
|
||||
#include "ddmm.h"
|
||||
|
||||
/*
|
||||
* FindDeviceCallback
|
||||
*/
|
||||
typedef struct {
|
||||
LPSTR szDevice;
|
||||
GUID* lpGUID;
|
||||
GUID GUID;
|
||||
BOOL fFound;
|
||||
} FindDeviceData;
|
||||
|
||||
BOOL CALLBACK FindDeviceCallback(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam) {
|
||||
FindDeviceData *p = (FindDeviceData*)lParam;
|
||||
|
||||
if(lstrcmpiA(p->szDevice, szDevice) == 0) {
|
||||
if(lpGUID) {
|
||||
p->GUID = *lpGUID;
|
||||
p->lpGUID = &p->GUID;
|
||||
}
|
||||
else {
|
||||
p->lpGUID = NULL;
|
||||
}
|
||||
p->fFound = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL CALLBACK FindDeviceCallbackEx(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam, HMONITOR hMonitor) {
|
||||
FindDeviceData *p = (FindDeviceData*)lParam;
|
||||
|
||||
if(lstrcmpiA(p->szDevice, szDevice) == 0) {
|
||||
if(lpGUID) {
|
||||
p->GUID = *lpGUID;
|
||||
p->lpGUID = &p->GUID;
|
||||
}
|
||||
else {
|
||||
p->lpGUID = NULL;
|
||||
}
|
||||
p->fFound = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DirectDrawCreateFromDevice
|
||||
*
|
||||
* create a DirectDraw object for a particular device
|
||||
*/
|
||||
IDirectDraw * DirectDrawCreateFromDevice(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) {
|
||||
IDirectDraw* pdd = NULL;
|
||||
FindDeviceData find;
|
||||
|
||||
if(szDevice == NULL) {
|
||||
DirectDrawCreateP(NULL, &pdd, NULL);
|
||||
return pdd;
|
||||
}
|
||||
|
||||
find.szDevice = szDevice;
|
||||
find.fFound = FALSE;
|
||||
DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find);
|
||||
|
||||
if(find.fFound) {
|
||||
//
|
||||
// In 4bpp mode the following DDraw call causes a message box to be popped
|
||||
// up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
|
||||
// make sure it doesn't happen.
|
||||
//
|
||||
UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
DirectDrawCreateP(find.lpGUID, &pdd, NULL);
|
||||
SetErrorMode(ErrorMode);
|
||||
}
|
||||
|
||||
return pdd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DirectDrawCreateFromDeviceEx
|
||||
*
|
||||
* create a DirectDraw object for a particular device
|
||||
*/
|
||||
IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) {
|
||||
IDirectDraw* pdd = NULL;
|
||||
FindDeviceData find;
|
||||
|
||||
if(szDevice == NULL) {
|
||||
DirectDrawCreateP(NULL, &pdd, NULL);
|
||||
return pdd;
|
||||
}
|
||||
|
||||
find.szDevice = szDevice;
|
||||
find.fFound = FALSE;
|
||||
DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find,
|
||||
DDENUM_ATTACHEDSECONDARYDEVICES);
|
||||
|
||||
if(find.fFound) {
|
||||
//
|
||||
// In 4bpp mode the following DDraw call causes a message box to be popped
|
||||
// up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
|
||||
// make sure it doesn't happen.
|
||||
//
|
||||
UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
DirectDrawCreateP(find.lpGUID, &pdd, NULL);
|
||||
SetErrorMode(ErrorMode);
|
||||
}
|
||||
|
||||
return pdd;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDMM.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements routines for using DirectDraw
|
||||
// on a multimonitor system.
|
||||
//
|
||||
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <ddraw.h>
|
||||
#include "ddmm.h"
|
||||
|
||||
/*
|
||||
* FindDeviceCallback
|
||||
*/
|
||||
typedef struct {
|
||||
LPSTR szDevice;
|
||||
GUID* lpGUID;
|
||||
GUID GUID;
|
||||
BOOL fFound;
|
||||
} FindDeviceData;
|
||||
|
||||
BOOL CALLBACK FindDeviceCallback(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam) {
|
||||
FindDeviceData *p = (FindDeviceData*)lParam;
|
||||
|
||||
if(lstrcmpiA(p->szDevice, szDevice) == 0) {
|
||||
if(lpGUID) {
|
||||
p->GUID = *lpGUID;
|
||||
p->lpGUID = &p->GUID;
|
||||
}
|
||||
else {
|
||||
p->lpGUID = NULL;
|
||||
}
|
||||
p->fFound = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL CALLBACK FindDeviceCallbackEx(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam, HMONITOR hMonitor) {
|
||||
FindDeviceData *p = (FindDeviceData*)lParam;
|
||||
|
||||
if(lstrcmpiA(p->szDevice, szDevice) == 0) {
|
||||
if(lpGUID) {
|
||||
p->GUID = *lpGUID;
|
||||
p->lpGUID = &p->GUID;
|
||||
}
|
||||
else {
|
||||
p->lpGUID = NULL;
|
||||
}
|
||||
p->fFound = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DirectDrawCreateFromDevice
|
||||
*
|
||||
* create a DirectDraw object for a particular device
|
||||
*/
|
||||
IDirectDraw * DirectDrawCreateFromDevice(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) {
|
||||
IDirectDraw* pdd = NULL;
|
||||
FindDeviceData find;
|
||||
|
||||
if(szDevice == NULL) {
|
||||
DirectDrawCreateP(NULL, &pdd, NULL);
|
||||
return pdd;
|
||||
}
|
||||
|
||||
find.szDevice = szDevice;
|
||||
find.fFound = FALSE;
|
||||
DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find);
|
||||
|
||||
if(find.fFound) {
|
||||
//
|
||||
// In 4bpp mode the following DDraw call causes a message box to be popped
|
||||
// up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
|
||||
// make sure it doesn't happen.
|
||||
//
|
||||
UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
DirectDrawCreateP(find.lpGUID, &pdd, NULL);
|
||||
SetErrorMode(ErrorMode);
|
||||
}
|
||||
|
||||
return pdd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DirectDrawCreateFromDeviceEx
|
||||
*
|
||||
* create a DirectDraw object for a particular device
|
||||
*/
|
||||
IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) {
|
||||
IDirectDraw* pdd = NULL;
|
||||
FindDeviceData find;
|
||||
|
||||
if(szDevice == NULL) {
|
||||
DirectDrawCreateP(NULL, &pdd, NULL);
|
||||
return pdd;
|
||||
}
|
||||
|
||||
find.szDevice = szDevice;
|
||||
find.fFound = FALSE;
|
||||
DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find,
|
||||
DDENUM_ATTACHEDSECONDARYDEVICES);
|
||||
|
||||
if(find.fFound) {
|
||||
//
|
||||
// In 4bpp mode the following DDraw call causes a message box to be popped
|
||||
// up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
|
||||
// make sure it doesn't happen.
|
||||
//
|
||||
UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
DirectDrawCreateP(find.lpGUID, &pdd, NULL);
|
||||
SetErrorMode(ErrorMode);
|
||||
}
|
||||
|
||||
return pdd;
|
||||
}
|
||||
|
||||
|
||||
+28
-28
@@ -1,28 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDMM.h
|
||||
//
|
||||
// Desc: DirectShow base classes - efines routines for using DirectDraw
|
||||
// on a multimonitor system.
|
||||
//
|
||||
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Assume C declarations for C++ */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// DDRAW.H might not include these
|
||||
#ifndef DDENUM_ATTACHEDSECONDARYDEVICES
|
||||
#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L
|
||||
#endif
|
||||
|
||||
typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN);
|
||||
typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID);
|
||||
|
||||
IDirectDraw * DirectDrawCreateFromDevice(LPSTR, PDRAWCREATE, PDRAWENUM);
|
||||
IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDMM.h
|
||||
//
|
||||
// Desc: DirectShow base classes - efines routines for using DirectDraw
|
||||
// on a multimonitor system.
|
||||
//
|
||||
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Assume C declarations for C++ */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// DDRAW.H might not include these
|
||||
#ifndef DDENUM_ATTACHEDSECONDARYDEVICES
|
||||
#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L
|
||||
#endif
|
||||
|
||||
typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN);
|
||||
typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID);
|
||||
|
||||
IDirectDraw * DirectDrawCreateFromDevice(LPSTR, PDRAWCREATE, PDRAWENUM);
|
||||
IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
+332
-332
@@ -1,332 +1,332 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DllEntry.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements classes used to support dll
|
||||
// entry points for COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <initguid.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef UNICODE
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif // _UNICODE
|
||||
#endif // UNICODE
|
||||
|
||||
#include <tchar.h>
|
||||
#endif // DEBUG
|
||||
|
||||
extern CFactoryTemplate g_Templates[];
|
||||
extern int g_cTemplates;
|
||||
|
||||
HINSTANCE g_hInst;
|
||||
DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
|
||||
OSVERSIONINFO g_osInfo;
|
||||
|
||||
//
|
||||
// an instance of this is created by the DLLGetClassObject entrypoint
|
||||
// it uses the CFactoryTemplate object it is given to support the
|
||||
// IClassFactory interface
|
||||
|
||||
class CClassFactory : public IClassFactory, public CBaseObject {
|
||||
|
||||
private:
|
||||
const CFactoryTemplate *const m_pTemplate;
|
||||
|
||||
ULONG m_cRef;
|
||||
|
||||
static int m_cLocked;
|
||||
public:
|
||||
CClassFactory(const CFactoryTemplate *);
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
|
||||
STDMETHODIMP_(ULONG)AddRef();
|
||||
STDMETHODIMP_(ULONG)Release();
|
||||
|
||||
// IClassFactory
|
||||
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv);
|
||||
STDMETHODIMP LockServer(BOOL fLock);
|
||||
|
||||
// allow DLLGetClassObject to know about global server lock status
|
||||
static BOOL IsLocked() {
|
||||
return (m_cLocked > 0);
|
||||
};
|
||||
};
|
||||
|
||||
// process-wide dll locked state
|
||||
int CClassFactory::m_cLocked = 0;
|
||||
|
||||
CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
|
||||
: CBaseObject(NAME("Class Factory"))
|
||||
, m_cRef(0)
|
||||
, m_pTemplate(pTemplate) {
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::QueryInterface(REFIID riid,void **ppv) {
|
||||
CheckPointer(ppv,E_POINTER)
|
||||
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
||||
*ppv = NULL;
|
||||
|
||||
// any interface on this object is the object pointer.
|
||||
if((riid == IID_IUnknown) || (riid == IID_IClassFactory)) {
|
||||
*ppv = (LPVOID) this;
|
||||
// AddRef returned interface pointer
|
||||
((LPUNKNOWN) *ppv)->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
return ResultFromScode(E_NOINTERFACE);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CClassFactory::AddRef() {
|
||||
return ++m_cRef;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CClassFactory::Release() {
|
||||
if(--m_cRef == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return m_cRef;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::CreateInstance(
|
||||
LPUNKNOWN pUnkOuter,
|
||||
REFIID riid,
|
||||
void **pv) {
|
||||
CheckPointer(pv,E_POINTER)
|
||||
ValidateReadWritePtr(pv,sizeof(void *));
|
||||
|
||||
/* Enforce the normal OLE rules regarding interfaces and delegation */
|
||||
|
||||
if(pUnkOuter != NULL) {
|
||||
if(IsEqualIID(riid,IID_IUnknown) == FALSE) {
|
||||
return ResultFromScode(E_NOINTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the new object through the derived class's create function */
|
||||
|
||||
HRESULT hr = NOERROR;
|
||||
CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
|
||||
|
||||
if(pObj == NULL) {
|
||||
if(SUCCEEDED(hr)) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Delete the object if we got a construction error */
|
||||
|
||||
if(FAILED(hr)) {
|
||||
delete pObj;
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Get a reference counted interface on the object */
|
||||
|
||||
/* We wrap the non-delegating QI with NDAddRef & NDRelease. */
|
||||
/* This protects any outer object from being prematurely */
|
||||
/* released by an inner object that may have to be created */
|
||||
/* in order to supply the requested interface. */
|
||||
pObj->NonDelegatingAddRef();
|
||||
hr = pObj->NonDelegatingQueryInterface(riid, pv);
|
||||
pObj->NonDelegatingRelease();
|
||||
|
||||
/* Note that if NonDelegatingQueryInterface fails, it will */
|
||||
/* not increment the ref count, so the NonDelegatingRelease */
|
||||
/* will drop the ref back to zero and the object will "self-*/
|
||||
/* destruct". Hence we don't need additional tidy-up code */
|
||||
/* to cope with NonDelegatingQueryInterface failing. */
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
ASSERT(*pv);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::LockServer(BOOL fLock) {
|
||||
if(fLock) {
|
||||
m_cLocked++;
|
||||
}
|
||||
else {
|
||||
m_cLocked--;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// --- COM entrypoints -----------------------------------------
|
||||
|
||||
//called by COM to get the class factory object for a given class
|
||||
STDAPI
|
||||
DllGetClassObject(
|
||||
REFCLSID rClsID,
|
||||
REFIID riid,
|
||||
void **pv) {
|
||||
if(!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
// traverse the array of templates looking for one with this
|
||||
// class id
|
||||
for(int i = 0; i < g_cTemplates; i++) {
|
||||
const CFactoryTemplate * pT = &g_Templates[i];
|
||||
if(pT->IsClassID(rClsID)) {
|
||||
|
||||
// found a template - make a class factory based on this
|
||||
// template
|
||||
|
||||
*pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
|
||||
if(*pv == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
((LPUNKNOWN)*pv)->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
//
|
||||
// Call any initialization routines
|
||||
//
|
||||
void
|
||||
DllInitClasses(BOOL bLoading) {
|
||||
int i;
|
||||
|
||||
// traverse the array of templates calling the init routine
|
||||
// if they have one
|
||||
for(i = 0; i < g_cTemplates; i++) {
|
||||
const CFactoryTemplate * pT = &g_Templates[i];
|
||||
if(pT->m_lpfnInit != NULL) {
|
||||
(*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// called by COM to determine if this dll can be unloaded
|
||||
// return ok unless there are outstanding objects or a lock requested
|
||||
// by IClassFactory::LockServer
|
||||
//
|
||||
// CClassFactory has a static function that can tell us about the locks,
|
||||
// and CCOMObject has a static function that can tell us about the active
|
||||
// object count
|
||||
STDAPI
|
||||
DllCanUnloadNow() {
|
||||
DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"),
|
||||
CClassFactory::IsLocked(),
|
||||
CBaseObject::ObjectsActive()));
|
||||
|
||||
if(CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) {
|
||||
return S_FALSE;
|
||||
}
|
||||
else {
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- standard WIN32 entrypoints --------------------------------------
|
||||
|
||||
|
||||
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
|
||||
|
||||
BOOL WINAPI
|
||||
DllEntryPoint(HINSTANCE hInstance, ULONG ulReason, LPVOID pv) {
|
||||
#ifdef DEBUG
|
||||
extern bool g_fDbgInDllEntryPoint;
|
||||
g_fDbgInDllEntryPoint = true;
|
||||
#endif
|
||||
|
||||
switch(ulReason) {
|
||||
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
#ifdef DEBUG
|
||||
DbgInitialise(hInstance);
|
||||
#endif
|
||||
|
||||
{
|
||||
// The platform identifier is used to work out whether
|
||||
// full unicode support is available or not. Hence the
|
||||
// default will be the lowest common denominator - i.e. N/A
|
||||
g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails
|
||||
|
||||
g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);
|
||||
if(GetVersionEx(&g_osInfo)) {
|
||||
g_amPlatform = g_osInfo.dwPlatformId;
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95")));
|
||||
}
|
||||
}
|
||||
|
||||
g_hInst = hInstance;
|
||||
DllInitClasses(TRUE);
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
DllInitClasses(FALSE);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(CBaseObject::ObjectsActive()) {
|
||||
DbgSetModuleLevel(LOG_MEMORY, 2);
|
||||
TCHAR szInfo[512];
|
||||
extern TCHAR m_ModuleName[]; // Cut down module name
|
||||
|
||||
TCHAR FullName[_MAX_PATH]; // Load the full path and module name
|
||||
TCHAR *pName; // Searches from the end for a backslash
|
||||
|
||||
GetModuleFileName(NULL,FullName,_MAX_PATH);
|
||||
pName = _tcsrchr(FullName,'\\');
|
||||
if(pName == NULL) {
|
||||
pName = FullName;
|
||||
}
|
||||
else {
|
||||
pName++;
|
||||
}
|
||||
|
||||
DWORD cch = wsprintf(szInfo, TEXT("Executable: %s Pid %x Tid %x. "),
|
||||
pName, GetCurrentProcessId(), GetCurrentThreadId());
|
||||
|
||||
wsprintf(szInfo+cch, TEXT("Module %s, %d objects left active!"),
|
||||
m_ModuleName, CBaseObject::ObjectsActive());
|
||||
DbgAssert(szInfo, TEXT(__FILE__),__LINE__);
|
||||
|
||||
// If running remotely wait for the Assert to be acknowledged
|
||||
// before dumping out the object register
|
||||
DbgDumpObjectRegister();
|
||||
}
|
||||
|
||||
DbgTerminate();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
g_fDbgInDllEntryPoint = false;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DllEntry.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements classes used to support dll
|
||||
// entry points for COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <initguid.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef UNICODE
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif // _UNICODE
|
||||
#endif // UNICODE
|
||||
|
||||
#include <tchar.h>
|
||||
#endif // DEBUG
|
||||
|
||||
extern CFactoryTemplate g_Templates[];
|
||||
extern int g_cTemplates;
|
||||
|
||||
HINSTANCE g_hInst;
|
||||
DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
|
||||
OSVERSIONINFO g_osInfo;
|
||||
|
||||
//
|
||||
// an instance of this is created by the DLLGetClassObject entrypoint
|
||||
// it uses the CFactoryTemplate object it is given to support the
|
||||
// IClassFactory interface
|
||||
|
||||
class CClassFactory : public IClassFactory, public CBaseObject {
|
||||
|
||||
private:
|
||||
const CFactoryTemplate *const m_pTemplate;
|
||||
|
||||
ULONG m_cRef;
|
||||
|
||||
static int m_cLocked;
|
||||
public:
|
||||
CClassFactory(const CFactoryTemplate *);
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
|
||||
STDMETHODIMP_(ULONG)AddRef();
|
||||
STDMETHODIMP_(ULONG)Release();
|
||||
|
||||
// IClassFactory
|
||||
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv);
|
||||
STDMETHODIMP LockServer(BOOL fLock);
|
||||
|
||||
// allow DLLGetClassObject to know about global server lock status
|
||||
static BOOL IsLocked() {
|
||||
return (m_cLocked > 0);
|
||||
};
|
||||
};
|
||||
|
||||
// process-wide dll locked state
|
||||
int CClassFactory::m_cLocked = 0;
|
||||
|
||||
CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
|
||||
: CBaseObject(NAME("Class Factory"))
|
||||
, m_cRef(0)
|
||||
, m_pTemplate(pTemplate) {
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::QueryInterface(REFIID riid,void **ppv) {
|
||||
CheckPointer(ppv,E_POINTER)
|
||||
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
||||
*ppv = NULL;
|
||||
|
||||
// any interface on this object is the object pointer.
|
||||
if((riid == IID_IUnknown) || (riid == IID_IClassFactory)) {
|
||||
*ppv = (LPVOID) this;
|
||||
// AddRef returned interface pointer
|
||||
((LPUNKNOWN) *ppv)->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
return ResultFromScode(E_NOINTERFACE);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CClassFactory::AddRef() {
|
||||
return ++m_cRef;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CClassFactory::Release() {
|
||||
if(--m_cRef == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return m_cRef;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::CreateInstance(
|
||||
LPUNKNOWN pUnkOuter,
|
||||
REFIID riid,
|
||||
void **pv) {
|
||||
CheckPointer(pv,E_POINTER)
|
||||
ValidateReadWritePtr(pv,sizeof(void *));
|
||||
|
||||
/* Enforce the normal OLE rules regarding interfaces and delegation */
|
||||
|
||||
if(pUnkOuter != NULL) {
|
||||
if(IsEqualIID(riid,IID_IUnknown) == FALSE) {
|
||||
return ResultFromScode(E_NOINTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the new object through the derived class's create function */
|
||||
|
||||
HRESULT hr = NOERROR;
|
||||
CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
|
||||
|
||||
if(pObj == NULL) {
|
||||
if(SUCCEEDED(hr)) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Delete the object if we got a construction error */
|
||||
|
||||
if(FAILED(hr)) {
|
||||
delete pObj;
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Get a reference counted interface on the object */
|
||||
|
||||
/* We wrap the non-delegating QI with NDAddRef & NDRelease. */
|
||||
/* This protects any outer object from being prematurely */
|
||||
/* released by an inner object that may have to be created */
|
||||
/* in order to supply the requested interface. */
|
||||
pObj->NonDelegatingAddRef();
|
||||
hr = pObj->NonDelegatingQueryInterface(riid, pv);
|
||||
pObj->NonDelegatingRelease();
|
||||
|
||||
/* Note that if NonDelegatingQueryInterface fails, it will */
|
||||
/* not increment the ref count, so the NonDelegatingRelease */
|
||||
/* will drop the ref back to zero and the object will "self-*/
|
||||
/* destruct". Hence we don't need additional tidy-up code */
|
||||
/* to cope with NonDelegatingQueryInterface failing. */
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
ASSERT(*pv);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::LockServer(BOOL fLock) {
|
||||
if(fLock) {
|
||||
m_cLocked++;
|
||||
}
|
||||
else {
|
||||
m_cLocked--;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// --- COM entrypoints -----------------------------------------
|
||||
|
||||
//called by COM to get the class factory object for a given class
|
||||
STDAPI
|
||||
DllGetClassObject(
|
||||
REFCLSID rClsID,
|
||||
REFIID riid,
|
||||
void **pv) {
|
||||
if(!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
// traverse the array of templates looking for one with this
|
||||
// class id
|
||||
for(int i = 0; i < g_cTemplates; i++) {
|
||||
const CFactoryTemplate * pT = &g_Templates[i];
|
||||
if(pT->IsClassID(rClsID)) {
|
||||
|
||||
// found a template - make a class factory based on this
|
||||
// template
|
||||
|
||||
*pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
|
||||
if(*pv == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
((LPUNKNOWN)*pv)->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
//
|
||||
// Call any initialization routines
|
||||
//
|
||||
void
|
||||
DllInitClasses(BOOL bLoading) {
|
||||
int i;
|
||||
|
||||
// traverse the array of templates calling the init routine
|
||||
// if they have one
|
||||
for(i = 0; i < g_cTemplates; i++) {
|
||||
const CFactoryTemplate * pT = &g_Templates[i];
|
||||
if(pT->m_lpfnInit != NULL) {
|
||||
(*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// called by COM to determine if this dll can be unloaded
|
||||
// return ok unless there are outstanding objects or a lock requested
|
||||
// by IClassFactory::LockServer
|
||||
//
|
||||
// CClassFactory has a static function that can tell us about the locks,
|
||||
// and CCOMObject has a static function that can tell us about the active
|
||||
// object count
|
||||
STDAPI
|
||||
DllCanUnloadNow() {
|
||||
DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"),
|
||||
CClassFactory::IsLocked(),
|
||||
CBaseObject::ObjectsActive()));
|
||||
|
||||
if(CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) {
|
||||
return S_FALSE;
|
||||
}
|
||||
else {
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- standard WIN32 entrypoints --------------------------------------
|
||||
|
||||
|
||||
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
|
||||
|
||||
BOOL WINAPI
|
||||
DllEntryPoint(HINSTANCE hInstance, ULONG ulReason, LPVOID pv) {
|
||||
#ifdef DEBUG
|
||||
extern bool g_fDbgInDllEntryPoint;
|
||||
g_fDbgInDllEntryPoint = true;
|
||||
#endif
|
||||
|
||||
switch(ulReason) {
|
||||
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
#ifdef DEBUG
|
||||
DbgInitialise(hInstance);
|
||||
#endif
|
||||
|
||||
{
|
||||
// The platform identifier is used to work out whether
|
||||
// full unicode support is available or not. Hence the
|
||||
// default will be the lowest common denominator - i.e. N/A
|
||||
g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails
|
||||
|
||||
g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);
|
||||
if(GetVersionEx(&g_osInfo)) {
|
||||
g_amPlatform = g_osInfo.dwPlatformId;
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95")));
|
||||
}
|
||||
}
|
||||
|
||||
g_hInst = hInstance;
|
||||
DllInitClasses(TRUE);
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
DllInitClasses(FALSE);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(CBaseObject::ObjectsActive()) {
|
||||
DbgSetModuleLevel(LOG_MEMORY, 2);
|
||||
TCHAR szInfo[512];
|
||||
extern TCHAR m_ModuleName[]; // Cut down module name
|
||||
|
||||
TCHAR FullName[_MAX_PATH]; // Load the full path and module name
|
||||
TCHAR *pName; // Searches from the end for a backslash
|
||||
|
||||
GetModuleFileName(NULL,FullName,_MAX_PATH);
|
||||
pName = _tcsrchr(FullName,'\\');
|
||||
if(pName == NULL) {
|
||||
pName = FullName;
|
||||
}
|
||||
else {
|
||||
pName++;
|
||||
}
|
||||
|
||||
DWORD cch = wsprintf(szInfo, TEXT("Executable: %s Pid %x Tid %x. "),
|
||||
pName, GetCurrentProcessId(), GetCurrentThreadId());
|
||||
|
||||
wsprintf(szInfo+cch, TEXT("Module %s, %d objects left active!"),
|
||||
m_ModuleName, CBaseObject::ObjectsActive());
|
||||
DbgAssert(szInfo, TEXT(__FILE__),__LINE__);
|
||||
|
||||
// If running remotely wait for the Assert to be acknowledged
|
||||
// before dumping out the object register
|
||||
DbgDumpObjectRegister();
|
||||
}
|
||||
|
||||
DbgTerminate();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
g_fDbgInDllEntryPoint = false;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+651
-651
File diff suppressed because it is too large
Load Diff
+46
-46
@@ -1,46 +1,46 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DllSetup.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// To be self registering, OLE servers must
|
||||
// export functions named DllRegisterServer
|
||||
// and DllUnregisterServer. To allow use of
|
||||
// custom and default implementations the
|
||||
// defaults are named AMovieDllRegisterServer
|
||||
// and AMovieDllUnregisterServer.
|
||||
//
|
||||
// To the use the default implementation you
|
||||
// must provide stub functions.
|
||||
//
|
||||
// i.e. STDAPI DllRegisterServer()
|
||||
// {
|
||||
// return AMovieDllRegisterServer();
|
||||
// }
|
||||
//
|
||||
// STDAPI DllUnregisterServer()
|
||||
// {
|
||||
// return AMovieDllUnregisterServer();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// AMovieDllRegisterServer calls IAMovieSetup.Register(), and
|
||||
// AMovieDllUnregisterServer calls IAMovieSetup.Unregister().
|
||||
|
||||
STDAPI AMovieDllRegisterServer2( BOOL );
|
||||
STDAPI AMovieDllRegisterServer();
|
||||
STDAPI AMovieDllUnregisterServer();
|
||||
|
||||
// helper functions
|
||||
STDAPI EliminateSubKey( HKEY, LPTSTR );
|
||||
|
||||
|
||||
STDAPI
|
||||
AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata
|
||||
, IFilterMapper2 * pIFM2
|
||||
, BOOL bRegister );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DllSetup.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// To be self registering, OLE servers must
|
||||
// export functions named DllRegisterServer
|
||||
// and DllUnregisterServer. To allow use of
|
||||
// custom and default implementations the
|
||||
// defaults are named AMovieDllRegisterServer
|
||||
// and AMovieDllUnregisterServer.
|
||||
//
|
||||
// To the use the default implementation you
|
||||
// must provide stub functions.
|
||||
//
|
||||
// i.e. STDAPI DllRegisterServer()
|
||||
// {
|
||||
// return AMovieDllRegisterServer();
|
||||
// }
|
||||
//
|
||||
// STDAPI DllUnregisterServer()
|
||||
// {
|
||||
// return AMovieDllUnregisterServer();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// AMovieDllRegisterServer calls IAMovieSetup.Register(), and
|
||||
// AMovieDllUnregisterServer calls IAMovieSetup.Unregister().
|
||||
|
||||
STDAPI AMovieDllRegisterServer2( BOOL );
|
||||
STDAPI AMovieDllRegisterServer();
|
||||
STDAPI AMovieDllUnregisterServer();
|
||||
|
||||
// helper functions
|
||||
STDAPI EliminateSubKey( HKEY, LPTSTR );
|
||||
|
||||
|
||||
STDAPI
|
||||
AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata
|
||||
, IFilterMapper2 * pIFM2
|
||||
, BOOL bRegister );
|
||||
|
||||
|
||||
+132
-132
@@ -1,132 +1,132 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DSSchedule.h (replaces DX8's schedule.h)
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __CAMSchedule__
|
||||
#define __CAMSchedule__
|
||||
|
||||
class CAMSchedule : private CBaseObject
|
||||
{
|
||||
public:
|
||||
virtual ~CAMSchedule();
|
||||
// ev is the event we should fire if the advise time needs re-evaluating
|
||||
CAMSchedule( HANDLE ev );
|
||||
|
||||
DWORD GetAdviseCount();
|
||||
REFERENCE_TIME GetNextAdviseTime();
|
||||
|
||||
// We need a method for derived classes to add advise packets, we return the cookie
|
||||
DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic );
|
||||
// And a way to cancel
|
||||
HRESULT Unadvise(DWORD_PTR dwAdviseCookie);
|
||||
|
||||
// Tell us the time please, and we'll dispatch the expired events. We return the time of the next event.
|
||||
// NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of
|
||||
// whoever is using this helper class (typically a clock).
|
||||
REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime );
|
||||
|
||||
// Get the event handle which will be set if advise time requires re-evaluation.
|
||||
HANDLE GetEvent() const { return m_ev; }
|
||||
|
||||
private:
|
||||
// We define the nodes that will be used in our singly linked list
|
||||
// of advise packets. The list is ordered by time, with the
|
||||
// elements that will expire first at the front.
|
||||
class CAdvisePacket
|
||||
{
|
||||
public:
|
||||
CAdvisePacket()
|
||||
{}
|
||||
|
||||
CAdvisePacket * m_next;
|
||||
DWORD_PTR m_dwAdviseCookie;
|
||||
REFERENCE_TIME m_rtEventTime; // Time at which event should be set
|
||||
REFERENCE_TIME m_rtPeriod; // Periodic time
|
||||
HANDLE m_hNotify; // Handle to event or semephore
|
||||
BOOL m_bPeriodic; // TRUE => Periodic event
|
||||
|
||||
CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time)
|
||||
{}
|
||||
|
||||
void InsertAfter( CAdvisePacket * p )
|
||||
{
|
||||
p->m_next = m_next;
|
||||
m_next = p;
|
||||
}
|
||||
|
||||
int IsZ() const // That is, is it the node that represents the end of the list
|
||||
{
|
||||
return m_next == 0;
|
||||
}
|
||||
|
||||
CAdvisePacket * RemoveNext()
|
||||
{
|
||||
CAdvisePacket *const next = m_next;
|
||||
CAdvisePacket *const new_next = next->m_next;
|
||||
m_next = new_next;
|
||||
return next;
|
||||
}
|
||||
|
||||
void DeleteNext()
|
||||
{
|
||||
delete RemoveNext();
|
||||
}
|
||||
|
||||
CAdvisePacket * Next() const
|
||||
{
|
||||
CAdvisePacket * result = m_next;
|
||||
if (result->IsZ()) result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD_PTR Cookie() const
|
||||
{
|
||||
return m_dwAdviseCookie;
|
||||
}
|
||||
};
|
||||
|
||||
// Structure is:
|
||||
// head -> elmt1 -> elmt2 -> z -> null
|
||||
// So an empty list is: head -> z -> null
|
||||
// Having head & z as links makes insertaion,
|
||||
// deletion and shunting much easier.
|
||||
CAdvisePacket head, z; // z is both a tail and a sentry
|
||||
|
||||
volatile DWORD_PTR m_dwNextCookie; // Strictly increasing
|
||||
volatile DWORD m_dwAdviseCount; // Number of elements on list
|
||||
|
||||
CCritSec m_Serialize;
|
||||
|
||||
// AddAdvisePacket: adds the packet, returns the cookie (0 if failed)
|
||||
DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket );
|
||||
// Event that we should set if the packed added above will be the next to fire.
|
||||
const HANDLE m_ev;
|
||||
|
||||
// A Shunt is where we have changed the first element in the
|
||||
// list and want it re-evaluating (i.e. repositioned) in
|
||||
// the list.
|
||||
void ShuntHead();
|
||||
|
||||
// Rather than delete advise packets, we cache them for future use
|
||||
CAdvisePacket * m_pAdviseCache;
|
||||
DWORD m_dwCacheCount;
|
||||
enum { dwCacheMax = 5 }; // Don't bother caching more than five
|
||||
|
||||
void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link
|
||||
|
||||
// Attributes and methods for debugging
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
void DumpLinkedList();
|
||||
#else
|
||||
void DumpLinkedList() {}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // __CAMSchedule__
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DSSchedule.h (replaces DX8's schedule.h)
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __CAMSchedule__
|
||||
#define __CAMSchedule__
|
||||
|
||||
class CAMSchedule : private CBaseObject
|
||||
{
|
||||
public:
|
||||
virtual ~CAMSchedule();
|
||||
// ev is the event we should fire if the advise time needs re-evaluating
|
||||
CAMSchedule( HANDLE ev );
|
||||
|
||||
DWORD GetAdviseCount();
|
||||
REFERENCE_TIME GetNextAdviseTime();
|
||||
|
||||
// We need a method for derived classes to add advise packets, we return the cookie
|
||||
DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic );
|
||||
// And a way to cancel
|
||||
HRESULT Unadvise(DWORD_PTR dwAdviseCookie);
|
||||
|
||||
// Tell us the time please, and we'll dispatch the expired events. We return the time of the next event.
|
||||
// NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of
|
||||
// whoever is using this helper class (typically a clock).
|
||||
REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime );
|
||||
|
||||
// Get the event handle which will be set if advise time requires re-evaluation.
|
||||
HANDLE GetEvent() const { return m_ev; }
|
||||
|
||||
private:
|
||||
// We define the nodes that will be used in our singly linked list
|
||||
// of advise packets. The list is ordered by time, with the
|
||||
// elements that will expire first at the front.
|
||||
class CAdvisePacket
|
||||
{
|
||||
public:
|
||||
CAdvisePacket()
|
||||
{}
|
||||
|
||||
CAdvisePacket * m_next;
|
||||
DWORD_PTR m_dwAdviseCookie;
|
||||
REFERENCE_TIME m_rtEventTime; // Time at which event should be set
|
||||
REFERENCE_TIME m_rtPeriod; // Periodic time
|
||||
HANDLE m_hNotify; // Handle to event or semephore
|
||||
BOOL m_bPeriodic; // TRUE => Periodic event
|
||||
|
||||
CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time)
|
||||
{}
|
||||
|
||||
void InsertAfter( CAdvisePacket * p )
|
||||
{
|
||||
p->m_next = m_next;
|
||||
m_next = p;
|
||||
}
|
||||
|
||||
int IsZ() const // That is, is it the node that represents the end of the list
|
||||
{
|
||||
return m_next == 0;
|
||||
}
|
||||
|
||||
CAdvisePacket * RemoveNext()
|
||||
{
|
||||
CAdvisePacket *const next = m_next;
|
||||
CAdvisePacket *const new_next = next->m_next;
|
||||
m_next = new_next;
|
||||
return next;
|
||||
}
|
||||
|
||||
void DeleteNext()
|
||||
{
|
||||
delete RemoveNext();
|
||||
}
|
||||
|
||||
CAdvisePacket * Next() const
|
||||
{
|
||||
CAdvisePacket * result = m_next;
|
||||
if (result->IsZ()) result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD_PTR Cookie() const
|
||||
{
|
||||
return m_dwAdviseCookie;
|
||||
}
|
||||
};
|
||||
|
||||
// Structure is:
|
||||
// head -> elmt1 -> elmt2 -> z -> null
|
||||
// So an empty list is: head -> z -> null
|
||||
// Having head & z as links makes insertaion,
|
||||
// deletion and shunting much easier.
|
||||
CAdvisePacket head, z; // z is both a tail and a sentry
|
||||
|
||||
volatile DWORD_PTR m_dwNextCookie; // Strictly increasing
|
||||
volatile DWORD m_dwAdviseCount; // Number of elements on list
|
||||
|
||||
CCritSec m_Serialize;
|
||||
|
||||
// AddAdvisePacket: adds the packet, returns the cookie (0 if failed)
|
||||
DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket );
|
||||
// Event that we should set if the packed added above will be the next to fire.
|
||||
const HANDLE m_ev;
|
||||
|
||||
// A Shunt is where we have changed the first element in the
|
||||
// list and want it re-evaluating (i.e. repositioned) in
|
||||
// the list.
|
||||
void ShuntHead();
|
||||
|
||||
// Rather than delete advise packets, we cache them for future use
|
||||
CAdvisePacket * m_pAdviseCache;
|
||||
DWORD m_dwCacheCount;
|
||||
enum { dwCacheMax = 5 }; // Don't bother caching more than five
|
||||
|
||||
void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link
|
||||
|
||||
// Attributes and methods for debugging
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
void DumpLinkedList();
|
||||
#else
|
||||
void DumpLinkedList() {}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // __CAMSchedule__
|
||||
|
||||
+100
-100
@@ -1,100 +1,100 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: FourCC.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// FOURCCMap
|
||||
//
|
||||
// provides a mapping between old-style multimedia format DWORDs
|
||||
// and new-style GUIDs.
|
||||
//
|
||||
// A range of 4 billion GUIDs has been allocated to ensure that this
|
||||
// mapping can be done straightforwardly one-to-one in both directions.
|
||||
//
|
||||
// January 95
|
||||
|
||||
|
||||
#ifndef __FOURCC__
|
||||
#define __FOURCC__
|
||||
|
||||
|
||||
// Multimedia format types are marked with DWORDs built from four 8-bit
|
||||
// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include
|
||||
// a subtype GUID. In order to simplify the mapping, GUIDs in the range:
|
||||
// XXXXXXXX-0000-0010-8000-00AA00389B71
|
||||
// are reserved for FOURCCs.
|
||||
|
||||
class FOURCCMap : public GUID
|
||||
{
|
||||
|
||||
public:
|
||||
FOURCCMap();
|
||||
FOURCCMap(DWORD Fourcc);
|
||||
FOURCCMap(const GUID *);
|
||||
|
||||
DWORD GetFOURCC(void);
|
||||
void SetFOURCC(DWORD fourcc);
|
||||
void SetFOURCC(const GUID *);
|
||||
|
||||
private:
|
||||
void InitGUID();
|
||||
};
|
||||
|
||||
#define GUID_Data2 0
|
||||
#define GUID_Data3 0x10
|
||||
#define GUID_Data4_1 0xaa000080
|
||||
#define GUID_Data4_2 0x719b3800
|
||||
|
||||
inline void
|
||||
FOURCCMap::InitGUID() {
|
||||
Data2 = GUID_Data2;
|
||||
Data3 = GUID_Data3;
|
||||
((DWORD *)Data4)[0] = GUID_Data4_1;
|
||||
((DWORD *)Data4)[1] = GUID_Data4_2;
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap() {
|
||||
InitGUID();
|
||||
SetFOURCC( DWORD(0));
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap(DWORD fourcc)
|
||||
{
|
||||
InitGUID();
|
||||
SetFOURCC(fourcc);
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap(const GUID * pGuid)
|
||||
{
|
||||
InitGUID();
|
||||
SetFOURCC(pGuid);
|
||||
}
|
||||
|
||||
inline void
|
||||
FOURCCMap::SetFOURCC(const GUID * pGuid)
|
||||
{
|
||||
FOURCCMap * p = (FOURCCMap*) pGuid;
|
||||
SetFOURCC(p->GetFOURCC());
|
||||
}
|
||||
|
||||
inline void
|
||||
FOURCCMap::SetFOURCC(DWORD fourcc)
|
||||
{
|
||||
Data1 = fourcc;
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
FOURCCMap::GetFOURCC(void)
|
||||
{
|
||||
return Data1;
|
||||
}
|
||||
|
||||
#endif /* __FOURCC__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: FourCC.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// FOURCCMap
|
||||
//
|
||||
// provides a mapping between old-style multimedia format DWORDs
|
||||
// and new-style GUIDs.
|
||||
//
|
||||
// A range of 4 billion GUIDs has been allocated to ensure that this
|
||||
// mapping can be done straightforwardly one-to-one in both directions.
|
||||
//
|
||||
// January 95
|
||||
|
||||
|
||||
#ifndef __FOURCC__
|
||||
#define __FOURCC__
|
||||
|
||||
|
||||
// Multimedia format types are marked with DWORDs built from four 8-bit
|
||||
// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include
|
||||
// a subtype GUID. In order to simplify the mapping, GUIDs in the range:
|
||||
// XXXXXXXX-0000-0010-8000-00AA00389B71
|
||||
// are reserved for FOURCCs.
|
||||
|
||||
class FOURCCMap : public GUID
|
||||
{
|
||||
|
||||
public:
|
||||
FOURCCMap();
|
||||
FOURCCMap(DWORD Fourcc);
|
||||
FOURCCMap(const GUID *);
|
||||
|
||||
DWORD GetFOURCC(void);
|
||||
void SetFOURCC(DWORD fourcc);
|
||||
void SetFOURCC(const GUID *);
|
||||
|
||||
private:
|
||||
void InitGUID();
|
||||
};
|
||||
|
||||
#define GUID_Data2 0
|
||||
#define GUID_Data3 0x10
|
||||
#define GUID_Data4_1 0xaa000080
|
||||
#define GUID_Data4_2 0x719b3800
|
||||
|
||||
inline void
|
||||
FOURCCMap::InitGUID() {
|
||||
Data2 = GUID_Data2;
|
||||
Data3 = GUID_Data3;
|
||||
((DWORD *)Data4)[0] = GUID_Data4_1;
|
||||
((DWORD *)Data4)[1] = GUID_Data4_2;
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap() {
|
||||
InitGUID();
|
||||
SetFOURCC( DWORD(0));
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap(DWORD fourcc)
|
||||
{
|
||||
InitGUID();
|
||||
SetFOURCC(fourcc);
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap(const GUID * pGuid)
|
||||
{
|
||||
InitGUID();
|
||||
SetFOURCC(pGuid);
|
||||
}
|
||||
|
||||
inline void
|
||||
FOURCCMap::SetFOURCC(const GUID * pGuid)
|
||||
{
|
||||
FOURCCMap * p = (FOURCCMap*) pGuid;
|
||||
SetFOURCC(p->GetFOURCC());
|
||||
}
|
||||
|
||||
inline void
|
||||
FOURCCMap::SetFOURCC(DWORD fourcc)
|
||||
{
|
||||
Data1 = fourcc;
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
FOURCCMap::GetFOURCC(void)
|
||||
{
|
||||
return Data1;
|
||||
}
|
||||
|
||||
#endif /* __FOURCC__ */
|
||||
|
||||
|
||||
+222
-222
@@ -1,222 +1,222 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Measure.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
The idea is to pepper the source code with interesting measurements and
|
||||
have the last few thousand of these recorded in a circular buffer that
|
||||
can be post-processed to give interesting numbers.
|
||||
|
||||
WHAT THE LOG LOOKS LIKE:
|
||||
|
||||
Time (sec) Type Delta Incident_Name
|
||||
0.055,41 NOTE -. Incident Nine - Another note
|
||||
0.055,42 NOTE 0.000,01 Incident Nine - Another note
|
||||
0.055,44 NOTE 0.000,02 Incident Nine - Another note
|
||||
0.055,45 STOP -. Incident Eight - Also random
|
||||
0.055,47 START -. Incident Seven - Random
|
||||
0.055,49 NOTE 0.000,05 Incident Nine - Another note
|
||||
------- <etc. there is a lot of this> ----------------
|
||||
0.125,60 STOP 0.000,03 Msr_Stop
|
||||
0.125,62 START -. Msr_Start
|
||||
0.125,63 START -. Incident Two - Start/Stop
|
||||
0.125,65 STOP 0.000,03 Msr_Start
|
||||
0.125,66 START -. Msr_Stop
|
||||
0.125,68 STOP 0.000,05 Incident Two - Start/Stop
|
||||
0.125,70 STOP 0.000,04 Msr_Stop
|
||||
0.125,72 START -. Msr_Start
|
||||
0.125,73 START -. Incident Two - Start/Stop
|
||||
0.125,75 STOP 0.000,03 Msr_Start
|
||||
0.125,77 START -. Msr_Stop
|
||||
0.125,78 STOP 0.000,05 Incident Two - Start/Stop
|
||||
0.125,80 STOP 0.000,03 Msr_Stop
|
||||
0.125,81 NOTE -. Incident Three - single Note
|
||||
0.125,83 START -. Incident Four - Start, no stop
|
||||
0.125,85 START -. Incident Five - Single Start/Stop
|
||||
0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop
|
||||
|
||||
Number Average StdDev Smallest Largest Incident_Name
|
||||
10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note
|
||||
50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop
|
||||
1 -. -. -. -. Incident Three - single Note
|
||||
0 -. -. -. -. Incident Four - Start, no stop
|
||||
1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop
|
||||
0 -. -. -. -. Incident Six - zero occurrences
|
||||
100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random
|
||||
100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random
|
||||
5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note
|
||||
10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note
|
||||
50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start
|
||||
50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop
|
||||
|
||||
WHAT IT MEANS:
|
||||
The log shows what happened and when. Each line shows the time at which
|
||||
something happened (see WHAT YOU CODE below) what it was that happened
|
||||
and (if approporate) the time since the corresponding previous event
|
||||
(that's the delta column).
|
||||
|
||||
The statistics show how many times each event occurred, what the average
|
||||
delta time was, also the standard deviation, largest and smalles delta.
|
||||
|
||||
WHAT YOU CODE:
|
||||
|
||||
Before anything else executes: - register your ids
|
||||
|
||||
int id1 = Msr_Register("Incident One - Note");
|
||||
int id2 = Msr_Register("Incident Two - Start/Stop");
|
||||
int id3 = Msr_Register("Incident Three - single Note");
|
||||
etc.
|
||||
|
||||
At interesting moments:
|
||||
|
||||
// To measure a repetitive event - e.g. end of bitblt to screen
|
||||
Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!"
|
||||
|
||||
or
|
||||
|
||||
// To measure an elapsed time e.g. time taken to decode an MPEG B-frame
|
||||
Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame"
|
||||
. . .
|
||||
MsrStop(Id2); // "Finished MPEG decode"
|
||||
|
||||
At the end:
|
||||
|
||||
HANDLE hFile;
|
||||
hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
Msr_Dump(hFile); // This writes the log out to the file
|
||||
CloseHandle(hFile);
|
||||
|
||||
or
|
||||
|
||||
Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... ));
|
||||
// but if you are writing it out to the debugger
|
||||
// then the times are probably all garbage because
|
||||
// the debugger can make things run awfully slow.
|
||||
|
||||
A given id should be used either for start / stop or Note calls. If Notes
|
||||
are mixed in with Starts and Stops their statistics will be gibberish.
|
||||
|
||||
If you code the calls in upper case i.e. MSR_START(idMunge); then you get
|
||||
macros which will turn into nothing unless PERF is defined.
|
||||
|
||||
You can reset the statistical counts for a given id by calling Reset(Id).
|
||||
They are reset by default at the start.
|
||||
It logs Reset as a special incident, so you can see it in the log.
|
||||
|
||||
The log is a circular buffer in storage (to try to minimise disk I/O).
|
||||
It overwrites the oldest entries once full. The statistics include ALL
|
||||
incidents since the last Reset, whether still visible in the log or not.
|
||||
*/
|
||||
|
||||
#ifndef __MEASURE__
|
||||
#define __MEASURE__
|
||||
|
||||
#ifdef PERF
|
||||
#define MSR_INIT() Msr_Init()
|
||||
#define MSR_TERMINATE() Msr_Terminate()
|
||||
#define MSR_REGISTER(a) Msr_Register(a)
|
||||
#define MSR_RESET(a) Msr_Reset(a)
|
||||
#define MSR_CONTROL(a) Msr_Control(a)
|
||||
#define MSR_START(a) Msr_Start(a)
|
||||
#define MSR_STOP(a) Msr_Stop(a)
|
||||
#define MSR_NOTE(a) Msr_Note(a)
|
||||
#define MSR_INTEGER(a,b) Msr_Integer(a,b)
|
||||
#define MSR_DUMP(a) Msr_Dump(a)
|
||||
#define MSR_DUMPSTATS(a) Msr_DumpStats(a)
|
||||
#else
|
||||
#define MSR_INIT() ((void)0)
|
||||
#define MSR_TERMINATE() ((void)0)
|
||||
#define MSR_REGISTER(a) 0
|
||||
#define MSR_RESET(a) ((void)0)
|
||||
#define MSR_CONTROL(a) ((void)0)
|
||||
#define MSR_START(a) ((void)0)
|
||||
#define MSR_STOP(a) ((void)0)
|
||||
#define MSR_NOTE(a) ((void)0)
|
||||
#define MSR_INTEGER(a,b) ((void)0)
|
||||
#define MSR_DUMP(a) ((void)0)
|
||||
#define MSR_DUMPSTATS(a) ((void)0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This must be called first - (called by the DllEntry)
|
||||
|
||||
void WINAPI Msr_Init(void);
|
||||
|
||||
|
||||
// Call this last to clean up (or just let it fall off the end - who cares?)
|
||||
|
||||
void WINAPI Msr_Terminate(void);
|
||||
|
||||
|
||||
// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note
|
||||
// everything that's logged is called an "incident".
|
||||
|
||||
int WINAPI Msr_Register(LPTSTR Incident);
|
||||
|
||||
|
||||
// Reset the statistical counts for an incident
|
||||
|
||||
void WINAPI Msr_Reset(int Id);
|
||||
|
||||
|
||||
// Reset all the counts for all incidents
|
||||
#define MSR_RESET_ALL 0
|
||||
#define MSR_PAUSE 1
|
||||
#define MSR_RUN 2
|
||||
|
||||
void WINAPI Msr_Control(int iAction);
|
||||
|
||||
|
||||
// log the start of an operation
|
||||
|
||||
void WINAPI Msr_Start(int Id);
|
||||
|
||||
|
||||
// log the end of an operation
|
||||
|
||||
void WINAPI Msr_Stop(int Id);
|
||||
|
||||
|
||||
// log a one-off or repetitive operation
|
||||
|
||||
void WINAPI Msr_Note(int Id);
|
||||
|
||||
|
||||
// log an integer (on which we can see statistics later)
|
||||
void WINAPI Msr_Integer(int Id, int n);
|
||||
|
||||
|
||||
// print out all the vaialable log (it may have wrapped) and then the statistics.
|
||||
// When the log wraps you lose log but the statistics are still complete.
|
||||
// hFIle==NULL => use DbgLog
|
||||
// otherwise hFile must have come from CreateFile or OpenFile.
|
||||
|
||||
void WINAPI Msr_Dump(HANDLE hFile);
|
||||
|
||||
|
||||
// just dump the statistics - never mind the log
|
||||
|
||||
void WINAPI Msr_DumpStats(HANDLE hFile);
|
||||
|
||||
// Type definitions in case you want to declare a pointer to the dump functions
|
||||
// (makes it a trifle easier to do dynamic linking
|
||||
// i.e. LoadModule, GetProcAddress and call that)
|
||||
|
||||
// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever
|
||||
typedef void WINAPI MSR_DUMPPROC(HANDLE hFile);
|
||||
typedef void WINAPI MSR_CONTROLPROC(int iAction);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __MEASURE__
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Measure.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
The idea is to pepper the source code with interesting measurements and
|
||||
have the last few thousand of these recorded in a circular buffer that
|
||||
can be post-processed to give interesting numbers.
|
||||
|
||||
WHAT THE LOG LOOKS LIKE:
|
||||
|
||||
Time (sec) Type Delta Incident_Name
|
||||
0.055,41 NOTE -. Incident Nine - Another note
|
||||
0.055,42 NOTE 0.000,01 Incident Nine - Another note
|
||||
0.055,44 NOTE 0.000,02 Incident Nine - Another note
|
||||
0.055,45 STOP -. Incident Eight - Also random
|
||||
0.055,47 START -. Incident Seven - Random
|
||||
0.055,49 NOTE 0.000,05 Incident Nine - Another note
|
||||
------- <etc. there is a lot of this> ----------------
|
||||
0.125,60 STOP 0.000,03 Msr_Stop
|
||||
0.125,62 START -. Msr_Start
|
||||
0.125,63 START -. Incident Two - Start/Stop
|
||||
0.125,65 STOP 0.000,03 Msr_Start
|
||||
0.125,66 START -. Msr_Stop
|
||||
0.125,68 STOP 0.000,05 Incident Two - Start/Stop
|
||||
0.125,70 STOP 0.000,04 Msr_Stop
|
||||
0.125,72 START -. Msr_Start
|
||||
0.125,73 START -. Incident Two - Start/Stop
|
||||
0.125,75 STOP 0.000,03 Msr_Start
|
||||
0.125,77 START -. Msr_Stop
|
||||
0.125,78 STOP 0.000,05 Incident Two - Start/Stop
|
||||
0.125,80 STOP 0.000,03 Msr_Stop
|
||||
0.125,81 NOTE -. Incident Three - single Note
|
||||
0.125,83 START -. Incident Four - Start, no stop
|
||||
0.125,85 START -. Incident Five - Single Start/Stop
|
||||
0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop
|
||||
|
||||
Number Average StdDev Smallest Largest Incident_Name
|
||||
10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note
|
||||
50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop
|
||||
1 -. -. -. -. Incident Three - single Note
|
||||
0 -. -. -. -. Incident Four - Start, no stop
|
||||
1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop
|
||||
0 -. -. -. -. Incident Six - zero occurrences
|
||||
100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random
|
||||
100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random
|
||||
5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note
|
||||
10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note
|
||||
50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start
|
||||
50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop
|
||||
|
||||
WHAT IT MEANS:
|
||||
The log shows what happened and when. Each line shows the time at which
|
||||
something happened (see WHAT YOU CODE below) what it was that happened
|
||||
and (if approporate) the time since the corresponding previous event
|
||||
(that's the delta column).
|
||||
|
||||
The statistics show how many times each event occurred, what the average
|
||||
delta time was, also the standard deviation, largest and smalles delta.
|
||||
|
||||
WHAT YOU CODE:
|
||||
|
||||
Before anything else executes: - register your ids
|
||||
|
||||
int id1 = Msr_Register("Incident One - Note");
|
||||
int id2 = Msr_Register("Incident Two - Start/Stop");
|
||||
int id3 = Msr_Register("Incident Three - single Note");
|
||||
etc.
|
||||
|
||||
At interesting moments:
|
||||
|
||||
// To measure a repetitive event - e.g. end of bitblt to screen
|
||||
Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!"
|
||||
|
||||
or
|
||||
|
||||
// To measure an elapsed time e.g. time taken to decode an MPEG B-frame
|
||||
Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame"
|
||||
. . .
|
||||
MsrStop(Id2); // "Finished MPEG decode"
|
||||
|
||||
At the end:
|
||||
|
||||
HANDLE hFile;
|
||||
hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
Msr_Dump(hFile); // This writes the log out to the file
|
||||
CloseHandle(hFile);
|
||||
|
||||
or
|
||||
|
||||
Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... ));
|
||||
// but if you are writing it out to the debugger
|
||||
// then the times are probably all garbage because
|
||||
// the debugger can make things run awfully slow.
|
||||
|
||||
A given id should be used either for start / stop or Note calls. If Notes
|
||||
are mixed in with Starts and Stops their statistics will be gibberish.
|
||||
|
||||
If you code the calls in upper case i.e. MSR_START(idMunge); then you get
|
||||
macros which will turn into nothing unless PERF is defined.
|
||||
|
||||
You can reset the statistical counts for a given id by calling Reset(Id).
|
||||
They are reset by default at the start.
|
||||
It logs Reset as a special incident, so you can see it in the log.
|
||||
|
||||
The log is a circular buffer in storage (to try to minimise disk I/O).
|
||||
It overwrites the oldest entries once full. The statistics include ALL
|
||||
incidents since the last Reset, whether still visible in the log or not.
|
||||
*/
|
||||
|
||||
#ifndef __MEASURE__
|
||||
#define __MEASURE__
|
||||
|
||||
#ifdef PERF
|
||||
#define MSR_INIT() Msr_Init()
|
||||
#define MSR_TERMINATE() Msr_Terminate()
|
||||
#define MSR_REGISTER(a) Msr_Register(a)
|
||||
#define MSR_RESET(a) Msr_Reset(a)
|
||||
#define MSR_CONTROL(a) Msr_Control(a)
|
||||
#define MSR_START(a) Msr_Start(a)
|
||||
#define MSR_STOP(a) Msr_Stop(a)
|
||||
#define MSR_NOTE(a) Msr_Note(a)
|
||||
#define MSR_INTEGER(a,b) Msr_Integer(a,b)
|
||||
#define MSR_DUMP(a) Msr_Dump(a)
|
||||
#define MSR_DUMPSTATS(a) Msr_DumpStats(a)
|
||||
#else
|
||||
#define MSR_INIT() ((void)0)
|
||||
#define MSR_TERMINATE() ((void)0)
|
||||
#define MSR_REGISTER(a) 0
|
||||
#define MSR_RESET(a) ((void)0)
|
||||
#define MSR_CONTROL(a) ((void)0)
|
||||
#define MSR_START(a) ((void)0)
|
||||
#define MSR_STOP(a) ((void)0)
|
||||
#define MSR_NOTE(a) ((void)0)
|
||||
#define MSR_INTEGER(a,b) ((void)0)
|
||||
#define MSR_DUMP(a) ((void)0)
|
||||
#define MSR_DUMPSTATS(a) ((void)0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This must be called first - (called by the DllEntry)
|
||||
|
||||
void WINAPI Msr_Init(void);
|
||||
|
||||
|
||||
// Call this last to clean up (or just let it fall off the end - who cares?)
|
||||
|
||||
void WINAPI Msr_Terminate(void);
|
||||
|
||||
|
||||
// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note
|
||||
// everything that's logged is called an "incident".
|
||||
|
||||
int WINAPI Msr_Register(LPTSTR Incident);
|
||||
|
||||
|
||||
// Reset the statistical counts for an incident
|
||||
|
||||
void WINAPI Msr_Reset(int Id);
|
||||
|
||||
|
||||
// Reset all the counts for all incidents
|
||||
#define MSR_RESET_ALL 0
|
||||
#define MSR_PAUSE 1
|
||||
#define MSR_RUN 2
|
||||
|
||||
void WINAPI Msr_Control(int iAction);
|
||||
|
||||
|
||||
// log the start of an operation
|
||||
|
||||
void WINAPI Msr_Start(int Id);
|
||||
|
||||
|
||||
// log the end of an operation
|
||||
|
||||
void WINAPI Msr_Stop(int Id);
|
||||
|
||||
|
||||
// log a one-off or repetitive operation
|
||||
|
||||
void WINAPI Msr_Note(int Id);
|
||||
|
||||
|
||||
// log an integer (on which we can see statistics later)
|
||||
void WINAPI Msr_Integer(int Id, int n);
|
||||
|
||||
|
||||
// print out all the vaialable log (it may have wrapped) and then the statistics.
|
||||
// When the log wraps you lose log but the statistics are still complete.
|
||||
// hFIle==NULL => use DbgLog
|
||||
// otherwise hFile must have come from CreateFile or OpenFile.
|
||||
|
||||
void WINAPI Msr_Dump(HANDLE hFile);
|
||||
|
||||
|
||||
// just dump the statistics - never mind the log
|
||||
|
||||
void WINAPI Msr_DumpStats(HANDLE hFile);
|
||||
|
||||
// Type definitions in case you want to declare a pointer to the dump functions
|
||||
// (makes it a trifle easier to do dynamic linking
|
||||
// i.e. LoadModule, GetProcAddress and call that)
|
||||
|
||||
// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever
|
||||
typedef void WINAPI MSR_DUMPPROC(HANDLE hFile);
|
||||
typedef void WINAPI MSR_CONTROLPROC(int iAction);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __MEASURE__
|
||||
|
||||
+120
-120
@@ -1,120 +1,120 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MsgThrd.h
|
||||
//
|
||||
// Desc: DirectShow base classes - provides support for a worker thread
|
||||
// class to which one can asynchronously post messages.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Message class - really just a structure.
|
||||
//
|
||||
class CMsg {
|
||||
public:
|
||||
UINT uMsg;
|
||||
DWORD dwFlags;
|
||||
LPVOID lpParam;
|
||||
CAMEvent *pEvent;
|
||||
|
||||
CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt)
|
||||
: uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {}
|
||||
|
||||
CMsg()
|
||||
: uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {}
|
||||
};
|
||||
|
||||
// This is the actual thread class. It exports all the usual thread control
|
||||
// functions. The created thread is different from a normal WIN32 thread in
|
||||
// that it is prompted to perform particaular tasks by responding to messages
|
||||
// posted to its message queue.
|
||||
//
|
||||
class AM_NOVTABLE CMsgThread {
|
||||
private:
|
||||
static DWORD WINAPI DefaultThreadProc(LPVOID lpParam);
|
||||
DWORD m_ThreadId;
|
||||
HANDLE m_hThread;
|
||||
|
||||
protected:
|
||||
|
||||
// if you want to override GetThreadMsg to block on other things
|
||||
// as well as this queue, you need access to this
|
||||
CGenericList<CMsg> m_ThreadQueue;
|
||||
CCritSec m_Lock;
|
||||
HANDLE m_hSem;
|
||||
LONG m_lWaiting;
|
||||
|
||||
public:
|
||||
CMsgThread()
|
||||
: m_ThreadId(0),
|
||||
m_hThread(NULL),
|
||||
m_lWaiting(0),
|
||||
m_hSem(NULL),
|
||||
// make a list with a cache of 5 items
|
||||
m_ThreadQueue(NAME("MsgThread list"), 5)
|
||||
{
|
||||
}
|
||||
|
||||
~CMsgThread();
|
||||
// override this if you want to block on other things as well
|
||||
// as the message loop
|
||||
void virtual GetThreadMsg(CMsg *msg);
|
||||
|
||||
// override this if you want to do something on thread startup
|
||||
virtual void OnThreadInit() { };
|
||||
|
||||
BOOL CreateThread();
|
||||
|
||||
BOOL WaitForThreadExit(LPDWORD lpdwExitCode) {
|
||||
if (m_hThread != NULL) {
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
return GetExitCodeThread(m_hThread, lpdwExitCode);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD ResumeThread() {
|
||||
return ::ResumeThread(m_hThread);
|
||||
}
|
||||
|
||||
DWORD SuspendThread() {
|
||||
return ::SuspendThread(m_hThread);
|
||||
}
|
||||
|
||||
int GetThreadPriority() {
|
||||
return ::GetThreadPriority(m_hThread);
|
||||
}
|
||||
|
||||
BOOL SetThreadPriority(int nPriority) {
|
||||
return ::SetThreadPriority(m_hThread, nPriority);
|
||||
}
|
||||
|
||||
HANDLE GetThreadHandle() {
|
||||
return m_hThread;
|
||||
}
|
||||
|
||||
DWORD GetThreadId() {
|
||||
return m_ThreadId;
|
||||
}
|
||||
|
||||
|
||||
void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags,
|
||||
LPVOID lpMsgParam, CAMEvent *pEvent = NULL) {
|
||||
CAutoLock lck(&m_Lock);
|
||||
CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent);
|
||||
m_ThreadQueue.AddTail(pMsg);
|
||||
|
||||
if (m_lWaiting != 0) {
|
||||
ReleaseSemaphore(m_hSem, m_lWaiting, 0);
|
||||
m_lWaiting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This is the function prototype of the function that the client
|
||||
// supplies. It is always called on the created thread, never on
|
||||
// the creator thread.
|
||||
//
|
||||
virtual LRESULT ThreadMessageProc(
|
||||
UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MsgThrd.h
|
||||
//
|
||||
// Desc: DirectShow base classes - provides support for a worker thread
|
||||
// class to which one can asynchronously post messages.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Message class - really just a structure.
|
||||
//
|
||||
class CMsg {
|
||||
public:
|
||||
UINT uMsg;
|
||||
DWORD dwFlags;
|
||||
LPVOID lpParam;
|
||||
CAMEvent *pEvent;
|
||||
|
||||
CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt)
|
||||
: uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {}
|
||||
|
||||
CMsg()
|
||||
: uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {}
|
||||
};
|
||||
|
||||
// This is the actual thread class. It exports all the usual thread control
|
||||
// functions. The created thread is different from a normal WIN32 thread in
|
||||
// that it is prompted to perform particaular tasks by responding to messages
|
||||
// posted to its message queue.
|
||||
//
|
||||
class AM_NOVTABLE CMsgThread {
|
||||
private:
|
||||
static DWORD WINAPI DefaultThreadProc(LPVOID lpParam);
|
||||
DWORD m_ThreadId;
|
||||
HANDLE m_hThread;
|
||||
|
||||
protected:
|
||||
|
||||
// if you want to override GetThreadMsg to block on other things
|
||||
// as well as this queue, you need access to this
|
||||
CGenericList<CMsg> m_ThreadQueue;
|
||||
CCritSec m_Lock;
|
||||
HANDLE m_hSem;
|
||||
LONG m_lWaiting;
|
||||
|
||||
public:
|
||||
CMsgThread()
|
||||
: m_ThreadId(0),
|
||||
m_hThread(NULL),
|
||||
m_lWaiting(0),
|
||||
m_hSem(NULL),
|
||||
// make a list with a cache of 5 items
|
||||
m_ThreadQueue(NAME("MsgThread list"), 5)
|
||||
{
|
||||
}
|
||||
|
||||
~CMsgThread();
|
||||
// override this if you want to block on other things as well
|
||||
// as the message loop
|
||||
void virtual GetThreadMsg(CMsg *msg);
|
||||
|
||||
// override this if you want to do something on thread startup
|
||||
virtual void OnThreadInit() { };
|
||||
|
||||
BOOL CreateThread();
|
||||
|
||||
BOOL WaitForThreadExit(LPDWORD lpdwExitCode) {
|
||||
if (m_hThread != NULL) {
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
return GetExitCodeThread(m_hThread, lpdwExitCode);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD ResumeThread() {
|
||||
return ::ResumeThread(m_hThread);
|
||||
}
|
||||
|
||||
DWORD SuspendThread() {
|
||||
return ::SuspendThread(m_hThread);
|
||||
}
|
||||
|
||||
int GetThreadPriority() {
|
||||
return ::GetThreadPriority(m_hThread);
|
||||
}
|
||||
|
||||
BOOL SetThreadPriority(int nPriority) {
|
||||
return ::SetThreadPriority(m_hThread, nPriority);
|
||||
}
|
||||
|
||||
HANDLE GetThreadHandle() {
|
||||
return m_hThread;
|
||||
}
|
||||
|
||||
DWORD GetThreadId() {
|
||||
return m_ThreadId;
|
||||
}
|
||||
|
||||
|
||||
void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags,
|
||||
LPVOID lpMsgParam, CAMEvent *pEvent = NULL) {
|
||||
CAutoLock lck(&m_Lock);
|
||||
CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent);
|
||||
m_ThreadQueue.AddTail(pMsg);
|
||||
|
||||
if (m_lWaiting != 0) {
|
||||
ReleaseSemaphore(m_hSem, m_lWaiting, 0);
|
||||
m_lWaiting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This is the function prototype of the function that the client
|
||||
// supplies. It is always called on the created thread, never on
|
||||
// the creator thread.
|
||||
//
|
||||
virtual LRESULT ThreadMessageProc(
|
||||
UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0;
|
||||
};
|
||||
|
||||
|
||||
+478
-478
@@ -1,478 +1,478 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MType.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements a class that holds and
|
||||
// manages media type information.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// helper class that derived pin objects can use to compare media
|
||||
// types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
||||
// in the streams IDL file, but also has (non-virtual) functions
|
||||
|
||||
#include <streams.h>
|
||||
#include <mmreg.h>
|
||||
|
||||
CMediaType::~CMediaType(){
|
||||
FreeMediaType(*this);
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType()
|
||||
{
|
||||
InitMediaType();
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType(const GUID * type)
|
||||
{
|
||||
InitMediaType();
|
||||
majortype = *type;
|
||||
}
|
||||
|
||||
|
||||
// copy constructor does a deep copy of the format block
|
||||
|
||||
CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, HRESULT* phr)
|
||||
{
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr) && (NULL != phr)) {
|
||||
*phr = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType(const CMediaType& rt, HRESULT* phr)
|
||||
{
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr) && (NULL != phr)) {
|
||||
*phr = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate
|
||||
// the following assignment operator itself, however it could introduce some
|
||||
// memory conflicts and leaks in the process because the structure contains
|
||||
// a dynamically allocated block (pbFormat) which it will not copy correctly
|
||||
|
||||
CMediaType&
|
||||
CMediaType::operator=(const AM_MEDIA_TYPE& rt)
|
||||
{
|
||||
Set(rt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CMediaType&
|
||||
CMediaType::operator=(const CMediaType& rt)
|
||||
{
|
||||
*this = (AM_MEDIA_TYPE &) rt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::operator == (const CMediaType& rt) const
|
||||
{
|
||||
// I don't believe we need to check sample size or
|
||||
// temporal compression flags, since I think these must
|
||||
// be represented in the type, subtype and format somehow. They
|
||||
// are pulled out as separate flags so that people who don't understand
|
||||
// the particular format representation can still see them, but
|
||||
// they should duplicate information in the format block.
|
||||
|
||||
return ((IsEqualGUID(majortype,rt.majortype) == TRUE) &&
|
||||
(IsEqualGUID(subtype,rt.subtype) == TRUE) &&
|
||||
(IsEqualGUID(formattype,rt.formattype) == TRUE) &&
|
||||
(cbFormat == rt.cbFormat) &&
|
||||
( (cbFormat == 0) ||
|
||||
(memcmp(pbFormat, rt.pbFormat, cbFormat) == 0)));
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMediaType::operator != (const CMediaType& rt) const
|
||||
{
|
||||
/* Check to see if they are equal */
|
||||
|
||||
if (*this == rt) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CMediaType::Set(const CMediaType& rt)
|
||||
{
|
||||
return Set((AM_MEDIA_TYPE &) rt);
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CMediaType::Set(const AM_MEDIA_TYPE& rt)
|
||||
{
|
||||
if (&rt != this) {
|
||||
FreeMediaType(*this);
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr)) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMediaType::IsValid() const
|
||||
{
|
||||
return (!IsEqualGUID(majortype,GUID_NULL));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetType(const GUID* ptype)
|
||||
{
|
||||
majortype = *ptype;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetSubtype(const GUID* ptype)
|
||||
{
|
||||
subtype = *ptype;
|
||||
}
|
||||
|
||||
|
||||
ULONG
|
||||
CMediaType::GetSampleSize() const {
|
||||
if (IsFixedSize()) {
|
||||
return lSampleSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetSampleSize(ULONG sz) {
|
||||
if (sz == 0) {
|
||||
SetVariableSize();
|
||||
} else {
|
||||
bFixedSizeSamples = TRUE;
|
||||
lSampleSize = sz;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetVariableSize() {
|
||||
bFixedSizeSamples = FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetTemporalCompression(BOOL bCompressed) {
|
||||
bTemporalCompression = bCompressed;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::SetFormat(BYTE * pformat, ULONG cb)
|
||||
{
|
||||
if (NULL == AllocFormatBuffer(cb))
|
||||
return(FALSE);
|
||||
|
||||
ASSERT(pbFormat);
|
||||
memcpy(pbFormat, pformat, cb);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// set the type of the media type format block, this type defines what you
|
||||
// will actually find in the format pointer. For example FORMAT_VideoInfo or
|
||||
// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a
|
||||
// property set. Before sending out media types this should be filled in.
|
||||
|
||||
void
|
||||
CMediaType::SetFormatType(const GUID *pformattype)
|
||||
{
|
||||
formattype = *pformattype;
|
||||
}
|
||||
|
||||
|
||||
// reset the format buffer
|
||||
|
||||
void CMediaType::ResetFormatBuffer()
|
||||
{
|
||||
if (cbFormat) {
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
cbFormat = 0;
|
||||
pbFormat = NULL;
|
||||
}
|
||||
|
||||
|
||||
// allocate length bytes for the format and return a read/write pointer
|
||||
// If we cannot allocate the new block of memory we return NULL leaving
|
||||
// the original block of memory untouched (as does ReallocFormatBuffer)
|
||||
|
||||
BYTE*
|
||||
CMediaType::AllocFormatBuffer(ULONG length)
|
||||
{
|
||||
ASSERT(length);
|
||||
|
||||
// do the types have the same buffer size
|
||||
|
||||
if (cbFormat == length) {
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
// allocate the new format buffer
|
||||
|
||||
BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
||||
if (pNewFormat == NULL) {
|
||||
if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// delete the old format
|
||||
|
||||
if (cbFormat != 0) {
|
||||
ASSERT(pbFormat);
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
|
||||
cbFormat = length;
|
||||
pbFormat = pNewFormat;
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
|
||||
// reallocate length bytes for the format and return a read/write pointer
|
||||
// to it. We keep as much information as we can given the new buffer size
|
||||
// if this fails the original format buffer is left untouched. The caller
|
||||
// is responsible for ensuring the size of memory required is non zero
|
||||
|
||||
BYTE*
|
||||
CMediaType::ReallocFormatBuffer(ULONG length)
|
||||
{
|
||||
ASSERT(length);
|
||||
|
||||
// do the types have the same buffer size
|
||||
|
||||
if (cbFormat == length) {
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
// allocate the new format buffer
|
||||
|
||||
BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
||||
if (pNewFormat == NULL) {
|
||||
if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// copy any previous format (or part of if new is smaller)
|
||||
// delete the old format and replace with the new one
|
||||
|
||||
if (cbFormat != 0) {
|
||||
ASSERT(pbFormat);
|
||||
memcpy(pNewFormat,pbFormat,min(length,cbFormat));
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
|
||||
cbFormat = length;
|
||||
pbFormat = pNewFormat;
|
||||
return pNewFormat;
|
||||
}
|
||||
|
||||
// initialise a media type structure
|
||||
|
||||
void CMediaType::InitMediaType()
|
||||
{
|
||||
ZeroMemory((PVOID)this, sizeof(*this));
|
||||
lSampleSize = 1;
|
||||
bFixedSizeSamples = TRUE;
|
||||
}
|
||||
|
||||
|
||||
// a partially specified media type can be passed to IPin::Connect
|
||||
// as a constraint on the media type used in the connection.
|
||||
// the type, subtype or format type can be null.
|
||||
BOOL
|
||||
CMediaType::IsPartiallySpecified(void) const
|
||||
{
|
||||
if ((majortype == GUID_NULL) ||
|
||||
(formattype == GUID_NULL)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::MatchesPartial(const CMediaType* ppartial) const
|
||||
{
|
||||
if ((ppartial->majortype != GUID_NULL) &&
|
||||
(majortype != ppartial->majortype)) {
|
||||
return FALSE;
|
||||
}
|
||||
if ((ppartial->subtype != GUID_NULL) &&
|
||||
(subtype != ppartial->subtype)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ppartial->formattype != GUID_NULL) {
|
||||
// if the format block is specified then it must match exactly
|
||||
if (formattype != ppartial->formattype) {
|
||||
return FALSE;
|
||||
}
|
||||
if (cbFormat != ppartial->cbFormat) {
|
||||
return FALSE;
|
||||
}
|
||||
if ((cbFormat != 0) &&
|
||||
(memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure
|
||||
// which is useful when calling IEnumMediaTypes::Next as the interface
|
||||
// implementation allocates the structures which you must later delete
|
||||
// the format block may also be a pointer to an interface to release
|
||||
|
||||
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt)
|
||||
{
|
||||
// allow NULL pointers for coding simplicity
|
||||
|
||||
if (pmt == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreeMediaType(*pmt);
|
||||
CoTaskMemFree((PVOID)pmt);
|
||||
}
|
||||
|
||||
|
||||
// this also comes in useful when using the IEnumMediaTypes interface so
|
||||
// that you can copy a media type, you can do nearly the same by creating
|
||||
// a CMediaType object but as soon as it goes out of scope the destructor
|
||||
// will delete the memory it allocated (this takes a copy of the memory)
|
||||
|
||||
AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc)
|
||||
{
|
||||
ASSERT(pSrc);
|
||||
|
||||
// Allocate a block of memory for the media type
|
||||
|
||||
AM_MEDIA_TYPE *pMediaType =
|
||||
(AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
|
||||
|
||||
if (pMediaType == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Copy the variable length format block
|
||||
|
||||
HRESULT hr = CopyMediaType(pMediaType,pSrc);
|
||||
if (FAILED(hr)) {
|
||||
CoTaskMemFree((PVOID)pMediaType);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pMediaType;
|
||||
}
|
||||
|
||||
|
||||
// Copy 1 media type to another
|
||||
|
||||
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource)
|
||||
{
|
||||
// We'll leak if we copy onto one that already exists - there's one
|
||||
// case we can check like that - copying to itself.
|
||||
ASSERT(pmtSource != pmtTarget);
|
||||
*pmtTarget = *pmtSource;
|
||||
if (pmtSource->cbFormat != 0) {
|
||||
ASSERT(pmtSource->pbFormat != NULL);
|
||||
pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat);
|
||||
if (pmtTarget->pbFormat == NULL) {
|
||||
pmtTarget->cbFormat = 0;
|
||||
return E_OUTOFMEMORY;
|
||||
} else {
|
||||
CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
|
||||
pmtTarget->cbFormat);
|
||||
}
|
||||
}
|
||||
if (pmtTarget->pUnk != NULL) {
|
||||
pmtTarget->pUnk->AddRef();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Free an existing media type (ie free resources it holds)
|
||||
|
||||
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt)
|
||||
{
|
||||
if (mt.cbFormat != 0) {
|
||||
CoTaskMemFree((PVOID)mt.pbFormat);
|
||||
|
||||
// Strictly unnecessary but tidier
|
||||
mt.cbFormat = 0;
|
||||
mt.pbFormat = NULL;
|
||||
}
|
||||
if (mt.pUnk != NULL) {
|
||||
mt.pUnk->Release();
|
||||
mt.pUnk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a media type from a WAVEFORMATEX
|
||||
|
||||
STDAPI CreateAudioMediaType(
|
||||
const WAVEFORMATEX *pwfx,
|
||||
AM_MEDIA_TYPE *pmt,
|
||||
BOOL bSetFormat
|
||||
)
|
||||
{
|
||||
pmt->majortype = MEDIATYPE_Audio;
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat;
|
||||
} else {
|
||||
pmt->subtype = FOURCCMap(pwfx->wFormatTag);
|
||||
}
|
||||
|
||||
pmt->formattype = FORMAT_WaveFormatEx;
|
||||
pmt->bFixedSizeSamples = TRUE;
|
||||
pmt->bTemporalCompression = FALSE;
|
||||
pmt->lSampleSize = pwfx->nBlockAlign;
|
||||
pmt->pUnk = NULL;
|
||||
if (bSetFormat) {
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
pmt->cbFormat = sizeof(WAVEFORMATEX);
|
||||
} else {
|
||||
pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize;
|
||||
}
|
||||
pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat);
|
||||
if (pmt->pbFormat == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT));
|
||||
((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0;
|
||||
} else {
|
||||
CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat);
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// eliminate very many spurious warnings from MS compiler
|
||||
#pragma warning(disable:4514)
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MType.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements a class that holds and
|
||||
// manages media type information.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// helper class that derived pin objects can use to compare media
|
||||
// types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
||||
// in the streams IDL file, but also has (non-virtual) functions
|
||||
|
||||
#include <streams.h>
|
||||
#include <mmreg.h>
|
||||
|
||||
CMediaType::~CMediaType(){
|
||||
FreeMediaType(*this);
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType()
|
||||
{
|
||||
InitMediaType();
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType(const GUID * type)
|
||||
{
|
||||
InitMediaType();
|
||||
majortype = *type;
|
||||
}
|
||||
|
||||
|
||||
// copy constructor does a deep copy of the format block
|
||||
|
||||
CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, HRESULT* phr)
|
||||
{
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr) && (NULL != phr)) {
|
||||
*phr = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType(const CMediaType& rt, HRESULT* phr)
|
||||
{
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr) && (NULL != phr)) {
|
||||
*phr = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate
|
||||
// the following assignment operator itself, however it could introduce some
|
||||
// memory conflicts and leaks in the process because the structure contains
|
||||
// a dynamically allocated block (pbFormat) which it will not copy correctly
|
||||
|
||||
CMediaType&
|
||||
CMediaType::operator=(const AM_MEDIA_TYPE& rt)
|
||||
{
|
||||
Set(rt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CMediaType&
|
||||
CMediaType::operator=(const CMediaType& rt)
|
||||
{
|
||||
*this = (AM_MEDIA_TYPE &) rt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::operator == (const CMediaType& rt) const
|
||||
{
|
||||
// I don't believe we need to check sample size or
|
||||
// temporal compression flags, since I think these must
|
||||
// be represented in the type, subtype and format somehow. They
|
||||
// are pulled out as separate flags so that people who don't understand
|
||||
// the particular format representation can still see them, but
|
||||
// they should duplicate information in the format block.
|
||||
|
||||
return ((IsEqualGUID(majortype,rt.majortype) == TRUE) &&
|
||||
(IsEqualGUID(subtype,rt.subtype) == TRUE) &&
|
||||
(IsEqualGUID(formattype,rt.formattype) == TRUE) &&
|
||||
(cbFormat == rt.cbFormat) &&
|
||||
( (cbFormat == 0) ||
|
||||
(memcmp(pbFormat, rt.pbFormat, cbFormat) == 0)));
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMediaType::operator != (const CMediaType& rt) const
|
||||
{
|
||||
/* Check to see if they are equal */
|
||||
|
||||
if (*this == rt) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CMediaType::Set(const CMediaType& rt)
|
||||
{
|
||||
return Set((AM_MEDIA_TYPE &) rt);
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CMediaType::Set(const AM_MEDIA_TYPE& rt)
|
||||
{
|
||||
if (&rt != this) {
|
||||
FreeMediaType(*this);
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr)) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMediaType::IsValid() const
|
||||
{
|
||||
return (!IsEqualGUID(majortype,GUID_NULL));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetType(const GUID* ptype)
|
||||
{
|
||||
majortype = *ptype;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetSubtype(const GUID* ptype)
|
||||
{
|
||||
subtype = *ptype;
|
||||
}
|
||||
|
||||
|
||||
ULONG
|
||||
CMediaType::GetSampleSize() const {
|
||||
if (IsFixedSize()) {
|
||||
return lSampleSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetSampleSize(ULONG sz) {
|
||||
if (sz == 0) {
|
||||
SetVariableSize();
|
||||
} else {
|
||||
bFixedSizeSamples = TRUE;
|
||||
lSampleSize = sz;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetVariableSize() {
|
||||
bFixedSizeSamples = FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetTemporalCompression(BOOL bCompressed) {
|
||||
bTemporalCompression = bCompressed;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::SetFormat(BYTE * pformat, ULONG cb)
|
||||
{
|
||||
if (NULL == AllocFormatBuffer(cb))
|
||||
return(FALSE);
|
||||
|
||||
ASSERT(pbFormat);
|
||||
memcpy(pbFormat, pformat, cb);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// set the type of the media type format block, this type defines what you
|
||||
// will actually find in the format pointer. For example FORMAT_VideoInfo or
|
||||
// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a
|
||||
// property set. Before sending out media types this should be filled in.
|
||||
|
||||
void
|
||||
CMediaType::SetFormatType(const GUID *pformattype)
|
||||
{
|
||||
formattype = *pformattype;
|
||||
}
|
||||
|
||||
|
||||
// reset the format buffer
|
||||
|
||||
void CMediaType::ResetFormatBuffer()
|
||||
{
|
||||
if (cbFormat) {
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
cbFormat = 0;
|
||||
pbFormat = NULL;
|
||||
}
|
||||
|
||||
|
||||
// allocate length bytes for the format and return a read/write pointer
|
||||
// If we cannot allocate the new block of memory we return NULL leaving
|
||||
// the original block of memory untouched (as does ReallocFormatBuffer)
|
||||
|
||||
BYTE*
|
||||
CMediaType::AllocFormatBuffer(ULONG length)
|
||||
{
|
||||
ASSERT(length);
|
||||
|
||||
// do the types have the same buffer size
|
||||
|
||||
if (cbFormat == length) {
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
// allocate the new format buffer
|
||||
|
||||
BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
||||
if (pNewFormat == NULL) {
|
||||
if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// delete the old format
|
||||
|
||||
if (cbFormat != 0) {
|
||||
ASSERT(pbFormat);
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
|
||||
cbFormat = length;
|
||||
pbFormat = pNewFormat;
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
|
||||
// reallocate length bytes for the format and return a read/write pointer
|
||||
// to it. We keep as much information as we can given the new buffer size
|
||||
// if this fails the original format buffer is left untouched. The caller
|
||||
// is responsible for ensuring the size of memory required is non zero
|
||||
|
||||
BYTE*
|
||||
CMediaType::ReallocFormatBuffer(ULONG length)
|
||||
{
|
||||
ASSERT(length);
|
||||
|
||||
// do the types have the same buffer size
|
||||
|
||||
if (cbFormat == length) {
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
// allocate the new format buffer
|
||||
|
||||
BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
||||
if (pNewFormat == NULL) {
|
||||
if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// copy any previous format (or part of if new is smaller)
|
||||
// delete the old format and replace with the new one
|
||||
|
||||
if (cbFormat != 0) {
|
||||
ASSERT(pbFormat);
|
||||
memcpy(pNewFormat,pbFormat,min(length,cbFormat));
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
|
||||
cbFormat = length;
|
||||
pbFormat = pNewFormat;
|
||||
return pNewFormat;
|
||||
}
|
||||
|
||||
// initialise a media type structure
|
||||
|
||||
void CMediaType::InitMediaType()
|
||||
{
|
||||
ZeroMemory((PVOID)this, sizeof(*this));
|
||||
lSampleSize = 1;
|
||||
bFixedSizeSamples = TRUE;
|
||||
}
|
||||
|
||||
|
||||
// a partially specified media type can be passed to IPin::Connect
|
||||
// as a constraint on the media type used in the connection.
|
||||
// the type, subtype or format type can be null.
|
||||
BOOL
|
||||
CMediaType::IsPartiallySpecified(void) const
|
||||
{
|
||||
if ((majortype == GUID_NULL) ||
|
||||
(formattype == GUID_NULL)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::MatchesPartial(const CMediaType* ppartial) const
|
||||
{
|
||||
if ((ppartial->majortype != GUID_NULL) &&
|
||||
(majortype != ppartial->majortype)) {
|
||||
return FALSE;
|
||||
}
|
||||
if ((ppartial->subtype != GUID_NULL) &&
|
||||
(subtype != ppartial->subtype)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ppartial->formattype != GUID_NULL) {
|
||||
// if the format block is specified then it must match exactly
|
||||
if (formattype != ppartial->formattype) {
|
||||
return FALSE;
|
||||
}
|
||||
if (cbFormat != ppartial->cbFormat) {
|
||||
return FALSE;
|
||||
}
|
||||
if ((cbFormat != 0) &&
|
||||
(memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure
|
||||
// which is useful when calling IEnumMediaTypes::Next as the interface
|
||||
// implementation allocates the structures which you must later delete
|
||||
// the format block may also be a pointer to an interface to release
|
||||
|
||||
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt)
|
||||
{
|
||||
// allow NULL pointers for coding simplicity
|
||||
|
||||
if (pmt == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreeMediaType(*pmt);
|
||||
CoTaskMemFree((PVOID)pmt);
|
||||
}
|
||||
|
||||
|
||||
// this also comes in useful when using the IEnumMediaTypes interface so
|
||||
// that you can copy a media type, you can do nearly the same by creating
|
||||
// a CMediaType object but as soon as it goes out of scope the destructor
|
||||
// will delete the memory it allocated (this takes a copy of the memory)
|
||||
|
||||
AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc)
|
||||
{
|
||||
ASSERT(pSrc);
|
||||
|
||||
// Allocate a block of memory for the media type
|
||||
|
||||
AM_MEDIA_TYPE *pMediaType =
|
||||
(AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
|
||||
|
||||
if (pMediaType == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Copy the variable length format block
|
||||
|
||||
HRESULT hr = CopyMediaType(pMediaType,pSrc);
|
||||
if (FAILED(hr)) {
|
||||
CoTaskMemFree((PVOID)pMediaType);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pMediaType;
|
||||
}
|
||||
|
||||
|
||||
// Copy 1 media type to another
|
||||
|
||||
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource)
|
||||
{
|
||||
// We'll leak if we copy onto one that already exists - there's one
|
||||
// case we can check like that - copying to itself.
|
||||
ASSERT(pmtSource != pmtTarget);
|
||||
*pmtTarget = *pmtSource;
|
||||
if (pmtSource->cbFormat != 0) {
|
||||
ASSERT(pmtSource->pbFormat != NULL);
|
||||
pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat);
|
||||
if (pmtTarget->pbFormat == NULL) {
|
||||
pmtTarget->cbFormat = 0;
|
||||
return E_OUTOFMEMORY;
|
||||
} else {
|
||||
CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
|
||||
pmtTarget->cbFormat);
|
||||
}
|
||||
}
|
||||
if (pmtTarget->pUnk != NULL) {
|
||||
pmtTarget->pUnk->AddRef();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Free an existing media type (ie free resources it holds)
|
||||
|
||||
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt)
|
||||
{
|
||||
if (mt.cbFormat != 0) {
|
||||
CoTaskMemFree((PVOID)mt.pbFormat);
|
||||
|
||||
// Strictly unnecessary but tidier
|
||||
mt.cbFormat = 0;
|
||||
mt.pbFormat = NULL;
|
||||
}
|
||||
if (mt.pUnk != NULL) {
|
||||
mt.pUnk->Release();
|
||||
mt.pUnk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a media type from a WAVEFORMATEX
|
||||
|
||||
STDAPI CreateAudioMediaType(
|
||||
const WAVEFORMATEX *pwfx,
|
||||
AM_MEDIA_TYPE *pmt,
|
||||
BOOL bSetFormat
|
||||
)
|
||||
{
|
||||
pmt->majortype = MEDIATYPE_Audio;
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat;
|
||||
} else {
|
||||
pmt->subtype = FOURCCMap(pwfx->wFormatTag);
|
||||
}
|
||||
|
||||
pmt->formattype = FORMAT_WaveFormatEx;
|
||||
pmt->bFixedSizeSamples = TRUE;
|
||||
pmt->bTemporalCompression = FALSE;
|
||||
pmt->lSampleSize = pwfx->nBlockAlign;
|
||||
pmt->pUnk = NULL;
|
||||
if (bSetFormat) {
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
pmt->cbFormat = sizeof(WAVEFORMATEX);
|
||||
} else {
|
||||
pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize;
|
||||
}
|
||||
pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat);
|
||||
if (pmt->pbFormat == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT));
|
||||
((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0;
|
||||
} else {
|
||||
CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat);
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// eliminate very many spurious warnings from MS compiler
|
||||
#pragma warning(disable:4514)
|
||||
|
||||
+89
-89
@@ -1,89 +1,89 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MtType.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class that holds and manages
|
||||
// media type information.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __MTYPE__
|
||||
#define __MTYPE__
|
||||
|
||||
/* Helper class that derived pin objects can use to compare media
|
||||
types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
||||
in the streams IDL file, but also has (non-virtual) functions */
|
||||
|
||||
class CMediaType : public _AMMediaType {
|
||||
|
||||
public:
|
||||
|
||||
~CMediaType();
|
||||
CMediaType();
|
||||
CMediaType(const GUID * majortype);
|
||||
CMediaType(const AM_MEDIA_TYPE&, HRESULT* phr = NULL);
|
||||
CMediaType(const CMediaType&, HRESULT* phr = NULL);
|
||||
|
||||
CMediaType& operator=(const CMediaType&);
|
||||
CMediaType& operator=(const AM_MEDIA_TYPE&);
|
||||
|
||||
BOOL operator == (const CMediaType&) const;
|
||||
BOOL operator != (const CMediaType&) const;
|
||||
|
||||
HRESULT Set(const CMediaType& rt);
|
||||
HRESULT Set(const AM_MEDIA_TYPE& rt);
|
||||
|
||||
BOOL IsValid() const;
|
||||
|
||||
const GUID *Type() const { return &majortype;} ;
|
||||
void SetType(const GUID *);
|
||||
const GUID *Subtype() const { return &subtype;} ;
|
||||
void SetSubtype(const GUID *);
|
||||
|
||||
BOOL IsFixedSize() const {return bFixedSizeSamples; };
|
||||
BOOL IsTemporalCompressed() const {return bTemporalCompression; };
|
||||
ULONG GetSampleSize() const;
|
||||
|
||||
void SetSampleSize(ULONG sz);
|
||||
void SetVariableSize();
|
||||
void SetTemporalCompression(BOOL bCompressed);
|
||||
|
||||
// read/write pointer to format - can't change length without
|
||||
// calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer
|
||||
|
||||
BYTE* Format() const {return pbFormat; };
|
||||
ULONG FormatLength() const { return cbFormat; };
|
||||
|
||||
void SetFormatType(const GUID *);
|
||||
const GUID *FormatType() const {return &formattype; };
|
||||
BOOL SetFormat(BYTE *pFormat, ULONG length);
|
||||
void ResetFormatBuffer();
|
||||
BYTE* AllocFormatBuffer(ULONG length);
|
||||
BYTE* ReallocFormatBuffer(ULONG length);
|
||||
|
||||
void InitMediaType();
|
||||
|
||||
BOOL MatchesPartial(const CMediaType* ppartial) const;
|
||||
BOOL IsPartiallySpecified(void) const;
|
||||
};
|
||||
|
||||
|
||||
/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE
|
||||
structure which is useful when using the IEnumMediaFormats interface as
|
||||
the implementation allocates the structures which you must later delete */
|
||||
|
||||
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt);
|
||||
AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc);
|
||||
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource);
|
||||
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt);
|
||||
|
||||
// Initialize a media type from a WAVEFORMATEX
|
||||
|
||||
STDAPI CreateAudioMediaType(
|
||||
const WAVEFORMATEX *pwfx,
|
||||
AM_MEDIA_TYPE *pmt,
|
||||
BOOL bSetFormat);
|
||||
|
||||
#endif /* __MTYPE__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MtType.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class that holds and manages
|
||||
// media type information.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __MTYPE__
|
||||
#define __MTYPE__
|
||||
|
||||
/* Helper class that derived pin objects can use to compare media
|
||||
types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
||||
in the streams IDL file, but also has (non-virtual) functions */
|
||||
|
||||
class CMediaType : public _AMMediaType {
|
||||
|
||||
public:
|
||||
|
||||
~CMediaType();
|
||||
CMediaType();
|
||||
CMediaType(const GUID * majortype);
|
||||
CMediaType(const AM_MEDIA_TYPE&, HRESULT* phr = NULL);
|
||||
CMediaType(const CMediaType&, HRESULT* phr = NULL);
|
||||
|
||||
CMediaType& operator=(const CMediaType&);
|
||||
CMediaType& operator=(const AM_MEDIA_TYPE&);
|
||||
|
||||
BOOL operator == (const CMediaType&) const;
|
||||
BOOL operator != (const CMediaType&) const;
|
||||
|
||||
HRESULT Set(const CMediaType& rt);
|
||||
HRESULT Set(const AM_MEDIA_TYPE& rt);
|
||||
|
||||
BOOL IsValid() const;
|
||||
|
||||
const GUID *Type() const { return &majortype;} ;
|
||||
void SetType(const GUID *);
|
||||
const GUID *Subtype() const { return &subtype;} ;
|
||||
void SetSubtype(const GUID *);
|
||||
|
||||
BOOL IsFixedSize() const {return bFixedSizeSamples; };
|
||||
BOOL IsTemporalCompressed() const {return bTemporalCompression; };
|
||||
ULONG GetSampleSize() const;
|
||||
|
||||
void SetSampleSize(ULONG sz);
|
||||
void SetVariableSize();
|
||||
void SetTemporalCompression(BOOL bCompressed);
|
||||
|
||||
// read/write pointer to format - can't change length without
|
||||
// calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer
|
||||
|
||||
BYTE* Format() const {return pbFormat; };
|
||||
ULONG FormatLength() const { return cbFormat; };
|
||||
|
||||
void SetFormatType(const GUID *);
|
||||
const GUID *FormatType() const {return &formattype; };
|
||||
BOOL SetFormat(BYTE *pFormat, ULONG length);
|
||||
void ResetFormatBuffer();
|
||||
BYTE* AllocFormatBuffer(ULONG length);
|
||||
BYTE* ReallocFormatBuffer(ULONG length);
|
||||
|
||||
void InitMediaType();
|
||||
|
||||
BOOL MatchesPartial(const CMediaType* ppartial) const;
|
||||
BOOL IsPartiallySpecified(void) const;
|
||||
};
|
||||
|
||||
|
||||
/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE
|
||||
structure which is useful when using the IEnumMediaFormats interface as
|
||||
the implementation allocates the structures which you must later delete */
|
||||
|
||||
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt);
|
||||
AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc);
|
||||
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource);
|
||||
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt);
|
||||
|
||||
// Initialize a media type from a WAVEFORMATEX
|
||||
|
||||
STDAPI CreateAudioMediaType(
|
||||
const WAVEFORMATEX *pwfx,
|
||||
AM_MEDIA_TYPE *pmt,
|
||||
BOOL bSetFormat);
|
||||
|
||||
#endif /* __MTYPE__ */
|
||||
|
||||
|
||||
+790
-790
File diff suppressed because it is too large
Load Diff
+137
-137
@@ -1,137 +1,137 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: OutputQ.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines the COutputQueue class, which
|
||||
// makes a queue of samples and sends them to an output pin. The
|
||||
// class will optionally send the samples to the pin directly.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef CGenericList<IMediaSample> CSampleList;
|
||||
|
||||
class COutputQueue : public CCritSec
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
COutputQueue(IPin *pInputPin, // Pin to send stuff to
|
||||
HRESULT *phr, // 'Return code'
|
||||
BOOL bAuto = TRUE, // Ask pin if blocks
|
||||
BOOL bQueue = TRUE, // Send through queue (ignored if
|
||||
// bAuto set)
|
||||
LONG lBatchSize = 1, // Batch
|
||||
BOOL bBatchExact = FALSE,// Batch exactly to BatchSize
|
||||
LONG lListSize = // Likely number in the list
|
||||
DEFAULTCACHE,
|
||||
DWORD dwPriority = // Priority of thread to create
|
||||
THREAD_PRIORITY_NORMAL,
|
||||
bool bFlushingOpt = false // flushing optimization
|
||||
);
|
||||
~COutputQueue();
|
||||
|
||||
// enter flush state - discard all data
|
||||
void BeginFlush(); // Begin flushing samples
|
||||
|
||||
// re-enable receives (pass this downstream)
|
||||
void EndFlush(); // Complete flush of samples - downstream
|
||||
// pin guaranteed not to block at this stage
|
||||
|
||||
void EOS(); // Call this on End of stream
|
||||
|
||||
void SendAnyway(); // Send batched samples anyway (if bBatchExact set)
|
||||
|
||||
void NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// do something with these media samples
|
||||
HRESULT ReceiveMultiple (
|
||||
IMediaSample **pSamples,
|
||||
long nSamples,
|
||||
long *nSamplesProcessed);
|
||||
|
||||
void Reset(); // Reset m_hr ready for more data
|
||||
|
||||
// See if its idle or not
|
||||
BOOL IsIdle();
|
||||
|
||||
// give the class an event to fire after everything removed from the queue
|
||||
void SetPopEvent(HANDLE hEvent);
|
||||
|
||||
protected:
|
||||
static DWORD WINAPI InitialThreadProc(LPVOID pv);
|
||||
DWORD ThreadProc();
|
||||
BOOL IsQueued()
|
||||
{
|
||||
return m_List != NULL;
|
||||
}
|
||||
|
||||
// The critical section MUST be held when this is called
|
||||
void QueueSample(IMediaSample *pSample);
|
||||
|
||||
BOOL IsSpecialSample(IMediaSample *pSample)
|
||||
{
|
||||
return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16);
|
||||
}
|
||||
|
||||
// Remove and Release() batched and queued samples
|
||||
void FreeSamples();
|
||||
|
||||
// Notify the thread there is something to do
|
||||
void NotifyThread();
|
||||
|
||||
|
||||
protected:
|
||||
// Queue 'messages'
|
||||
#define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch
|
||||
#define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream
|
||||
#define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr
|
||||
#define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment
|
||||
|
||||
// new segment packet is always followed by one of these
|
||||
struct NewSegmentPacket {
|
||||
REFERENCE_TIME tStart;
|
||||
REFERENCE_TIME tStop;
|
||||
double dRate;
|
||||
};
|
||||
|
||||
// Remember input stuff
|
||||
IPin * const m_pPin;
|
||||
IMemInputPin * m_pInputPin;
|
||||
BOOL const m_bBatchExact;
|
||||
LONG const m_lBatchSize;
|
||||
|
||||
CSampleList * m_List;
|
||||
HANDLE m_hSem;
|
||||
CAMEvent m_evFlushComplete;
|
||||
HANDLE m_hThread;
|
||||
IMediaSample ** m_ppSamples;
|
||||
LONG m_nBatched;
|
||||
|
||||
// Wait optimization
|
||||
LONG m_lWaiting;
|
||||
// Flush synchronization
|
||||
BOOL m_bFlushing;
|
||||
|
||||
// flushing optimization. some downstream filters have trouble
|
||||
// with the queue's flushing optimization. other rely on it
|
||||
BOOL m_bFlushed;
|
||||
bool m_bFlushingOpt;
|
||||
|
||||
// Terminate now
|
||||
BOOL m_bTerminate;
|
||||
|
||||
// Send anyway flag for batching
|
||||
BOOL m_bSendAnyway;
|
||||
|
||||
// Deferred 'return code'
|
||||
BOOL volatile m_hr;
|
||||
|
||||
// an event that can be fired after every deliver
|
||||
HANDLE m_hEventPop;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: OutputQ.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines the COutputQueue class, which
|
||||
// makes a queue of samples and sends them to an output pin. The
|
||||
// class will optionally send the samples to the pin directly.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef CGenericList<IMediaSample> CSampleList;
|
||||
|
||||
class COutputQueue : public CCritSec
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
COutputQueue(IPin *pInputPin, // Pin to send stuff to
|
||||
HRESULT *phr, // 'Return code'
|
||||
BOOL bAuto = TRUE, // Ask pin if blocks
|
||||
BOOL bQueue = TRUE, // Send through queue (ignored if
|
||||
// bAuto set)
|
||||
LONG lBatchSize = 1, // Batch
|
||||
BOOL bBatchExact = FALSE,// Batch exactly to BatchSize
|
||||
LONG lListSize = // Likely number in the list
|
||||
DEFAULTCACHE,
|
||||
DWORD dwPriority = // Priority of thread to create
|
||||
THREAD_PRIORITY_NORMAL,
|
||||
bool bFlushingOpt = false // flushing optimization
|
||||
);
|
||||
~COutputQueue();
|
||||
|
||||
// enter flush state - discard all data
|
||||
void BeginFlush(); // Begin flushing samples
|
||||
|
||||
// re-enable receives (pass this downstream)
|
||||
void EndFlush(); // Complete flush of samples - downstream
|
||||
// pin guaranteed not to block at this stage
|
||||
|
||||
void EOS(); // Call this on End of stream
|
||||
|
||||
void SendAnyway(); // Send batched samples anyway (if bBatchExact set)
|
||||
|
||||
void NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// do something with these media samples
|
||||
HRESULT ReceiveMultiple (
|
||||
IMediaSample **pSamples,
|
||||
long nSamples,
|
||||
long *nSamplesProcessed);
|
||||
|
||||
void Reset(); // Reset m_hr ready for more data
|
||||
|
||||
// See if its idle or not
|
||||
BOOL IsIdle();
|
||||
|
||||
// give the class an event to fire after everything removed from the queue
|
||||
void SetPopEvent(HANDLE hEvent);
|
||||
|
||||
protected:
|
||||
static DWORD WINAPI InitialThreadProc(LPVOID pv);
|
||||
DWORD ThreadProc();
|
||||
BOOL IsQueued()
|
||||
{
|
||||
return m_List != NULL;
|
||||
}
|
||||
|
||||
// The critical section MUST be held when this is called
|
||||
void QueueSample(IMediaSample *pSample);
|
||||
|
||||
BOOL IsSpecialSample(IMediaSample *pSample)
|
||||
{
|
||||
return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16);
|
||||
}
|
||||
|
||||
// Remove and Release() batched and queued samples
|
||||
void FreeSamples();
|
||||
|
||||
// Notify the thread there is something to do
|
||||
void NotifyThread();
|
||||
|
||||
|
||||
protected:
|
||||
// Queue 'messages'
|
||||
#define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch
|
||||
#define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream
|
||||
#define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr
|
||||
#define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment
|
||||
|
||||
// new segment packet is always followed by one of these
|
||||
struct NewSegmentPacket {
|
||||
REFERENCE_TIME tStart;
|
||||
REFERENCE_TIME tStop;
|
||||
double dRate;
|
||||
};
|
||||
|
||||
// Remember input stuff
|
||||
IPin * const m_pPin;
|
||||
IMemInputPin * m_pInputPin;
|
||||
BOOL const m_bBatchExact;
|
||||
LONG const m_lBatchSize;
|
||||
|
||||
CSampleList * m_List;
|
||||
HANDLE m_hSem;
|
||||
CAMEvent m_evFlushComplete;
|
||||
HANDLE m_hThread;
|
||||
IMediaSample ** m_ppSamples;
|
||||
LONG m_nBatched;
|
||||
|
||||
// Wait optimization
|
||||
LONG m_lWaiting;
|
||||
// Flush synchronization
|
||||
BOOL m_bFlushing;
|
||||
|
||||
// flushing optimization. some downstream filters have trouble
|
||||
// with the queue's flushing optimization. other rely on it
|
||||
BOOL m_bFlushed;
|
||||
bool m_bFlushingOpt;
|
||||
|
||||
// Terminate now
|
||||
BOOL m_bTerminate;
|
||||
|
||||
// Send anyway flag for batching
|
||||
BOOL m_bSendAnyway;
|
||||
|
||||
// Deferred 'return code'
|
||||
BOOL volatile m_hr;
|
||||
|
||||
// an event that can be fired after every deliver
|
||||
HANDLE m_hEventPop;
|
||||
};
|
||||
|
||||
|
||||
+196
-196
@@ -1,196 +1,196 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PStream.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#ifdef PERF
|
||||
#include <measure.h>
|
||||
#endif
|
||||
// #include "pstream.h" in streams.h
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
CPersistStream::CPersistStream(IUnknown *punk, HRESULT *phr)
|
||||
: mPS_fDirty(FALSE)
|
||||
{
|
||||
mPS_dwFileVersion = GetSoftwareVersion();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Destructor
|
||||
//
|
||||
CPersistStream::~CPersistStream() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
#if 0
|
||||
SAMPLE CODE TO COPY - not active at the moment
|
||||
|
||||
//
|
||||
// NonDelegatingQueryInterface
|
||||
//
|
||||
// This object supports IPersist & IPersistStream
|
||||
STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
if (riid == IID_IPersist) {
|
||||
return GetInterface((IPersist *) this, ppv); // ???
|
||||
}
|
||||
else if (riid == IID_IPersistStream) {
|
||||
return GetInterface((IPersistStream *) this, ppv);
|
||||
}
|
||||
else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// WriteToStream
|
||||
//
|
||||
// Writes to the stream (default action is to write nothing)
|
||||
HRESULT CPersistStream::WriteToStream(IStream *pStream)
|
||||
{
|
||||
// You can override this to do things like
|
||||
// hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL);
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CPersistStream::ReadFromStream(IStream * pStream)
|
||||
{
|
||||
// You can override this to do things like
|
||||
// hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL);
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Load
|
||||
//
|
||||
// Load all the data from the given stream
|
||||
STDMETHODIMP CPersistStream::Load(LPSTREAM pStm)
|
||||
{
|
||||
HRESULT hr;
|
||||
// Load the version number then the data
|
||||
mPS_dwFileVersion = ReadInt(pStm, hr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ReadFromStream(pStm);
|
||||
} // Load
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Save
|
||||
//
|
||||
// Save the contents of this Stream.
|
||||
STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty)
|
||||
{
|
||||
|
||||
HRESULT hr = WriteInt(pStm, GetSoftwareVersion());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = WriteToStream(pStm);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
mPS_fDirty = !fClearDirty;
|
||||
|
||||
return hr;
|
||||
} // Save
|
||||
|
||||
|
||||
// WriteInt
|
||||
//
|
||||
// Writes an integer to an IStream as 11 UNICODE characters followed by one space.
|
||||
// You could use this for shorts or unsigneds or anything (up to 32 bits)
|
||||
// where the value isn't actually truncated by squeezing it into 32 bits.
|
||||
// Values such as (unsigned) 0x80000000 would come out as -2147483648
|
||||
// but would then load as 0x80000000 through ReadInt. Cast as you please.
|
||||
|
||||
STDAPI WriteInt(IStream *pIStream, int n)
|
||||
{
|
||||
WCHAR Buff[13]; // Allows for trailing null that we don't write
|
||||
wsprintfW(Buff, L"%011d ",n);
|
||||
return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL);
|
||||
} // WriteInt
|
||||
|
||||
|
||||
// ReadInt
|
||||
//
|
||||
// Reads an integer from an IStream.
|
||||
// Read as 4 bytes. You could use this for shorts or unsigneds or anything
|
||||
// where the value isn't actually truncated by squeezing it into 32 bits
|
||||
// Striped down subset of what sscanf can do (without dragging in the C runtime)
|
||||
|
||||
STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr)
|
||||
{
|
||||
|
||||
int Sign = 1;
|
||||
unsigned int n = 0; // result wil be n*Sign
|
||||
WCHAR wch;
|
||||
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wch==L'-'){
|
||||
Sign = -1;
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for( ; ; ) {
|
||||
if (wch>=L'0' && wch<=L'9') {
|
||||
n = 10*n+(int)(wch-L'0');
|
||||
} else if ( wch == L' '
|
||||
|| wch == L'\t'
|
||||
|| wch == L'\r'
|
||||
|| wch == L'\n'
|
||||
|| wch == L'\0'
|
||||
) {
|
||||
break;
|
||||
} else {
|
||||
hr = VFW_E_INVALID_FILE_FORMAT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n==0x80000000 && Sign==-1) {
|
||||
// This is the negative number that has no positive version!
|
||||
return (int)n;
|
||||
}
|
||||
else return (int)n * Sign;
|
||||
} // ReadInt
|
||||
|
||||
|
||||
// The microsoft C/C++ compile generates level 4 warnings to the effect that
|
||||
// a particular inline function (from some base class) was not needed.
|
||||
// This line gets rid of hundreds of such unwanted messages and makes
|
||||
// -W4 compilation feasible:
|
||||
#pragma warning(disable: 4514)
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PStream.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#ifdef PERF
|
||||
#include <measure.h>
|
||||
#endif
|
||||
// #include "pstream.h" in streams.h
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
CPersistStream::CPersistStream(IUnknown *punk, HRESULT *phr)
|
||||
: mPS_fDirty(FALSE)
|
||||
{
|
||||
mPS_dwFileVersion = GetSoftwareVersion();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Destructor
|
||||
//
|
||||
CPersistStream::~CPersistStream() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
#if 0
|
||||
SAMPLE CODE TO COPY - not active at the moment
|
||||
|
||||
//
|
||||
// NonDelegatingQueryInterface
|
||||
//
|
||||
// This object supports IPersist & IPersistStream
|
||||
STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
if (riid == IID_IPersist) {
|
||||
return GetInterface((IPersist *) this, ppv); // ???
|
||||
}
|
||||
else if (riid == IID_IPersistStream) {
|
||||
return GetInterface((IPersistStream *) this, ppv);
|
||||
}
|
||||
else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// WriteToStream
|
||||
//
|
||||
// Writes to the stream (default action is to write nothing)
|
||||
HRESULT CPersistStream::WriteToStream(IStream *pStream)
|
||||
{
|
||||
// You can override this to do things like
|
||||
// hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL);
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CPersistStream::ReadFromStream(IStream * pStream)
|
||||
{
|
||||
// You can override this to do things like
|
||||
// hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL);
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Load
|
||||
//
|
||||
// Load all the data from the given stream
|
||||
STDMETHODIMP CPersistStream::Load(LPSTREAM pStm)
|
||||
{
|
||||
HRESULT hr;
|
||||
// Load the version number then the data
|
||||
mPS_dwFileVersion = ReadInt(pStm, hr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ReadFromStream(pStm);
|
||||
} // Load
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Save
|
||||
//
|
||||
// Save the contents of this Stream.
|
||||
STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty)
|
||||
{
|
||||
|
||||
HRESULT hr = WriteInt(pStm, GetSoftwareVersion());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = WriteToStream(pStm);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
mPS_fDirty = !fClearDirty;
|
||||
|
||||
return hr;
|
||||
} // Save
|
||||
|
||||
|
||||
// WriteInt
|
||||
//
|
||||
// Writes an integer to an IStream as 11 UNICODE characters followed by one space.
|
||||
// You could use this for shorts or unsigneds or anything (up to 32 bits)
|
||||
// where the value isn't actually truncated by squeezing it into 32 bits.
|
||||
// Values such as (unsigned) 0x80000000 would come out as -2147483648
|
||||
// but would then load as 0x80000000 through ReadInt. Cast as you please.
|
||||
|
||||
STDAPI WriteInt(IStream *pIStream, int n)
|
||||
{
|
||||
WCHAR Buff[13]; // Allows for trailing null that we don't write
|
||||
wsprintfW(Buff, L"%011d ",n);
|
||||
return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL);
|
||||
} // WriteInt
|
||||
|
||||
|
||||
// ReadInt
|
||||
//
|
||||
// Reads an integer from an IStream.
|
||||
// Read as 4 bytes. You could use this for shorts or unsigneds or anything
|
||||
// where the value isn't actually truncated by squeezing it into 32 bits
|
||||
// Striped down subset of what sscanf can do (without dragging in the C runtime)
|
||||
|
||||
STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr)
|
||||
{
|
||||
|
||||
int Sign = 1;
|
||||
unsigned int n = 0; // result wil be n*Sign
|
||||
WCHAR wch;
|
||||
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wch==L'-'){
|
||||
Sign = -1;
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for( ; ; ) {
|
||||
if (wch>=L'0' && wch<=L'9') {
|
||||
n = 10*n+(int)(wch-L'0');
|
||||
} else if ( wch == L' '
|
||||
|| wch == L'\t'
|
||||
|| wch == L'\r'
|
||||
|| wch == L'\n'
|
||||
|| wch == L'\0'
|
||||
) {
|
||||
break;
|
||||
} else {
|
||||
hr = VFW_E_INVALID_FILE_FORMAT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n==0x80000000 && Sign==-1) {
|
||||
// This is the negative number that has no positive version!
|
||||
return (int)n;
|
||||
}
|
||||
else return (int)n * Sign;
|
||||
} // ReadInt
|
||||
|
||||
|
||||
// The microsoft C/C++ compile generates level 4 warnings to the effect that
|
||||
// a particular inline function (from some base class) was not needed.
|
||||
// This line gets rid of hundreds of such unwanted messages and makes
|
||||
// -W4 compilation feasible:
|
||||
#pragma warning(disable: 4514)
|
||||
|
||||
+114
-114
@@ -1,114 +1,114 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PStream.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class for persistent properties
|
||||
// of filters.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __PSTREAM__
|
||||
#define __PSTREAM__
|
||||
|
||||
// Base class for persistent properties of filters
|
||||
// (i.e. filter properties in saved graphs)
|
||||
|
||||
// The simplest way to use this is:
|
||||
// 1. Arrange for your filter to inherit this class
|
||||
// 2. Implement in your class WriteToStream and ReadFromStream
|
||||
// These will override the "do nothing" functions here.
|
||||
// 3. Change your NonDelegatingQueryInterface to handle IPersistStream
|
||||
// 4. Implement SizeMax to return the number of bytes of data you save.
|
||||
// If you save UNICODE data, don't forget a char is 2 bytes.
|
||||
// 5. Whenever your data changes, call SetDirty()
|
||||
//
|
||||
// At some point you may decide to alter, or extend the format of your data.
|
||||
// At that point you will wish that you had a version number in all the old
|
||||
// saved graphs, so that you can tell, when you read them, whether they
|
||||
// represent the old or new form. To assist you in this, this class
|
||||
// writes and reads a version number.
|
||||
// When it writes, it calls GetSoftwareVersion() to enquire what version
|
||||
// of the software we have at the moment. (In effect this is a version number
|
||||
// of the data layout in the file). It writes this as the first thing in the data.
|
||||
// If you want to change the version, implement (override) GetSoftwareVersion().
|
||||
// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream,
|
||||
// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading
|
||||
// an old version file.
|
||||
// Normally you should accept files whose version is no newer than the software
|
||||
// version that's reading them.
|
||||
|
||||
|
||||
// CPersistStream
|
||||
//
|
||||
// Implements IPersistStream.
|
||||
// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for
|
||||
// more implementation information.
|
||||
class CPersistStream : public IPersistStream {
|
||||
private:
|
||||
|
||||
// Internal state:
|
||||
|
||||
protected:
|
||||
DWORD mPS_dwFileVersion; // version number of file (being read)
|
||||
BOOL mPS_fDirty;
|
||||
|
||||
public:
|
||||
|
||||
// IPersistStream methods
|
||||
|
||||
STDMETHODIMP IsDirty()
|
||||
{return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean
|
||||
STDMETHODIMP Load(LPSTREAM pStm);
|
||||
STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty);
|
||||
STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize)
|
||||
// Allow 24 bytes for version.
|
||||
{ pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; }
|
||||
|
||||
// implementation
|
||||
|
||||
CPersistStream(IUnknown *punk, HRESULT *phr);
|
||||
~CPersistStream();
|
||||
|
||||
HRESULT SetDirty(BOOL fDirty)
|
||||
{ mPS_fDirty = fDirty; return NOERROR;}
|
||||
|
||||
|
||||
// override to reveal IPersist & IPersistStream
|
||||
// STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
|
||||
|
||||
// --- IPersist ---
|
||||
|
||||
// You must override this to provide your own class id
|
||||
STDMETHODIMP GetClassID(CLSID *pClsid) PURE;
|
||||
|
||||
// overrideable if you want
|
||||
// file version number. Override it if you ever change format
|
||||
virtual DWORD GetSoftwareVersion(void) { return 0; }
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// OVERRIDE THESE to read and write your data
|
||||
// OVERRIDE THESE to read and write your data
|
||||
// OVERRIDE THESE to read and write your data
|
||||
|
||||
virtual int SizeMax() {return 0;}
|
||||
virtual HRESULT WriteToStream(IStream *pStream);
|
||||
virtual HRESULT ReadFromStream(IStream *pStream);
|
||||
//=========================================================================
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
// --- Useful helpers ---
|
||||
|
||||
|
||||
// Writes an int to an IStream as UNICODE.
|
||||
STDAPI WriteInt(IStream *pIStream, int n);
|
||||
|
||||
// inverse of WriteInt
|
||||
STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr);
|
||||
|
||||
#endif // __PSTREAM__
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PStream.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class for persistent properties
|
||||
// of filters.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __PSTREAM__
|
||||
#define __PSTREAM__
|
||||
|
||||
// Base class for persistent properties of filters
|
||||
// (i.e. filter properties in saved graphs)
|
||||
|
||||
// The simplest way to use this is:
|
||||
// 1. Arrange for your filter to inherit this class
|
||||
// 2. Implement in your class WriteToStream and ReadFromStream
|
||||
// These will override the "do nothing" functions here.
|
||||
// 3. Change your NonDelegatingQueryInterface to handle IPersistStream
|
||||
// 4. Implement SizeMax to return the number of bytes of data you save.
|
||||
// If you save UNICODE data, don't forget a char is 2 bytes.
|
||||
// 5. Whenever your data changes, call SetDirty()
|
||||
//
|
||||
// At some point you may decide to alter, or extend the format of your data.
|
||||
// At that point you will wish that you had a version number in all the old
|
||||
// saved graphs, so that you can tell, when you read them, whether they
|
||||
// represent the old or new form. To assist you in this, this class
|
||||
// writes and reads a version number.
|
||||
// When it writes, it calls GetSoftwareVersion() to enquire what version
|
||||
// of the software we have at the moment. (In effect this is a version number
|
||||
// of the data layout in the file). It writes this as the first thing in the data.
|
||||
// If you want to change the version, implement (override) GetSoftwareVersion().
|
||||
// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream,
|
||||
// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading
|
||||
// an old version file.
|
||||
// Normally you should accept files whose version is no newer than the software
|
||||
// version that's reading them.
|
||||
|
||||
|
||||
// CPersistStream
|
||||
//
|
||||
// Implements IPersistStream.
|
||||
// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for
|
||||
// more implementation information.
|
||||
class CPersistStream : public IPersistStream {
|
||||
private:
|
||||
|
||||
// Internal state:
|
||||
|
||||
protected:
|
||||
DWORD mPS_dwFileVersion; // version number of file (being read)
|
||||
BOOL mPS_fDirty;
|
||||
|
||||
public:
|
||||
|
||||
// IPersistStream methods
|
||||
|
||||
STDMETHODIMP IsDirty()
|
||||
{return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean
|
||||
STDMETHODIMP Load(LPSTREAM pStm);
|
||||
STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty);
|
||||
STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize)
|
||||
// Allow 24 bytes for version.
|
||||
{ pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; }
|
||||
|
||||
// implementation
|
||||
|
||||
CPersistStream(IUnknown *punk, HRESULT *phr);
|
||||
~CPersistStream();
|
||||
|
||||
HRESULT SetDirty(BOOL fDirty)
|
||||
{ mPS_fDirty = fDirty; return NOERROR;}
|
||||
|
||||
|
||||
// override to reveal IPersist & IPersistStream
|
||||
// STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
|
||||
|
||||
// --- IPersist ---
|
||||
|
||||
// You must override this to provide your own class id
|
||||
STDMETHODIMP GetClassID(CLSID *pClsid) PURE;
|
||||
|
||||
// overrideable if you want
|
||||
// file version number. Override it if you ever change format
|
||||
virtual DWORD GetSoftwareVersion(void) { return 0; }
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// OVERRIDE THESE to read and write your data
|
||||
// OVERRIDE THESE to read and write your data
|
||||
// OVERRIDE THESE to read and write your data
|
||||
|
||||
virtual int SizeMax() {return 0;}
|
||||
virtual HRESULT WriteToStream(IStream *pStream);
|
||||
virtual HRESULT ReadFromStream(IStream *pStream);
|
||||
//=========================================================================
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
// --- Useful helpers ---
|
||||
|
||||
|
||||
// Writes an int to an IStream as UNICODE.
|
||||
STDAPI WriteInt(IStream *pIStream, int n);
|
||||
|
||||
// inverse of WriteInt
|
||||
STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr);
|
||||
|
||||
#endif // __PSTREAM__
|
||||
|
||||
+510
-510
File diff suppressed because it is too large
Load Diff
+152
-152
@@ -1,152 +1,152 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PullPin.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines CPullPin class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __PULLPIN_H__
|
||||
#define __PULLPIN_H__
|
||||
|
||||
//
|
||||
// CPullPin
|
||||
//
|
||||
// object supporting pulling data from an IAsyncReader interface.
|
||||
// Given a start/stop position, calls a pure Receive method with each
|
||||
// IMediaSample received.
|
||||
//
|
||||
// This is essentially for use in a MemInputPin when it finds itself
|
||||
// connected to an IAsyncReader pin instead of a pushing pin.
|
||||
//
|
||||
|
||||
class CPullPin : public CAMThread
|
||||
{
|
||||
IAsyncReader* m_pReader;
|
||||
REFERENCE_TIME m_tStart;
|
||||
REFERENCE_TIME m_tStop;
|
||||
REFERENCE_TIME m_tDuration;
|
||||
BOOL m_bSync;
|
||||
|
||||
enum ThreadMsg {
|
||||
TM_Pause, // stop pulling and wait for next message
|
||||
TM_Start, // start pulling
|
||||
TM_Exit, // stop and exit
|
||||
};
|
||||
|
||||
ThreadMsg m_State;
|
||||
|
||||
// override pure thread proc from CAMThread
|
||||
DWORD ThreadProc(void);
|
||||
|
||||
// running pull method (check m_bSync)
|
||||
void Process(void);
|
||||
|
||||
// clean up any cancelled i/o after a flush
|
||||
void CleanupCancelled(void);
|
||||
|
||||
// suspend thread from pulling, eg during seek
|
||||
HRESULT PauseThread();
|
||||
|
||||
// start thread pulling - create thread if necy
|
||||
HRESULT StartThread();
|
||||
|
||||
// stop and close thread
|
||||
HRESULT StopThread();
|
||||
|
||||
// called from ProcessAsync to queue and collect requests
|
||||
HRESULT QueueSample(
|
||||
REFERENCE_TIME& tCurrent,
|
||||
REFERENCE_TIME tAlignStop,
|
||||
BOOL bDiscontinuity);
|
||||
|
||||
HRESULT CollectAndDeliver(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop);
|
||||
|
||||
HRESULT DeliverSample(
|
||||
IMediaSample* pSample,
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop);
|
||||
|
||||
protected:
|
||||
IMemAllocator * m_pAlloc;
|
||||
|
||||
public:
|
||||
CPullPin();
|
||||
virtual ~CPullPin();
|
||||
|
||||
// returns S_OK if successfully connected to an IAsyncReader interface
|
||||
// from this object
|
||||
// Optional allocator should be proposed as a preferred allocator if
|
||||
// necessary
|
||||
// bSync is TRUE if we are to use sync reads instead of the
|
||||
// async methods.
|
||||
HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync);
|
||||
|
||||
// disconnect any connection made in Connect
|
||||
HRESULT Disconnect();
|
||||
|
||||
// agree an allocator using RequestAllocator - optional
|
||||
// props param specifies your requirements (non-zero fields).
|
||||
// returns an error code if fail to match requirements.
|
||||
// optional IMemAllocator interface is offered as a preferred allocator
|
||||
// but no error occurs if it can't be met.
|
||||
virtual HRESULT DecideAllocator(
|
||||
IMemAllocator* pAlloc,
|
||||
ALLOCATOR_PROPERTIES * pProps);
|
||||
|
||||
// set start and stop position. if active, will start immediately at
|
||||
// the new position. Default is 0 to duration
|
||||
HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop);
|
||||
|
||||
// return the total duration
|
||||
HRESULT Duration(REFERENCE_TIME* ptDuration);
|
||||
|
||||
// start pulling data
|
||||
HRESULT Active(void);
|
||||
|
||||
// stop pulling data
|
||||
HRESULT Inactive(void);
|
||||
|
||||
// helper functions
|
||||
LONGLONG AlignDown(LONGLONG ll, LONG lAlign) {
|
||||
// aligning downwards is just truncation
|
||||
return ll & ~(lAlign-1);
|
||||
};
|
||||
|
||||
LONGLONG AlignUp(LONGLONG ll, LONG lAlign) {
|
||||
// align up: round up to next boundary
|
||||
return (ll + (lAlign -1)) & ~(lAlign -1);
|
||||
};
|
||||
|
||||
// GetReader returns the (addrefed) IAsyncReader interface
|
||||
// for SyncRead etc
|
||||
IAsyncReader* GetReader() {
|
||||
m_pReader->AddRef();
|
||||
return m_pReader;
|
||||
};
|
||||
|
||||
// -- pure --
|
||||
|
||||
// override this to handle data arrival
|
||||
// return value other than S_OK will stop data
|
||||
virtual HRESULT Receive(IMediaSample*) PURE;
|
||||
|
||||
// override this to handle end-of-stream
|
||||
virtual HRESULT EndOfStream(void) PURE;
|
||||
|
||||
// called on runtime errors that will have caused pulling
|
||||
// to stop
|
||||
// these errors are all returned from the upstream filter, who
|
||||
// will have already reported any errors to the filtergraph.
|
||||
virtual void OnError(HRESULT hr) PURE;
|
||||
|
||||
// flush this pin and all downstream
|
||||
virtual HRESULT BeginFlush() PURE;
|
||||
virtual HRESULT EndFlush() PURE;
|
||||
|
||||
};
|
||||
|
||||
#endif //__PULLPIN_H__
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PullPin.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines CPullPin class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __PULLPIN_H__
|
||||
#define __PULLPIN_H__
|
||||
|
||||
//
|
||||
// CPullPin
|
||||
//
|
||||
// object supporting pulling data from an IAsyncReader interface.
|
||||
// Given a start/stop position, calls a pure Receive method with each
|
||||
// IMediaSample received.
|
||||
//
|
||||
// This is essentially for use in a MemInputPin when it finds itself
|
||||
// connected to an IAsyncReader pin instead of a pushing pin.
|
||||
//
|
||||
|
||||
class CPullPin : public CAMThread
|
||||
{
|
||||
IAsyncReader* m_pReader;
|
||||
REFERENCE_TIME m_tStart;
|
||||
REFERENCE_TIME m_tStop;
|
||||
REFERENCE_TIME m_tDuration;
|
||||
BOOL m_bSync;
|
||||
|
||||
enum ThreadMsg {
|
||||
TM_Pause, // stop pulling and wait for next message
|
||||
TM_Start, // start pulling
|
||||
TM_Exit, // stop and exit
|
||||
};
|
||||
|
||||
ThreadMsg m_State;
|
||||
|
||||
// override pure thread proc from CAMThread
|
||||
DWORD ThreadProc(void);
|
||||
|
||||
// running pull method (check m_bSync)
|
||||
void Process(void);
|
||||
|
||||
// clean up any cancelled i/o after a flush
|
||||
void CleanupCancelled(void);
|
||||
|
||||
// suspend thread from pulling, eg during seek
|
||||
HRESULT PauseThread();
|
||||
|
||||
// start thread pulling - create thread if necy
|
||||
HRESULT StartThread();
|
||||
|
||||
// stop and close thread
|
||||
HRESULT StopThread();
|
||||
|
||||
// called from ProcessAsync to queue and collect requests
|
||||
HRESULT QueueSample(
|
||||
REFERENCE_TIME& tCurrent,
|
||||
REFERENCE_TIME tAlignStop,
|
||||
BOOL bDiscontinuity);
|
||||
|
||||
HRESULT CollectAndDeliver(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop);
|
||||
|
||||
HRESULT DeliverSample(
|
||||
IMediaSample* pSample,
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop);
|
||||
|
||||
protected:
|
||||
IMemAllocator * m_pAlloc;
|
||||
|
||||
public:
|
||||
CPullPin();
|
||||
virtual ~CPullPin();
|
||||
|
||||
// returns S_OK if successfully connected to an IAsyncReader interface
|
||||
// from this object
|
||||
// Optional allocator should be proposed as a preferred allocator if
|
||||
// necessary
|
||||
// bSync is TRUE if we are to use sync reads instead of the
|
||||
// async methods.
|
||||
HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync);
|
||||
|
||||
// disconnect any connection made in Connect
|
||||
HRESULT Disconnect();
|
||||
|
||||
// agree an allocator using RequestAllocator - optional
|
||||
// props param specifies your requirements (non-zero fields).
|
||||
// returns an error code if fail to match requirements.
|
||||
// optional IMemAllocator interface is offered as a preferred allocator
|
||||
// but no error occurs if it can't be met.
|
||||
virtual HRESULT DecideAllocator(
|
||||
IMemAllocator* pAlloc,
|
||||
ALLOCATOR_PROPERTIES * pProps);
|
||||
|
||||
// set start and stop position. if active, will start immediately at
|
||||
// the new position. Default is 0 to duration
|
||||
HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop);
|
||||
|
||||
// return the total duration
|
||||
HRESULT Duration(REFERENCE_TIME* ptDuration);
|
||||
|
||||
// start pulling data
|
||||
HRESULT Active(void);
|
||||
|
||||
// stop pulling data
|
||||
HRESULT Inactive(void);
|
||||
|
||||
// helper functions
|
||||
LONGLONG AlignDown(LONGLONG ll, LONG lAlign) {
|
||||
// aligning downwards is just truncation
|
||||
return ll & ~(lAlign-1);
|
||||
};
|
||||
|
||||
LONGLONG AlignUp(LONGLONG ll, LONG lAlign) {
|
||||
// align up: round up to next boundary
|
||||
return (ll + (lAlign -1)) & ~(lAlign -1);
|
||||
};
|
||||
|
||||
// GetReader returns the (addrefed) IAsyncReader interface
|
||||
// for SyncRead etc
|
||||
IAsyncReader* GetReader() {
|
||||
m_pReader->AddRef();
|
||||
return m_pReader;
|
||||
};
|
||||
|
||||
// -- pure --
|
||||
|
||||
// override this to handle data arrival
|
||||
// return value other than S_OK will stop data
|
||||
virtual HRESULT Receive(IMediaSample*) PURE;
|
||||
|
||||
// override this to handle end-of-stream
|
||||
virtual HRESULT EndOfStream(void) PURE;
|
||||
|
||||
// called on runtime errors that will have caused pulling
|
||||
// to stop
|
||||
// these errors are all returned from the upstream filter, who
|
||||
// will have already reported any errors to the filtergraph.
|
||||
virtual void OnError(HRESULT hr) PURE;
|
||||
|
||||
// flush this pin and all downstream
|
||||
virtual HRESULT BeginFlush() PURE;
|
||||
virtual HRESULT EndFlush() PURE;
|
||||
|
||||
};
|
||||
|
||||
#endif //__PULLPIN_H__
|
||||
|
||||
+25
-25
@@ -1,25 +1,25 @@
|
||||
DirectShow Sample -- Base Classes
|
||||
---------------------------------
|
||||
|
||||
The Microsoft DirectShow base classes are a set of C++ classes
|
||||
and utility functions that you can use to implement DirectShow filters.
|
||||
For complete documentation of the base classes, see "DirectShow Base Classes"
|
||||
in the DirectShow Reference section of the DirectX SDK documentation.
|
||||
|
||||
NOTE: The BaseClasses header file schedule.h has been renamed to dsschedule.h
|
||||
to prevent conflicts with the Platform SDK <schedule.h>. Only the refclock.h
|
||||
header in the BaseClasses directory uses this header, so the impact should
|
||||
be minimal.
|
||||
|
||||
Building for Windows XP
|
||||
-----------------------
|
||||
If you want to target Windows XP specifically to use its new features,
|
||||
you must set WINVER=0x501 in the BaseClasses project file. You must also
|
||||
install the Windows XP Platform SDK, however, to ensure that you have the
|
||||
latest header files. For example, wxutil.cpp uses the new TIME_KILL_SYNCHRONOUS flag
|
||||
only if (WINVER >= 0x501). This flag is conditionally defined in the Windows XP
|
||||
Platform SDK in mmsystem.h, but only if WINVER is also set to 0x501 when compiling.
|
||||
|
||||
#if (WINVER >= 0x501)
|
||||
#define TIME_KILL_SYNCHRONOUS 0x0100
|
||||
#endif
|
||||
DirectShow Sample -- Base Classes
|
||||
---------------------------------
|
||||
|
||||
The Microsoft DirectShow base classes are a set of C++ classes
|
||||
and utility functions that you can use to implement DirectShow filters.
|
||||
For complete documentation of the base classes, see "DirectShow Base Classes"
|
||||
in the DirectShow Reference section of the DirectX SDK documentation.
|
||||
|
||||
NOTE: The BaseClasses header file schedule.h has been renamed to dsschedule.h
|
||||
to prevent conflicts with the Platform SDK <schedule.h>. Only the refclock.h
|
||||
header in the BaseClasses directory uses this header, so the impact should
|
||||
be minimal.
|
||||
|
||||
Building for Windows XP
|
||||
-----------------------
|
||||
If you want to target Windows XP specifically to use its new features,
|
||||
you must set WINVER=0x501 in the BaseClasses project file. You must also
|
||||
install the Windows XP Platform SDK, however, to ensure that you have the
|
||||
latest header files. For example, wxutil.cpp uses the new TIME_KILL_SYNCHRONOUS flag
|
||||
only if (WINVER >= 0x501). This flag is conditionally defined in the Windows XP
|
||||
Platform SDK in mmsystem.h, but only if WINVER is also set to 0x501 when compiling.
|
||||
|
||||
#if (WINVER >= 0x501)
|
||||
#define TIME_KILL_SYNCHRONOUS 0x0100
|
||||
#endif
|
||||
|
||||
+308
-308
@@ -1,308 +1,308 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefClock.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements the IReferenceClock interface.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
|
||||
// 'this' used in constructor list
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface(
|
||||
REFIID riid,
|
||||
void ** ppv) {
|
||||
HRESULT hr;
|
||||
|
||||
if(riid == IID_IReferenceClock) {
|
||||
hr = GetInterface((IReferenceClock *) this, ppv);
|
||||
}
|
||||
else {
|
||||
hr = CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
CBaseReferenceClock::~CBaseReferenceClock() {
|
||||
|
||||
if(m_TimerResolution) timeEndPeriod(m_TimerResolution);
|
||||
|
||||
m_pSchedule->DumpLinkedList();
|
||||
|
||||
if(m_hThread) {
|
||||
m_bAbort = TRUE;
|
||||
TriggerThread();
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
EXECUTE_ASSERT(CloseHandle(m_hThread));
|
||||
m_hThread = 0;
|
||||
EXECUTE_ASSERT(CloseHandle(m_pSchedule->GetEvent()));
|
||||
delete m_pSchedule;
|
||||
}
|
||||
}
|
||||
|
||||
// A derived class may supply a hThreadEvent if it has its own thread that will take care
|
||||
// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread()
|
||||
// to see what such a thread has to do.)
|
||||
CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed )
|
||||
: CUnknown( pName, pUnk )
|
||||
, m_rtLastGotTime(0)
|
||||
, m_TimerResolution(0)
|
||||
, m_bAbort( FALSE )
|
||||
, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) )
|
||||
, m_hThread(0) {
|
||||
|
||||
|
||||
ASSERT(m_pSchedule);
|
||||
if(!m_pSchedule) {
|
||||
*phr = E_OUTOFMEMORY;
|
||||
}
|
||||
else {
|
||||
// Set up the highest resolution timer we can manage
|
||||
TIMECAPS tc;
|
||||
m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc)))
|
||||
? tc.wPeriodMin : 1;
|
||||
|
||||
timeBeginPeriod(m_TimerResolution);
|
||||
|
||||
/* Initialise our system times - the derived clock should set the right values */
|
||||
m_dwPrevSystemTime = timeGetTime();
|
||||
m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime;
|
||||
|
||||
#ifdef PERF
|
||||
m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime"));
|
||||
#endif
|
||||
|
||||
if(!pShed) {
|
||||
DWORD ThreadID;
|
||||
m_hThread = ::CreateThread(NULL, // Security attributes
|
||||
(DWORD) 0, // Initial stack size
|
||||
AdviseThreadFunction, // Thread start address
|
||||
(LPVOID) this, // Thread parameter
|
||||
(DWORD) 0, // Creation flags
|
||||
&ThreadID); // Thread identifier
|
||||
|
||||
if(m_hThread) {
|
||||
SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
else {
|
||||
*phr = E_FAIL;
|
||||
EXECUTE_ASSERT(CloseHandle(m_pSchedule->GetEvent()));
|
||||
delete m_pSchedule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::GetTime(REFERENCE_TIME *pTime) {
|
||||
HRESULT hr;
|
||||
if(pTime) {
|
||||
REFERENCE_TIME rtNow;
|
||||
Lock();
|
||||
rtNow = GetPrivateTime();
|
||||
if(rtNow > m_rtLastGotTime) {
|
||||
m_rtLastGotTime = rtNow;
|
||||
hr = S_OK;
|
||||
}
|
||||
else {
|
||||
hr = S_FALSE;
|
||||
}
|
||||
|
||||
*pTime = m_rtLastGotTime;
|
||||
Unlock();
|
||||
MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)));
|
||||
}
|
||||
else hr = E_POINTER;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Ask for an async notification that a time has elapsed */
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::AdviseTime(
|
||||
REFERENCE_TIME baseTime, // base reference time
|
||||
REFERENCE_TIME streamTime, // stream offset time
|
||||
HEVENT hEvent, // advise via this event
|
||||
DWORD_PTR *pdwAdviseCookie) // where your cookie goes
|
||||
{
|
||||
CheckPointer(pdwAdviseCookie, E_POINTER);
|
||||
*pdwAdviseCookie = 0;
|
||||
|
||||
// Check that the event is not already set
|
||||
ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0));
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
const REFERENCE_TIME lRefTime = baseTime + streamTime;
|
||||
if(lRefTime <= 0 || lRefTime == MAX_TIME) {
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else {
|
||||
*pdwAdviseCookie = m_pSchedule->AddAdvisePacket(lRefTime, 0, HANDLE(hEvent), FALSE);
|
||||
hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
/* Ask for an asynchronous periodic notification that a time has elapsed */
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::AdvisePeriodic(
|
||||
REFERENCE_TIME StartTime, // starting at this time
|
||||
REFERENCE_TIME PeriodTime, // time between notifications
|
||||
HSEMAPHORE hSemaphore, // advise via a semaphore
|
||||
DWORD_PTR *pdwAdviseCookie) // where your cookie goes
|
||||
{
|
||||
CheckPointer(pdwAdviseCookie, E_POINTER);
|
||||
*pdwAdviseCookie = 0;
|
||||
|
||||
HRESULT hr;
|
||||
if(StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME) {
|
||||
*pdwAdviseCookie = m_pSchedule->AddAdvisePacket(StartTime, PeriodTime, HANDLE(hSemaphore), TRUE);
|
||||
hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
|
||||
}
|
||||
else hr = E_INVALIDARG;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) {
|
||||
return m_pSchedule->Unadvise(dwAdviseCookie);
|
||||
}
|
||||
|
||||
|
||||
REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() {
|
||||
CAutoLock cObjectLock(this);
|
||||
|
||||
|
||||
/* If the clock has wrapped then the current time will be less than
|
||||
* the last time we were notified so add on the extra milliseconds
|
||||
*
|
||||
* The time period is long enough so that the likelihood of
|
||||
* successive calls spanning the clock cycle is not considered.
|
||||
*/
|
||||
|
||||
DWORD dwTime = timeGetTime(); {
|
||||
m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime));
|
||||
m_dwPrevSystemTime = dwTime;
|
||||
}
|
||||
|
||||
return m_rtPrivateTime;
|
||||
}
|
||||
|
||||
|
||||
/* Adjust the current time by the input value. This allows an
|
||||
external time source to work out some of the latency of the clock
|
||||
system and adjust the "current" time accordingly. The intent is
|
||||
that the time returned to the user is synchronised to a clock
|
||||
source and allows drift to be catered for.
|
||||
|
||||
For example: if the clock source detects a drift it can pass a delta
|
||||
to the current time rather than having to set an explicit time.
|
||||
*/
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) {
|
||||
#ifdef DEBUG
|
||||
|
||||
// Just break if passed an improper time delta value
|
||||
LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta;
|
||||
if(llDelta > UNITS * 1000) {
|
||||
DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta")));
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
// We're going to calculate a "severity" for the time change. Max -1
|
||||
// min 8. We'll then use this as the debug logging level for a
|
||||
// debug log message.
|
||||
const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs
|
||||
|
||||
DWORD delta = abs(usDelta); // varying delta
|
||||
// Severity == 8 - ceil(log<base 8>(abs( micro-secs delta)))
|
||||
int Severity = 8;
|
||||
while(delta > 0) {
|
||||
delta >>= 3; // div 8
|
||||
Severity--;
|
||||
}
|
||||
|
||||
// Sev == 0 => > 2 second delta!
|
||||
DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity,
|
||||
TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."),
|
||||
Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)),
|
||||
DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) ));
|
||||
|
||||
// Don't want the DbgBreak to fire when running stress on debug-builds.
|
||||
#ifdef BREAK_ON_SEVERE_TIME_DELTA
|
||||
if(Severity < 0)
|
||||
DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"),
|
||||
TEXT(__FILE__),__LINE__);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
CAutoLock cObjectLock(this);
|
||||
m_rtPrivateTime += TimeDelta;
|
||||
// If time goes forwards, and we have advises, then we need to
|
||||
// trigger the thread so that it can re-evaluate its wait time.
|
||||
// Since we don't want the cost of the thread switches if the change
|
||||
// is really small, only do it if clock goes forward by more than
|
||||
// 0.5 millisecond. If the time goes backwards, the thread will
|
||||
// wake up "early" (relativly speaking) and will re-evaluate at
|
||||
// that time.
|
||||
if(TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0) TriggerThread();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Thread stuff
|
||||
|
||||
DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(LPVOID p) {
|
||||
return DWORD(reinterpret_cast<CBaseReferenceClock*>(p)->AdviseThread());
|
||||
}
|
||||
|
||||
HRESULT CBaseReferenceClock::AdviseThread() {
|
||||
DWORD dwWait = INFINITE;
|
||||
|
||||
// The first thing we do is wait until something interesting happens
|
||||
// (meaning a first advise or shutdown). This prevents us calling
|
||||
// GetPrivateTime immediately which is goodness as that is a virtual
|
||||
// routine and the derived class may not yet be constructed. (This
|
||||
// thread is created in the base class constructor.)
|
||||
|
||||
while(!m_bAbort) {
|
||||
// Wait for an interesting event to happen
|
||||
DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait ));
|
||||
WaitForSingleObject(m_pSchedule->GetEvent(), dwWait);
|
||||
if(m_bAbort) break;
|
||||
|
||||
// There are several reasons why we need to work from the internal
|
||||
// time, mainly to do with what happens when time goes backwards.
|
||||
// Mainly, it stop us looping madly if an event is just about to
|
||||
// expire when the clock goes backward (i.e. GetTime stop for a
|
||||
// while).
|
||||
const REFERENCE_TIME rtNow = GetPrivateTime();
|
||||
|
||||
DbgLog((LOG_TIMING, 3,
|
||||
TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"),
|
||||
ConvertToMilliseconds(rtNow) ));
|
||||
|
||||
// We must add in a millisecond, since this is the resolution of our
|
||||
// WaitForSingleObject timer. Failure to do so will cause us to loop
|
||||
// franticly for (approx) 1 a millisecond.
|
||||
m_rtNextAdvise = m_pSchedule->Advise(10000 + rtNow);
|
||||
LONGLONG llWait = m_rtNextAdvise - rtNow;
|
||||
|
||||
ASSERT(llWait > 0);
|
||||
|
||||
llWait = ConvertToMilliseconds(llWait);
|
||||
// DON'T replace this with a max!! (The type's of these things is VERY important)
|
||||
dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait);
|
||||
};
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefClock.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements the IReferenceClock interface.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
|
||||
// 'this' used in constructor list
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface(
|
||||
REFIID riid,
|
||||
void ** ppv) {
|
||||
HRESULT hr;
|
||||
|
||||
if(riid == IID_IReferenceClock) {
|
||||
hr = GetInterface((IReferenceClock *) this, ppv);
|
||||
}
|
||||
else {
|
||||
hr = CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
CBaseReferenceClock::~CBaseReferenceClock() {
|
||||
|
||||
if(m_TimerResolution) timeEndPeriod(m_TimerResolution);
|
||||
|
||||
m_pSchedule->DumpLinkedList();
|
||||
|
||||
if(m_hThread) {
|
||||
m_bAbort = TRUE;
|
||||
TriggerThread();
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
EXECUTE_ASSERT(CloseHandle(m_hThread));
|
||||
m_hThread = 0;
|
||||
EXECUTE_ASSERT(CloseHandle(m_pSchedule->GetEvent()));
|
||||
delete m_pSchedule;
|
||||
}
|
||||
}
|
||||
|
||||
// A derived class may supply a hThreadEvent if it has its own thread that will take care
|
||||
// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread()
|
||||
// to see what such a thread has to do.)
|
||||
CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed )
|
||||
: CUnknown( pName, pUnk )
|
||||
, m_rtLastGotTime(0)
|
||||
, m_TimerResolution(0)
|
||||
, m_bAbort( FALSE )
|
||||
, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) )
|
||||
, m_hThread(0) {
|
||||
|
||||
|
||||
ASSERT(m_pSchedule);
|
||||
if(!m_pSchedule) {
|
||||
*phr = E_OUTOFMEMORY;
|
||||
}
|
||||
else {
|
||||
// Set up the highest resolution timer we can manage
|
||||
TIMECAPS tc;
|
||||
m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc)))
|
||||
? tc.wPeriodMin : 1;
|
||||
|
||||
timeBeginPeriod(m_TimerResolution);
|
||||
|
||||
/* Initialise our system times - the derived clock should set the right values */
|
||||
m_dwPrevSystemTime = timeGetTime();
|
||||
m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime;
|
||||
|
||||
#ifdef PERF
|
||||
m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime"));
|
||||
#endif
|
||||
|
||||
if(!pShed) {
|
||||
DWORD ThreadID;
|
||||
m_hThread = ::CreateThread(NULL, // Security attributes
|
||||
(DWORD) 0, // Initial stack size
|
||||
AdviseThreadFunction, // Thread start address
|
||||
(LPVOID) this, // Thread parameter
|
||||
(DWORD) 0, // Creation flags
|
||||
&ThreadID); // Thread identifier
|
||||
|
||||
if(m_hThread) {
|
||||
SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
else {
|
||||
*phr = E_FAIL;
|
||||
EXECUTE_ASSERT(CloseHandle(m_pSchedule->GetEvent()));
|
||||
delete m_pSchedule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::GetTime(REFERENCE_TIME *pTime) {
|
||||
HRESULT hr;
|
||||
if(pTime) {
|
||||
REFERENCE_TIME rtNow;
|
||||
Lock();
|
||||
rtNow = GetPrivateTime();
|
||||
if(rtNow > m_rtLastGotTime) {
|
||||
m_rtLastGotTime = rtNow;
|
||||
hr = S_OK;
|
||||
}
|
||||
else {
|
||||
hr = S_FALSE;
|
||||
}
|
||||
|
||||
*pTime = m_rtLastGotTime;
|
||||
Unlock();
|
||||
MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)));
|
||||
}
|
||||
else hr = E_POINTER;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Ask for an async notification that a time has elapsed */
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::AdviseTime(
|
||||
REFERENCE_TIME baseTime, // base reference time
|
||||
REFERENCE_TIME streamTime, // stream offset time
|
||||
HEVENT hEvent, // advise via this event
|
||||
DWORD_PTR *pdwAdviseCookie) // where your cookie goes
|
||||
{
|
||||
CheckPointer(pdwAdviseCookie, E_POINTER);
|
||||
*pdwAdviseCookie = 0;
|
||||
|
||||
// Check that the event is not already set
|
||||
ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0));
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
const REFERENCE_TIME lRefTime = baseTime + streamTime;
|
||||
if(lRefTime <= 0 || lRefTime == MAX_TIME) {
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else {
|
||||
*pdwAdviseCookie = m_pSchedule->AddAdvisePacket(lRefTime, 0, HANDLE(hEvent), FALSE);
|
||||
hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
/* Ask for an asynchronous periodic notification that a time has elapsed */
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::AdvisePeriodic(
|
||||
REFERENCE_TIME StartTime, // starting at this time
|
||||
REFERENCE_TIME PeriodTime, // time between notifications
|
||||
HSEMAPHORE hSemaphore, // advise via a semaphore
|
||||
DWORD_PTR *pdwAdviseCookie) // where your cookie goes
|
||||
{
|
||||
CheckPointer(pdwAdviseCookie, E_POINTER);
|
||||
*pdwAdviseCookie = 0;
|
||||
|
||||
HRESULT hr;
|
||||
if(StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME) {
|
||||
*pdwAdviseCookie = m_pSchedule->AddAdvisePacket(StartTime, PeriodTime, HANDLE(hSemaphore), TRUE);
|
||||
hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
|
||||
}
|
||||
else hr = E_INVALIDARG;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) {
|
||||
return m_pSchedule->Unadvise(dwAdviseCookie);
|
||||
}
|
||||
|
||||
|
||||
REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() {
|
||||
CAutoLock cObjectLock(this);
|
||||
|
||||
|
||||
/* If the clock has wrapped then the current time will be less than
|
||||
* the last time we were notified so add on the extra milliseconds
|
||||
*
|
||||
* The time period is long enough so that the likelihood of
|
||||
* successive calls spanning the clock cycle is not considered.
|
||||
*/
|
||||
|
||||
DWORD dwTime = timeGetTime(); {
|
||||
m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime));
|
||||
m_dwPrevSystemTime = dwTime;
|
||||
}
|
||||
|
||||
return m_rtPrivateTime;
|
||||
}
|
||||
|
||||
|
||||
/* Adjust the current time by the input value. This allows an
|
||||
external time source to work out some of the latency of the clock
|
||||
system and adjust the "current" time accordingly. The intent is
|
||||
that the time returned to the user is synchronised to a clock
|
||||
source and allows drift to be catered for.
|
||||
|
||||
For example: if the clock source detects a drift it can pass a delta
|
||||
to the current time rather than having to set an explicit time.
|
||||
*/
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) {
|
||||
#ifdef DEBUG
|
||||
|
||||
// Just break if passed an improper time delta value
|
||||
LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta;
|
||||
if(llDelta > UNITS * 1000) {
|
||||
DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta")));
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
// We're going to calculate a "severity" for the time change. Max -1
|
||||
// min 8. We'll then use this as the debug logging level for a
|
||||
// debug log message.
|
||||
const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs
|
||||
|
||||
DWORD delta = abs(usDelta); // varying delta
|
||||
// Severity == 8 - ceil(log<base 8>(abs( micro-secs delta)))
|
||||
int Severity = 8;
|
||||
while(delta > 0) {
|
||||
delta >>= 3; // div 8
|
||||
Severity--;
|
||||
}
|
||||
|
||||
// Sev == 0 => > 2 second delta!
|
||||
DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity,
|
||||
TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."),
|
||||
Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)),
|
||||
DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) ));
|
||||
|
||||
// Don't want the DbgBreak to fire when running stress on debug-builds.
|
||||
#ifdef BREAK_ON_SEVERE_TIME_DELTA
|
||||
if(Severity < 0)
|
||||
DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"),
|
||||
TEXT(__FILE__),__LINE__);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
CAutoLock cObjectLock(this);
|
||||
m_rtPrivateTime += TimeDelta;
|
||||
// If time goes forwards, and we have advises, then we need to
|
||||
// trigger the thread so that it can re-evaluate its wait time.
|
||||
// Since we don't want the cost of the thread switches if the change
|
||||
// is really small, only do it if clock goes forward by more than
|
||||
// 0.5 millisecond. If the time goes backwards, the thread will
|
||||
// wake up "early" (relativly speaking) and will re-evaluate at
|
||||
// that time.
|
||||
if(TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0) TriggerThread();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Thread stuff
|
||||
|
||||
DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(LPVOID p) {
|
||||
return DWORD(reinterpret_cast<CBaseReferenceClock*>(p)->AdviseThread());
|
||||
}
|
||||
|
||||
HRESULT CBaseReferenceClock::AdviseThread() {
|
||||
DWORD dwWait = INFINITE;
|
||||
|
||||
// The first thing we do is wait until something interesting happens
|
||||
// (meaning a first advise or shutdown). This prevents us calling
|
||||
// GetPrivateTime immediately which is goodness as that is a virtual
|
||||
// routine and the derived class may not yet be constructed. (This
|
||||
// thread is created in the base class constructor.)
|
||||
|
||||
while(!m_bAbort) {
|
||||
// Wait for an interesting event to happen
|
||||
DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait ));
|
||||
WaitForSingleObject(m_pSchedule->GetEvent(), dwWait);
|
||||
if(m_bAbort) break;
|
||||
|
||||
// There are several reasons why we need to work from the internal
|
||||
// time, mainly to do with what happens when time goes backwards.
|
||||
// Mainly, it stop us looping madly if an event is just about to
|
||||
// expire when the clock goes backward (i.e. GetTime stop for a
|
||||
// while).
|
||||
const REFERENCE_TIME rtNow = GetPrivateTime();
|
||||
|
||||
DbgLog((LOG_TIMING, 3,
|
||||
TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"),
|
||||
ConvertToMilliseconds(rtNow) ));
|
||||
|
||||
// We must add in a millisecond, since this is the resolution of our
|
||||
// WaitForSingleObject timer. Failure to do so will cause us to loop
|
||||
// franticly for (approx) 1 a millisecond.
|
||||
m_rtNextAdvise = m_pSchedule->Advise(10000 + rtNow);
|
||||
LONGLONG llWait = m_rtNextAdvise - rtNow;
|
||||
|
||||
ASSERT(llWait > 0);
|
||||
|
||||
llWait = ConvertToMilliseconds(llWait);
|
||||
// DON'T replace this with a max!! (The type's of these things is VERY important)
|
||||
dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait);
|
||||
};
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
+169
-169
@@ -1,169 +1,169 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefClock.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines the IReferenceClock interface.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __BASEREFCLOCK__
|
||||
#define __BASEREFCLOCK__
|
||||
|
||||
#include "dsschedule.h"
|
||||
|
||||
const UINT RESOLUTION = 1; /* High resolution timer */
|
||||
const INT ADVISE_CACHE = 4; /* Default cache size */
|
||||
const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */
|
||||
|
||||
inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT)
|
||||
{
|
||||
/* This converts an arbitrary value representing a reference time
|
||||
into a MILLISECONDS value for use in subsequent system calls */
|
||||
|
||||
return (RT / (UNITS / MILLISECONDS));
|
||||
}
|
||||
|
||||
/* This class hierarchy will support an IReferenceClock interface so
|
||||
that an audio card (or other externally driven clock) can update the
|
||||
system wide clock that everyone uses.
|
||||
|
||||
The interface will be pretty thin with probably just one update method
|
||||
This interface has not yet been defined.
|
||||
*/
|
||||
|
||||
/* This abstract base class implements the IReferenceClock
|
||||
* interface. Classes that actually provide clock signals (from
|
||||
* whatever source) have to be derived from this class.
|
||||
*
|
||||
* The abstract class provides implementations for:
|
||||
* CUnknown support
|
||||
* locking support (CCritSec)
|
||||
* client advise code (creates a thread)
|
||||
*
|
||||
* Question: what can we do about quality? Change the timer
|
||||
* resolution to lower the system load? Up the priority of the
|
||||
* timer thread to force more responsive signals?
|
||||
*
|
||||
* During class construction we create a worker thread that is destroyed during
|
||||
* destuction. This thread executes a series of WaitForSingleObject calls,
|
||||
* waking up when a command is given to the thread or the next wake up point
|
||||
* is reached. The wakeup points are determined by clients making Advise
|
||||
* calls.
|
||||
*
|
||||
* Each advise call defines a point in time when they wish to be notified. A
|
||||
* periodic advise is a series of these such events. We maintain a list of
|
||||
* advise links and calculate when the nearest event notification is due for.
|
||||
* We then call WaitForSingleObject with a timeout equal to this time. The
|
||||
* handle we wait on is used by the class to signal that something has changed
|
||||
* and that we must reschedule the next event. This typically happens when
|
||||
* someone comes in and asks for an advise link while we are waiting for an
|
||||
* event to timeout.
|
||||
*
|
||||
* While we are modifying the list of advise requests we
|
||||
* are protected from interference through a critical section. Clients are NOT
|
||||
* advised through callbacks. One shot clients have an event set, while
|
||||
* periodic clients have a semaphore released for each event notification. A
|
||||
* semaphore allows a client to be kept up to date with the number of events
|
||||
* actually triggered and be assured that they can't miss multiple events being
|
||||
* set.
|
||||
*
|
||||
* Keeping track of advises is taken care of by the CAMSchedule class.
|
||||
*/
|
||||
|
||||
class CBaseReferenceClock
|
||||
: public CUnknown, public IReferenceClock, public CCritSec
|
||||
{
|
||||
protected:
|
||||
virtual ~CBaseReferenceClock(); // Don't let me be created on the stack!
|
||||
public:
|
||||
CBaseReferenceClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pSched = 0 );
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
/* IReferenceClock methods */
|
||||
// Derived classes must implement GetPrivateTime(). All our GetTime
|
||||
// does is call GetPrivateTime and then check so that time does not
|
||||
// go backwards. A return code of S_FALSE implies that the internal
|
||||
// clock has gone backwards and GetTime time has halted until internal
|
||||
// time has caught up. (Don't know if this will be much use to folk,
|
||||
// but it seems odd not to use the return code for something useful.)
|
||||
STDMETHODIMP GetTime(REFERENCE_TIME *pTime);
|
||||
// When this is called, it sets m_rtLastGotTime to the time it returns.
|
||||
|
||||
/* Provide standard mechanisms for scheduling events */
|
||||
|
||||
/* Ask for an async notification that a time has elapsed */
|
||||
STDMETHODIMP AdviseTime(
|
||||
REFERENCE_TIME baseTime, // base reference time
|
||||
REFERENCE_TIME streamTime, // stream offset time
|
||||
HEVENT hEvent, // advise via this event
|
||||
DWORD_PTR *pdwAdviseCookie // where your cookie goes
|
||||
);
|
||||
|
||||
/* Ask for an asynchronous periodic notification that a time has elapsed */
|
||||
STDMETHODIMP AdvisePeriodic(
|
||||
REFERENCE_TIME StartTime, // starting at this time
|
||||
REFERENCE_TIME PeriodTime, // time between notifications
|
||||
HSEMAPHORE hSemaphore, // advise via a semaphore
|
||||
DWORD_PTR *pdwAdviseCookie // where your cookie goes
|
||||
);
|
||||
|
||||
/* Cancel a request for notification(s) - if the notification was
|
||||
* a one shot timer then this function doesn't need to be called
|
||||
* as the advise is automatically cancelled, however it does no
|
||||
* harm to explicitly cancel a one-shot advise. It is REQUIRED that
|
||||
* clients call Unadvise to clear a Periodic advise setting.
|
||||
*/
|
||||
|
||||
STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie);
|
||||
|
||||
/* Methods for the benefit of derived classes or outer objects */
|
||||
|
||||
// GetPrivateTime() is the REAL clock. GetTime is just a cover for
|
||||
// it. Derived classes will probably override this method but not
|
||||
// GetTime() itself.
|
||||
// The important point about GetPrivateTime() is it's allowed to go
|
||||
// backwards. Our GetTime() will keep returning the LastGotTime
|
||||
// until GetPrivateTime() catches up.
|
||||
virtual REFERENCE_TIME GetPrivateTime();
|
||||
|
||||
/* Provide a method for correcting drift */
|
||||
STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta );
|
||||
|
||||
CAMSchedule * GetSchedule() const { return m_pSchedule; }
|
||||
|
||||
private:
|
||||
REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time
|
||||
DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime
|
||||
REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime
|
||||
REFERENCE_TIME m_rtNextAdvise; // Time of next advise
|
||||
UINT m_TimerResolution;
|
||||
|
||||
#ifdef PERF
|
||||
int m_idGetSystemTime;
|
||||
#endif
|
||||
|
||||
// Thread stuff
|
||||
public:
|
||||
void TriggerThread() // Wakes thread up. Need to do this if
|
||||
{ // time to next advise needs reevaluating.
|
||||
EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent()));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
BOOL m_bAbort; // Flag used for thread shutdown
|
||||
HANDLE m_hThread; // Thread handle
|
||||
|
||||
HRESULT AdviseThread(); // Method in which the advise thread runs
|
||||
static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there
|
||||
|
||||
protected:
|
||||
CAMSchedule * const m_pSchedule;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefClock.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines the IReferenceClock interface.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __BASEREFCLOCK__
|
||||
#define __BASEREFCLOCK__
|
||||
|
||||
#include "dsschedule.h"
|
||||
|
||||
const UINT RESOLUTION = 1; /* High resolution timer */
|
||||
const INT ADVISE_CACHE = 4; /* Default cache size */
|
||||
const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */
|
||||
|
||||
inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT)
|
||||
{
|
||||
/* This converts an arbitrary value representing a reference time
|
||||
into a MILLISECONDS value for use in subsequent system calls */
|
||||
|
||||
return (RT / (UNITS / MILLISECONDS));
|
||||
}
|
||||
|
||||
/* This class hierarchy will support an IReferenceClock interface so
|
||||
that an audio card (or other externally driven clock) can update the
|
||||
system wide clock that everyone uses.
|
||||
|
||||
The interface will be pretty thin with probably just one update method
|
||||
This interface has not yet been defined.
|
||||
*/
|
||||
|
||||
/* This abstract base class implements the IReferenceClock
|
||||
* interface. Classes that actually provide clock signals (from
|
||||
* whatever source) have to be derived from this class.
|
||||
*
|
||||
* The abstract class provides implementations for:
|
||||
* CUnknown support
|
||||
* locking support (CCritSec)
|
||||
* client advise code (creates a thread)
|
||||
*
|
||||
* Question: what can we do about quality? Change the timer
|
||||
* resolution to lower the system load? Up the priority of the
|
||||
* timer thread to force more responsive signals?
|
||||
*
|
||||
* During class construction we create a worker thread that is destroyed during
|
||||
* destuction. This thread executes a series of WaitForSingleObject calls,
|
||||
* waking up when a command is given to the thread or the next wake up point
|
||||
* is reached. The wakeup points are determined by clients making Advise
|
||||
* calls.
|
||||
*
|
||||
* Each advise call defines a point in time when they wish to be notified. A
|
||||
* periodic advise is a series of these such events. We maintain a list of
|
||||
* advise links and calculate when the nearest event notification is due for.
|
||||
* We then call WaitForSingleObject with a timeout equal to this time. The
|
||||
* handle we wait on is used by the class to signal that something has changed
|
||||
* and that we must reschedule the next event. This typically happens when
|
||||
* someone comes in and asks for an advise link while we are waiting for an
|
||||
* event to timeout.
|
||||
*
|
||||
* While we are modifying the list of advise requests we
|
||||
* are protected from interference through a critical section. Clients are NOT
|
||||
* advised through callbacks. One shot clients have an event set, while
|
||||
* periodic clients have a semaphore released for each event notification. A
|
||||
* semaphore allows a client to be kept up to date with the number of events
|
||||
* actually triggered and be assured that they can't miss multiple events being
|
||||
* set.
|
||||
*
|
||||
* Keeping track of advises is taken care of by the CAMSchedule class.
|
||||
*/
|
||||
|
||||
class CBaseReferenceClock
|
||||
: public CUnknown, public IReferenceClock, public CCritSec
|
||||
{
|
||||
protected:
|
||||
virtual ~CBaseReferenceClock(); // Don't let me be created on the stack!
|
||||
public:
|
||||
CBaseReferenceClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pSched = 0 );
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
/* IReferenceClock methods */
|
||||
// Derived classes must implement GetPrivateTime(). All our GetTime
|
||||
// does is call GetPrivateTime and then check so that time does not
|
||||
// go backwards. A return code of S_FALSE implies that the internal
|
||||
// clock has gone backwards and GetTime time has halted until internal
|
||||
// time has caught up. (Don't know if this will be much use to folk,
|
||||
// but it seems odd not to use the return code for something useful.)
|
||||
STDMETHODIMP GetTime(REFERENCE_TIME *pTime);
|
||||
// When this is called, it sets m_rtLastGotTime to the time it returns.
|
||||
|
||||
/* Provide standard mechanisms for scheduling events */
|
||||
|
||||
/* Ask for an async notification that a time has elapsed */
|
||||
STDMETHODIMP AdviseTime(
|
||||
REFERENCE_TIME baseTime, // base reference time
|
||||
REFERENCE_TIME streamTime, // stream offset time
|
||||
HEVENT hEvent, // advise via this event
|
||||
DWORD_PTR *pdwAdviseCookie // where your cookie goes
|
||||
);
|
||||
|
||||
/* Ask for an asynchronous periodic notification that a time has elapsed */
|
||||
STDMETHODIMP AdvisePeriodic(
|
||||
REFERENCE_TIME StartTime, // starting at this time
|
||||
REFERENCE_TIME PeriodTime, // time between notifications
|
||||
HSEMAPHORE hSemaphore, // advise via a semaphore
|
||||
DWORD_PTR *pdwAdviseCookie // where your cookie goes
|
||||
);
|
||||
|
||||
/* Cancel a request for notification(s) - if the notification was
|
||||
* a one shot timer then this function doesn't need to be called
|
||||
* as the advise is automatically cancelled, however it does no
|
||||
* harm to explicitly cancel a one-shot advise. It is REQUIRED that
|
||||
* clients call Unadvise to clear a Periodic advise setting.
|
||||
*/
|
||||
|
||||
STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie);
|
||||
|
||||
/* Methods for the benefit of derived classes or outer objects */
|
||||
|
||||
// GetPrivateTime() is the REAL clock. GetTime is just a cover for
|
||||
// it. Derived classes will probably override this method but not
|
||||
// GetTime() itself.
|
||||
// The important point about GetPrivateTime() is it's allowed to go
|
||||
// backwards. Our GetTime() will keep returning the LastGotTime
|
||||
// until GetPrivateTime() catches up.
|
||||
virtual REFERENCE_TIME GetPrivateTime();
|
||||
|
||||
/* Provide a method for correcting drift */
|
||||
STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta );
|
||||
|
||||
CAMSchedule * GetSchedule() const { return m_pSchedule; }
|
||||
|
||||
private:
|
||||
REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time
|
||||
DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime
|
||||
REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime
|
||||
REFERENCE_TIME m_rtNextAdvise; // Time of next advise
|
||||
UINT m_TimerResolution;
|
||||
|
||||
#ifdef PERF
|
||||
int m_idGetSystemTime;
|
||||
#endif
|
||||
|
||||
// Thread stuff
|
||||
public:
|
||||
void TriggerThread() // Wakes thread up. Need to do this if
|
||||
{ // time to next advise needs reevaluating.
|
||||
EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent()));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
BOOL m_bAbort; // Flag used for thread shutdown
|
||||
HANDLE m_hThread; // Thread handle
|
||||
|
||||
HRESULT AdviseThread(); // Method in which the advise thread runs
|
||||
static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there
|
||||
|
||||
protected:
|
||||
CAMSchedule * const m_pSchedule;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+116
-116
@@ -1,116 +1,116 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefTime.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines CRefTime, a class that manages
|
||||
// reference times.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// CRefTime
|
||||
//
|
||||
// Manage reference times.
|
||||
// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual)
|
||||
// functions providing simple comparison, conversion and arithmetic.
|
||||
//
|
||||
// A reference time (at the moment) is a unit of seconds represented in
|
||||
// 100ns units as is used in the Win32 FILETIME structure. BUT the time
|
||||
// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it
|
||||
// will either be stream time or reference time depending upon context
|
||||
//
|
||||
// This class provides simple arithmetic operations on reference times
|
||||
//
|
||||
// keep non-virtual otherwise the data layout will not be the same as
|
||||
// REFERENCE_TIME
|
||||
|
||||
|
||||
// -----
|
||||
// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but
|
||||
// you will need to do so explicitly
|
||||
// -----
|
||||
|
||||
|
||||
#ifndef __REFTIME__
|
||||
#define __REFTIME__
|
||||
|
||||
|
||||
const LONGLONG MILLISECONDS = (1000); // 10 ^ 3
|
||||
const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9
|
||||
const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7
|
||||
|
||||
/* Unfortunately an inline function here generates a call to __allmul
|
||||
- even for constants!
|
||||
*/
|
||||
#define MILLISECONDS_TO_100NS_UNITS(lMs) \
|
||||
Int32x32To64((lMs), (UNITS / MILLISECONDS))
|
||||
|
||||
class CRefTime
|
||||
{
|
||||
public:
|
||||
|
||||
// *MUST* be the only data member so that this class is exactly
|
||||
// equivalent to a REFERENCE_TIME.
|
||||
// Also, must be *no virtual functions*
|
||||
|
||||
REFERENCE_TIME m_time;
|
||||
|
||||
inline CRefTime()
|
||||
{
|
||||
// default to 0 time
|
||||
m_time = 0;
|
||||
};
|
||||
|
||||
inline CRefTime(LONG msecs)
|
||||
{
|
||||
m_time = MILLISECONDS_TO_100NS_UNITS(msecs);
|
||||
};
|
||||
|
||||
inline CRefTime(REFERENCE_TIME rt)
|
||||
{
|
||||
m_time = rt;
|
||||
};
|
||||
|
||||
inline operator REFERENCE_TIME() const
|
||||
{
|
||||
return m_time;
|
||||
};
|
||||
|
||||
inline CRefTime& operator=(const CRefTime& rt)
|
||||
{
|
||||
m_time = rt.m_time;
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline CRefTime& operator=(const LONGLONG ll)
|
||||
{
|
||||
m_time = ll;
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline CRefTime& operator+=(const CRefTime& rt)
|
||||
{
|
||||
return (*this = *this + rt);
|
||||
};
|
||||
|
||||
inline CRefTime& operator-=(const CRefTime& rt)
|
||||
{
|
||||
return (*this = *this - rt);
|
||||
};
|
||||
|
||||
inline LONG Millisecs(void)
|
||||
{
|
||||
return (LONG)(m_time / (UNITS / MILLISECONDS));
|
||||
};
|
||||
|
||||
inline LONGLONG GetUnits(void)
|
||||
{
|
||||
return m_time;
|
||||
};
|
||||
};
|
||||
|
||||
const LONGLONG TimeZero = 0;
|
||||
|
||||
#endif /* __REFTIME__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefTime.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines CRefTime, a class that manages
|
||||
// reference times.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// CRefTime
|
||||
//
|
||||
// Manage reference times.
|
||||
// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual)
|
||||
// functions providing simple comparison, conversion and arithmetic.
|
||||
//
|
||||
// A reference time (at the moment) is a unit of seconds represented in
|
||||
// 100ns units as is used in the Win32 FILETIME structure. BUT the time
|
||||
// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it
|
||||
// will either be stream time or reference time depending upon context
|
||||
//
|
||||
// This class provides simple arithmetic operations on reference times
|
||||
//
|
||||
// keep non-virtual otherwise the data layout will not be the same as
|
||||
// REFERENCE_TIME
|
||||
|
||||
|
||||
// -----
|
||||
// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but
|
||||
// you will need to do so explicitly
|
||||
// -----
|
||||
|
||||
|
||||
#ifndef __REFTIME__
|
||||
#define __REFTIME__
|
||||
|
||||
|
||||
const LONGLONG MILLISECONDS = (1000); // 10 ^ 3
|
||||
const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9
|
||||
const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7
|
||||
|
||||
/* Unfortunately an inline function here generates a call to __allmul
|
||||
- even for constants!
|
||||
*/
|
||||
#define MILLISECONDS_TO_100NS_UNITS(lMs) \
|
||||
Int32x32To64((lMs), (UNITS / MILLISECONDS))
|
||||
|
||||
class CRefTime
|
||||
{
|
||||
public:
|
||||
|
||||
// *MUST* be the only data member so that this class is exactly
|
||||
// equivalent to a REFERENCE_TIME.
|
||||
// Also, must be *no virtual functions*
|
||||
|
||||
REFERENCE_TIME m_time;
|
||||
|
||||
inline CRefTime()
|
||||
{
|
||||
// default to 0 time
|
||||
m_time = 0;
|
||||
};
|
||||
|
||||
inline CRefTime(LONG msecs)
|
||||
{
|
||||
m_time = MILLISECONDS_TO_100NS_UNITS(msecs);
|
||||
};
|
||||
|
||||
inline CRefTime(REFERENCE_TIME rt)
|
||||
{
|
||||
m_time = rt;
|
||||
};
|
||||
|
||||
inline operator REFERENCE_TIME() const
|
||||
{
|
||||
return m_time;
|
||||
};
|
||||
|
||||
inline CRefTime& operator=(const CRefTime& rt)
|
||||
{
|
||||
m_time = rt.m_time;
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline CRefTime& operator=(const LONGLONG ll)
|
||||
{
|
||||
m_time = ll;
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline CRefTime& operator+=(const CRefTime& rt)
|
||||
{
|
||||
return (*this = *this + rt);
|
||||
};
|
||||
|
||||
inline CRefTime& operator-=(const CRefTime& rt)
|
||||
{
|
||||
return (*this = *this - rt);
|
||||
};
|
||||
|
||||
inline LONG Millisecs(void)
|
||||
{
|
||||
return (LONG)(m_time / (UNITS / MILLISECONDS));
|
||||
};
|
||||
|
||||
inline LONGLONG GetUnits(void)
|
||||
{
|
||||
return m_time;
|
||||
};
|
||||
};
|
||||
|
||||
const LONGLONG TimeZero = 0;
|
||||
|
||||
#endif /* __REFTIME__ */
|
||||
|
||||
|
||||
+2833
-2833
File diff suppressed because it is too large
Load Diff
+479
-479
@@ -1,479 +1,479 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RenBase.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a generic ActiveX base renderer
|
||||
// class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __RENBASE__
|
||||
#define __RENBASE__
|
||||
|
||||
// Forward class declarations
|
||||
|
||||
class CBaseRenderer;
|
||||
class CBaseVideoRenderer;
|
||||
class CRendererInputPin;
|
||||
|
||||
// This is our input pin class that channels calls to the renderer
|
||||
|
||||
class CRendererInputPin : public CBaseInputPin
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseRenderer *m_pRenderer;
|
||||
|
||||
public:
|
||||
|
||||
CRendererInputPin(CBaseRenderer *pRenderer,
|
||||
HRESULT *phr,
|
||||
LPCWSTR Name);
|
||||
|
||||
// Overriden from the base pin classes
|
||||
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
HRESULT SetMediaType(const CMediaType *pmt);
|
||||
HRESULT CheckMediaType(const CMediaType *pmt);
|
||||
HRESULT Active();
|
||||
HRESULT Inactive();
|
||||
|
||||
// Add rendering behaviour to interface functions
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR *Id);
|
||||
STDMETHODIMP EndOfStream();
|
||||
STDMETHODIMP BeginFlush();
|
||||
STDMETHODIMP EndFlush();
|
||||
STDMETHODIMP Receive(IMediaSample *pMediaSample);
|
||||
|
||||
// Helper
|
||||
IMemAllocator inline *Allocator() const
|
||||
{
|
||||
return m_pAllocator;
|
||||
}
|
||||
};
|
||||
|
||||
// Main renderer class that handles synchronisation and state changes
|
||||
|
||||
class CBaseRenderer : public CBaseFilter
|
||||
{
|
||||
protected:
|
||||
|
||||
friend class CRendererInputPin;
|
||||
|
||||
friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier
|
||||
UINT uMsg, // Not currently used
|
||||
DWORD_PTR dwUser, // User information
|
||||
DWORD_PTR dw1, // Windows reserved
|
||||
DWORD_PTR dw2); // Is also reserved
|
||||
|
||||
CRendererPosPassThru *m_pPosition; // Media seeking pass by object
|
||||
CAMEvent m_RenderEvent; // Used to signal timer events
|
||||
CAMEvent m_ThreadSignal; // Signalled to release worker thread
|
||||
CAMEvent m_evComplete; // Signalled when state complete
|
||||
BOOL m_bAbort; // Stop us from rendering more data
|
||||
BOOL m_bStreaming; // Are we currently streaming
|
||||
DWORD_PTR m_dwAdvise; // Timer advise cookie
|
||||
IMediaSample *m_pMediaSample; // Current image media sample
|
||||
BOOL m_bEOS; // Any more samples in the stream
|
||||
BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE
|
||||
CRendererInputPin *m_pInputPin; // Our renderer input pin object
|
||||
CCritSec m_InterfaceLock; // Critical section for interfaces
|
||||
CCritSec m_RendererLock; // Controls access to internals
|
||||
IQualityControl * m_pQSink; // QualityControl sink
|
||||
BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT
|
||||
|
||||
// Avoid some deadlocks by tracking filter during stop
|
||||
volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive
|
||||
// And actually processing the sample
|
||||
REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE
|
||||
UINT m_EndOfStreamTimer; // Used to signal end of stream
|
||||
CCritSec m_ObjectCreationLock; // This lock protects the creation and
|
||||
// of m_pPosition and m_pInputPin. It
|
||||
// ensures that two threads cannot create
|
||||
// either object simultaneously.
|
||||
|
||||
public:
|
||||
|
||||
CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer
|
||||
TCHAR *pName, // Debug ONLY description
|
||||
LPUNKNOWN pUnk, // Aggregated owner object
|
||||
HRESULT *phr); // General OLE return code
|
||||
|
||||
~CBaseRenderer();
|
||||
|
||||
// Overriden to say what interfaces we support and where
|
||||
|
||||
virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv);
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
|
||||
|
||||
virtual HRESULT SourceThreadCanWait(BOOL bCanWait);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug only dump of the renderer state
|
||||
void DisplayRendererState();
|
||||
#endif
|
||||
virtual HRESULT WaitForRenderTime();
|
||||
virtual HRESULT CompleteStateChange(FILTER_STATE OldState);
|
||||
|
||||
// Return internal information about this filter
|
||||
|
||||
BOOL IsEndOfStream() { return m_bEOS; };
|
||||
BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; };
|
||||
BOOL IsStreaming() { return m_bStreaming; };
|
||||
void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; };
|
||||
virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { };
|
||||
CAMEvent *GetRenderEvent() { return &m_RenderEvent; };
|
||||
|
||||
// Permit access to the transition state
|
||||
|
||||
void Ready() { m_evComplete.Set(); };
|
||||
void NotReady() { m_evComplete.Reset(); };
|
||||
BOOL CheckReady() { return m_evComplete.Check(); };
|
||||
|
||||
virtual int GetPinCount();
|
||||
virtual CBasePin *GetPin(int n);
|
||||
FILTER_STATE GetRealState();
|
||||
void SendRepaint();
|
||||
void SendNotifyWindow(IPin *pPin,HWND hwnd);
|
||||
BOOL OnDisplayChange();
|
||||
void SetRepaintStatus(BOOL bRepaint);
|
||||
|
||||
// Override the filter and pin interface functions
|
||||
|
||||
STDMETHODIMP Stop();
|
||||
STDMETHODIMP Pause();
|
||||
STDMETHODIMP Run(REFERENCE_TIME StartTime);
|
||||
STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State);
|
||||
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
|
||||
|
||||
// These are available for a quality management implementation
|
||||
|
||||
virtual void OnRenderStart(IMediaSample *pMediaSample);
|
||||
virtual void OnRenderEnd(IMediaSample *pMediaSample);
|
||||
virtual HRESULT OnStartStreaming() { return NOERROR; };
|
||||
virtual HRESULT OnStopStreaming() { return NOERROR; };
|
||||
virtual void OnWaitStart() { };
|
||||
virtual void OnWaitEnd() { };
|
||||
virtual void PrepareRender() { };
|
||||
|
||||
#ifdef PERF
|
||||
REFERENCE_TIME m_trRenderStart; // Just before we started drawing
|
||||
// Set in OnRenderStart, Used in OnRenderEnd
|
||||
int m_idBaseStamp; // MSR_id for frame time stamp
|
||||
int m_idBaseRenderTime; // MSR_id for true wait time
|
||||
int m_idBaseAccuracy; // MSR_id for time frame is late (int)
|
||||
#endif
|
||||
|
||||
// Quality management implementation for scheduling rendering
|
||||
|
||||
virtual BOOL ScheduleSample(IMediaSample *pMediaSample);
|
||||
virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *pStartTime,
|
||||
REFERENCE_TIME *pEndTime);
|
||||
|
||||
virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *ptrStart,
|
||||
REFERENCE_TIME *ptrEnd);
|
||||
|
||||
// Lots of end of stream complexities
|
||||
|
||||
void TimerCallback();
|
||||
void ResetEndOfStreamTimer();
|
||||
HRESULT NotifyEndOfStream();
|
||||
virtual HRESULT SendEndOfStream();
|
||||
virtual HRESULT ResetEndOfStream();
|
||||
virtual HRESULT EndOfStream();
|
||||
|
||||
// Rendering is based around the clock
|
||||
|
||||
void SignalTimerFired();
|
||||
virtual HRESULT CancelNotification();
|
||||
virtual HRESULT ClearPendingSample();
|
||||
|
||||
// Called when the filter changes state
|
||||
|
||||
virtual HRESULT Active();
|
||||
virtual HRESULT Inactive();
|
||||
virtual HRESULT StartStreaming();
|
||||
virtual HRESULT StopStreaming();
|
||||
virtual HRESULT BeginFlush();
|
||||
virtual HRESULT EndFlush();
|
||||
|
||||
// Deal with connections and type changes
|
||||
|
||||
virtual HRESULT BreakConnect();
|
||||
virtual HRESULT SetMediaType(const CMediaType *pmt);
|
||||
virtual HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// These look after the handling of data samples
|
||||
|
||||
virtual HRESULT PrepareReceive(IMediaSample *pMediaSample);
|
||||
virtual HRESULT Receive(IMediaSample *pMediaSample);
|
||||
virtual BOOL HaveCurrentSample();
|
||||
virtual IMediaSample *GetCurrentSample();
|
||||
virtual HRESULT Render(IMediaSample *pMediaSample);
|
||||
|
||||
// Derived classes MUST override these
|
||||
virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE;
|
||||
virtual HRESULT CheckMediaType(const CMediaType *) PURE;
|
||||
|
||||
// Helper
|
||||
void WaitForReceiveToComplete();
|
||||
};
|
||||
|
||||
|
||||
// CBaseVideoRenderer is a renderer class (see its ancestor class) and
|
||||
// it handles scheduling of media samples so that they are drawn at the
|
||||
// correct time by the reference clock. It implements a degradation
|
||||
// strategy. Possible degradation modes are:
|
||||
// Drop frames here (only useful if the drawing takes significant time)
|
||||
// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip.
|
||||
// Signal supplier to change the frame rate - i.e. ongoing skipping.
|
||||
// Or any combination of the above.
|
||||
// In order to determine what's useful to try we need to know what's going
|
||||
// on. This is done by timing various operations (including the supplier).
|
||||
// This timing is done by using timeGetTime as it is accurate enough and
|
||||
// usually cheaper than calling the reference clock. It also tells the
|
||||
// truth if there is an audio break and the reference clock stops.
|
||||
// We provide a number of public entry points (named OnXxxStart, OnXxxEnd)
|
||||
// which the rest of the renderer calls at significant moments. These do
|
||||
// the timing.
|
||||
|
||||
// the number of frames that the sliding averages are averaged over.
|
||||
// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
|
||||
#define AVGPERIOD 4
|
||||
#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
|
||||
// Spot the bug in this macro - I can't. but it doesn't work!
|
||||
|
||||
class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class
|
||||
public IQualProp, // Property page guff
|
||||
public IQualityControl // Allow throttling
|
||||
{
|
||||
protected:
|
||||
|
||||
// Hungarian:
|
||||
// tFoo is the time Foo in mSec (beware m_tStart from filter.h)
|
||||
// trBar is the time Bar by the reference clock
|
||||
|
||||
//******************************************************************
|
||||
// State variables to control synchronisation
|
||||
//******************************************************************
|
||||
|
||||
// Control of sending Quality messages. We need to know whether
|
||||
// we are in trouble (e.g. frames being dropped) and where the time
|
||||
// is being spent.
|
||||
|
||||
// When we drop a frame we play the next one early.
|
||||
// The frame after that is likely to wait before drawing and counting this
|
||||
// wait as spare time is unfair, so we count it as a zero wait.
|
||||
// We therefore need to know whether we are playing frames early or not.
|
||||
|
||||
int m_nNormal; // The number of consecutive frames
|
||||
// drawn at their normal time (not early)
|
||||
// -1 means we just dropped a frame.
|
||||
|
||||
#ifdef PERF
|
||||
BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm
|
||||
// not keen on people using it!)
|
||||
#endif
|
||||
|
||||
BOOL m_bSupplierHandlingQuality;// The response to Quality messages says
|
||||
// our supplier is handling things.
|
||||
// We will allow things to go extra late
|
||||
// before dropping frames. We will play
|
||||
// very early after he has dropped one.
|
||||
|
||||
// Control of scheduling, frame dropping etc.
|
||||
// We need to know where the time is being spent so as to tell whether
|
||||
// we should be taking action here, signalling supplier or what.
|
||||
// The variables are initialised to a mode of NOT dropping frames.
|
||||
// They will tell the truth after a few frames.
|
||||
// We typically record a start time for an event, later we get the time
|
||||
// again and subtract to get the elapsed time, and we average this over
|
||||
// a few frames. The average is used to tell what mode we are in.
|
||||
|
||||
// Although these are reference times (64 bit) they are all DIFFERENCES
|
||||
// between times which are small. An int will go up to 214 secs before
|
||||
// overflow. Avoiding 64 bit multiplications and divisions seems
|
||||
// worth while.
|
||||
|
||||
|
||||
|
||||
// Audio-video throttling. If the user has turned up audio quality
|
||||
// very high (in principle it could be any other stream, not just audio)
|
||||
// then we can receive cries for help via the graph manager. In this case
|
||||
// we put in a wait for some time after rendering each frame.
|
||||
int m_trThrottle;
|
||||
|
||||
// The time taken to render (i.e. BitBlt) frames controls which component
|
||||
// needs to degrade. If the blt is expensive, the renderer degrades.
|
||||
// If the blt is cheap it's done anyway and the supplier degrades.
|
||||
int m_trRenderAvg; // Time frames are taking to blt
|
||||
int m_trRenderLast; // Time for last frame blt
|
||||
int m_tRenderStart; // Just before we started drawing (mSec)
|
||||
// derived from timeGetTime.
|
||||
|
||||
// When frames are dropped we will play the next frame as early as we can.
|
||||
// If it was a false alarm and the machine is fast we slide gently back to
|
||||
// normal timing. To do this, we record the offset showing just how early
|
||||
// we really are. This will normally be negative meaning early or zero.
|
||||
int m_trEarliness;
|
||||
|
||||
// Target provides slow long-term feedback to try to reduce the
|
||||
// average sync offset to zero. Whenever a frame is actually rendered
|
||||
// early we add a msec or two, whenever late we take off a few.
|
||||
// We add or take off 1/32 of the error time.
|
||||
// Eventually we should be hovering around zero. For a really bad case
|
||||
// where we were (say) 300mSec off, it might take 100 odd frames to
|
||||
// settle down. The rate of change of this is intended to be slower
|
||||
// than any other mechanism in Quartz, thereby avoiding hunting.
|
||||
int m_trTarget;
|
||||
|
||||
// The proportion of time spent waiting for the right moment to blt
|
||||
// controls whether we bother to drop a frame or whether we reckon that
|
||||
// we're doing well enough that we can stand a one-frame glitch.
|
||||
int m_trWaitAvg; // Average of last few wait times
|
||||
// (actually we just average how early
|
||||
// we were). Negative here means LATE.
|
||||
|
||||
// The average inter-frame time.
|
||||
// This is used to calculate the proportion of the time used by the
|
||||
// three operations (supplying us, waiting, rendering)
|
||||
int m_trFrameAvg; // Average inter-frame time
|
||||
int m_trDuration; // duration of last frame.
|
||||
|
||||
#ifdef PERF
|
||||
// Performance logging identifiers
|
||||
int m_idTimeStamp; // MSR_id for frame time stamp
|
||||
int m_idEarliness; // MSR_id for earliness fudge
|
||||
int m_idTarget; // MSR_id for Target fudge
|
||||
int m_idWaitReal; // MSR_id for true wait time
|
||||
int m_idWait; // MSR_id for wait time recorded
|
||||
int m_idFrameAccuracy; // MSR_id for time frame is late (int)
|
||||
int m_idRenderAvg; // MSR_id for Render time recorded (int)
|
||||
int m_idSchLateTime; // MSR_id for lateness at scheduler
|
||||
int m_idQualityRate; // MSR_id for Quality rate requested
|
||||
int m_idQualityTime; // MSR_id for Quality time requested
|
||||
int m_idDecision; // MSR_id for decision code
|
||||
int m_idDuration; // MSR_id for duration of a frame
|
||||
int m_idThrottle; // MSR_id for audio-video throttling
|
||||
//int m_idDebug; // MSR_id for trace style debugging
|
||||
//int m_idSendQuality; // MSR_id for timing the notifications per se
|
||||
#endif // PERF
|
||||
REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame
|
||||
// with no earliness fudges etc.
|
||||
#ifdef PERF
|
||||
REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered
|
||||
|
||||
// debug...
|
||||
int m_idFrameAvg;
|
||||
int m_idWaitAvg;
|
||||
#endif
|
||||
|
||||
// PROPERTY PAGE
|
||||
// This has edit fields that show the user what's happening
|
||||
// These member variables hold these counts.
|
||||
|
||||
int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER
|
||||
int m_cFramesDrawn; // Frames since streaming started seen BY THE
|
||||
// RENDERER (some may be dropped upstream)
|
||||
|
||||
// Next two support average sync offset and standard deviation of sync offset.
|
||||
LONGLONG m_iTotAcc; // Sum of accuracies in mSec
|
||||
LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec)
|
||||
|
||||
// Next two allow jitter calculation. Jitter is std deviation of frame time.
|
||||
REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times)
|
||||
LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec)
|
||||
LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec
|
||||
|
||||
// To get performance statistics on frame rate, jitter etc, we need
|
||||
// to record the lateness and inter-frame time. What we actually need are the
|
||||
// data above (sum, sum of squares and number of entries for each) but the data
|
||||
// is generated just ahead of time and only later do we discover whether the
|
||||
// frame was actually drawn or not. So we have to hang on to the data
|
||||
int m_trLate; // hold onto frame lateness
|
||||
int m_trFrame; // hold onto inter-frame time
|
||||
|
||||
int m_tStreamingStart; // if streaming then time streaming started
|
||||
// else time of last streaming session
|
||||
// used for property page statistics
|
||||
#ifdef PERF
|
||||
LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
||||
CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer
|
||||
TCHAR *pName, // Debug ONLY description
|
||||
LPUNKNOWN pUnk, // Aggregated owner object
|
||||
HRESULT *phr); // General OLE return code
|
||||
|
||||
~CBaseVideoRenderer();
|
||||
|
||||
// IQualityControl methods - Notify allows audio-video throttling
|
||||
|
||||
STDMETHODIMP SetSink( IQualityControl * piqc);
|
||||
STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q);
|
||||
|
||||
// These provide a full video quality management implementation
|
||||
|
||||
void OnRenderStart(IMediaSample *pMediaSample);
|
||||
void OnRenderEnd(IMediaSample *pMediaSample);
|
||||
void OnWaitStart();
|
||||
void OnWaitEnd();
|
||||
HRESULT OnStartStreaming();
|
||||
HRESULT OnStopStreaming();
|
||||
void ThrottleWait();
|
||||
|
||||
// Handle the statistics gathering for our quality management
|
||||
|
||||
void PreparePerformanceData(int trLate, int trFrame);
|
||||
virtual void RecordFrameLateness(int trLate, int trFrame);
|
||||
virtual void OnDirectRender(IMediaSample *pMediaSample);
|
||||
virtual HRESULT ResetStreamingTimes();
|
||||
BOOL ScheduleSample(IMediaSample *pMediaSample);
|
||||
HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *ptrStart,
|
||||
REFERENCE_TIME *ptrEnd);
|
||||
|
||||
virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream);
|
||||
STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName);
|
||||
|
||||
//
|
||||
// Do estimates for standard deviations for per-frame
|
||||
// statistics
|
||||
//
|
||||
// *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
|
||||
// (m_cFramesDrawn - 2)
|
||||
// or 0 if m_cFramesDrawn <= 3
|
||||
//
|
||||
HRESULT GetStdDev(
|
||||
int nSamples,
|
||||
int *piResult,
|
||||
LONGLONG llSumSq,
|
||||
LONGLONG iTot
|
||||
);
|
||||
public:
|
||||
|
||||
// IQualProp property page support
|
||||
|
||||
STDMETHODIMP get_FramesDroppedInRenderer(int *cFramesDropped);
|
||||
STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn);
|
||||
STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate);
|
||||
STDMETHODIMP get_Jitter(int *piJitter);
|
||||
STDMETHODIMP get_AvgSyncOffset(int *piAvg);
|
||||
STDMETHODIMP get_DevSyncOffset(int *piDev);
|
||||
|
||||
// Implement an IUnknown interface and expose IQualProp
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,VOID **ppv);
|
||||
};
|
||||
|
||||
#endif // __RENBASE__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RenBase.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a generic ActiveX base renderer
|
||||
// class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __RENBASE__
|
||||
#define __RENBASE__
|
||||
|
||||
// Forward class declarations
|
||||
|
||||
class CBaseRenderer;
|
||||
class CBaseVideoRenderer;
|
||||
class CRendererInputPin;
|
||||
|
||||
// This is our input pin class that channels calls to the renderer
|
||||
|
||||
class CRendererInputPin : public CBaseInputPin
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseRenderer *m_pRenderer;
|
||||
|
||||
public:
|
||||
|
||||
CRendererInputPin(CBaseRenderer *pRenderer,
|
||||
HRESULT *phr,
|
||||
LPCWSTR Name);
|
||||
|
||||
// Overriden from the base pin classes
|
||||
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
HRESULT SetMediaType(const CMediaType *pmt);
|
||||
HRESULT CheckMediaType(const CMediaType *pmt);
|
||||
HRESULT Active();
|
||||
HRESULT Inactive();
|
||||
|
||||
// Add rendering behaviour to interface functions
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR *Id);
|
||||
STDMETHODIMP EndOfStream();
|
||||
STDMETHODIMP BeginFlush();
|
||||
STDMETHODIMP EndFlush();
|
||||
STDMETHODIMP Receive(IMediaSample *pMediaSample);
|
||||
|
||||
// Helper
|
||||
IMemAllocator inline *Allocator() const
|
||||
{
|
||||
return m_pAllocator;
|
||||
}
|
||||
};
|
||||
|
||||
// Main renderer class that handles synchronisation and state changes
|
||||
|
||||
class CBaseRenderer : public CBaseFilter
|
||||
{
|
||||
protected:
|
||||
|
||||
friend class CRendererInputPin;
|
||||
|
||||
friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier
|
||||
UINT uMsg, // Not currently used
|
||||
DWORD_PTR dwUser, // User information
|
||||
DWORD_PTR dw1, // Windows reserved
|
||||
DWORD_PTR dw2); // Is also reserved
|
||||
|
||||
CRendererPosPassThru *m_pPosition; // Media seeking pass by object
|
||||
CAMEvent m_RenderEvent; // Used to signal timer events
|
||||
CAMEvent m_ThreadSignal; // Signalled to release worker thread
|
||||
CAMEvent m_evComplete; // Signalled when state complete
|
||||
BOOL m_bAbort; // Stop us from rendering more data
|
||||
BOOL m_bStreaming; // Are we currently streaming
|
||||
DWORD_PTR m_dwAdvise; // Timer advise cookie
|
||||
IMediaSample *m_pMediaSample; // Current image media sample
|
||||
BOOL m_bEOS; // Any more samples in the stream
|
||||
BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE
|
||||
CRendererInputPin *m_pInputPin; // Our renderer input pin object
|
||||
CCritSec m_InterfaceLock; // Critical section for interfaces
|
||||
CCritSec m_RendererLock; // Controls access to internals
|
||||
IQualityControl * m_pQSink; // QualityControl sink
|
||||
BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT
|
||||
|
||||
// Avoid some deadlocks by tracking filter during stop
|
||||
volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive
|
||||
// And actually processing the sample
|
||||
REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE
|
||||
UINT m_EndOfStreamTimer; // Used to signal end of stream
|
||||
CCritSec m_ObjectCreationLock; // This lock protects the creation and
|
||||
// of m_pPosition and m_pInputPin. It
|
||||
// ensures that two threads cannot create
|
||||
// either object simultaneously.
|
||||
|
||||
public:
|
||||
|
||||
CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer
|
||||
TCHAR *pName, // Debug ONLY description
|
||||
LPUNKNOWN pUnk, // Aggregated owner object
|
||||
HRESULT *phr); // General OLE return code
|
||||
|
||||
~CBaseRenderer();
|
||||
|
||||
// Overriden to say what interfaces we support and where
|
||||
|
||||
virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv);
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
|
||||
|
||||
virtual HRESULT SourceThreadCanWait(BOOL bCanWait);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug only dump of the renderer state
|
||||
void DisplayRendererState();
|
||||
#endif
|
||||
virtual HRESULT WaitForRenderTime();
|
||||
virtual HRESULT CompleteStateChange(FILTER_STATE OldState);
|
||||
|
||||
// Return internal information about this filter
|
||||
|
||||
BOOL IsEndOfStream() { return m_bEOS; };
|
||||
BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; };
|
||||
BOOL IsStreaming() { return m_bStreaming; };
|
||||
void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; };
|
||||
virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { };
|
||||
CAMEvent *GetRenderEvent() { return &m_RenderEvent; };
|
||||
|
||||
// Permit access to the transition state
|
||||
|
||||
void Ready() { m_evComplete.Set(); };
|
||||
void NotReady() { m_evComplete.Reset(); };
|
||||
BOOL CheckReady() { return m_evComplete.Check(); };
|
||||
|
||||
virtual int GetPinCount();
|
||||
virtual CBasePin *GetPin(int n);
|
||||
FILTER_STATE GetRealState();
|
||||
void SendRepaint();
|
||||
void SendNotifyWindow(IPin *pPin,HWND hwnd);
|
||||
BOOL OnDisplayChange();
|
||||
void SetRepaintStatus(BOOL bRepaint);
|
||||
|
||||
// Override the filter and pin interface functions
|
||||
|
||||
STDMETHODIMP Stop();
|
||||
STDMETHODIMP Pause();
|
||||
STDMETHODIMP Run(REFERENCE_TIME StartTime);
|
||||
STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State);
|
||||
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
|
||||
|
||||
// These are available for a quality management implementation
|
||||
|
||||
virtual void OnRenderStart(IMediaSample *pMediaSample);
|
||||
virtual void OnRenderEnd(IMediaSample *pMediaSample);
|
||||
virtual HRESULT OnStartStreaming() { return NOERROR; };
|
||||
virtual HRESULT OnStopStreaming() { return NOERROR; };
|
||||
virtual void OnWaitStart() { };
|
||||
virtual void OnWaitEnd() { };
|
||||
virtual void PrepareRender() { };
|
||||
|
||||
#ifdef PERF
|
||||
REFERENCE_TIME m_trRenderStart; // Just before we started drawing
|
||||
// Set in OnRenderStart, Used in OnRenderEnd
|
||||
int m_idBaseStamp; // MSR_id for frame time stamp
|
||||
int m_idBaseRenderTime; // MSR_id for true wait time
|
||||
int m_idBaseAccuracy; // MSR_id for time frame is late (int)
|
||||
#endif
|
||||
|
||||
// Quality management implementation for scheduling rendering
|
||||
|
||||
virtual BOOL ScheduleSample(IMediaSample *pMediaSample);
|
||||
virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *pStartTime,
|
||||
REFERENCE_TIME *pEndTime);
|
||||
|
||||
virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *ptrStart,
|
||||
REFERENCE_TIME *ptrEnd);
|
||||
|
||||
// Lots of end of stream complexities
|
||||
|
||||
void TimerCallback();
|
||||
void ResetEndOfStreamTimer();
|
||||
HRESULT NotifyEndOfStream();
|
||||
virtual HRESULT SendEndOfStream();
|
||||
virtual HRESULT ResetEndOfStream();
|
||||
virtual HRESULT EndOfStream();
|
||||
|
||||
// Rendering is based around the clock
|
||||
|
||||
void SignalTimerFired();
|
||||
virtual HRESULT CancelNotification();
|
||||
virtual HRESULT ClearPendingSample();
|
||||
|
||||
// Called when the filter changes state
|
||||
|
||||
virtual HRESULT Active();
|
||||
virtual HRESULT Inactive();
|
||||
virtual HRESULT StartStreaming();
|
||||
virtual HRESULT StopStreaming();
|
||||
virtual HRESULT BeginFlush();
|
||||
virtual HRESULT EndFlush();
|
||||
|
||||
// Deal with connections and type changes
|
||||
|
||||
virtual HRESULT BreakConnect();
|
||||
virtual HRESULT SetMediaType(const CMediaType *pmt);
|
||||
virtual HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// These look after the handling of data samples
|
||||
|
||||
virtual HRESULT PrepareReceive(IMediaSample *pMediaSample);
|
||||
virtual HRESULT Receive(IMediaSample *pMediaSample);
|
||||
virtual BOOL HaveCurrentSample();
|
||||
virtual IMediaSample *GetCurrentSample();
|
||||
virtual HRESULT Render(IMediaSample *pMediaSample);
|
||||
|
||||
// Derived classes MUST override these
|
||||
virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE;
|
||||
virtual HRESULT CheckMediaType(const CMediaType *) PURE;
|
||||
|
||||
// Helper
|
||||
void WaitForReceiveToComplete();
|
||||
};
|
||||
|
||||
|
||||
// CBaseVideoRenderer is a renderer class (see its ancestor class) and
|
||||
// it handles scheduling of media samples so that they are drawn at the
|
||||
// correct time by the reference clock. It implements a degradation
|
||||
// strategy. Possible degradation modes are:
|
||||
// Drop frames here (only useful if the drawing takes significant time)
|
||||
// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip.
|
||||
// Signal supplier to change the frame rate - i.e. ongoing skipping.
|
||||
// Or any combination of the above.
|
||||
// In order to determine what's useful to try we need to know what's going
|
||||
// on. This is done by timing various operations (including the supplier).
|
||||
// This timing is done by using timeGetTime as it is accurate enough and
|
||||
// usually cheaper than calling the reference clock. It also tells the
|
||||
// truth if there is an audio break and the reference clock stops.
|
||||
// We provide a number of public entry points (named OnXxxStart, OnXxxEnd)
|
||||
// which the rest of the renderer calls at significant moments. These do
|
||||
// the timing.
|
||||
|
||||
// the number of frames that the sliding averages are averaged over.
|
||||
// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
|
||||
#define AVGPERIOD 4
|
||||
#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
|
||||
// Spot the bug in this macro - I can't. but it doesn't work!
|
||||
|
||||
class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class
|
||||
public IQualProp, // Property page guff
|
||||
public IQualityControl // Allow throttling
|
||||
{
|
||||
protected:
|
||||
|
||||
// Hungarian:
|
||||
// tFoo is the time Foo in mSec (beware m_tStart from filter.h)
|
||||
// trBar is the time Bar by the reference clock
|
||||
|
||||
//******************************************************************
|
||||
// State variables to control synchronisation
|
||||
//******************************************************************
|
||||
|
||||
// Control of sending Quality messages. We need to know whether
|
||||
// we are in trouble (e.g. frames being dropped) and where the time
|
||||
// is being spent.
|
||||
|
||||
// When we drop a frame we play the next one early.
|
||||
// The frame after that is likely to wait before drawing and counting this
|
||||
// wait as spare time is unfair, so we count it as a zero wait.
|
||||
// We therefore need to know whether we are playing frames early or not.
|
||||
|
||||
int m_nNormal; // The number of consecutive frames
|
||||
// drawn at their normal time (not early)
|
||||
// -1 means we just dropped a frame.
|
||||
|
||||
#ifdef PERF
|
||||
BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm
|
||||
// not keen on people using it!)
|
||||
#endif
|
||||
|
||||
BOOL m_bSupplierHandlingQuality;// The response to Quality messages says
|
||||
// our supplier is handling things.
|
||||
// We will allow things to go extra late
|
||||
// before dropping frames. We will play
|
||||
// very early after he has dropped one.
|
||||
|
||||
// Control of scheduling, frame dropping etc.
|
||||
// We need to know where the time is being spent so as to tell whether
|
||||
// we should be taking action here, signalling supplier or what.
|
||||
// The variables are initialised to a mode of NOT dropping frames.
|
||||
// They will tell the truth after a few frames.
|
||||
// We typically record a start time for an event, later we get the time
|
||||
// again and subtract to get the elapsed time, and we average this over
|
||||
// a few frames. The average is used to tell what mode we are in.
|
||||
|
||||
// Although these are reference times (64 bit) they are all DIFFERENCES
|
||||
// between times which are small. An int will go up to 214 secs before
|
||||
// overflow. Avoiding 64 bit multiplications and divisions seems
|
||||
// worth while.
|
||||
|
||||
|
||||
|
||||
// Audio-video throttling. If the user has turned up audio quality
|
||||
// very high (in principle it could be any other stream, not just audio)
|
||||
// then we can receive cries for help via the graph manager. In this case
|
||||
// we put in a wait for some time after rendering each frame.
|
||||
int m_trThrottle;
|
||||
|
||||
// The time taken to render (i.e. BitBlt) frames controls which component
|
||||
// needs to degrade. If the blt is expensive, the renderer degrades.
|
||||
// If the blt is cheap it's done anyway and the supplier degrades.
|
||||
int m_trRenderAvg; // Time frames are taking to blt
|
||||
int m_trRenderLast; // Time for last frame blt
|
||||
int m_tRenderStart; // Just before we started drawing (mSec)
|
||||
// derived from timeGetTime.
|
||||
|
||||
// When frames are dropped we will play the next frame as early as we can.
|
||||
// If it was a false alarm and the machine is fast we slide gently back to
|
||||
// normal timing. To do this, we record the offset showing just how early
|
||||
// we really are. This will normally be negative meaning early or zero.
|
||||
int m_trEarliness;
|
||||
|
||||
// Target provides slow long-term feedback to try to reduce the
|
||||
// average sync offset to zero. Whenever a frame is actually rendered
|
||||
// early we add a msec or two, whenever late we take off a few.
|
||||
// We add or take off 1/32 of the error time.
|
||||
// Eventually we should be hovering around zero. For a really bad case
|
||||
// where we were (say) 300mSec off, it might take 100 odd frames to
|
||||
// settle down. The rate of change of this is intended to be slower
|
||||
// than any other mechanism in Quartz, thereby avoiding hunting.
|
||||
int m_trTarget;
|
||||
|
||||
// The proportion of time spent waiting for the right moment to blt
|
||||
// controls whether we bother to drop a frame or whether we reckon that
|
||||
// we're doing well enough that we can stand a one-frame glitch.
|
||||
int m_trWaitAvg; // Average of last few wait times
|
||||
// (actually we just average how early
|
||||
// we were). Negative here means LATE.
|
||||
|
||||
// The average inter-frame time.
|
||||
// This is used to calculate the proportion of the time used by the
|
||||
// three operations (supplying us, waiting, rendering)
|
||||
int m_trFrameAvg; // Average inter-frame time
|
||||
int m_trDuration; // duration of last frame.
|
||||
|
||||
#ifdef PERF
|
||||
// Performance logging identifiers
|
||||
int m_idTimeStamp; // MSR_id for frame time stamp
|
||||
int m_idEarliness; // MSR_id for earliness fudge
|
||||
int m_idTarget; // MSR_id for Target fudge
|
||||
int m_idWaitReal; // MSR_id for true wait time
|
||||
int m_idWait; // MSR_id for wait time recorded
|
||||
int m_idFrameAccuracy; // MSR_id for time frame is late (int)
|
||||
int m_idRenderAvg; // MSR_id for Render time recorded (int)
|
||||
int m_idSchLateTime; // MSR_id for lateness at scheduler
|
||||
int m_idQualityRate; // MSR_id for Quality rate requested
|
||||
int m_idQualityTime; // MSR_id for Quality time requested
|
||||
int m_idDecision; // MSR_id for decision code
|
||||
int m_idDuration; // MSR_id for duration of a frame
|
||||
int m_idThrottle; // MSR_id for audio-video throttling
|
||||
//int m_idDebug; // MSR_id for trace style debugging
|
||||
//int m_idSendQuality; // MSR_id for timing the notifications per se
|
||||
#endif // PERF
|
||||
REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame
|
||||
// with no earliness fudges etc.
|
||||
#ifdef PERF
|
||||
REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered
|
||||
|
||||
// debug...
|
||||
int m_idFrameAvg;
|
||||
int m_idWaitAvg;
|
||||
#endif
|
||||
|
||||
// PROPERTY PAGE
|
||||
// This has edit fields that show the user what's happening
|
||||
// These member variables hold these counts.
|
||||
|
||||
int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER
|
||||
int m_cFramesDrawn; // Frames since streaming started seen BY THE
|
||||
// RENDERER (some may be dropped upstream)
|
||||
|
||||
// Next two support average sync offset and standard deviation of sync offset.
|
||||
LONGLONG m_iTotAcc; // Sum of accuracies in mSec
|
||||
LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec)
|
||||
|
||||
// Next two allow jitter calculation. Jitter is std deviation of frame time.
|
||||
REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times)
|
||||
LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec)
|
||||
LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec
|
||||
|
||||
// To get performance statistics on frame rate, jitter etc, we need
|
||||
// to record the lateness and inter-frame time. What we actually need are the
|
||||
// data above (sum, sum of squares and number of entries for each) but the data
|
||||
// is generated just ahead of time and only later do we discover whether the
|
||||
// frame was actually drawn or not. So we have to hang on to the data
|
||||
int m_trLate; // hold onto frame lateness
|
||||
int m_trFrame; // hold onto inter-frame time
|
||||
|
||||
int m_tStreamingStart; // if streaming then time streaming started
|
||||
// else time of last streaming session
|
||||
// used for property page statistics
|
||||
#ifdef PERF
|
||||
LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
||||
CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer
|
||||
TCHAR *pName, // Debug ONLY description
|
||||
LPUNKNOWN pUnk, // Aggregated owner object
|
||||
HRESULT *phr); // General OLE return code
|
||||
|
||||
~CBaseVideoRenderer();
|
||||
|
||||
// IQualityControl methods - Notify allows audio-video throttling
|
||||
|
||||
STDMETHODIMP SetSink( IQualityControl * piqc);
|
||||
STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q);
|
||||
|
||||
// These provide a full video quality management implementation
|
||||
|
||||
void OnRenderStart(IMediaSample *pMediaSample);
|
||||
void OnRenderEnd(IMediaSample *pMediaSample);
|
||||
void OnWaitStart();
|
||||
void OnWaitEnd();
|
||||
HRESULT OnStartStreaming();
|
||||
HRESULT OnStopStreaming();
|
||||
void ThrottleWait();
|
||||
|
||||
// Handle the statistics gathering for our quality management
|
||||
|
||||
void PreparePerformanceData(int trLate, int trFrame);
|
||||
virtual void RecordFrameLateness(int trLate, int trFrame);
|
||||
virtual void OnDirectRender(IMediaSample *pMediaSample);
|
||||
virtual HRESULT ResetStreamingTimes();
|
||||
BOOL ScheduleSample(IMediaSample *pMediaSample);
|
||||
HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *ptrStart,
|
||||
REFERENCE_TIME *ptrEnd);
|
||||
|
||||
virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream);
|
||||
STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName);
|
||||
|
||||
//
|
||||
// Do estimates for standard deviations for per-frame
|
||||
// statistics
|
||||
//
|
||||
// *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
|
||||
// (m_cFramesDrawn - 2)
|
||||
// or 0 if m_cFramesDrawn <= 3
|
||||
//
|
||||
HRESULT GetStdDev(
|
||||
int nSamples,
|
||||
int *piResult,
|
||||
LONGLONG llSumSq,
|
||||
LONGLONG iTot
|
||||
);
|
||||
public:
|
||||
|
||||
// IQualProp property page support
|
||||
|
||||
STDMETHODIMP get_FramesDroppedInRenderer(int *cFramesDropped);
|
||||
STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn);
|
||||
STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate);
|
||||
STDMETHODIMP get_Jitter(int *piJitter);
|
||||
STDMETHODIMP get_AvgSyncOffset(int *piAvg);
|
||||
STDMETHODIMP get_DevSyncOffset(int *piDev);
|
||||
|
||||
// Implement an IUnknown interface and expose IQualProp
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,VOID **ppv);
|
||||
};
|
||||
|
||||
#endif // __RENBASE__
|
||||
|
||||
|
||||
+265
-265
@@ -1,265 +1,265 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Schedule.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#pragma warning(disable:4706) // C4706: assignment within conditional expression
|
||||
|
||||
// DbgLog values (all on LOG_TIMING):
|
||||
//
|
||||
// 2 for schedulting, firing and shunting of events
|
||||
// 3 for wait delays and wake-up times of event thread
|
||||
// 4 for details of whats on the list when the thread awakes
|
||||
|
||||
/* Construct & destructors */
|
||||
|
||||
CAMSchedule::CAMSchedule( HANDLE ev )
|
||||
: CBaseObject(TEXT("CAMSchedule"))
|
||||
, head(&z, 0), z(0, MAX_TIME)
|
||||
, m_dwNextCookie(0), m_dwAdviseCount(0)
|
||||
, m_pAdviseCache(0), m_dwCacheCount(0)
|
||||
, m_ev( ev ) {
|
||||
head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
|
||||
}
|
||||
|
||||
CAMSchedule::~CAMSchedule() {
|
||||
m_Serialize.Lock();
|
||||
|
||||
// Delete cache
|
||||
CAdvisePacket * p = m_pAdviseCache;
|
||||
while(p) {
|
||||
CAdvisePacket *const p_next = p->m_next;
|
||||
delete p;
|
||||
p = p_next;
|
||||
}
|
||||
|
||||
ASSERT(m_dwAdviseCount == 0);
|
||||
// Better to be safe than sorry
|
||||
if(m_dwAdviseCount > 0) {
|
||||
DumpLinkedList();
|
||||
while(!head.m_next->IsZ()) {
|
||||
head.DeleteNext();
|
||||
--m_dwAdviseCount;
|
||||
}
|
||||
}
|
||||
|
||||
// If, in the debug version, we assert twice, it means, not only
|
||||
// did we have left over advises, but we have also let m_dwAdviseCount
|
||||
// get out of sync. with the number of advises actually on the list.
|
||||
ASSERT(m_dwAdviseCount == 0);
|
||||
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
|
||||
/* Public methods */
|
||||
|
||||
DWORD CAMSchedule::GetAdviseCount() {
|
||||
// No need to lock, m_dwAdviseCount is 32bits & declared volatile
|
||||
return m_dwAdviseCount;
|
||||
}
|
||||
|
||||
REFERENCE_TIME CAMSchedule::GetNextAdviseTime() {
|
||||
CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing
|
||||
return head.m_next->m_rtEventTime;
|
||||
}
|
||||
|
||||
DWORD_PTR CAMSchedule::AddAdvisePacket
|
||||
( const REFERENCE_TIME & time1
|
||||
, const REFERENCE_TIME & time2
|
||||
, HANDLE h, BOOL periodic
|
||||
) {
|
||||
// Since we use MAX_TIME as a sentry, we can't afford to
|
||||
// schedule a notification at MAX_TIME
|
||||
ASSERT(time1 < MAX_TIME);
|
||||
DWORD_PTR Result;
|
||||
CAdvisePacket * p;
|
||||
|
||||
m_Serialize.Lock();
|
||||
|
||||
if(m_pAdviseCache) {
|
||||
p = m_pAdviseCache;
|
||||
m_pAdviseCache = p->m_next;
|
||||
--m_dwCacheCount;
|
||||
}
|
||||
else {
|
||||
p = new CAdvisePacket();
|
||||
}
|
||||
if(p) {
|
||||
p->m_rtEventTime = time1; p->m_rtPeriod = time2;
|
||||
p->m_hNotify = h; p->m_bPeriodic = periodic;
|
||||
Result = AddAdvisePacket(p);
|
||||
}
|
||||
else Result = 0;
|
||||
|
||||
m_Serialize.Unlock();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) {
|
||||
HRESULT hr = S_FALSE;
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
m_Serialize.Lock();
|
||||
while(p_n = p_prev->Next()) // The Next() method returns NULL when it hits z
|
||||
{
|
||||
if(p_n->m_dwAdviseCookie == dwAdviseCookie) {
|
||||
Delete(p_prev->RemoveNext());
|
||||
--m_dwAdviseCount;
|
||||
hr = S_OK;
|
||||
// Having found one cookie that matches, there should be no more
|
||||
#ifdef DEBUG
|
||||
while(p_n = p_prev->Next()) {
|
||||
ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
|
||||
p_prev = p_n;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
p_prev = p_n;
|
||||
};
|
||||
m_Serialize.Unlock();
|
||||
return hr;
|
||||
}
|
||||
|
||||
REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) {
|
||||
REFERENCE_TIME rtNextTime;
|
||||
CAdvisePacket * pAdvise;
|
||||
|
||||
DbgLog((LOG_TIMING, 2,
|
||||
TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
|
||||
|
||||
CAutoLock lck(&m_Serialize);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList();
|
||||
#endif
|
||||
|
||||
// Note - DON'T cache the difference, it might overflow
|
||||
while(rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
|
||||
!pAdvise->IsZ()) {
|
||||
ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!!
|
||||
|
||||
ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
|
||||
|
||||
if(pAdvise->m_bPeriodic == TRUE) {
|
||||
ReleaseSemaphore(pAdvise->m_hNotify,1,NULL);
|
||||
pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
|
||||
ShuntHead();
|
||||
}
|
||||
else {
|
||||
ASSERT(pAdvise->m_bPeriodic == FALSE);
|
||||
EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
|
||||
--m_dwAdviseCount;
|
||||
Delete(head.RemoveNext());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DbgLog((LOG_TIMING, 3,
|
||||
TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."),
|
||||
DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie ));
|
||||
|
||||
return rtNextTime;
|
||||
}
|
||||
|
||||
/* Private methods */
|
||||
|
||||
DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket ) {
|
||||
ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
|
||||
ASSERT(CritCheckIn(&m_Serialize));
|
||||
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
|
||||
const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie;
|
||||
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
||||
for(;;p_prev = p_n)
|
||||
{
|
||||
p_n = p_prev->m_next;
|
||||
if(p_n->m_rtEventTime >= pPacket->m_rtEventTime)
|
||||
break;
|
||||
}
|
||||
p_prev->InsertAfter( pPacket );
|
||||
++m_dwAdviseCount;
|
||||
|
||||
DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"),
|
||||
pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
||||
|
||||
// If packet added at the head, then clock needs to re-evaluate wait time.
|
||||
if(p_prev == &head) SetEvent(m_ev);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void CAMSchedule::Delete( CAdvisePacket * pPacket ) {
|
||||
if(m_dwCacheCount >= dwCacheMax) delete pPacket;
|
||||
else {
|
||||
m_Serialize.Lock();
|
||||
pPacket->m_next = m_pAdviseCache;
|
||||
m_pAdviseCache = pPacket;
|
||||
++m_dwCacheCount;
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Takes the head of the list & repositions it
|
||||
void CAMSchedule::ShuntHead() {
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
|
||||
m_Serialize.Lock();
|
||||
CAdvisePacket *const pPacket = head.m_next;
|
||||
|
||||
// This will catch both an empty list,
|
||||
// and if somehow a MAX_TIME time gets into the list
|
||||
// (which would also break this method).
|
||||
ASSERT(pPacket->m_rtEventTime < MAX_TIME);
|
||||
|
||||
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
||||
for(;;p_prev = p_n)
|
||||
{
|
||||
p_n = p_prev->m_next;
|
||||
if(p_n->m_rtEventTime > pPacket->m_rtEventTime)
|
||||
break;
|
||||
}
|
||||
|
||||
// If p_prev == pPacket then we're already in the right place
|
||||
if(p_prev != pPacket)
|
||||
{
|
||||
head.m_next = pPacket->m_next;
|
||||
(p_prev->m_next = pPacket)->m_next = p_n;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"),
|
||||
pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
||||
#endif
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void CAMSchedule::DumpLinkedList() {
|
||||
m_Serialize.Lock();
|
||||
int i=0;
|
||||
DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this));
|
||||
for(CAdvisePacket * p = &head
|
||||
; p
|
||||
; p = p->m_next , i++) {
|
||||
DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
|
||||
i,
|
||||
p->m_dwAdviseCookie,
|
||||
p->m_rtEventTime / (UNITS / MILLISECONDS)
|
||||
));
|
||||
}
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Schedule.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#pragma warning(disable:4706) // C4706: assignment within conditional expression
|
||||
|
||||
// DbgLog values (all on LOG_TIMING):
|
||||
//
|
||||
// 2 for schedulting, firing and shunting of events
|
||||
// 3 for wait delays and wake-up times of event thread
|
||||
// 4 for details of whats on the list when the thread awakes
|
||||
|
||||
/* Construct & destructors */
|
||||
|
||||
CAMSchedule::CAMSchedule( HANDLE ev )
|
||||
: CBaseObject(TEXT("CAMSchedule"))
|
||||
, head(&z, 0), z(0, MAX_TIME)
|
||||
, m_dwNextCookie(0), m_dwAdviseCount(0)
|
||||
, m_pAdviseCache(0), m_dwCacheCount(0)
|
||||
, m_ev( ev ) {
|
||||
head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
|
||||
}
|
||||
|
||||
CAMSchedule::~CAMSchedule() {
|
||||
m_Serialize.Lock();
|
||||
|
||||
// Delete cache
|
||||
CAdvisePacket * p = m_pAdviseCache;
|
||||
while(p) {
|
||||
CAdvisePacket *const p_next = p->m_next;
|
||||
delete p;
|
||||
p = p_next;
|
||||
}
|
||||
|
||||
ASSERT(m_dwAdviseCount == 0);
|
||||
// Better to be safe than sorry
|
||||
if(m_dwAdviseCount > 0) {
|
||||
DumpLinkedList();
|
||||
while(!head.m_next->IsZ()) {
|
||||
head.DeleteNext();
|
||||
--m_dwAdviseCount;
|
||||
}
|
||||
}
|
||||
|
||||
// If, in the debug version, we assert twice, it means, not only
|
||||
// did we have left over advises, but we have also let m_dwAdviseCount
|
||||
// get out of sync. with the number of advises actually on the list.
|
||||
ASSERT(m_dwAdviseCount == 0);
|
||||
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
|
||||
/* Public methods */
|
||||
|
||||
DWORD CAMSchedule::GetAdviseCount() {
|
||||
// No need to lock, m_dwAdviseCount is 32bits & declared volatile
|
||||
return m_dwAdviseCount;
|
||||
}
|
||||
|
||||
REFERENCE_TIME CAMSchedule::GetNextAdviseTime() {
|
||||
CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing
|
||||
return head.m_next->m_rtEventTime;
|
||||
}
|
||||
|
||||
DWORD_PTR CAMSchedule::AddAdvisePacket
|
||||
( const REFERENCE_TIME & time1
|
||||
, const REFERENCE_TIME & time2
|
||||
, HANDLE h, BOOL periodic
|
||||
) {
|
||||
// Since we use MAX_TIME as a sentry, we can't afford to
|
||||
// schedule a notification at MAX_TIME
|
||||
ASSERT(time1 < MAX_TIME);
|
||||
DWORD_PTR Result;
|
||||
CAdvisePacket * p;
|
||||
|
||||
m_Serialize.Lock();
|
||||
|
||||
if(m_pAdviseCache) {
|
||||
p = m_pAdviseCache;
|
||||
m_pAdviseCache = p->m_next;
|
||||
--m_dwCacheCount;
|
||||
}
|
||||
else {
|
||||
p = new CAdvisePacket();
|
||||
}
|
||||
if(p) {
|
||||
p->m_rtEventTime = time1; p->m_rtPeriod = time2;
|
||||
p->m_hNotify = h; p->m_bPeriodic = periodic;
|
||||
Result = AddAdvisePacket(p);
|
||||
}
|
||||
else Result = 0;
|
||||
|
||||
m_Serialize.Unlock();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) {
|
||||
HRESULT hr = S_FALSE;
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
m_Serialize.Lock();
|
||||
while(p_n = p_prev->Next()) // The Next() method returns NULL when it hits z
|
||||
{
|
||||
if(p_n->m_dwAdviseCookie == dwAdviseCookie) {
|
||||
Delete(p_prev->RemoveNext());
|
||||
--m_dwAdviseCount;
|
||||
hr = S_OK;
|
||||
// Having found one cookie that matches, there should be no more
|
||||
#ifdef DEBUG
|
||||
while(p_n = p_prev->Next()) {
|
||||
ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
|
||||
p_prev = p_n;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
p_prev = p_n;
|
||||
};
|
||||
m_Serialize.Unlock();
|
||||
return hr;
|
||||
}
|
||||
|
||||
REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) {
|
||||
REFERENCE_TIME rtNextTime;
|
||||
CAdvisePacket * pAdvise;
|
||||
|
||||
DbgLog((LOG_TIMING, 2,
|
||||
TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
|
||||
|
||||
CAutoLock lck(&m_Serialize);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList();
|
||||
#endif
|
||||
|
||||
// Note - DON'T cache the difference, it might overflow
|
||||
while(rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
|
||||
!pAdvise->IsZ()) {
|
||||
ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!!
|
||||
|
||||
ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
|
||||
|
||||
if(pAdvise->m_bPeriodic == TRUE) {
|
||||
ReleaseSemaphore(pAdvise->m_hNotify,1,NULL);
|
||||
pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
|
||||
ShuntHead();
|
||||
}
|
||||
else {
|
||||
ASSERT(pAdvise->m_bPeriodic == FALSE);
|
||||
EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
|
||||
--m_dwAdviseCount;
|
||||
Delete(head.RemoveNext());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DbgLog((LOG_TIMING, 3,
|
||||
TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."),
|
||||
DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie ));
|
||||
|
||||
return rtNextTime;
|
||||
}
|
||||
|
||||
/* Private methods */
|
||||
|
||||
DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket ) {
|
||||
ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
|
||||
ASSERT(CritCheckIn(&m_Serialize));
|
||||
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
|
||||
const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie;
|
||||
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
||||
for(;;p_prev = p_n)
|
||||
{
|
||||
p_n = p_prev->m_next;
|
||||
if(p_n->m_rtEventTime >= pPacket->m_rtEventTime)
|
||||
break;
|
||||
}
|
||||
p_prev->InsertAfter( pPacket );
|
||||
++m_dwAdviseCount;
|
||||
|
||||
DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"),
|
||||
pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
||||
|
||||
// If packet added at the head, then clock needs to re-evaluate wait time.
|
||||
if(p_prev == &head) SetEvent(m_ev);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void CAMSchedule::Delete( CAdvisePacket * pPacket ) {
|
||||
if(m_dwCacheCount >= dwCacheMax) delete pPacket;
|
||||
else {
|
||||
m_Serialize.Lock();
|
||||
pPacket->m_next = m_pAdviseCache;
|
||||
m_pAdviseCache = pPacket;
|
||||
++m_dwCacheCount;
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Takes the head of the list & repositions it
|
||||
void CAMSchedule::ShuntHead() {
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
|
||||
m_Serialize.Lock();
|
||||
CAdvisePacket *const pPacket = head.m_next;
|
||||
|
||||
// This will catch both an empty list,
|
||||
// and if somehow a MAX_TIME time gets into the list
|
||||
// (which would also break this method).
|
||||
ASSERT(pPacket->m_rtEventTime < MAX_TIME);
|
||||
|
||||
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
||||
for(;;p_prev = p_n)
|
||||
{
|
||||
p_n = p_prev->m_next;
|
||||
if(p_n->m_rtEventTime > pPacket->m_rtEventTime)
|
||||
break;
|
||||
}
|
||||
|
||||
// If p_prev == pPacket then we're already in the right place
|
||||
if(p_prev != pPacket)
|
||||
{
|
||||
head.m_next = pPacket->m_next;
|
||||
(p_prev->m_next = pPacket)->m_next = p_n;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"),
|
||||
pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
||||
#endif
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void CAMSchedule::DumpLinkedList() {
|
||||
m_Serialize.Lock();
|
||||
int i=0;
|
||||
DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this));
|
||||
for(CAdvisePacket * p = &head
|
||||
; p
|
||||
; p = p->m_next , i++) {
|
||||
DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
|
||||
i,
|
||||
p->m_dwAdviseCookie,
|
||||
p->m_rtEventTime / (UNITS / MILLISECONDS)
|
||||
));
|
||||
}
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+83
-83
@@ -1,83 +1,83 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SeekPT.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include "seekpt.h"
|
||||
|
||||
//==================================================================
|
||||
// CreateInstance
|
||||
// This goes in the factory template table to create new instances
|
||||
// If there is already a mapper instance - return that, else make one
|
||||
// and save it in a static variable so that forever after we can return that.
|
||||
//==================================================================
|
||||
|
||||
CUnknown * CSeekingPassThru::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
|
||||
{
|
||||
return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
if (riid == IID_ISeekingPassThru) {
|
||||
return GetInterface((ISeekingPassThru *) this, ppv);
|
||||
} else {
|
||||
if (m_pPosPassThru &&
|
||||
(riid == IID_IMediaSeeking ||
|
||||
riid == IID_IMediaPosition)) {
|
||||
return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr )
|
||||
: CUnknown(pName, pUnk, phr),
|
||||
m_pPosPassThru(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CSeekingPassThru::~CSeekingPassThru()
|
||||
{
|
||||
delete m_pPosPassThru;
|
||||
}
|
||||
|
||||
STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin)
|
||||
{
|
||||
HRESULT hr = NOERROR;
|
||||
if (m_pPosPassThru) {
|
||||
hr = E_FAIL;
|
||||
} else {
|
||||
m_pPosPassThru =
|
||||
bRendererSeeking ?
|
||||
new CRendererPosPassThru(
|
||||
NAME("Render Seeking COM object"),
|
||||
(IUnknown *)this,
|
||||
&hr,
|
||||
pPin) :
|
||||
new CPosPassThru(
|
||||
NAME("Render Seeking COM object"),
|
||||
(IUnknown *)this,
|
||||
&hr,
|
||||
pPin);
|
||||
if (!m_pPosPassThru) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
} else {
|
||||
if (FAILED(hr)) {
|
||||
delete m_pPosPassThru;
|
||||
m_pPosPassThru = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SeekPT.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include "seekpt.h"
|
||||
|
||||
//==================================================================
|
||||
// CreateInstance
|
||||
// This goes in the factory template table to create new instances
|
||||
// If there is already a mapper instance - return that, else make one
|
||||
// and save it in a static variable so that forever after we can return that.
|
||||
//==================================================================
|
||||
|
||||
CUnknown * CSeekingPassThru::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
|
||||
{
|
||||
return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
if (riid == IID_ISeekingPassThru) {
|
||||
return GetInterface((ISeekingPassThru *) this, ppv);
|
||||
} else {
|
||||
if (m_pPosPassThru &&
|
||||
(riid == IID_IMediaSeeking ||
|
||||
riid == IID_IMediaPosition)) {
|
||||
return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr )
|
||||
: CUnknown(pName, pUnk, phr),
|
||||
m_pPosPassThru(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CSeekingPassThru::~CSeekingPassThru()
|
||||
{
|
||||
delete m_pPosPassThru;
|
||||
}
|
||||
|
||||
STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin)
|
||||
{
|
||||
HRESULT hr = NOERROR;
|
||||
if (m_pPosPassThru) {
|
||||
hr = E_FAIL;
|
||||
} else {
|
||||
m_pPosPassThru =
|
||||
bRendererSeeking ?
|
||||
new CRendererPosPassThru(
|
||||
NAME("Render Seeking COM object"),
|
||||
(IUnknown *)this,
|
||||
&hr,
|
||||
pPin) :
|
||||
new CPosPassThru(
|
||||
NAME("Render Seeking COM object"),
|
||||
(IUnknown *)this,
|
||||
&hr,
|
||||
pPin);
|
||||
if (!m_pPosPassThru) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
} else {
|
||||
if (FAILED(hr)) {
|
||||
delete m_pPosPassThru;
|
||||
m_pPosPassThru = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
+30
-30
@@ -1,30 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SeekPT.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __seekpt_h__
|
||||
#define __seekpt_h__
|
||||
|
||||
|
||||
class CSeekingPassThru : public ISeekingPassThru, public CUnknown
|
||||
{
|
||||
public:
|
||||
static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
|
||||
~CSeekingPassThru();
|
||||
|
||||
DECLARE_IUNKNOWN;
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
|
||||
|
||||
STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin);
|
||||
|
||||
private:
|
||||
CPosPassThru *m_pPosPassThru;
|
||||
};
|
||||
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SeekPT.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __seekpt_h__
|
||||
#define __seekpt_h__
|
||||
|
||||
|
||||
class CSeekingPassThru : public ISeekingPassThru, public CUnknown
|
||||
{
|
||||
public:
|
||||
static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
|
||||
~CSeekingPassThru();
|
||||
|
||||
DECLARE_IUNKNOWN;
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
|
||||
|
||||
STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin);
|
||||
|
||||
private:
|
||||
CPosPassThru *m_pPosPassThru;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+519
-519
File diff suppressed because it is too large
Load Diff
+172
-172
@@ -1,172 +1,172 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Source.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes to simplify creation of
|
||||
// ActiveX source filters that support continuous generation of data.
|
||||
// No support is provided for IMediaControl or IMediaPosition.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// Derive your source filter from CSource.
|
||||
// During construction either:
|
||||
// Create some CSourceStream objects to manage your pins
|
||||
// Provide the user with a means of doing so eg, an IPersistFile interface.
|
||||
//
|
||||
// CSource provides:
|
||||
// IBaseFilter interface management
|
||||
// IMediaFilter interface management, via CBaseFilter
|
||||
// Pin counting for CBaseFilter
|
||||
//
|
||||
// Derive a class from CSourceStream to manage your output pin types
|
||||
// Implement GetMediaType/1 to return the type you support. If you support multiple
|
||||
// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount.
|
||||
// Implement Fillbuffer() to put data into one buffer.
|
||||
//
|
||||
// CSourceStream provides:
|
||||
// IPin management via CBaseOutputPin
|
||||
// Worker thread management
|
||||
|
||||
#ifndef __CSOURCE__
|
||||
#define __CSOURCE__
|
||||
|
||||
class CSourceStream; // The class that will handle each pin
|
||||
|
||||
|
||||
//
|
||||
// CSource
|
||||
//
|
||||
// Override construction to provide a means of creating
|
||||
// CSourceStream derived objects - ie a way of creating pins.
|
||||
class CSource : public CBaseFilter {
|
||||
public:
|
||||
|
||||
CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
|
||||
CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
|
||||
#ifdef UNICODE
|
||||
CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
|
||||
CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
|
||||
#endif
|
||||
~CSource();
|
||||
|
||||
int GetPinCount(void);
|
||||
CBasePin *GetPin(int n);
|
||||
|
||||
// -- Utilities --
|
||||
|
||||
CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section
|
||||
|
||||
HRESULT AddPin(CSourceStream *);
|
||||
HRESULT RemovePin(CSourceStream *);
|
||||
|
||||
STDMETHODIMP FindPin(
|
||||
LPCWSTR Id,
|
||||
IPin ** ppPin
|
||||
);
|
||||
|
||||
int FindPinNumber(IPin *iPin);
|
||||
|
||||
protected:
|
||||
|
||||
int m_iPins; // The number of pins on this filter. Updated by CSourceStream
|
||||
// constructors & destructors.
|
||||
CSourceStream **m_paStreams; // the pins on this filter.
|
||||
|
||||
CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CSourceStream
|
||||
//
|
||||
// Use this class to manage a stream of data that comes from a
|
||||
// pin.
|
||||
// Uses a worker thread to put data on the pin.
|
||||
class CSourceStream : public CAMThread, public CBaseOutputPin {
|
||||
public:
|
||||
|
||||
CSourceStream(TCHAR *pObjectName,
|
||||
HRESULT *phr,
|
||||
CSource *pms,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CSourceStream(CHAR *pObjectName,
|
||||
HRESULT *phr,
|
||||
CSource *pms,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too.
|
||||
|
||||
protected:
|
||||
|
||||
CSource *m_pFilter; // The parent of this stream
|
||||
|
||||
// *
|
||||
// * Data Source
|
||||
// *
|
||||
// * The following three functions: FillBuffer, OnThreadCreate/Destroy, are
|
||||
// * called from within the ThreadProc. They are used in the creation of
|
||||
// * the media samples this pin will provide
|
||||
// *
|
||||
|
||||
// Override this to provide the worker thread a means
|
||||
// of processing a buffer
|
||||
virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE;
|
||||
|
||||
// Called as the thread is created/destroyed - use to perform
|
||||
// jobs such as start/stop streaming mode
|
||||
// If OnThreadCreate returns an error the thread will exit.
|
||||
virtual HRESULT OnThreadCreate(void) {return NOERROR;};
|
||||
virtual HRESULT OnThreadDestroy(void) {return NOERROR;};
|
||||
virtual HRESULT OnThreadStartPlay(void) {return NOERROR;};
|
||||
|
||||
// *
|
||||
// * Worker Thread
|
||||
// *
|
||||
|
||||
HRESULT Active(void); // Starts up the worker thread
|
||||
HRESULT Inactive(void); // Exits the worker thread.
|
||||
|
||||
public:
|
||||
// thread commands
|
||||
enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT};
|
||||
HRESULT Init(void) { return CallWorker(CMD_INIT); }
|
||||
HRESULT Exit(void) { return CallWorker(CMD_EXIT); }
|
||||
HRESULT Run(void) { return CallWorker(CMD_RUN); }
|
||||
HRESULT Pause(void) { return CallWorker(CMD_PAUSE); }
|
||||
HRESULT Stop(void) { return CallWorker(CMD_STOP); }
|
||||
|
||||
protected:
|
||||
Command GetRequest(void) { return (Command) CAMThread::GetRequest(); }
|
||||
BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); }
|
||||
|
||||
// override these if you want to add thread commands
|
||||
virtual DWORD ThreadProc(void); // the thread function
|
||||
|
||||
virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running
|
||||
|
||||
|
||||
// *
|
||||
// * AM_MEDIA_TYPE support
|
||||
// *
|
||||
|
||||
// If you support more than one media type then override these 2 functions
|
||||
virtual HRESULT CheckMediaType(const CMediaType *pMediaType);
|
||||
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); // List pos. 0-n
|
||||
|
||||
// If you support only one type then override this fn.
|
||||
// This will only be called by the default implementations
|
||||
// of CheckMediaType and GetMediaType(int, CMediaType*)
|
||||
// You must override this fn. or the above 2!
|
||||
virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;}
|
||||
|
||||
STDMETHODIMP QueryId(
|
||||
LPWSTR * Id
|
||||
);
|
||||
};
|
||||
|
||||
#endif // __CSOURCE__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Source.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes to simplify creation of
|
||||
// ActiveX source filters that support continuous generation of data.
|
||||
// No support is provided for IMediaControl or IMediaPosition.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// Derive your source filter from CSource.
|
||||
// During construction either:
|
||||
// Create some CSourceStream objects to manage your pins
|
||||
// Provide the user with a means of doing so eg, an IPersistFile interface.
|
||||
//
|
||||
// CSource provides:
|
||||
// IBaseFilter interface management
|
||||
// IMediaFilter interface management, via CBaseFilter
|
||||
// Pin counting for CBaseFilter
|
||||
//
|
||||
// Derive a class from CSourceStream to manage your output pin types
|
||||
// Implement GetMediaType/1 to return the type you support. If you support multiple
|
||||
// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount.
|
||||
// Implement Fillbuffer() to put data into one buffer.
|
||||
//
|
||||
// CSourceStream provides:
|
||||
// IPin management via CBaseOutputPin
|
||||
// Worker thread management
|
||||
|
||||
#ifndef __CSOURCE__
|
||||
#define __CSOURCE__
|
||||
|
||||
class CSourceStream; // The class that will handle each pin
|
||||
|
||||
|
||||
//
|
||||
// CSource
|
||||
//
|
||||
// Override construction to provide a means of creating
|
||||
// CSourceStream derived objects - ie a way of creating pins.
|
||||
class CSource : public CBaseFilter {
|
||||
public:
|
||||
|
||||
CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
|
||||
CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
|
||||
#ifdef UNICODE
|
||||
CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
|
||||
CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
|
||||
#endif
|
||||
~CSource();
|
||||
|
||||
int GetPinCount(void);
|
||||
CBasePin *GetPin(int n);
|
||||
|
||||
// -- Utilities --
|
||||
|
||||
CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section
|
||||
|
||||
HRESULT AddPin(CSourceStream *);
|
||||
HRESULT RemovePin(CSourceStream *);
|
||||
|
||||
STDMETHODIMP FindPin(
|
||||
LPCWSTR Id,
|
||||
IPin ** ppPin
|
||||
);
|
||||
|
||||
int FindPinNumber(IPin *iPin);
|
||||
|
||||
protected:
|
||||
|
||||
int m_iPins; // The number of pins on this filter. Updated by CSourceStream
|
||||
// constructors & destructors.
|
||||
CSourceStream **m_paStreams; // the pins on this filter.
|
||||
|
||||
CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CSourceStream
|
||||
//
|
||||
// Use this class to manage a stream of data that comes from a
|
||||
// pin.
|
||||
// Uses a worker thread to put data on the pin.
|
||||
class CSourceStream : public CAMThread, public CBaseOutputPin {
|
||||
public:
|
||||
|
||||
CSourceStream(TCHAR *pObjectName,
|
||||
HRESULT *phr,
|
||||
CSource *pms,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CSourceStream(CHAR *pObjectName,
|
||||
HRESULT *phr,
|
||||
CSource *pms,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too.
|
||||
|
||||
protected:
|
||||
|
||||
CSource *m_pFilter; // The parent of this stream
|
||||
|
||||
// *
|
||||
// * Data Source
|
||||
// *
|
||||
// * The following three functions: FillBuffer, OnThreadCreate/Destroy, are
|
||||
// * called from within the ThreadProc. They are used in the creation of
|
||||
// * the media samples this pin will provide
|
||||
// *
|
||||
|
||||
// Override this to provide the worker thread a means
|
||||
// of processing a buffer
|
||||
virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE;
|
||||
|
||||
// Called as the thread is created/destroyed - use to perform
|
||||
// jobs such as start/stop streaming mode
|
||||
// If OnThreadCreate returns an error the thread will exit.
|
||||
virtual HRESULT OnThreadCreate(void) {return NOERROR;};
|
||||
virtual HRESULT OnThreadDestroy(void) {return NOERROR;};
|
||||
virtual HRESULT OnThreadStartPlay(void) {return NOERROR;};
|
||||
|
||||
// *
|
||||
// * Worker Thread
|
||||
// *
|
||||
|
||||
HRESULT Active(void); // Starts up the worker thread
|
||||
HRESULT Inactive(void); // Exits the worker thread.
|
||||
|
||||
public:
|
||||
// thread commands
|
||||
enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT};
|
||||
HRESULT Init(void) { return CallWorker(CMD_INIT); }
|
||||
HRESULT Exit(void) { return CallWorker(CMD_EXIT); }
|
||||
HRESULT Run(void) { return CallWorker(CMD_RUN); }
|
||||
HRESULT Pause(void) { return CallWorker(CMD_PAUSE); }
|
||||
HRESULT Stop(void) { return CallWorker(CMD_STOP); }
|
||||
|
||||
protected:
|
||||
Command GetRequest(void) { return (Command) CAMThread::GetRequest(); }
|
||||
BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); }
|
||||
|
||||
// override these if you want to add thread commands
|
||||
virtual DWORD ThreadProc(void); // the thread function
|
||||
|
||||
virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running
|
||||
|
||||
|
||||
// *
|
||||
// * AM_MEDIA_TYPE support
|
||||
// *
|
||||
|
||||
// If you support more than one media type then override these 2 functions
|
||||
virtual HRESULT CheckMediaType(const CMediaType *pMediaType);
|
||||
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); // List pos. 0-n
|
||||
|
||||
// If you support only one type then override this fn.
|
||||
// This will only be called by the default implementations
|
||||
// of CheckMediaType and GetMediaType(int, CMediaType*)
|
||||
// You must override this fn. or the above 2!
|
||||
virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;}
|
||||
|
||||
STDMETHODIMP QueryId(
|
||||
LPWSTR * Id
|
||||
);
|
||||
};
|
||||
|
||||
#endif // __CSOURCE__
|
||||
|
||||
|
||||
+172
-172
@@ -1,172 +1,172 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Streams.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines overall streams architecture.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __STREAMS__
|
||||
#define __STREAMS__
|
||||
|
||||
// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable
|
||||
#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter
|
||||
#pragma warning(disable:4127) // warning C4127: conditional expression is constant
|
||||
#pragma warning(disable:4189) // warning C4189: local variable is initialized but not referenced
|
||||
#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
|
||||
#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated
|
||||
#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated
|
||||
#pragma warning(disable:4514) // warning C4514: unreferenced inline function has been removed
|
||||
#pragma warning(disable:4710) // warning C4710: 'function' not inlined
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER>=1100
|
||||
#define AM_NOVTABLE __declspec(novtable)
|
||||
#else
|
||||
#define AM_NOVTABLE
|
||||
#endif
|
||||
#endif // MSC_VER
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <olectl.h>
|
||||
#include <ddraw.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#ifndef NUMELMS
|
||||
#define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The following definitions come from the Platform SDK and are required if
|
||||
// the applicaiton is being compiled with the headers from Visual C++ 6.0.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#ifndef InterlockedExchangePointer
|
||||
#define InterlockedExchangePointer(Target, Value) \
|
||||
(PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
|
||||
#endif
|
||||
|
||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||
#define _WAVEFORMATEXTENSIBLE_
|
||||
typedef struct {
|
||||
WAVEFORMATEX Format;
|
||||
union {
|
||||
WORD wValidBitsPerSample; /* bits of precision */
|
||||
WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
|
||||
WORD wReserved; /* If neither applies, set to zero. */
|
||||
} Samples;
|
||||
DWORD dwChannelMask; /* which channels are */
|
||||
/* present in stream */
|
||||
GUID SubFormat;
|
||||
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
|
||||
#endif // !_WAVEFORMATEXTENSIBLE_
|
||||
|
||||
#if !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
|
||||
#endif // !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
|
||||
#ifndef GetWindowLongPtr
|
||||
#define GetWindowLongPtrA GetWindowLongA
|
||||
#define GetWindowLongPtrW GetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define GetWindowLongPtr GetWindowLongPtrW
|
||||
#else
|
||||
#define GetWindowLongPtr GetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
#endif // !GetWindowLongPtr
|
||||
|
||||
#ifndef SetWindowLongPtr
|
||||
#define SetWindowLongPtrA SetWindowLongA
|
||||
#define SetWindowLongPtrW SetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define SetWindowLongPtr SetWindowLongPtrW
|
||||
#else
|
||||
#define SetWindowLongPtr SetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
#endif // !SetWindowLongPtr
|
||||
|
||||
#ifndef GWLP_WNDPROC
|
||||
#define GWLP_WNDPROC (-4)
|
||||
#endif
|
||||
#ifndef GWLP_HINSTANCE
|
||||
#define GWLP_HINSTANCE (-6)
|
||||
#endif
|
||||
#ifndef GWLP_HWNDPARENT
|
||||
#define GWLP_HWNDPARENT (-8)
|
||||
#endif
|
||||
#ifndef GWLP_USERDATA
|
||||
#define GWLP_USERDATA (-21)
|
||||
#endif
|
||||
#ifndef GWLP_ID
|
||||
#define GWLP_ID (-12)
|
||||
#endif
|
||||
#ifndef DWLP_MSGRESULT
|
||||
#define DWLP_MSGRESULT 0
|
||||
#endif
|
||||
#ifndef DWLP_DLGPROC
|
||||
#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT)
|
||||
#endif
|
||||
#ifndef DWLP_USER
|
||||
#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC)
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// End Platform SDK definitions
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
|
||||
#include <strmif.h> // Generated IDL header file for streams interfaces
|
||||
|
||||
//
|
||||
// Modified by Chris to look in local baseclasses directory instead of include path
|
||||
//
|
||||
#include "baseclasses/reftime.h" // Helper class for REFERENCE_TIME management
|
||||
#include "baseclasses/wxdebug.h" // Debug support for logging and ASSERTs
|
||||
#include "baseclasses/amvideo.h" // ActiveMovie video interfaces and definitions
|
||||
|
||||
//include amaudio.h explicitly if you need it. it requires the DX SDK.
|
||||
//#include <amaudio.h> // ActiveMovie audio interfaces and definitions
|
||||
|
||||
#include "baseclasses/wxutil.h" // General helper classes for threads etc
|
||||
#include "baseclasses/combase.h" // Base COM classes to support IUnknown
|
||||
#include "baseclasses/dllsetup.h" // Filter registration support functions
|
||||
#include "baseclasses/measure.h" // Performance measurement
|
||||
#include <comlite.h> // Light weight com function prototypes
|
||||
|
||||
#include "baseclasses/cache.h" // Simple cache container class
|
||||
#include "baseclasses/wxlist.h" // Non MFC generic list class
|
||||
#include "baseclasses/msgthrd.h" // CMsgThread
|
||||
#include "baseclasses/mtype.h" // Helper class for managing media types
|
||||
#include "baseclasses/fourcc.h" // conversions between FOURCCs and GUIDs
|
||||
#include <control.h> // generated from control.odl
|
||||
#include "baseclasses/ctlutil.h" // control interface utility classes
|
||||
#include <evcode.h> // event code definitions
|
||||
#include "baseclasses/amfilter.h" // Main streams architecture class hierachy
|
||||
#include "baseclasses/transfrm.h" // Generic transform filter
|
||||
#include "baseclasses/transip.h" // Generic transform-in-place filter
|
||||
#include <uuids.h> // declaration of type GUIDs and well-known clsids
|
||||
#include "baseclasses/source.h" // Generic source filter
|
||||
#include "baseclasses/outputq.h" // Output pin queueing
|
||||
#include <errors.h> // HRESULT status and error definitions
|
||||
#include "baseclasses/renbase.h" // Base class for writing ActiveX renderers
|
||||
#include "baseclasses/winutil.h" // Helps with filters that manage windows
|
||||
#include "baseclasses/winctrl.h" // Implements the IVideoWindow interface
|
||||
#include "baseclasses/videoctl.h" // Specifically video related classes
|
||||
#include "baseclasses/refclock.h" // Base clock class
|
||||
#include "baseclasses/sysclock.h" // System clock
|
||||
#include "baseclasses/pstream.h" // IPersistStream helper class
|
||||
#include "baseclasses/vtrans.h" // Video Transform Filter base class
|
||||
#include "baseclasses/amextra.h"
|
||||
#include "baseclasses/cprop.h" // Base property page class
|
||||
#include "baseclasses/strmctl.h" // IAMStreamControl support
|
||||
#include <edevdefs.h> // External device control interface defines
|
||||
#include <audevcod.h> // audio filter device error event codes
|
||||
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
#pragma message("STREAMS.H included TWICE")
|
||||
#endif
|
||||
#endif // __STREAMS__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Streams.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines overall streams architecture.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __STREAMS__
|
||||
#define __STREAMS__
|
||||
|
||||
// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable
|
||||
#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter
|
||||
#pragma warning(disable:4127) // warning C4127: conditional expression is constant
|
||||
#pragma warning(disable:4189) // warning C4189: local variable is initialized but not referenced
|
||||
#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
|
||||
#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated
|
||||
#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated
|
||||
#pragma warning(disable:4514) // warning C4514: unreferenced inline function has been removed
|
||||
#pragma warning(disable:4710) // warning C4710: 'function' not inlined
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER>=1100
|
||||
#define AM_NOVTABLE __declspec(novtable)
|
||||
#else
|
||||
#define AM_NOVTABLE
|
||||
#endif
|
||||
#endif // MSC_VER
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <olectl.h>
|
||||
#include <ddraw.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#ifndef NUMELMS
|
||||
#define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The following definitions come from the Platform SDK and are required if
|
||||
// the applicaiton is being compiled with the headers from Visual C++ 6.0.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#ifndef InterlockedExchangePointer
|
||||
#define InterlockedExchangePointer(Target, Value) \
|
||||
(PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
|
||||
#endif
|
||||
|
||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||
#define _WAVEFORMATEXTENSIBLE_
|
||||
typedef struct {
|
||||
WAVEFORMATEX Format;
|
||||
union {
|
||||
WORD wValidBitsPerSample; /* bits of precision */
|
||||
WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
|
||||
WORD wReserved; /* If neither applies, set to zero. */
|
||||
} Samples;
|
||||
DWORD dwChannelMask; /* which channels are */
|
||||
/* present in stream */
|
||||
GUID SubFormat;
|
||||
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
|
||||
#endif // !_WAVEFORMATEXTENSIBLE_
|
||||
|
||||
#if !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
|
||||
#endif // !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
|
||||
#ifndef GetWindowLongPtr
|
||||
#define GetWindowLongPtrA GetWindowLongA
|
||||
#define GetWindowLongPtrW GetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define GetWindowLongPtr GetWindowLongPtrW
|
||||
#else
|
||||
#define GetWindowLongPtr GetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
#endif // !GetWindowLongPtr
|
||||
|
||||
#ifndef SetWindowLongPtr
|
||||
#define SetWindowLongPtrA SetWindowLongA
|
||||
#define SetWindowLongPtrW SetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define SetWindowLongPtr SetWindowLongPtrW
|
||||
#else
|
||||
#define SetWindowLongPtr SetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
#endif // !SetWindowLongPtr
|
||||
|
||||
#ifndef GWLP_WNDPROC
|
||||
#define GWLP_WNDPROC (-4)
|
||||
#endif
|
||||
#ifndef GWLP_HINSTANCE
|
||||
#define GWLP_HINSTANCE (-6)
|
||||
#endif
|
||||
#ifndef GWLP_HWNDPARENT
|
||||
#define GWLP_HWNDPARENT (-8)
|
||||
#endif
|
||||
#ifndef GWLP_USERDATA
|
||||
#define GWLP_USERDATA (-21)
|
||||
#endif
|
||||
#ifndef GWLP_ID
|
||||
#define GWLP_ID (-12)
|
||||
#endif
|
||||
#ifndef DWLP_MSGRESULT
|
||||
#define DWLP_MSGRESULT 0
|
||||
#endif
|
||||
#ifndef DWLP_DLGPROC
|
||||
#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT)
|
||||
#endif
|
||||
#ifndef DWLP_USER
|
||||
#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC)
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// End Platform SDK definitions
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
|
||||
#include <strmif.h> // Generated IDL header file for streams interfaces
|
||||
|
||||
//
|
||||
// Modified by Chris to look in local baseclasses directory instead of include path
|
||||
//
|
||||
#include "baseclasses/reftime.h" // Helper class for REFERENCE_TIME management
|
||||
#include "baseclasses/wxdebug.h" // Debug support for logging and ASSERTs
|
||||
#include "baseclasses/amvideo.h" // ActiveMovie video interfaces and definitions
|
||||
|
||||
//include amaudio.h explicitly if you need it. it requires the DX SDK.
|
||||
//#include <amaudio.h> // ActiveMovie audio interfaces and definitions
|
||||
|
||||
#include "baseclasses/wxutil.h" // General helper classes for threads etc
|
||||
#include "baseclasses/combase.h" // Base COM classes to support IUnknown
|
||||
#include "baseclasses/dllsetup.h" // Filter registration support functions
|
||||
#include "baseclasses/measure.h" // Performance measurement
|
||||
#include <comlite.h> // Light weight com function prototypes
|
||||
|
||||
#include "baseclasses/cache.h" // Simple cache container class
|
||||
#include "baseclasses/wxlist.h" // Non MFC generic list class
|
||||
#include "baseclasses/msgthrd.h" // CMsgThread
|
||||
#include "baseclasses/mtype.h" // Helper class for managing media types
|
||||
#include "baseclasses/fourcc.h" // conversions between FOURCCs and GUIDs
|
||||
#include <control.h> // generated from control.odl
|
||||
#include "baseclasses/ctlutil.h" // control interface utility classes
|
||||
#include <evcode.h> // event code definitions
|
||||
#include "baseclasses/amfilter.h" // Main streams architecture class hierachy
|
||||
#include "baseclasses/transfrm.h" // Generic transform filter
|
||||
#include "baseclasses/transip.h" // Generic transform-in-place filter
|
||||
#include <uuids.h> // declaration of type GUIDs and well-known clsids
|
||||
#include "baseclasses/source.h" // Generic source filter
|
||||
#include "baseclasses/outputq.h" // Output pin queueing
|
||||
#include <errors.h> // HRESULT status and error definitions
|
||||
#include "baseclasses/renbase.h" // Base class for writing ActiveX renderers
|
||||
#include "baseclasses/winutil.h" // Helps with filters that manage windows
|
||||
#include "baseclasses/winctrl.h" // Implements the IVideoWindow interface
|
||||
#include "baseclasses/videoctl.h" // Specifically video related classes
|
||||
#include "baseclasses/refclock.h" // Base clock class
|
||||
#include "baseclasses/sysclock.h" // System clock
|
||||
#include "baseclasses/pstream.h" // IPersistStream helper class
|
||||
#include "baseclasses/vtrans.h" // Video Transform Filter base class
|
||||
#include "baseclasses/amextra.h"
|
||||
#include "baseclasses/cprop.h" // Base property page class
|
||||
#include "baseclasses/strmctl.h" // IAMStreamControl support
|
||||
#include <edevdefs.h> // External device control interface defines
|
||||
#include <audevcod.h> // audio filter device error event codes
|
||||
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
#pragma message("STREAMS.H included TWICE")
|
||||
#endif
|
||||
#endif // __STREAMS__
|
||||
|
||||
|
||||
+386
-386
@@ -1,386 +1,386 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: StrmCtl.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <strmctl.h>
|
||||
|
||||
CBaseStreamControl::CBaseStreamControl()
|
||||
: m_StreamState(STREAM_FLOWING)
|
||||
, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop
|
||||
, m_tStartTime(MAX_TIME)
|
||||
, m_tStopTime(MAX_TIME)
|
||||
, m_dwStartCookie(0)
|
||||
, m_dwStopCookie(0)
|
||||
, m_pRefClock(NULL)
|
||||
, m_FilterState(State_Stopped)
|
||||
, m_bIsFlushing(FALSE)
|
||||
, m_bStopSendExtra(FALSE) {
|
||||
}
|
||||
|
||||
CBaseStreamControl::~CBaseStreamControl() {
|
||||
// Make sure we release the clock.
|
||||
SetSyncSource(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
m_bStopSendExtra = FALSE; // reset
|
||||
m_bStopExtraSent = FALSE;
|
||||
if(ptStop) {
|
||||
if(*ptStop == MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop")));
|
||||
CancelStop();
|
||||
// If there's now a command to start in the future, we assume
|
||||
// they want to be stopped when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) {
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"),
|
||||
(int)(*ptStop/10000), bSendExtra));
|
||||
// if the first command is to stop in the future, then we assume they
|
||||
// want to be started when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStartTime > *ptStop) {
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
|
||||
}
|
||||
m_bStopSendExtra = bSendExtra;
|
||||
m_tStopTime = *ptStop;
|
||||
m_dwStopCookie = dwCookie;
|
||||
m_StreamStateOnStop = STREAM_DISCARDING;
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: now")));
|
||||
// sending an extra frame when told to stop now would mess people up
|
||||
m_bStopSendExtra = FALSE;
|
||||
m_tStopTime = MAX_TIME;
|
||||
m_dwStopCookie = 0;
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
m_StreamStateOnStop = STREAM_FLOWING; // no pending stop
|
||||
}
|
||||
// we might change our mind what to do with a sample we're blocking
|
||||
m_StreamEvent.Set();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseStreamControl::StartAt
|
||||
( const REFERENCE_TIME *ptStart, DWORD dwCookie ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
if(ptStart) {
|
||||
if(*ptStart == MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start")));
|
||||
CancelStart();
|
||||
// If there's now a command to stop in the future, we assume
|
||||
// they want to be started when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000)));
|
||||
// if the first command is to start in the future, then we assume they
|
||||
// want to be stopped when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStopTime >= *ptStart) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
}
|
||||
m_tStartTime = *ptStart;
|
||||
m_dwStartCookie = dwCookie;
|
||||
// if (m_tStopTime == m_tStartTime) CancelStop();
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: now")));
|
||||
m_tStartTime = MAX_TIME;
|
||||
m_dwStartCookie = 0;
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
}
|
||||
// we might change our mind what to do with a sample we're blocking
|
||||
m_StreamEvent.Set();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Retrieve information about current settings
|
||||
STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo) {
|
||||
if(pInfo == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
pInfo->tStart = m_tStartTime;
|
||||
pInfo->tStop = m_tStopTime;
|
||||
pInfo->dwStartCookie = m_dwStartCookie;
|
||||
pInfo->dwStopCookie = m_dwStopCookie;
|
||||
pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0;
|
||||
pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED;
|
||||
pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED;
|
||||
switch(m_StreamState) {
|
||||
default:
|
||||
DbgBreak("Invalid stream state");
|
||||
case STREAM_FLOWING:
|
||||
break;
|
||||
case STREAM_DISCARDING:
|
||||
pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING;
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::ExecuteStop() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_StreamState = m_StreamStateOnStop;
|
||||
if(m_dwStopCookie && m_pSink) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"),
|
||||
m_dwStopCookie));
|
||||
m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie);
|
||||
}
|
||||
CancelStop(); // This will do the tidy up
|
||||
}
|
||||
|
||||
void CBaseStreamControl::ExecuteStart() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
if(m_dwStartCookie) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"),
|
||||
m_dwStartCookie));
|
||||
m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie);
|
||||
}
|
||||
CancelStart(); // This will do the tidy up
|
||||
}
|
||||
|
||||
void CBaseStreamControl::CancelStop() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_tStopTime = MAX_TIME;
|
||||
m_dwStopCookie = 0;
|
||||
m_StreamStateOnStop = STREAM_FLOWING;
|
||||
}
|
||||
|
||||
void CBaseStreamControl::CancelStart() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_tStartTime = MAX_TIME;
|
||||
m_dwStartCookie = 0;
|
||||
}
|
||||
|
||||
|
||||
// This guy will return one of the three StreamControlState's. Here's what the caller
|
||||
// should do for each one:
|
||||
//
|
||||
// STREAM_FLOWING: Proceed as usual (render or pass the sample on)
|
||||
// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long
|
||||
// for the event handle (GetStreamEventHandle()). If the
|
||||
// wait expires, throw the sample away. If the event
|
||||
// fires, call me back, I've changed my mind.
|
||||
// I use pSampleStart (not Stop) so that live sources don't
|
||||
// block for the duration of their samples, since the clock
|
||||
// will always read approximately pSampleStart when called
|
||||
|
||||
|
||||
// All through this code, you'll notice the following rules:
|
||||
// - When start and stop time are the same, it's as if start was first
|
||||
// - An event is considered inside the sample when it's >= sample start time
|
||||
// but < sample stop time
|
||||
// - if any part of the sample is supposed to be sent, we'll send the whole
|
||||
// thing since we don't break it into smaller pieces
|
||||
// - If we skip over a start or stop without doing it, we still signal the event
|
||||
// and reset ourselves in case somebody's waiting for the event, and to make
|
||||
// sure we notice that the event is past and should be forgotten
|
||||
// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample):
|
||||
//
|
||||
// 1. xo<--> start then stop
|
||||
// 2. ox<--> stop then start
|
||||
// 3. x<o-> start
|
||||
// 4. o<x-> stop then start
|
||||
// 5. x<-->o start
|
||||
// 6. o<-->x stop
|
||||
// 7. <x->o start
|
||||
// 8. <o->x no change
|
||||
// 9. <xo> start
|
||||
// 10. <ox> stop then start
|
||||
// 11. <-->xo no change
|
||||
// 12. <-->ox no change
|
||||
// 13. x<--> start
|
||||
// 14. <x-> start
|
||||
// 15. <-->x no change
|
||||
// 16. o<--> stop
|
||||
// 17. <o-> no change
|
||||
// 18. <-->o no change
|
||||
// 19. <--> no change
|
||||
|
||||
|
||||
enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes
|
||||
( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
|
||||
ASSERT(!m_bIsFlushing);
|
||||
ASSERT(pSampleStart && pSampleStop);
|
||||
|
||||
// Don't ask how I came up with the code below to handle all 19 cases...
|
||||
if(m_tStopTime >= *pSampleStart) {
|
||||
if(m_tStartTime >= *pSampleStop)
|
||||
return m_StreamState; // cases 8 11 12 15 17 18 19
|
||||
|
||||
if(m_tStopTime < m_tStartTime)
|
||||
ExecuteStop(); // case 10
|
||||
|
||||
ExecuteStart(); // cases 3 5 7 9 13 14
|
||||
return m_StreamState;
|
||||
}
|
||||
|
||||
if(m_tStartTime >= *pSampleStop) {
|
||||
ExecuteStop(); // cases 6 16
|
||||
return m_StreamState;
|
||||
}
|
||||
|
||||
if(m_tStartTime <= m_tStopTime) {
|
||||
ExecuteStart();
|
||||
ExecuteStop();
|
||||
}
|
||||
else {
|
||||
ExecuteStop();
|
||||
ExecuteStart();
|
||||
}
|
||||
|
||||
return m_StreamState; // case 1, 2, or 4
|
||||
}
|
||||
|
||||
|
||||
enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) {
|
||||
|
||||
REFERENCE_TIME rtBufferStart, rtBufferStop;
|
||||
const BOOL bNoBufferTimes =
|
||||
pSample == NULL ||
|
||||
FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop));
|
||||
|
||||
StreamControlState state;
|
||||
LONG lWait;
|
||||
|
||||
do {
|
||||
// something has to break out of the blocking
|
||||
if(m_bIsFlushing || m_FilterState == State_Stopped)
|
||||
return STREAM_DISCARDING;
|
||||
|
||||
if(bNoBufferTimes) {
|
||||
// Can't do anything until we get a time stamp
|
||||
state = m_StreamState;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
state = CheckSampleTimes(&rtBufferStart, &rtBufferStop);
|
||||
if(state == STREAM_FLOWING)
|
||||
break;
|
||||
|
||||
// we aren't supposed to send this, but we've been
|
||||
// told to send one more than we were supposed to
|
||||
// (and the stop isn't still pending and we're streaming)
|
||||
if(m_bStopSendExtra && !m_bStopExtraSent &&
|
||||
m_tStopTime == MAX_TIME &&
|
||||
m_FilterState != State_Stopped) {
|
||||
m_bStopExtraSent = TRUE;
|
||||
DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"),
|
||||
m_dwStopCookie));
|
||||
state = STREAM_FLOWING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We're in discarding mode
|
||||
|
||||
// If we've no clock, discard as fast as we can
|
||||
if(!m_pRefClock) {
|
||||
break;
|
||||
|
||||
// If we're paused, we can't discard in a timely manner because
|
||||
// there's no such thing as stream times. We must block until
|
||||
// we run or stop, or we'll end up throwing the whole stream away
|
||||
// as quickly as possible
|
||||
}
|
||||
else if(m_FilterState == State_Paused) {
|
||||
lWait = INFINITE;
|
||||
|
||||
}
|
||||
else {
|
||||
// wait until it's time for the sample until we say "discard"
|
||||
// ("discard in a timely fashion")
|
||||
REFERENCE_TIME rtNow;
|
||||
EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow)));
|
||||
rtNow -= m_tRunStart; // Into relative ref-time
|
||||
lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms
|
||||
if(lWait < 10) break; // Not worth waiting - discard early
|
||||
}
|
||||
|
||||
} while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
|
||||
// or we will get confused
|
||||
if(m_FilterState == new_state)
|
||||
return;
|
||||
|
||||
switch(new_state) {
|
||||
case State_Stopped:
|
||||
|
||||
DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED")));
|
||||
|
||||
// execute any pending starts and stops in the right order,
|
||||
// to make sure all notifications get sent, and we end up
|
||||
// in the right state to begin next time (??? why not?)
|
||||
|
||||
if(m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) {
|
||||
ExecuteStart();
|
||||
}
|
||||
else if(m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) {
|
||||
ExecuteStop();
|
||||
}
|
||||
else if(m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) {
|
||||
if(m_tStartTime <= m_tStopTime) {
|
||||
ExecuteStart();
|
||||
ExecuteStop();
|
||||
}
|
||||
else {
|
||||
ExecuteStop();
|
||||
ExecuteStart();
|
||||
}
|
||||
}
|
||||
// always start off flowing when the graph starts streaming
|
||||
// unless told otherwise
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
m_FilterState = new_state;
|
||||
break;
|
||||
|
||||
case State_Running:
|
||||
|
||||
DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING")));
|
||||
|
||||
m_tRunStart = tStart;
|
||||
// fall-through
|
||||
|
||||
default: // case State_Paused:
|
||||
m_FilterState = new_state;
|
||||
}
|
||||
// unblock!
|
||||
m_StreamEvent.Set();
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::Flushing(BOOL bInProgress) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
m_bIsFlushing = bInProgress;
|
||||
m_StreamEvent.Set();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: StrmCtl.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <strmctl.h>
|
||||
|
||||
CBaseStreamControl::CBaseStreamControl()
|
||||
: m_StreamState(STREAM_FLOWING)
|
||||
, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop
|
||||
, m_tStartTime(MAX_TIME)
|
||||
, m_tStopTime(MAX_TIME)
|
||||
, m_dwStartCookie(0)
|
||||
, m_dwStopCookie(0)
|
||||
, m_pRefClock(NULL)
|
||||
, m_FilterState(State_Stopped)
|
||||
, m_bIsFlushing(FALSE)
|
||||
, m_bStopSendExtra(FALSE) {
|
||||
}
|
||||
|
||||
CBaseStreamControl::~CBaseStreamControl() {
|
||||
// Make sure we release the clock.
|
||||
SetSyncSource(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
m_bStopSendExtra = FALSE; // reset
|
||||
m_bStopExtraSent = FALSE;
|
||||
if(ptStop) {
|
||||
if(*ptStop == MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop")));
|
||||
CancelStop();
|
||||
// If there's now a command to start in the future, we assume
|
||||
// they want to be stopped when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) {
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"),
|
||||
(int)(*ptStop/10000), bSendExtra));
|
||||
// if the first command is to stop in the future, then we assume they
|
||||
// want to be started when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStartTime > *ptStop) {
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
|
||||
}
|
||||
m_bStopSendExtra = bSendExtra;
|
||||
m_tStopTime = *ptStop;
|
||||
m_dwStopCookie = dwCookie;
|
||||
m_StreamStateOnStop = STREAM_DISCARDING;
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: now")));
|
||||
// sending an extra frame when told to stop now would mess people up
|
||||
m_bStopSendExtra = FALSE;
|
||||
m_tStopTime = MAX_TIME;
|
||||
m_dwStopCookie = 0;
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
m_StreamStateOnStop = STREAM_FLOWING; // no pending stop
|
||||
}
|
||||
// we might change our mind what to do with a sample we're blocking
|
||||
m_StreamEvent.Set();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseStreamControl::StartAt
|
||||
( const REFERENCE_TIME *ptStart, DWORD dwCookie ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
if(ptStart) {
|
||||
if(*ptStart == MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start")));
|
||||
CancelStart();
|
||||
// If there's now a command to stop in the future, we assume
|
||||
// they want to be started when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000)));
|
||||
// if the first command is to start in the future, then we assume they
|
||||
// want to be stopped when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStopTime >= *ptStart) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
}
|
||||
m_tStartTime = *ptStart;
|
||||
m_dwStartCookie = dwCookie;
|
||||
// if (m_tStopTime == m_tStartTime) CancelStop();
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: now")));
|
||||
m_tStartTime = MAX_TIME;
|
||||
m_dwStartCookie = 0;
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
}
|
||||
// we might change our mind what to do with a sample we're blocking
|
||||
m_StreamEvent.Set();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Retrieve information about current settings
|
||||
STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo) {
|
||||
if(pInfo == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
pInfo->tStart = m_tStartTime;
|
||||
pInfo->tStop = m_tStopTime;
|
||||
pInfo->dwStartCookie = m_dwStartCookie;
|
||||
pInfo->dwStopCookie = m_dwStopCookie;
|
||||
pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0;
|
||||
pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED;
|
||||
pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED;
|
||||
switch(m_StreamState) {
|
||||
default:
|
||||
DbgBreak("Invalid stream state");
|
||||
case STREAM_FLOWING:
|
||||
break;
|
||||
case STREAM_DISCARDING:
|
||||
pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING;
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::ExecuteStop() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_StreamState = m_StreamStateOnStop;
|
||||
if(m_dwStopCookie && m_pSink) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"),
|
||||
m_dwStopCookie));
|
||||
m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie);
|
||||
}
|
||||
CancelStop(); // This will do the tidy up
|
||||
}
|
||||
|
||||
void CBaseStreamControl::ExecuteStart() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
if(m_dwStartCookie) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"),
|
||||
m_dwStartCookie));
|
||||
m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie);
|
||||
}
|
||||
CancelStart(); // This will do the tidy up
|
||||
}
|
||||
|
||||
void CBaseStreamControl::CancelStop() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_tStopTime = MAX_TIME;
|
||||
m_dwStopCookie = 0;
|
||||
m_StreamStateOnStop = STREAM_FLOWING;
|
||||
}
|
||||
|
||||
void CBaseStreamControl::CancelStart() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_tStartTime = MAX_TIME;
|
||||
m_dwStartCookie = 0;
|
||||
}
|
||||
|
||||
|
||||
// This guy will return one of the three StreamControlState's. Here's what the caller
|
||||
// should do for each one:
|
||||
//
|
||||
// STREAM_FLOWING: Proceed as usual (render or pass the sample on)
|
||||
// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long
|
||||
// for the event handle (GetStreamEventHandle()). If the
|
||||
// wait expires, throw the sample away. If the event
|
||||
// fires, call me back, I've changed my mind.
|
||||
// I use pSampleStart (not Stop) so that live sources don't
|
||||
// block for the duration of their samples, since the clock
|
||||
// will always read approximately pSampleStart when called
|
||||
|
||||
|
||||
// All through this code, you'll notice the following rules:
|
||||
// - When start and stop time are the same, it's as if start was first
|
||||
// - An event is considered inside the sample when it's >= sample start time
|
||||
// but < sample stop time
|
||||
// - if any part of the sample is supposed to be sent, we'll send the whole
|
||||
// thing since we don't break it into smaller pieces
|
||||
// - If we skip over a start or stop without doing it, we still signal the event
|
||||
// and reset ourselves in case somebody's waiting for the event, and to make
|
||||
// sure we notice that the event is past and should be forgotten
|
||||
// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample):
|
||||
//
|
||||
// 1. xo<--> start then stop
|
||||
// 2. ox<--> stop then start
|
||||
// 3. x<o-> start
|
||||
// 4. o<x-> stop then start
|
||||
// 5. x<-->o start
|
||||
// 6. o<-->x stop
|
||||
// 7. <x->o start
|
||||
// 8. <o->x no change
|
||||
// 9. <xo> start
|
||||
// 10. <ox> stop then start
|
||||
// 11. <-->xo no change
|
||||
// 12. <-->ox no change
|
||||
// 13. x<--> start
|
||||
// 14. <x-> start
|
||||
// 15. <-->x no change
|
||||
// 16. o<--> stop
|
||||
// 17. <o-> no change
|
||||
// 18. <-->o no change
|
||||
// 19. <--> no change
|
||||
|
||||
|
||||
enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes
|
||||
( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
|
||||
ASSERT(!m_bIsFlushing);
|
||||
ASSERT(pSampleStart && pSampleStop);
|
||||
|
||||
// Don't ask how I came up with the code below to handle all 19 cases...
|
||||
if(m_tStopTime >= *pSampleStart) {
|
||||
if(m_tStartTime >= *pSampleStop)
|
||||
return m_StreamState; // cases 8 11 12 15 17 18 19
|
||||
|
||||
if(m_tStopTime < m_tStartTime)
|
||||
ExecuteStop(); // case 10
|
||||
|
||||
ExecuteStart(); // cases 3 5 7 9 13 14
|
||||
return m_StreamState;
|
||||
}
|
||||
|
||||
if(m_tStartTime >= *pSampleStop) {
|
||||
ExecuteStop(); // cases 6 16
|
||||
return m_StreamState;
|
||||
}
|
||||
|
||||
if(m_tStartTime <= m_tStopTime) {
|
||||
ExecuteStart();
|
||||
ExecuteStop();
|
||||
}
|
||||
else {
|
||||
ExecuteStop();
|
||||
ExecuteStart();
|
||||
}
|
||||
|
||||
return m_StreamState; // case 1, 2, or 4
|
||||
}
|
||||
|
||||
|
||||
enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) {
|
||||
|
||||
REFERENCE_TIME rtBufferStart, rtBufferStop;
|
||||
const BOOL bNoBufferTimes =
|
||||
pSample == NULL ||
|
||||
FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop));
|
||||
|
||||
StreamControlState state;
|
||||
LONG lWait;
|
||||
|
||||
do {
|
||||
// something has to break out of the blocking
|
||||
if(m_bIsFlushing || m_FilterState == State_Stopped)
|
||||
return STREAM_DISCARDING;
|
||||
|
||||
if(bNoBufferTimes) {
|
||||
// Can't do anything until we get a time stamp
|
||||
state = m_StreamState;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
state = CheckSampleTimes(&rtBufferStart, &rtBufferStop);
|
||||
if(state == STREAM_FLOWING)
|
||||
break;
|
||||
|
||||
// we aren't supposed to send this, but we've been
|
||||
// told to send one more than we were supposed to
|
||||
// (and the stop isn't still pending and we're streaming)
|
||||
if(m_bStopSendExtra && !m_bStopExtraSent &&
|
||||
m_tStopTime == MAX_TIME &&
|
||||
m_FilterState != State_Stopped) {
|
||||
m_bStopExtraSent = TRUE;
|
||||
DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"),
|
||||
m_dwStopCookie));
|
||||
state = STREAM_FLOWING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We're in discarding mode
|
||||
|
||||
// If we've no clock, discard as fast as we can
|
||||
if(!m_pRefClock) {
|
||||
break;
|
||||
|
||||
// If we're paused, we can't discard in a timely manner because
|
||||
// there's no such thing as stream times. We must block until
|
||||
// we run or stop, or we'll end up throwing the whole stream away
|
||||
// as quickly as possible
|
||||
}
|
||||
else if(m_FilterState == State_Paused) {
|
||||
lWait = INFINITE;
|
||||
|
||||
}
|
||||
else {
|
||||
// wait until it's time for the sample until we say "discard"
|
||||
// ("discard in a timely fashion")
|
||||
REFERENCE_TIME rtNow;
|
||||
EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow)));
|
||||
rtNow -= m_tRunStart; // Into relative ref-time
|
||||
lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms
|
||||
if(lWait < 10) break; // Not worth waiting - discard early
|
||||
}
|
||||
|
||||
} while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
|
||||
// or we will get confused
|
||||
if(m_FilterState == new_state)
|
||||
return;
|
||||
|
||||
switch(new_state) {
|
||||
case State_Stopped:
|
||||
|
||||
DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED")));
|
||||
|
||||
// execute any pending starts and stops in the right order,
|
||||
// to make sure all notifications get sent, and we end up
|
||||
// in the right state to begin next time (??? why not?)
|
||||
|
||||
if(m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) {
|
||||
ExecuteStart();
|
||||
}
|
||||
else if(m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) {
|
||||
ExecuteStop();
|
||||
}
|
||||
else if(m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) {
|
||||
if(m_tStartTime <= m_tStopTime) {
|
||||
ExecuteStart();
|
||||
ExecuteStop();
|
||||
}
|
||||
else {
|
||||
ExecuteStop();
|
||||
ExecuteStart();
|
||||
}
|
||||
}
|
||||
// always start off flowing when the graph starts streaming
|
||||
// unless told otherwise
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
m_FilterState = new_state;
|
||||
break;
|
||||
|
||||
case State_Running:
|
||||
|
||||
DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING")));
|
||||
|
||||
m_tRunStart = tStart;
|
||||
// fall-through
|
||||
|
||||
default: // case State_Paused:
|
||||
m_FilterState = new_state;
|
||||
}
|
||||
// unblock!
|
||||
m_StreamEvent.Set();
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::Flushing(BOOL bInProgress) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
m_bIsFlushing = bInProgress;
|
||||
m_StreamEvent.Set();
|
||||
}
|
||||
|
||||
|
||||
+158
-158
@@ -1,158 +1,158 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: StrmCtl.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __strmctl_h__
|
||||
#define __strmctl_h__
|
||||
|
||||
class CBaseStreamControl : public IAMStreamControl
|
||||
{
|
||||
public:
|
||||
// Used by the implementation
|
||||
enum StreamControlState
|
||||
{ STREAM_FLOWING = 0x1000,
|
||||
STREAM_DISCARDING
|
||||
};
|
||||
|
||||
private:
|
||||
enum StreamControlState m_StreamState; // Current stream state
|
||||
enum StreamControlState m_StreamStateOnStop; // State after next stop
|
||||
// (i.e.Blocking or Discarding)
|
||||
|
||||
REFERENCE_TIME m_tStartTime; // MAX_TIME implies none
|
||||
REFERENCE_TIME m_tStopTime; // MAX_TIME implies none
|
||||
DWORD m_dwStartCookie; // Cookie for notification to app
|
||||
DWORD m_dwStopCookie; // Cookie for notification to app
|
||||
volatile BOOL m_bIsFlushing; // No optimization pls!
|
||||
volatile BOOL m_bStopSendExtra; // bSendExtra was set
|
||||
volatile BOOL m_bStopExtraSent; // the extra one was sent
|
||||
|
||||
CCritSec m_CritSec; // CritSec to guard above attributes
|
||||
|
||||
// Event to fire when we can come
|
||||
// out of blocking, or to come out of waiting
|
||||
// to discard if we change our minds.
|
||||
//
|
||||
CAMEvent m_StreamEvent;
|
||||
|
||||
// All of these methods execute immediately. Helpers for others.
|
||||
//
|
||||
void ExecuteStop();
|
||||
void ExecuteStart();
|
||||
void CancelStop();
|
||||
void CancelStart();
|
||||
|
||||
// Some things we need to be told by our owning filter
|
||||
// Your pin must also expose IAMStreamControl when QI'd for it!
|
||||
//
|
||||
IReferenceClock * m_pRefClock; // Need it to set advises
|
||||
// Filter must tell us via
|
||||
// SetSyncSource
|
||||
IMediaEventSink * m_pSink; // Event sink
|
||||
// Filter must tell us after it
|
||||
// creates it in JoinFilterGraph()
|
||||
FILTER_STATE m_FilterState; // Just need it!
|
||||
// Filter must tell us via
|
||||
// NotifyFilterState
|
||||
REFERENCE_TIME m_tRunStart; // Per the Run call to the filter
|
||||
|
||||
// This guy will return one of the three StreamControlState's. Here's what
|
||||
// the caller should do for each one:
|
||||
//
|
||||
// STREAM_FLOWING: Proceed as usual (render or pass the sample on)
|
||||
// STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait
|
||||
// that long for the event handle
|
||||
// (GetStreamEventHandle()). If the wait
|
||||
// expires, throw the sample away. If the event
|
||||
// fires, call me back - I've changed my mind.
|
||||
//
|
||||
enum StreamControlState CheckSampleTimes( const REFERENCE_TIME * pSampleStart,
|
||||
const REFERENCE_TIME * pSampleStop );
|
||||
|
||||
public:
|
||||
// You don't have to tell us much when we're created, but there are other
|
||||
// obligations that must be met. See SetSyncSource & NotifyFilterState
|
||||
// below.
|
||||
//
|
||||
CBaseStreamControl();
|
||||
~CBaseStreamControl();
|
||||
|
||||
// If you want this class to work properly, there are thing you need to
|
||||
// (keep) telling it. Filters with pins that use this class
|
||||
// should ensure that they pass through to this method any calls they
|
||||
// receive on their SetSyncSource.
|
||||
|
||||
// We need a clock to see what time it is. This is for the
|
||||
// "discard in a timely fashion" logic. If we discard everything as
|
||||
// quick as possible, a whole 60 minute file could get discarded in the
|
||||
// first 10 seconds, and if somebody wants to turn streaming on at 30
|
||||
// minutes into the file, and they make the call more than a few seconds
|
||||
// after the graph is run, it may be too late!
|
||||
// So we hold every sample until it's time has gone, then we discard it.
|
||||
// The filter should call this when it gets a SetSyncSource
|
||||
//
|
||||
void SetSyncSource( IReferenceClock * pRefClock )
|
||||
{
|
||||
CAutoLock lck(&m_CritSec);
|
||||
if (m_pRefClock) m_pRefClock->Release();
|
||||
m_pRefClock = pRefClock;
|
||||
if (m_pRefClock)
|
||||
m_pRefClock->AddRef();
|
||||
}
|
||||
|
||||
// Set event sink for notifications
|
||||
// The filter should call this in its JoinFilterGraph after it creates the
|
||||
// IMediaEventSink
|
||||
//
|
||||
void SetFilterGraph( IMediaEventSink *pSink ) {
|
||||
m_pSink = pSink;
|
||||
}
|
||||
|
||||
// Since we schedule in stream time, we need the tStart and must track the
|
||||
// state of our owning filter.
|
||||
// The app should call this ever state change
|
||||
//
|
||||
void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 );
|
||||
|
||||
// Filter should call Flushing(TRUE) in BeginFlush,
|
||||
// and Flushing(FALSE) in EndFlush.
|
||||
//
|
||||
void Flushing( BOOL bInProgress );
|
||||
|
||||
|
||||
// The two main methods of IAMStreamControl
|
||||
|
||||
// Class adds default values suitable for immediate
|
||||
// muting and unmuting of the stream.
|
||||
|
||||
STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL,
|
||||
BOOL bSendExtra = FALSE,
|
||||
DWORD dwCookie = 0 );
|
||||
STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL,
|
||||
DWORD dwCookie = 0 );
|
||||
STDMETHODIMP GetInfo( AM_STREAM_INFO *pInfo);
|
||||
|
||||
// Helper function for pin's receive method. Call this with
|
||||
// the sample and we'll tell you what to do with it. We'll do a
|
||||
// WaitForSingleObject within this call if one is required. This is
|
||||
// a "What should I do with this sample?" kind of call. We'll tell the
|
||||
// caller to either flow it or discard it.
|
||||
// If pSample is NULL we evaluate based on the current state
|
||||
// settings
|
||||
enum StreamControlState CheckStreamState( IMediaSample * pSample );
|
||||
|
||||
private:
|
||||
// These don't require locking, but we are relying on the fact that
|
||||
// m_StreamState can be retrieved with integrity, and is a snap shot that
|
||||
// may have just been, or may be just about to be, changed.
|
||||
HANDLE GetStreamEventHandle() const { return m_StreamEvent; }
|
||||
enum StreamControlState GetStreamState() const { return m_StreamState; }
|
||||
BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; }
|
||||
};
|
||||
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
// File: StrmCtl.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __strmctl_h__
|
||||
#define __strmctl_h__
|
||||
|
||||
class CBaseStreamControl : public IAMStreamControl
|
||||
{
|
||||
public:
|
||||
// Used by the implementation
|
||||
enum StreamControlState
|
||||
{ STREAM_FLOWING = 0x1000,
|
||||
STREAM_DISCARDING
|
||||
};
|
||||
|
||||
private:
|
||||
enum StreamControlState m_StreamState; // Current stream state
|
||||
enum StreamControlState m_StreamStateOnStop; // State after next stop
|
||||
// (i.e.Blocking or Discarding)
|
||||
|
||||
REFERENCE_TIME m_tStartTime; // MAX_TIME implies none
|
||||
REFERENCE_TIME m_tStopTime; // MAX_TIME implies none
|
||||
DWORD m_dwStartCookie; // Cookie for notification to app
|
||||
DWORD m_dwStopCookie; // Cookie for notification to app
|
||||
volatile BOOL m_bIsFlushing; // No optimization pls!
|
||||
volatile BOOL m_bStopSendExtra; // bSendExtra was set
|
||||
volatile BOOL m_bStopExtraSent; // the extra one was sent
|
||||
|
||||
CCritSec m_CritSec; // CritSec to guard above attributes
|
||||
|
||||
// Event to fire when we can come
|
||||
// out of blocking, or to come out of waiting
|
||||
// to discard if we change our minds.
|
||||
//
|
||||
CAMEvent m_StreamEvent;
|
||||
|
||||
// All of these methods execute immediately. Helpers for others.
|
||||
//
|
||||
void ExecuteStop();
|
||||
void ExecuteStart();
|
||||
void CancelStop();
|
||||
void CancelStart();
|
||||
|
||||
// Some things we need to be told by our owning filter
|
||||
// Your pin must also expose IAMStreamControl when QI'd for it!
|
||||
//
|
||||
IReferenceClock * m_pRefClock; // Need it to set advises
|
||||
// Filter must tell us via
|
||||
// SetSyncSource
|
||||
IMediaEventSink * m_pSink; // Event sink
|
||||
// Filter must tell us after it
|
||||
// creates it in JoinFilterGraph()
|
||||
FILTER_STATE m_FilterState; // Just need it!
|
||||
// Filter must tell us via
|
||||
// NotifyFilterState
|
||||
REFERENCE_TIME m_tRunStart; // Per the Run call to the filter
|
||||
|
||||
// This guy will return one of the three StreamControlState's. Here's what
|
||||
// the caller should do for each one:
|
||||
//
|
||||
// STREAM_FLOWING: Proceed as usual (render or pass the sample on)
|
||||
// STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait
|
||||
// that long for the event handle
|
||||
// (GetStreamEventHandle()). If the wait
|
||||
// expires, throw the sample away. If the event
|
||||
// fires, call me back - I've changed my mind.
|
||||
//
|
||||
enum StreamControlState CheckSampleTimes( const REFERENCE_TIME * pSampleStart,
|
||||
const REFERENCE_TIME * pSampleStop );
|
||||
|
||||
public:
|
||||
// You don't have to tell us much when we're created, but there are other
|
||||
// obligations that must be met. See SetSyncSource & NotifyFilterState
|
||||
// below.
|
||||
//
|
||||
CBaseStreamControl();
|
||||
~CBaseStreamControl();
|
||||
|
||||
// If you want this class to work properly, there are thing you need to
|
||||
// (keep) telling it. Filters with pins that use this class
|
||||
// should ensure that they pass through to this method any calls they
|
||||
// receive on their SetSyncSource.
|
||||
|
||||
// We need a clock to see what time it is. This is for the
|
||||
// "discard in a timely fashion" logic. If we discard everything as
|
||||
// quick as possible, a whole 60 minute file could get discarded in the
|
||||
// first 10 seconds, and if somebody wants to turn streaming on at 30
|
||||
// minutes into the file, and they make the call more than a few seconds
|
||||
// after the graph is run, it may be too late!
|
||||
// So we hold every sample until it's time has gone, then we discard it.
|
||||
// The filter should call this when it gets a SetSyncSource
|
||||
//
|
||||
void SetSyncSource( IReferenceClock * pRefClock )
|
||||
{
|
||||
CAutoLock lck(&m_CritSec);
|
||||
if (m_pRefClock) m_pRefClock->Release();
|
||||
m_pRefClock = pRefClock;
|
||||
if (m_pRefClock)
|
||||
m_pRefClock->AddRef();
|
||||
}
|
||||
|
||||
// Set event sink for notifications
|
||||
// The filter should call this in its JoinFilterGraph after it creates the
|
||||
// IMediaEventSink
|
||||
//
|
||||
void SetFilterGraph( IMediaEventSink *pSink ) {
|
||||
m_pSink = pSink;
|
||||
}
|
||||
|
||||
// Since we schedule in stream time, we need the tStart and must track the
|
||||
// state of our owning filter.
|
||||
// The app should call this ever state change
|
||||
//
|
||||
void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 );
|
||||
|
||||
// Filter should call Flushing(TRUE) in BeginFlush,
|
||||
// and Flushing(FALSE) in EndFlush.
|
||||
//
|
||||
void Flushing( BOOL bInProgress );
|
||||
|
||||
|
||||
// The two main methods of IAMStreamControl
|
||||
|
||||
// Class adds default values suitable for immediate
|
||||
// muting and unmuting of the stream.
|
||||
|
||||
STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL,
|
||||
BOOL bSendExtra = FALSE,
|
||||
DWORD dwCookie = 0 );
|
||||
STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL,
|
||||
DWORD dwCookie = 0 );
|
||||
STDMETHODIMP GetInfo( AM_STREAM_INFO *pInfo);
|
||||
|
||||
// Helper function for pin's receive method. Call this with
|
||||
// the sample and we'll tell you what to do with it. We'll do a
|
||||
// WaitForSingleObject within this call if one is required. This is
|
||||
// a "What should I do with this sample?" kind of call. We'll tell the
|
||||
// caller to either flow it or discard it.
|
||||
// If pSample is NULL we evaluate based on the current state
|
||||
// settings
|
||||
enum StreamControlState CheckStreamState( IMediaSample * pSample );
|
||||
|
||||
private:
|
||||
// These don't require locking, but we are relying on the fact that
|
||||
// m_StreamState can be retrieved with integrity, and is a snap shot that
|
||||
// may have just been, or may be just about to be, changed.
|
||||
HANDLE GetStreamEventHandle() const { return m_StreamEvent; }
|
||||
enum StreamControlState GetStreamState() const { return m_StreamState; }
|
||||
BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,75 +1,75 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SysClock.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements a system clock based on
|
||||
// IReferenceClock.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
/*NABIL: I changed this*/
|
||||
//#ifdef FILTER_DLL
|
||||
|
||||
/* List of class IDs and creator functions for the class factory. This
|
||||
provides the link between the OLE entry point in the DLL and an object
|
||||
being created. The class factory will call the static CreateInstance
|
||||
function when it is asked to create a CLSID_SystemClock object */
|
||||
|
||||
/*NABIL: This was screwed up....(It didn't have the "blah")*/
|
||||
CFactoryTemplate g_Templates[1] = {
|
||||
{ (const WCHAR *) "blah", &CLSID_SystemClock, CSystemClock::CreateInstance }
|
||||
};
|
||||
|
||||
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
|
||||
//#endif
|
||||
|
||||
/* This goes in the factory template table to create new instances */
|
||||
CUnknown * WINAPI CSystemClock::CreateInstance(LPUNKNOWN pUnk,HRESULT *phr)
|
||||
{
|
||||
return new CSystemClock(NAME("System reference clock"),pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
CSystemClock::CSystemClock(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseReferenceClock(pName, pUnk, phr)
|
||||
{
|
||||
}
|
||||
|
||||
STDMETHODIMP CSystemClock::NonDelegatingQueryInterface(
|
||||
REFIID riid,
|
||||
void ** ppv)
|
||||
{
|
||||
if (riid == IID_IPersist)
|
||||
{
|
||||
return GetInterface(static_cast<IPersist *>(this), ppv);
|
||||
}
|
||||
else if (riid == IID_IAMClockAdjust)
|
||||
{
|
||||
return GetInterface(static_cast<IAMClockAdjust *>(this), ppv);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the clock's clsid */
|
||||
STDMETHODIMP
|
||||
CSystemClock::GetClassID(CLSID *pClsID)
|
||||
{
|
||||
CheckPointer(pClsID,E_POINTER);
|
||||
ValidateReadWritePtr(pClsID,sizeof(CLSID));
|
||||
*pClsID = CLSID_SystemClock;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta)
|
||||
{
|
||||
return SetTimeDelta(rtDelta);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SysClock.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements a system clock based on
|
||||
// IReferenceClock.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
/*NABIL: I changed this*/
|
||||
//#ifdef FILTER_DLL
|
||||
|
||||
/* List of class IDs and creator functions for the class factory. This
|
||||
provides the link between the OLE entry point in the DLL and an object
|
||||
being created. The class factory will call the static CreateInstance
|
||||
function when it is asked to create a CLSID_SystemClock object */
|
||||
|
||||
/*NABIL: This was screwed up....(It didn't have the "blah")*/
|
||||
CFactoryTemplate g_Templates[1] = {
|
||||
{ (const WCHAR *) "blah", &CLSID_SystemClock, CSystemClock::CreateInstance }
|
||||
};
|
||||
|
||||
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
|
||||
//#endif
|
||||
|
||||
/* This goes in the factory template table to create new instances */
|
||||
CUnknown * WINAPI CSystemClock::CreateInstance(LPUNKNOWN pUnk,HRESULT *phr)
|
||||
{
|
||||
return new CSystemClock(NAME("System reference clock"),pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
CSystemClock::CSystemClock(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseReferenceClock(pName, pUnk, phr)
|
||||
{
|
||||
}
|
||||
|
||||
STDMETHODIMP CSystemClock::NonDelegatingQueryInterface(
|
||||
REFIID riid,
|
||||
void ** ppv)
|
||||
{
|
||||
if (riid == IID_IPersist)
|
||||
{
|
||||
return GetInterface(static_cast<IPersist *>(this), ppv);
|
||||
}
|
||||
else if (riid == IID_IAMClockAdjust)
|
||||
{
|
||||
return GetInterface(static_cast<IAMClockAdjust *>(this), ppv);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the clock's clsid */
|
||||
STDMETHODIMP
|
||||
CSystemClock::GetClassID(CLSID *pClsID)
|
||||
{
|
||||
CheckPointer(pClsID,E_POINTER);
|
||||
ValidateReadWritePtr(pClsID,sizeof(CLSID));
|
||||
*pClsID = CLSID_SystemClock;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta)
|
||||
{
|
||||
return SetTimeDelta(rtDelta);
|
||||
}
|
||||
|
||||
+39
-39
@@ -1,39 +1,39 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SysClock.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a system clock implementation of
|
||||
// IReferenceClock.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __SYSTEMCLOCK__
|
||||
#define __SYSTEMCLOCK__
|
||||
|
||||
//
|
||||
// Base clock. Uses timeGetTime ONLY
|
||||
// Uses most of the code in the base reference clock.
|
||||
// Provides GetTime
|
||||
//
|
||||
|
||||
class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist
|
||||
{
|
||||
public:
|
||||
// We must be able to create an instance of ourselves
|
||||
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
CSystemClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv);
|
||||
|
||||
// Yield up our class id so that we can be persisted
|
||||
// Implement required Ipersist method
|
||||
STDMETHODIMP GetClassID(CLSID *pClsID);
|
||||
|
||||
// IAMClockAdjust methods
|
||||
STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta);
|
||||
}; //CSystemClock
|
||||
|
||||
#endif /* __SYSTEMCLOCK__ */
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SysClock.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a system clock implementation of
|
||||
// IReferenceClock.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __SYSTEMCLOCK__
|
||||
#define __SYSTEMCLOCK__
|
||||
|
||||
//
|
||||
// Base clock. Uses timeGetTime ONLY
|
||||
// Uses most of the code in the base reference clock.
|
||||
// Provides GetTime
|
||||
//
|
||||
|
||||
class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist
|
||||
{
|
||||
public:
|
||||
// We must be able to create an instance of ourselves
|
||||
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
CSystemClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv);
|
||||
|
||||
// Yield up our class id so that we can be persisted
|
||||
// Implement required Ipersist method
|
||||
STDMETHODIMP GetClassID(CLSID *pClsID);
|
||||
|
||||
// IAMClockAdjust methods
|
||||
STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta);
|
||||
}; //CSystemClock
|
||||
|
||||
#endif /* __SYSTEMCLOCK__ */
|
||||
|
||||
+974
-974
File diff suppressed because it is too large
Load Diff
+304
-304
@@ -1,304 +1,304 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Transfrm.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes from which simple
|
||||
// transform codecs may be derived.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// It assumes the codec has one input and one output stream, and has no
|
||||
// interest in memory management, interface negotiation or anything else.
|
||||
//
|
||||
// derive your class from this, and supply Transform and the media type/format
|
||||
// negotiation functions. Implement that class, compile and link and
|
||||
// you're done.
|
||||
|
||||
|
||||
#ifndef __TRANSFRM__
|
||||
#define __TRANSFRM__
|
||||
|
||||
// ======================================================================
|
||||
// This is the com object that represents a simple transform filter. It
|
||||
// supports IBaseFilter, IMediaFilter and two pins through nested interfaces
|
||||
// ======================================================================
|
||||
|
||||
class CTransformFilter;
|
||||
|
||||
// ==================================================
|
||||
// Implements the input pin
|
||||
// ==================================================
|
||||
|
||||
class CTransformInputPin : public CBaseInputPin
|
||||
{
|
||||
friend class CTransformFilter;
|
||||
|
||||
protected:
|
||||
CTransformFilter *m_pTransformFilter;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CTransformInputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CTransformInputPin(
|
||||
char *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR * Id)
|
||||
{
|
||||
return AMGetWideString(L"In", Id);
|
||||
}
|
||||
|
||||
// Grab and release extra interfaces if required
|
||||
|
||||
HRESULT CheckConnect(IPin *pPin);
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// check that we can support this output type
|
||||
HRESULT CheckMediaType(const CMediaType* mtIn);
|
||||
|
||||
// set the connection media type
|
||||
HRESULT SetMediaType(const CMediaType* mt);
|
||||
|
||||
// --- IMemInputPin -----
|
||||
|
||||
// here's the next block of data from the stream.
|
||||
// AddRef it yourself if you need to hold it beyond the end
|
||||
// of this call.
|
||||
STDMETHODIMP Receive(IMediaSample * pSample);
|
||||
|
||||
// provide EndOfStream that passes straight downstream
|
||||
// (there is no queued data)
|
||||
STDMETHODIMP EndOfStream(void);
|
||||
|
||||
// passes it to CTransformFilter::BeginFlush
|
||||
STDMETHODIMP BeginFlush(void);
|
||||
|
||||
// passes it to CTransformFilter::EndFlush
|
||||
STDMETHODIMP EndFlush(void);
|
||||
|
||||
STDMETHODIMP NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
// Check if it's OK to process samples
|
||||
virtual HRESULT CheckStreaming();
|
||||
|
||||
// Media type
|
||||
public:
|
||||
CMediaType& CurrentMediaType() { return m_mt; };
|
||||
|
||||
};
|
||||
|
||||
// ==================================================
|
||||
// Implements the output pin
|
||||
// ==================================================
|
||||
|
||||
class CTransformOutputPin : public CBaseOutputPin
|
||||
{
|
||||
friend class CTransformFilter;
|
||||
|
||||
protected:
|
||||
CTransformFilter *m_pTransformFilter;
|
||||
|
||||
public:
|
||||
|
||||
// implement IMediaPosition by passing upstream
|
||||
IUnknown * m_pPosition;
|
||||
|
||||
CTransformOutputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CTransformOutputPin(
|
||||
CHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
~CTransformOutputPin();
|
||||
|
||||
// override to expose IMediaPosition
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
|
||||
|
||||
// --- CBaseOutputPin ------------
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR * Id)
|
||||
{
|
||||
return AMGetWideString(L"Out", Id);
|
||||
}
|
||||
|
||||
// Grab and release extra interfaces if required
|
||||
|
||||
HRESULT CheckConnect(IPin *pPin);
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// check that we can support this output type
|
||||
HRESULT CheckMediaType(const CMediaType* mtOut);
|
||||
|
||||
// set the connection media type
|
||||
HRESULT SetMediaType(const CMediaType *pmt);
|
||||
|
||||
// called from CBaseOutputPin during connection to ask for
|
||||
// the count and size of buffers we need.
|
||||
HRESULT DecideBufferSize(
|
||||
IMemAllocator * pAlloc,
|
||||
ALLOCATOR_PROPERTIES *pProp);
|
||||
|
||||
// returns the preferred formats for a pin
|
||||
HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);
|
||||
|
||||
// inherited from IQualityControl via CBasePin
|
||||
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
|
||||
|
||||
// Media type
|
||||
public:
|
||||
CMediaType& CurrentMediaType() { return m_mt; };
|
||||
};
|
||||
|
||||
|
||||
class AM_NOVTABLE CTransformFilter : public CBaseFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// map getpin/getpincount for base enum of pins to owner
|
||||
// override this to return more specialised pin objects
|
||||
|
||||
virtual int GetPinCount();
|
||||
virtual CBasePin * GetPin(int n);
|
||||
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
|
||||
|
||||
// override state changes to allow derived transform filter
|
||||
// to control streaming start/stop
|
||||
STDMETHODIMP Stop();
|
||||
STDMETHODIMP Pause();
|
||||
|
||||
public:
|
||||
|
||||
CTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
#ifdef UNICODE
|
||||
CTransformFilter(CHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
#endif
|
||||
~CTransformFilter();
|
||||
|
||||
// =================================================================
|
||||
// ----- override these bits ---------------------------------------
|
||||
// =================================================================
|
||||
|
||||
// These must be supplied in a derived class
|
||||
|
||||
virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
|
||||
|
||||
// check if you can support mtIn
|
||||
virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
|
||||
|
||||
// check if you can support the transform from this input to this output
|
||||
virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE;
|
||||
|
||||
// this goes in the factory template table to create new instances
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
// call the SetProperties function with appropriate arguments
|
||||
virtual HRESULT DecideBufferSize(
|
||||
IMemAllocator * pAllocator,
|
||||
ALLOCATOR_PROPERTIES *pprop) PURE;
|
||||
|
||||
// override to suggest OUTPUT pin media types
|
||||
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
|
||||
|
||||
|
||||
|
||||
// =================================================================
|
||||
// ----- Optional Override Methods -----------------------
|
||||
// =================================================================
|
||||
|
||||
// you can also override these if you want to know about streaming
|
||||
virtual HRESULT StartStreaming();
|
||||
virtual HRESULT StopStreaming();
|
||||
|
||||
// override if you can do anything constructive with quality notifications
|
||||
virtual HRESULT AlterQuality(Quality q);
|
||||
|
||||
// override this to know when the media type is actually set
|
||||
virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
|
||||
|
||||
// chance to grab extra interfaces on connection
|
||||
virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
|
||||
virtual HRESULT BreakConnect(PIN_DIRECTION dir);
|
||||
virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
|
||||
|
||||
// chance to customize the transform process
|
||||
virtual HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// Standard setup for output sample
|
||||
HRESULT InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample);
|
||||
|
||||
// if you override Receive, you may need to override these three too
|
||||
virtual HRESULT EndOfStream(void);
|
||||
virtual HRESULT BeginFlush(void);
|
||||
virtual HRESULT EndFlush(void);
|
||||
virtual HRESULT NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
#ifdef PERF
|
||||
// Override to register performance measurement with a less generic string
|
||||
// You should do this to avoid confusion with other filters
|
||||
virtual void RegisterPerfId()
|
||||
{m_idTransform = MSR_REGISTER(TEXT("Transform"));}
|
||||
#endif // PERF
|
||||
|
||||
|
||||
// implementation details
|
||||
|
||||
protected:
|
||||
|
||||
#ifdef PERF
|
||||
int m_idTransform; // performance measuring id
|
||||
#endif
|
||||
BOOL m_bEOSDelivered; // have we sent EndOfStream
|
||||
BOOL m_bSampleSkipped; // Did we just skip a frame
|
||||
BOOL m_bQualityChanged; // Have we degraded?
|
||||
|
||||
// critical section protecting filter state.
|
||||
|
||||
CCritSec m_csFilter;
|
||||
|
||||
// critical section stopping state changes (ie Stop) while we're
|
||||
// processing a sample.
|
||||
//
|
||||
// This critical section is held when processing
|
||||
// events that occur on the receive thread - Receive() and EndOfStream().
|
||||
//
|
||||
// If you want to hold both m_csReceive and m_csFilter then grab
|
||||
// m_csFilter FIRST - like CTransformFilter::Stop() does.
|
||||
|
||||
CCritSec m_csReceive;
|
||||
|
||||
// these hold our input and output pins
|
||||
|
||||
friend class CTransformInputPin;
|
||||
friend class CTransformOutputPin;
|
||||
CTransformInputPin *m_pInput;
|
||||
CTransformOutputPin *m_pOutput;
|
||||
};
|
||||
|
||||
#endif /* __TRANSFRM__ */
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Transfrm.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes from which simple
|
||||
// transform codecs may be derived.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// It assumes the codec has one input and one output stream, and has no
|
||||
// interest in memory management, interface negotiation or anything else.
|
||||
//
|
||||
// derive your class from this, and supply Transform and the media type/format
|
||||
// negotiation functions. Implement that class, compile and link and
|
||||
// you're done.
|
||||
|
||||
|
||||
#ifndef __TRANSFRM__
|
||||
#define __TRANSFRM__
|
||||
|
||||
// ======================================================================
|
||||
// This is the com object that represents a simple transform filter. It
|
||||
// supports IBaseFilter, IMediaFilter and two pins through nested interfaces
|
||||
// ======================================================================
|
||||
|
||||
class CTransformFilter;
|
||||
|
||||
// ==================================================
|
||||
// Implements the input pin
|
||||
// ==================================================
|
||||
|
||||
class CTransformInputPin : public CBaseInputPin
|
||||
{
|
||||
friend class CTransformFilter;
|
||||
|
||||
protected:
|
||||
CTransformFilter *m_pTransformFilter;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CTransformInputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CTransformInputPin(
|
||||
char *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR * Id)
|
||||
{
|
||||
return AMGetWideString(L"In", Id);
|
||||
}
|
||||
|
||||
// Grab and release extra interfaces if required
|
||||
|
||||
HRESULT CheckConnect(IPin *pPin);
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// check that we can support this output type
|
||||
HRESULT CheckMediaType(const CMediaType* mtIn);
|
||||
|
||||
// set the connection media type
|
||||
HRESULT SetMediaType(const CMediaType* mt);
|
||||
|
||||
// --- IMemInputPin -----
|
||||
|
||||
// here's the next block of data from the stream.
|
||||
// AddRef it yourself if you need to hold it beyond the end
|
||||
// of this call.
|
||||
STDMETHODIMP Receive(IMediaSample * pSample);
|
||||
|
||||
// provide EndOfStream that passes straight downstream
|
||||
// (there is no queued data)
|
||||
STDMETHODIMP EndOfStream(void);
|
||||
|
||||
// passes it to CTransformFilter::BeginFlush
|
||||
STDMETHODIMP BeginFlush(void);
|
||||
|
||||
// passes it to CTransformFilter::EndFlush
|
||||
STDMETHODIMP EndFlush(void);
|
||||
|
||||
STDMETHODIMP NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
// Check if it's OK to process samples
|
||||
virtual HRESULT CheckStreaming();
|
||||
|
||||
// Media type
|
||||
public:
|
||||
CMediaType& CurrentMediaType() { return m_mt; };
|
||||
|
||||
};
|
||||
|
||||
// ==================================================
|
||||
// Implements the output pin
|
||||
// ==================================================
|
||||
|
||||
class CTransformOutputPin : public CBaseOutputPin
|
||||
{
|
||||
friend class CTransformFilter;
|
||||
|
||||
protected:
|
||||
CTransformFilter *m_pTransformFilter;
|
||||
|
||||
public:
|
||||
|
||||
// implement IMediaPosition by passing upstream
|
||||
IUnknown * m_pPosition;
|
||||
|
||||
CTransformOutputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CTransformOutputPin(
|
||||
CHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
~CTransformOutputPin();
|
||||
|
||||
// override to expose IMediaPosition
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
|
||||
|
||||
// --- CBaseOutputPin ------------
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR * Id)
|
||||
{
|
||||
return AMGetWideString(L"Out", Id);
|
||||
}
|
||||
|
||||
// Grab and release extra interfaces if required
|
||||
|
||||
HRESULT CheckConnect(IPin *pPin);
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// check that we can support this output type
|
||||
HRESULT CheckMediaType(const CMediaType* mtOut);
|
||||
|
||||
// set the connection media type
|
||||
HRESULT SetMediaType(const CMediaType *pmt);
|
||||
|
||||
// called from CBaseOutputPin during connection to ask for
|
||||
// the count and size of buffers we need.
|
||||
HRESULT DecideBufferSize(
|
||||
IMemAllocator * pAlloc,
|
||||
ALLOCATOR_PROPERTIES *pProp);
|
||||
|
||||
// returns the preferred formats for a pin
|
||||
HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);
|
||||
|
||||
// inherited from IQualityControl via CBasePin
|
||||
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
|
||||
|
||||
// Media type
|
||||
public:
|
||||
CMediaType& CurrentMediaType() { return m_mt; };
|
||||
};
|
||||
|
||||
|
||||
class AM_NOVTABLE CTransformFilter : public CBaseFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// map getpin/getpincount for base enum of pins to owner
|
||||
// override this to return more specialised pin objects
|
||||
|
||||
virtual int GetPinCount();
|
||||
virtual CBasePin * GetPin(int n);
|
||||
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
|
||||
|
||||
// override state changes to allow derived transform filter
|
||||
// to control streaming start/stop
|
||||
STDMETHODIMP Stop();
|
||||
STDMETHODIMP Pause();
|
||||
|
||||
public:
|
||||
|
||||
CTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
#ifdef UNICODE
|
||||
CTransformFilter(CHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
#endif
|
||||
~CTransformFilter();
|
||||
|
||||
// =================================================================
|
||||
// ----- override these bits ---------------------------------------
|
||||
// =================================================================
|
||||
|
||||
// These must be supplied in a derived class
|
||||
|
||||
virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
|
||||
|
||||
// check if you can support mtIn
|
||||
virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
|
||||
|
||||
// check if you can support the transform from this input to this output
|
||||
virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE;
|
||||
|
||||
// this goes in the factory template table to create new instances
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
// call the SetProperties function with appropriate arguments
|
||||
virtual HRESULT DecideBufferSize(
|
||||
IMemAllocator * pAllocator,
|
||||
ALLOCATOR_PROPERTIES *pprop) PURE;
|
||||
|
||||
// override to suggest OUTPUT pin media types
|
||||
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
|
||||
|
||||
|
||||
|
||||
// =================================================================
|
||||
// ----- Optional Override Methods -----------------------
|
||||
// =================================================================
|
||||
|
||||
// you can also override these if you want to know about streaming
|
||||
virtual HRESULT StartStreaming();
|
||||
virtual HRESULT StopStreaming();
|
||||
|
||||
// override if you can do anything constructive with quality notifications
|
||||
virtual HRESULT AlterQuality(Quality q);
|
||||
|
||||
// override this to know when the media type is actually set
|
||||
virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
|
||||
|
||||
// chance to grab extra interfaces on connection
|
||||
virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
|
||||
virtual HRESULT BreakConnect(PIN_DIRECTION dir);
|
||||
virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
|
||||
|
||||
// chance to customize the transform process
|
||||
virtual HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// Standard setup for output sample
|
||||
HRESULT InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample);
|
||||
|
||||
// if you override Receive, you may need to override these three too
|
||||
virtual HRESULT EndOfStream(void);
|
||||
virtual HRESULT BeginFlush(void);
|
||||
virtual HRESULT EndFlush(void);
|
||||
virtual HRESULT NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
#ifdef PERF
|
||||
// Override to register performance measurement with a less generic string
|
||||
// You should do this to avoid confusion with other filters
|
||||
virtual void RegisterPerfId()
|
||||
{m_idTransform = MSR_REGISTER(TEXT("Transform"));}
|
||||
#endif // PERF
|
||||
|
||||
|
||||
// implementation details
|
||||
|
||||
protected:
|
||||
|
||||
#ifdef PERF
|
||||
int m_idTransform; // performance measuring id
|
||||
#endif
|
||||
BOOL m_bEOSDelivered; // have we sent EndOfStream
|
||||
BOOL m_bSampleSkipped; // Did we just skip a frame
|
||||
BOOL m_bQualityChanged; // Have we degraded?
|
||||
|
||||
// critical section protecting filter state.
|
||||
|
||||
CCritSec m_csFilter;
|
||||
|
||||
// critical section stopping state changes (ie Stop) while we're
|
||||
// processing a sample.
|
||||
//
|
||||
// This critical section is held when processing
|
||||
// events that occur on the receive thread - Receive() and EndOfStream().
|
||||
//
|
||||
// If you want to hold both m_csReceive and m_csFilter then grab
|
||||
// m_csFilter FIRST - like CTransformFilter::Stop() does.
|
||||
|
||||
CCritSec m_csReceive;
|
||||
|
||||
// these hold our input and output pins
|
||||
|
||||
friend class CTransformInputPin;
|
||||
friend class CTransformOutputPin;
|
||||
CTransformInputPin *m_pInput;
|
||||
CTransformOutputPin *m_pOutput;
|
||||
};
|
||||
|
||||
#endif /* __TRANSFRM__ */
|
||||
|
||||
|
||||
|
||||
+922
-922
File diff suppressed because it is too large
Load Diff
+246
-246
@@ -1,246 +1,246 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: TransIP.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes from which simple
|
||||
// Transform-In-Place filters may be derived.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// The difference between this and Transfrm.h is that Transfrm copies the data.
|
||||
//
|
||||
// It assumes the filter has one input and one output stream, and has no
|
||||
// interest in memory management, interface negotiation or anything else.
|
||||
//
|
||||
// Derive your class from this, and supply Transform and the media type/format
|
||||
// negotiation functions. Implement that class, compile and link and
|
||||
// you're done.
|
||||
|
||||
|
||||
#ifndef __TRANSIP__
|
||||
#define __TRANSIP__
|
||||
|
||||
// ======================================================================
|
||||
// This is the com object that represents a simple transform filter. It
|
||||
// supports IBaseFilter, IMediaFilter and two pins through nested interfaces
|
||||
// ======================================================================
|
||||
|
||||
class CTransInPlaceFilter;
|
||||
|
||||
// Several of the pin functions call filter functions to do the work,
|
||||
// so you can often use the pin classes unaltered, just overriding the
|
||||
// functions in CTransInPlaceFilter. If that's not enough and you want
|
||||
// to derive your own pin class, override GetPin in the filter to supply
|
||||
// your own pin classes to the filter.
|
||||
|
||||
// ==================================================
|
||||
// Implements the input pin
|
||||
// ==================================================
|
||||
|
||||
class CTransInPlaceInputPin : public CTransformInputPin
|
||||
{
|
||||
|
||||
protected:
|
||||
CTransInPlaceFilter * const m_pTIPFilter; // our filter
|
||||
BOOL m_bReadOnly; // incoming stream is read only
|
||||
|
||||
public:
|
||||
|
||||
CTransInPlaceInputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransInPlaceFilter *pFilter,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
|
||||
// --- IMemInputPin -----
|
||||
|
||||
// Provide an enumerator for media types by getting one from downstream
|
||||
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
|
||||
|
||||
// Say whether media type is acceptable.
|
||||
HRESULT CheckMediaType(const CMediaType* pmt);
|
||||
|
||||
// Return our upstream allocator
|
||||
STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator);
|
||||
|
||||
// get told which allocator the upstream output pin is actually
|
||||
// going to use.
|
||||
STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator,
|
||||
BOOL bReadOnly);
|
||||
|
||||
// Allow the filter to see what allocator we have
|
||||
// N.B. This does NOT AddRef
|
||||
IMemAllocator * PeekAllocator() const
|
||||
{ return m_pAllocator; }
|
||||
|
||||
// Pass this on downstream if it ever gets called.
|
||||
STDMETHODIMP
|
||||
CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps);
|
||||
|
||||
inline const BOOL ReadOnly() { return m_bReadOnly ; }
|
||||
|
||||
}; // CTransInPlaceInputPin
|
||||
|
||||
// ==================================================
|
||||
// Implements the output pin
|
||||
// ==================================================
|
||||
|
||||
class CTransInPlaceOutputPin : public CTransformOutputPin
|
||||
{
|
||||
|
||||
protected:
|
||||
// m_pFilter points to our CBaseFilter
|
||||
CTransInPlaceFilter * const m_pTIPFilter;
|
||||
|
||||
public:
|
||||
|
||||
CTransInPlaceOutputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransInPlaceFilter *pFilter,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
|
||||
|
||||
// --- CBaseOutputPin ------------
|
||||
|
||||
// negotiate the allocator and its buffer size/count
|
||||
// Insists on using our own allocator. (Actually the one upstream of us).
|
||||
// We don't override this - instead we just agree the default
|
||||
// then let the upstream filter decide for itself on reconnect
|
||||
// virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
|
||||
|
||||
// Provide a media type enumerator. Get it from upstream.
|
||||
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
|
||||
|
||||
// Say whether media type is acceptable.
|
||||
HRESULT CheckMediaType(const CMediaType* pmt);
|
||||
|
||||
// This just saves the allocator being used on the output pin
|
||||
// Also called by input pin's GetAllocator()
|
||||
void SetAllocator(IMemAllocator * pAllocator);
|
||||
|
||||
IMemInputPin * ConnectedIMemInputPin()
|
||||
{ return m_pInputPin; }
|
||||
|
||||
// Allow the filter to see what allocator we have
|
||||
// N.B. This does NOT AddRef
|
||||
IMemAllocator * PeekAllocator() const
|
||||
{ return m_pAllocator; }
|
||||
}; // CTransInPlaceOutputPin
|
||||
|
||||
|
||||
class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// map getpin/getpincount for base enum of pins to owner
|
||||
// override this to return more specialised pin objects
|
||||
|
||||
virtual CBasePin *GetPin(int n);
|
||||
|
||||
public:
|
||||
|
||||
// Set bModifiesData == false if your derived filter does
|
||||
// not modify the data samples (for instance it's just copying
|
||||
// them somewhere else or looking at the timestamps).
|
||||
|
||||
CTransInPlaceFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *,
|
||||
bool bModifiesData = true);
|
||||
#ifdef UNICODE
|
||||
CTransInPlaceFilter(CHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *,
|
||||
bool bModifiesData = true);
|
||||
#endif
|
||||
// The following are defined to avoid undefined pure virtuals.
|
||||
// Even if they are never called, they will give linkage warnings/errors
|
||||
|
||||
// We override EnumMediaTypes to bypass the transform class enumerator
|
||||
// which would otherwise call this.
|
||||
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType)
|
||||
{ DbgBreak("CTransInPlaceFilter::GetMediaType should never be called");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// This is called when we actually have to provide out own allocator.
|
||||
HRESULT DecideBufferSize(IMemAllocator*, ALLOCATOR_PROPERTIES *);
|
||||
|
||||
// The functions which call this in CTransform are overridden in this
|
||||
// class to call CheckInputType with the assumption that the type
|
||||
// does not change. In Debug builds some calls will be made and
|
||||
// we just ensure that they do not assert.
|
||||
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
|
||||
{
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
|
||||
// =================================================================
|
||||
// ----- You may want to override this -----------------------------
|
||||
// =================================================================
|
||||
|
||||
HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin);
|
||||
|
||||
// chance to customize the transform process
|
||||
virtual HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// =================================================================
|
||||
// ----- You MUST override these -----------------------------------
|
||||
// =================================================================
|
||||
|
||||
virtual HRESULT Transform(IMediaSample *pSample) PURE;
|
||||
|
||||
// this goes in the factory template table to create new instances
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
|
||||
#ifdef PERF
|
||||
// Override to register performance measurement with a less generic string
|
||||
// You should do this to avoid confusion with other filters
|
||||
virtual void RegisterPerfId()
|
||||
{m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));}
|
||||
#endif // PERF
|
||||
|
||||
|
||||
// implementation details
|
||||
|
||||
protected:
|
||||
|
||||
IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource);
|
||||
|
||||
#ifdef PERF
|
||||
int m_idTransInPlace; // performance measuring id
|
||||
#endif // PERF
|
||||
bool m_bModifiesData; // Does this filter change the data?
|
||||
|
||||
// these hold our input and output pins
|
||||
|
||||
friend class CTransInPlaceInputPin;
|
||||
friend class CTransInPlaceOutputPin;
|
||||
|
||||
CTransInPlaceInputPin *InputPin() const
|
||||
{
|
||||
return (CTransInPlaceInputPin *)m_pInput;
|
||||
};
|
||||
CTransInPlaceOutputPin *OutputPin() const
|
||||
{
|
||||
return (CTransInPlaceOutputPin *)m_pOutput;
|
||||
};
|
||||
|
||||
// Helper to see if the input and output types match
|
||||
BOOL TypesMatch()
|
||||
{
|
||||
return InputPin()->CurrentMediaType() ==
|
||||
OutputPin()->CurrentMediaType();
|
||||
}
|
||||
|
||||
// Are the input and output allocators different?
|
||||
BOOL UsingDifferentAllocators() const
|
||||
{
|
||||
return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator();
|
||||
}
|
||||
}; // CTransInPlaceFilter
|
||||
|
||||
#endif /* __TRANSIP__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: TransIP.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes from which simple
|
||||
// Transform-In-Place filters may be derived.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// The difference between this and Transfrm.h is that Transfrm copies the data.
|
||||
//
|
||||
// It assumes the filter has one input and one output stream, and has no
|
||||
// interest in memory management, interface negotiation or anything else.
|
||||
//
|
||||
// Derive your class from this, and supply Transform and the media type/format
|
||||
// negotiation functions. Implement that class, compile and link and
|
||||
// you're done.
|
||||
|
||||
|
||||
#ifndef __TRANSIP__
|
||||
#define __TRANSIP__
|
||||
|
||||
// ======================================================================
|
||||
// This is the com object that represents a simple transform filter. It
|
||||
// supports IBaseFilter, IMediaFilter and two pins through nested interfaces
|
||||
// ======================================================================
|
||||
|
||||
class CTransInPlaceFilter;
|
||||
|
||||
// Several of the pin functions call filter functions to do the work,
|
||||
// so you can often use the pin classes unaltered, just overriding the
|
||||
// functions in CTransInPlaceFilter. If that's not enough and you want
|
||||
// to derive your own pin class, override GetPin in the filter to supply
|
||||
// your own pin classes to the filter.
|
||||
|
||||
// ==================================================
|
||||
// Implements the input pin
|
||||
// ==================================================
|
||||
|
||||
class CTransInPlaceInputPin : public CTransformInputPin
|
||||
{
|
||||
|
||||
protected:
|
||||
CTransInPlaceFilter * const m_pTIPFilter; // our filter
|
||||
BOOL m_bReadOnly; // incoming stream is read only
|
||||
|
||||
public:
|
||||
|
||||
CTransInPlaceInputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransInPlaceFilter *pFilter,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
|
||||
// --- IMemInputPin -----
|
||||
|
||||
// Provide an enumerator for media types by getting one from downstream
|
||||
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
|
||||
|
||||
// Say whether media type is acceptable.
|
||||
HRESULT CheckMediaType(const CMediaType* pmt);
|
||||
|
||||
// Return our upstream allocator
|
||||
STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator);
|
||||
|
||||
// get told which allocator the upstream output pin is actually
|
||||
// going to use.
|
||||
STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator,
|
||||
BOOL bReadOnly);
|
||||
|
||||
// Allow the filter to see what allocator we have
|
||||
// N.B. This does NOT AddRef
|
||||
IMemAllocator * PeekAllocator() const
|
||||
{ return m_pAllocator; }
|
||||
|
||||
// Pass this on downstream if it ever gets called.
|
||||
STDMETHODIMP
|
||||
CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps);
|
||||
|
||||
inline const BOOL ReadOnly() { return m_bReadOnly ; }
|
||||
|
||||
}; // CTransInPlaceInputPin
|
||||
|
||||
// ==================================================
|
||||
// Implements the output pin
|
||||
// ==================================================
|
||||
|
||||
class CTransInPlaceOutputPin : public CTransformOutputPin
|
||||
{
|
||||
|
||||
protected:
|
||||
// m_pFilter points to our CBaseFilter
|
||||
CTransInPlaceFilter * const m_pTIPFilter;
|
||||
|
||||
public:
|
||||
|
||||
CTransInPlaceOutputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransInPlaceFilter *pFilter,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
|
||||
|
||||
// --- CBaseOutputPin ------------
|
||||
|
||||
// negotiate the allocator and its buffer size/count
|
||||
// Insists on using our own allocator. (Actually the one upstream of us).
|
||||
// We don't override this - instead we just agree the default
|
||||
// then let the upstream filter decide for itself on reconnect
|
||||
// virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
|
||||
|
||||
// Provide a media type enumerator. Get it from upstream.
|
||||
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
|
||||
|
||||
// Say whether media type is acceptable.
|
||||
HRESULT CheckMediaType(const CMediaType* pmt);
|
||||
|
||||
// This just saves the allocator being used on the output pin
|
||||
// Also called by input pin's GetAllocator()
|
||||
void SetAllocator(IMemAllocator * pAllocator);
|
||||
|
||||
IMemInputPin * ConnectedIMemInputPin()
|
||||
{ return m_pInputPin; }
|
||||
|
||||
// Allow the filter to see what allocator we have
|
||||
// N.B. This does NOT AddRef
|
||||
IMemAllocator * PeekAllocator() const
|
||||
{ return m_pAllocator; }
|
||||
}; // CTransInPlaceOutputPin
|
||||
|
||||
|
||||
class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// map getpin/getpincount for base enum of pins to owner
|
||||
// override this to return more specialised pin objects
|
||||
|
||||
virtual CBasePin *GetPin(int n);
|
||||
|
||||
public:
|
||||
|
||||
// Set bModifiesData == false if your derived filter does
|
||||
// not modify the data samples (for instance it's just copying
|
||||
// them somewhere else or looking at the timestamps).
|
||||
|
||||
CTransInPlaceFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *,
|
||||
bool bModifiesData = true);
|
||||
#ifdef UNICODE
|
||||
CTransInPlaceFilter(CHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *,
|
||||
bool bModifiesData = true);
|
||||
#endif
|
||||
// The following are defined to avoid undefined pure virtuals.
|
||||
// Even if they are never called, they will give linkage warnings/errors
|
||||
|
||||
// We override EnumMediaTypes to bypass the transform class enumerator
|
||||
// which would otherwise call this.
|
||||
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType)
|
||||
{ DbgBreak("CTransInPlaceFilter::GetMediaType should never be called");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// This is called when we actually have to provide out own allocator.
|
||||
HRESULT DecideBufferSize(IMemAllocator*, ALLOCATOR_PROPERTIES *);
|
||||
|
||||
// The functions which call this in CTransform are overridden in this
|
||||
// class to call CheckInputType with the assumption that the type
|
||||
// does not change. In Debug builds some calls will be made and
|
||||
// we just ensure that they do not assert.
|
||||
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
|
||||
{
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
|
||||
// =================================================================
|
||||
// ----- You may want to override this -----------------------------
|
||||
// =================================================================
|
||||
|
||||
HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin);
|
||||
|
||||
// chance to customize the transform process
|
||||
virtual HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// =================================================================
|
||||
// ----- You MUST override these -----------------------------------
|
||||
// =================================================================
|
||||
|
||||
virtual HRESULT Transform(IMediaSample *pSample) PURE;
|
||||
|
||||
// this goes in the factory template table to create new instances
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
|
||||
#ifdef PERF
|
||||
// Override to register performance measurement with a less generic string
|
||||
// You should do this to avoid confusion with other filters
|
||||
virtual void RegisterPerfId()
|
||||
{m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));}
|
||||
#endif // PERF
|
||||
|
||||
|
||||
// implementation details
|
||||
|
||||
protected:
|
||||
|
||||
IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource);
|
||||
|
||||
#ifdef PERF
|
||||
int m_idTransInPlace; // performance measuring id
|
||||
#endif // PERF
|
||||
bool m_bModifiesData; // Does this filter change the data?
|
||||
|
||||
// these hold our input and output pins
|
||||
|
||||
friend class CTransInPlaceInputPin;
|
||||
friend class CTransInPlaceOutputPin;
|
||||
|
||||
CTransInPlaceInputPin *InputPin() const
|
||||
{
|
||||
return (CTransInPlaceInputPin *)m_pInput;
|
||||
};
|
||||
CTransInPlaceOutputPin *OutputPin() const
|
||||
{
|
||||
return (CTransInPlaceOutputPin *)m_pOutput;
|
||||
};
|
||||
|
||||
// Helper to see if the input and output types match
|
||||
BOOL TypesMatch()
|
||||
{
|
||||
return InputPin()->CurrentMediaType() ==
|
||||
OutputPin()->CurrentMediaType();
|
||||
}
|
||||
|
||||
// Are the input and output allocators different?
|
||||
BOOL UsingDifferentAllocators() const
|
||||
{
|
||||
return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator();
|
||||
}
|
||||
}; // CTransInPlaceFilter
|
||||
|
||||
#endif /* __TRANSIP__ */
|
||||
|
||||
|
||||
+653
-653
File diff suppressed because it is too large
Load Diff
+178
-178
@@ -1,178 +1,178 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: VideoCtl.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __VIDEOCTL__
|
||||
#define __VIDEOCTL__
|
||||
|
||||
// These help with property page implementations. The first can be used to
|
||||
// load any string from a resource file. The buffer to load into is passed
|
||||
// as an input parameter. The same buffer is the return value if the string
|
||||
// was found otherwise it returns TEXT(""). The GetDialogSize is passed the
|
||||
// resource ID of a dialog box and returns the size of it in screen pixels
|
||||
|
||||
#define STR_MAX_LENGTH 256
|
||||
TCHAR * WINAPI StringFromResource(TCHAR *pBuffer, int iResourceID);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define WideStringFromResource StringFromResource
|
||||
char* WINAPI StringFromResource(char*pBuffer, int iResourceID);
|
||||
#else
|
||||
WCHAR * WINAPI WideStringFromResource(WCHAR *pBuffer, int iResourceID);
|
||||
#endif
|
||||
|
||||
|
||||
BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier
|
||||
DLGPROC pDlgProc, // Pointer to dialog procedure
|
||||
LPARAM lParam, // Any user data wanted in pDlgProc
|
||||
SIZE *pResult); // Returns the size of dialog box
|
||||
|
||||
// Class that aggregates an IDirectDraw interface
|
||||
|
||||
class CAggDirectDraw : public IDirectDraw, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPDIRECTDRAW m_pDirectDraw;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CAggDirectDraw(TCHAR *pName,LPUNKNOWN pUnk) :
|
||||
CUnknown(pName,pUnk),
|
||||
m_pDirectDraw(NULL) { };
|
||||
|
||||
virtual CAggDirectDraw::~CAggDirectDraw() { };
|
||||
|
||||
// Set the object we should be aggregating
|
||||
void SetDirectDraw(LPDIRECTDRAW pDirectDraw) {
|
||||
m_pDirectDraw = pDirectDraw;
|
||||
}
|
||||
|
||||
// IDirectDraw methods
|
||||
|
||||
STDMETHODIMP Compact();
|
||||
STDMETHODIMP CreateClipper(DWORD dwFlags,LPDIRECTDRAWCLIPPER *lplpDDClipper,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP CreatePalette(DWORD dwFlags,LPPALETTEENTRY lpColorTable,LPDIRECTDRAWPALETTE *lplpDDPalette,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc,LPDIRECTDRAWSURFACE *lplpDDSurface,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP DuplicateSurface(LPDIRECTDRAWSURFACE lpDDSurface,LPDIRECTDRAWSURFACE *lplpDupDDSurface);
|
||||
STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,LPDDSURFACEDESC lplpDDSurfaceDescList,LPVOID lpContext,LPDDENUMMODESCALLBACK lpEnumCallback);
|
||||
STDMETHODIMP EnumSurfaces(DWORD dwFlags,LPDDSURFACEDESC lpDDSD,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumCallback);
|
||||
STDMETHODIMP FlipToGDISurface();
|
||||
STDMETHODIMP GetCaps(LPDDCAPS lpDDDriverCaps,LPDDCAPS lpDDHELCaps);
|
||||
STDMETHODIMP GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP GetFourCCCodes(LPDWORD lpNumCodes,LPDWORD lpCodes);
|
||||
STDMETHODIMP GetGDISurface(LPDIRECTDRAWSURFACE *lplpGDIDDSurface);
|
||||
STDMETHODIMP GetMonitorFrequency(LPDWORD lpdwFrequency);
|
||||
STDMETHODIMP GetScanLine(LPDWORD lpdwScanLine);
|
||||
STDMETHODIMP GetVerticalBlankStatus(LPBOOL lpblsInVB);
|
||||
STDMETHODIMP Initialize(GUID *lpGUID);
|
||||
STDMETHODIMP RestoreDisplayMode();
|
||||
STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags);
|
||||
STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp);
|
||||
STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent);
|
||||
};
|
||||
|
||||
|
||||
// Class that aggregates an IDirectDrawSurface interface
|
||||
|
||||
class CAggDrawSurface : public IDirectDrawSurface, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPDIRECTDRAWSURFACE m_pDirectDrawSurface;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CAggDrawSurface(TCHAR *pName,LPUNKNOWN pUnk) :
|
||||
CUnknown(pName,pUnk),
|
||||
m_pDirectDrawSurface(NULL) { };
|
||||
|
||||
virtual ~CAggDrawSurface() { };
|
||||
|
||||
// Set the object we should be aggregating
|
||||
void SetDirectDrawSurface(LPDIRECTDRAWSURFACE pDirectDrawSurface) {
|
||||
m_pDirectDrawSurface = pDirectDrawSurface;
|
||||
}
|
||||
|
||||
// IDirectDrawSurface methods
|
||||
|
||||
STDMETHODIMP AddAttachedSurface(LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
|
||||
STDMETHODIMP AddOverlayDirtyRect(LPRECT lpRect);
|
||||
STDMETHODIMP Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx);
|
||||
STDMETHODIMP BltBatch(LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags);
|
||||
STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwTrans);
|
||||
STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
|
||||
STDMETHODIMP EnumAttachedSurfaces(LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback);
|
||||
STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpfnCallback);
|
||||
STDMETHODIMP Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags);
|
||||
STDMETHODIMP GetAttachedSurface(LPDDSCAPS lpDDSCaps,LPDIRECTDRAWSURFACE *lplpDDAttachedSurface);
|
||||
STDMETHODIMP GetBltStatus(DWORD dwFlags);
|
||||
STDMETHODIMP GetCaps(LPDDSCAPS lpDDSCaps);
|
||||
STDMETHODIMP GetClipper(LPDIRECTDRAWCLIPPER *lplpDDClipper);
|
||||
STDMETHODIMP GetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey);
|
||||
STDMETHODIMP GetDC(HDC *lphDC);
|
||||
STDMETHODIMP GetFlipStatus(DWORD dwFlags);
|
||||
STDMETHODIMP GetOverlayPosition(LPLONG lpdwX,LPLONG lpdwY);
|
||||
STDMETHODIMP GetPalette(LPDIRECTDRAWPALETTE *lplpDDPalette);
|
||||
STDMETHODIMP GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat);
|
||||
STDMETHODIMP GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP Initialize(LPDIRECTDRAW lpDD,LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP IsLost();
|
||||
STDMETHODIMP Lock(LPRECT lpDestRect,LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent);
|
||||
STDMETHODIMP ReleaseDC(HDC hDC);
|
||||
STDMETHODIMP Restore();
|
||||
STDMETHODIMP SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);
|
||||
STDMETHODIMP SetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey);
|
||||
STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY);
|
||||
STDMETHODIMP SetPalette(LPDIRECTDRAWPALETTE lpDDPalette);
|
||||
STDMETHODIMP Unlock(LPVOID lpSurfaceData);
|
||||
STDMETHODIMP UpdateOverlay(LPRECT lpSrcRect,LPDIRECTDRAWSURFACE lpDDDestSurface,LPRECT lpDestRect,DWORD dwFlags,LPDDOVERLAYFX lpDDOverlayFX);
|
||||
STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags);
|
||||
STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSReference);
|
||||
};
|
||||
|
||||
|
||||
// DirectShow must work on multiple platforms. In particular, it also runs on
|
||||
// Windows NT 3.51 which does not have DirectDraw capabilities. The filters
|
||||
// cannot therefore link statically to the DirectDraw library. To make their
|
||||
// lives that little bit easier we provide this class that manages loading
|
||||
// and unloading the library and creating the initial IDirectDraw interface
|
||||
|
||||
typedef DWORD (WINAPI *PGETFILEVERSIONINFOSIZE)(LPTSTR,LPDWORD);
|
||||
typedef BOOL (WINAPI *PGETFILEVERSIONINFO)(LPTSTR,DWORD,DWORD,LPVOID);
|
||||
typedef BOOL (WINAPI *PVERQUERYVALUE)(LPVOID,LPTSTR,LPVOID,PUINT);
|
||||
|
||||
class CLoadDirectDraw
|
||||
{
|
||||
LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance
|
||||
HINSTANCE m_hDirectDraw; // Handle to the loaded library
|
||||
|
||||
public:
|
||||
|
||||
CLoadDirectDraw();
|
||||
~CLoadDirectDraw();
|
||||
|
||||
HRESULT LoadDirectDraw(LPSTR szDevice);
|
||||
void ReleaseDirectDraw();
|
||||
HRESULT IsDirectDrawLoaded();
|
||||
LPDIRECTDRAW GetDirectDraw();
|
||||
BOOL IsDirectDrawVersion1();
|
||||
};
|
||||
|
||||
#endif // __VIDEOCTL__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: VideoCtl.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __VIDEOCTL__
|
||||
#define __VIDEOCTL__
|
||||
|
||||
// These help with property page implementations. The first can be used to
|
||||
// load any string from a resource file. The buffer to load into is passed
|
||||
// as an input parameter. The same buffer is the return value if the string
|
||||
// was found otherwise it returns TEXT(""). The GetDialogSize is passed the
|
||||
// resource ID of a dialog box and returns the size of it in screen pixels
|
||||
|
||||
#define STR_MAX_LENGTH 256
|
||||
TCHAR * WINAPI StringFromResource(TCHAR *pBuffer, int iResourceID);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define WideStringFromResource StringFromResource
|
||||
char* WINAPI StringFromResource(char*pBuffer, int iResourceID);
|
||||
#else
|
||||
WCHAR * WINAPI WideStringFromResource(WCHAR *pBuffer, int iResourceID);
|
||||
#endif
|
||||
|
||||
|
||||
BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier
|
||||
DLGPROC pDlgProc, // Pointer to dialog procedure
|
||||
LPARAM lParam, // Any user data wanted in pDlgProc
|
||||
SIZE *pResult); // Returns the size of dialog box
|
||||
|
||||
// Class that aggregates an IDirectDraw interface
|
||||
|
||||
class CAggDirectDraw : public IDirectDraw, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPDIRECTDRAW m_pDirectDraw;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CAggDirectDraw(TCHAR *pName,LPUNKNOWN pUnk) :
|
||||
CUnknown(pName,pUnk),
|
||||
m_pDirectDraw(NULL) { };
|
||||
|
||||
virtual CAggDirectDraw::~CAggDirectDraw() { };
|
||||
|
||||
// Set the object we should be aggregating
|
||||
void SetDirectDraw(LPDIRECTDRAW pDirectDraw) {
|
||||
m_pDirectDraw = pDirectDraw;
|
||||
}
|
||||
|
||||
// IDirectDraw methods
|
||||
|
||||
STDMETHODIMP Compact();
|
||||
STDMETHODIMP CreateClipper(DWORD dwFlags,LPDIRECTDRAWCLIPPER *lplpDDClipper,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP CreatePalette(DWORD dwFlags,LPPALETTEENTRY lpColorTable,LPDIRECTDRAWPALETTE *lplpDDPalette,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc,LPDIRECTDRAWSURFACE *lplpDDSurface,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP DuplicateSurface(LPDIRECTDRAWSURFACE lpDDSurface,LPDIRECTDRAWSURFACE *lplpDupDDSurface);
|
||||
STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,LPDDSURFACEDESC lplpDDSurfaceDescList,LPVOID lpContext,LPDDENUMMODESCALLBACK lpEnumCallback);
|
||||
STDMETHODIMP EnumSurfaces(DWORD dwFlags,LPDDSURFACEDESC lpDDSD,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumCallback);
|
||||
STDMETHODIMP FlipToGDISurface();
|
||||
STDMETHODIMP GetCaps(LPDDCAPS lpDDDriverCaps,LPDDCAPS lpDDHELCaps);
|
||||
STDMETHODIMP GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP GetFourCCCodes(LPDWORD lpNumCodes,LPDWORD lpCodes);
|
||||
STDMETHODIMP GetGDISurface(LPDIRECTDRAWSURFACE *lplpGDIDDSurface);
|
||||
STDMETHODIMP GetMonitorFrequency(LPDWORD lpdwFrequency);
|
||||
STDMETHODIMP GetScanLine(LPDWORD lpdwScanLine);
|
||||
STDMETHODIMP GetVerticalBlankStatus(LPBOOL lpblsInVB);
|
||||
STDMETHODIMP Initialize(GUID *lpGUID);
|
||||
STDMETHODIMP RestoreDisplayMode();
|
||||
STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags);
|
||||
STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp);
|
||||
STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent);
|
||||
};
|
||||
|
||||
|
||||
// Class that aggregates an IDirectDrawSurface interface
|
||||
|
||||
class CAggDrawSurface : public IDirectDrawSurface, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPDIRECTDRAWSURFACE m_pDirectDrawSurface;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CAggDrawSurface(TCHAR *pName,LPUNKNOWN pUnk) :
|
||||
CUnknown(pName,pUnk),
|
||||
m_pDirectDrawSurface(NULL) { };
|
||||
|
||||
virtual ~CAggDrawSurface() { };
|
||||
|
||||
// Set the object we should be aggregating
|
||||
void SetDirectDrawSurface(LPDIRECTDRAWSURFACE pDirectDrawSurface) {
|
||||
m_pDirectDrawSurface = pDirectDrawSurface;
|
||||
}
|
||||
|
||||
// IDirectDrawSurface methods
|
||||
|
||||
STDMETHODIMP AddAttachedSurface(LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
|
||||
STDMETHODIMP AddOverlayDirtyRect(LPRECT lpRect);
|
||||
STDMETHODIMP Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx);
|
||||
STDMETHODIMP BltBatch(LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags);
|
||||
STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwTrans);
|
||||
STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
|
||||
STDMETHODIMP EnumAttachedSurfaces(LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback);
|
||||
STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpfnCallback);
|
||||
STDMETHODIMP Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags);
|
||||
STDMETHODIMP GetAttachedSurface(LPDDSCAPS lpDDSCaps,LPDIRECTDRAWSURFACE *lplpDDAttachedSurface);
|
||||
STDMETHODIMP GetBltStatus(DWORD dwFlags);
|
||||
STDMETHODIMP GetCaps(LPDDSCAPS lpDDSCaps);
|
||||
STDMETHODIMP GetClipper(LPDIRECTDRAWCLIPPER *lplpDDClipper);
|
||||
STDMETHODIMP GetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey);
|
||||
STDMETHODIMP GetDC(HDC *lphDC);
|
||||
STDMETHODIMP GetFlipStatus(DWORD dwFlags);
|
||||
STDMETHODIMP GetOverlayPosition(LPLONG lpdwX,LPLONG lpdwY);
|
||||
STDMETHODIMP GetPalette(LPDIRECTDRAWPALETTE *lplpDDPalette);
|
||||
STDMETHODIMP GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat);
|
||||
STDMETHODIMP GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP Initialize(LPDIRECTDRAW lpDD,LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP IsLost();
|
||||
STDMETHODIMP Lock(LPRECT lpDestRect,LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent);
|
||||
STDMETHODIMP ReleaseDC(HDC hDC);
|
||||
STDMETHODIMP Restore();
|
||||
STDMETHODIMP SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);
|
||||
STDMETHODIMP SetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey);
|
||||
STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY);
|
||||
STDMETHODIMP SetPalette(LPDIRECTDRAWPALETTE lpDDPalette);
|
||||
STDMETHODIMP Unlock(LPVOID lpSurfaceData);
|
||||
STDMETHODIMP UpdateOverlay(LPRECT lpSrcRect,LPDIRECTDRAWSURFACE lpDDDestSurface,LPRECT lpDestRect,DWORD dwFlags,LPDDOVERLAYFX lpDDOverlayFX);
|
||||
STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags);
|
||||
STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSReference);
|
||||
};
|
||||
|
||||
|
||||
// DirectShow must work on multiple platforms. In particular, it also runs on
|
||||
// Windows NT 3.51 which does not have DirectDraw capabilities. The filters
|
||||
// cannot therefore link statically to the DirectDraw library. To make their
|
||||
// lives that little bit easier we provide this class that manages loading
|
||||
// and unloading the library and creating the initial IDirectDraw interface
|
||||
|
||||
typedef DWORD (WINAPI *PGETFILEVERSIONINFOSIZE)(LPTSTR,LPDWORD);
|
||||
typedef BOOL (WINAPI *PGETFILEVERSIONINFO)(LPTSTR,DWORD,DWORD,LPVOID);
|
||||
typedef BOOL (WINAPI *PVERQUERYVALUE)(LPVOID,LPTSTR,LPVOID,PUINT);
|
||||
|
||||
class CLoadDirectDraw
|
||||
{
|
||||
LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance
|
||||
HINSTANCE m_hDirectDraw; // Handle to the loaded library
|
||||
|
||||
public:
|
||||
|
||||
CLoadDirectDraw();
|
||||
~CLoadDirectDraw();
|
||||
|
||||
HRESULT LoadDirectDraw(LPSTR szDevice);
|
||||
void ReleaseDirectDraw();
|
||||
HRESULT IsDirectDrawLoaded();
|
||||
LPDIRECTDRAW GetDirectDraw();
|
||||
BOOL IsDirectDrawVersion1();
|
||||
};
|
||||
|
||||
#endif // __VIDEOCTL__
|
||||
|
||||
|
||||
+468
-468
@@ -1,468 +1,468 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Vtrans.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <measure.h>
|
||||
// #include <vtransfr.h> // now in precomp file streams.h
|
||||
|
||||
CVideoTransformFilter::CVideoTransformFilter
|
||||
( TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid)
|
||||
: CTransformFilter(pName, pUnk, clsid)
|
||||
, m_itrLate(0)
|
||||
, m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames
|
||||
, m_nFramesSinceKeyFrame(0)
|
||||
, m_bSkipping(FALSE)
|
||||
, m_tDecodeStart(0)
|
||||
, m_itrAvgDecode(300000) // 30mSec - probably allows skipping
|
||||
, m_bQualityChanged(FALSE) {
|
||||
#ifdef PERF
|
||||
RegisterPerfId();
|
||||
#endif // PERF
|
||||
}
|
||||
|
||||
|
||||
CVideoTransformFilter::~CVideoTransformFilter() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
// Reset our quality management state
|
||||
|
||||
HRESULT CVideoTransformFilter::StartStreaming() {
|
||||
m_itrLate = 0;
|
||||
m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames
|
||||
m_nFramesSinceKeyFrame = 0;
|
||||
m_bSkipping = FALSE;
|
||||
m_tDecodeStart = 0;
|
||||
m_itrAvgDecode = 300000; // 30mSec - probably allows skipping
|
||||
m_bQualityChanged = FALSE;
|
||||
m_bSampleSkipped = FALSE;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Overriden to reset quality management information
|
||||
|
||||
HRESULT CVideoTransformFilter::EndFlush() { {
|
||||
// Synchronize
|
||||
CAutoLock lck(&m_csReceive);
|
||||
|
||||
// Reset our stats
|
||||
//
|
||||
// Note - we don't want to call derived classes here,
|
||||
// we only want to reset our internal variables and this
|
||||
// is a convenient way to do it
|
||||
CVideoTransformFilter::StartStreaming();
|
||||
}
|
||||
return CTransformFilter::EndFlush();
|
||||
}
|
||||
|
||||
|
||||
HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) {
|
||||
NotifyEvent(EC_ERRORABORT, hr, 0);
|
||||
m_pOutput->DeliverEndOfStream();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Receive()
|
||||
//
|
||||
// Accept a sample from upstream, decide whether to process it
|
||||
// or drop it. If we process it then get a buffer from the
|
||||
// allocator of the downstream connection, transform it into the
|
||||
// new buffer and deliver it to the downstream filter.
|
||||
// If we decide not to process it then we do not get a buffer.
|
||||
|
||||
// Remember that although this code will notice format changes coming into
|
||||
// the input pin, it will NOT change its output format if that results
|
||||
// in the filter needing to make a corresponding output format change. Your
|
||||
// derived filter will have to take care of that. (eg. a palette change if
|
||||
// the input and output is an 8 bit format). If the input sample is discarded
|
||||
// and nothing is sent out for this Receive, please remember to put the format
|
||||
// change on the first output sample that you actually do send.
|
||||
// If your filter will produce the same output type even when the input type
|
||||
// changes, then this base class code will do everything you need.
|
||||
|
||||
HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) {
|
||||
// If the next filter downstream is the video renderer, then it may
|
||||
// be able to operate in DirectDraw mode which saves copying the data
|
||||
// and gives higher performance. In that case the buffer which we
|
||||
// get from GetDeliveryBuffer will be a DirectDraw buffer, and
|
||||
// drawing into this buffer draws directly onto the display surface.
|
||||
// This means that any waiting for the correct time to draw occurs
|
||||
// during GetDeliveryBuffer, and that once the buffer is given to us
|
||||
// the video renderer will count it in its statistics as a frame drawn.
|
||||
// This means that any decision to drop the frame must be taken before
|
||||
// calling GetDeliveryBuffer.
|
||||
|
||||
ASSERT(CritCheckIn(&m_csReceive));
|
||||
AM_MEDIA_TYPE *pmtOut, *pmt;
|
||||
#ifdef DEBUG
|
||||
FOURCCMap fccOut;
|
||||
#endif
|
||||
HRESULT hr;
|
||||
ASSERT(pSample);
|
||||
IMediaSample * pOutSample;
|
||||
|
||||
// If no output pin to deliver to then no point sending us data
|
||||
ASSERT(m_pOutput != NULL) ;
|
||||
|
||||
// The source filter may dynamically ask us to start transforming from a
|
||||
// different media type than the one we're using now. If we don't, we'll
|
||||
// draw garbage. (typically, this is a palette change in the movie,
|
||||
// but could be something more sinister like the compression type changing,
|
||||
// or even the video size changing)
|
||||
|
||||
#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource
|
||||
#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget
|
||||
|
||||
pSample->GetMediaType(&pmt);
|
||||
if(pmt != NULL && pmt->pbFormat != NULL) {
|
||||
|
||||
// spew some debug output
|
||||
ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL));
|
||||
#ifdef DEBUG
|
||||
fccOut.SetFOURCC(&pmt->subtype);
|
||||
LONG lCompression = HEADER(pmt->pbFormat)->biCompression;
|
||||
LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount;
|
||||
LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8;
|
||||
lStride = (lStride + 3) & ~3;
|
||||
DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to")));
|
||||
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
|
||||
fccOut.GetFOURCC(), lCompression, lBitCount));
|
||||
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
|
||||
HEADER(pmt->pbFormat)->biHeight,
|
||||
rcT1.left, rcT1.top, rcT1.right, rcT1.bottom));
|
||||
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
|
||||
rcS1.left, rcS1.top, rcS1.right, rcS1.bottom,
|
||||
lStride));
|
||||
#endif
|
||||
|
||||
// now switch to using the new format. I am assuming that the
|
||||
// derived filter will do the right thing when its media type is
|
||||
// switched and streaming is restarted.
|
||||
|
||||
StopStreaming();
|
||||
m_pInput->CurrentMediaType() = *pmt;
|
||||
DeleteMediaType(pmt);
|
||||
// if this fails, playback will stop, so signal an error
|
||||
hr = StartStreaming();
|
||||
if(FAILED(hr)) {
|
||||
return AbortPlayback(hr);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have noticed any format changes on the input sample, it's
|
||||
// OK to discard it.
|
||||
|
||||
if(ShouldSkipFrame(pSample)) {
|
||||
MSR_NOTE(m_idSkip);
|
||||
m_bSampleSkipped = TRUE;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Set up the output sample
|
||||
hr = InitializeOutputSample(pSample, &pOutSample);
|
||||
|
||||
if(FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_bSampleSkipped = FALSE;
|
||||
|
||||
// The renderer may ask us to on-the-fly to start transforming to a
|
||||
// different format. If we don't obey it, we'll draw garbage
|
||||
|
||||
#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource
|
||||
#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget
|
||||
|
||||
pOutSample->GetMediaType(&pmtOut);
|
||||
if(pmtOut != NULL && pmtOut->pbFormat != NULL) {
|
||||
|
||||
// spew some debug output
|
||||
ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL));
|
||||
#ifdef DEBUG
|
||||
fccOut.SetFOURCC(&pmtOut->subtype);
|
||||
LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression;
|
||||
LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount;
|
||||
LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8;
|
||||
lStride = (lStride + 3) & ~3;
|
||||
DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to")));
|
||||
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
|
||||
fccOut.GetFOURCC(), lCompression, lBitCount));
|
||||
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
|
||||
HEADER(pmtOut->pbFormat)->biHeight,
|
||||
rcT.left, rcT.top, rcT.right, rcT.bottom));
|
||||
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
|
||||
rcS.left, rcS.top, rcS.right, rcS.bottom,
|
||||
lStride));
|
||||
#endif
|
||||
|
||||
// now switch to using the new format. I am assuming that the
|
||||
// derived filter will do the right thing when its media type is
|
||||
// switched and streaming is restarted.
|
||||
|
||||
StopStreaming();
|
||||
m_pOutput->CurrentMediaType() = *pmtOut;
|
||||
DeleteMediaType(pmtOut);
|
||||
hr = StartStreaming();
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
// a new format, means a new empty buffer, so wait for a keyframe
|
||||
// before passing anything on to the renderer.
|
||||
// !!! a keyframe may never come, so give up after 30 frames
|
||||
DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe")));
|
||||
m_nWaitForKey = 30;
|
||||
|
||||
// if this fails, playback will stop, so signal an error
|
||||
}
|
||||
else {
|
||||
|
||||
// Must release the sample before calling AbortPlayback
|
||||
// because we might be holding the win16 lock or
|
||||
// ddraw lock
|
||||
pOutSample->Release();
|
||||
AbortPlayback(hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
// After a discontinuity, we need to wait for the next key frame
|
||||
if(pSample->IsDiscontinuity() == S_OK) {
|
||||
DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe")));
|
||||
m_nWaitForKey = 30;
|
||||
}
|
||||
|
||||
// Start timing the transform (and log it if PERF is defined)
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
m_tDecodeStart = timeGetTime();
|
||||
MSR_START(m_idTransform);
|
||||
|
||||
// have the derived class transform the data
|
||||
hr = Transform(pSample, pOutSample);
|
||||
|
||||
// Stop the clock (and log it if PERF is defined)
|
||||
MSR_STOP(m_idTransform);
|
||||
m_tDecodeStart = timeGetTime()-m_tDecodeStart;
|
||||
m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16);
|
||||
|
||||
// Maybe we're waiting for a keyframe still?
|
||||
if(m_nWaitForKey)
|
||||
m_nWaitForKey--;
|
||||
if(m_nWaitForKey && pSample->IsSyncPoint() == S_OK)
|
||||
m_nWaitForKey = FALSE;
|
||||
|
||||
// if so, then we don't want to pass this on to the renderer
|
||||
if(m_nWaitForKey && hr == NOERROR) {
|
||||
DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe")));
|
||||
hr = S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(FAILED(hr)) {
|
||||
DbgLog((LOG_TRACE,1,TEXT("Error from video transform")));
|
||||
}
|
||||
else {
|
||||
// the Transform() function can return S_FALSE to indicate that the
|
||||
// sample should not be delivered; we only deliver the sample if it's
|
||||
// really S_OK (same as NOERROR, of course.)
|
||||
// Try not to return S_FALSE to a direct draw buffer (it's wasteful)
|
||||
// Try to take the decision earlier - before you get it.
|
||||
|
||||
if(hr == NOERROR) {
|
||||
hr = m_pOutput->Deliver(pOutSample);
|
||||
}
|
||||
else {
|
||||
// S_FALSE returned from Transform is a PRIVATE agreement
|
||||
// We should return NOERROR from Receive() in this case because returning S_FALSE
|
||||
// from Receive() means that this is the end of the stream and no more data should
|
||||
// be sent.
|
||||
if(S_FALSE == hr) {
|
||||
|
||||
// We must Release() the sample before doing anything
|
||||
// like calling the filter graph because having the
|
||||
// sample means we may have the DirectDraw lock
|
||||
// (== win16 lock on some versions)
|
||||
pOutSample->Release();
|
||||
m_bSampleSkipped = TRUE;
|
||||
if(!m_bQualityChanged) {
|
||||
m_bQualityChanged = TRUE;
|
||||
NotifyEvent(EC_QUALITY_CHANGE,0,0);
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release the output buffer. If the connected pin still needs it,
|
||||
// it will have addrefed it itself.
|
||||
pOutSample->Release();
|
||||
ASSERT(CritCheckIn(&m_csReceive));
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) {
|
||||
REFERENCE_TIME trStart, trStopAt;
|
||||
HRESULT hr = pIn->GetTime(&trStart, &trStopAt);
|
||||
|
||||
// Don't skip frames with no timestamps
|
||||
if(hr != S_OK)
|
||||
return FALSE;
|
||||
|
||||
int itrFrame = (int)(trStopAt - trStart); // frame duration
|
||||
|
||||
if(S_OK==pIn->IsSyncPoint()) {
|
||||
MSR_INTEGER(m_idFrameType, 1);
|
||||
if(m_nKeyFramePeriod < m_nFramesSinceKeyFrame) {
|
||||
// record the max
|
||||
m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
|
||||
}
|
||||
m_nFramesSinceKeyFrame = 0;
|
||||
m_bSkipping = FALSE;
|
||||
}
|
||||
else {
|
||||
MSR_INTEGER(m_idFrameType, 2);
|
||||
if(m_nFramesSinceKeyFrame>m_nKeyFramePeriod
|
||||
&& m_nKeyFramePeriod>0) {
|
||||
// We haven't seen the key frame yet, but we were clearly being
|
||||
// overoptimistic about how frequent they are.
|
||||
m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Whatever we might otherwise decide,
|
||||
// if we are taking only a small fraction of the required frame time to decode
|
||||
// then any quality problems are actually coming from somewhere else.
|
||||
// Could be a net problem at the source for instance. In this case there's
|
||||
// no point in us skipping frames here.
|
||||
if(m_itrAvgDecode*4>itrFrame) {
|
||||
|
||||
// Don't skip unless we are at least a whole frame late.
|
||||
// (We would skip B frames if more than 1/2 frame late, but they're safe).
|
||||
if(m_itrLate > itrFrame) {
|
||||
|
||||
// Don't skip unless the anticipated key frame would be no more than
|
||||
// 1 frame early. If the renderer has not been waiting (we *guess*
|
||||
// it hasn't because we're late) then it will allow frames to be
|
||||
// played early by up to a frame.
|
||||
|
||||
// Let T = Stream time from now to anticipated next key frame
|
||||
// = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame)
|
||||
// So we skip if T - Late < one frame i.e.
|
||||
// (duration) * (freq - FramesSince) - Late < duration
|
||||
// or (duration) * (freq - FramesSince - 1) < Late
|
||||
|
||||
// We don't dare skip until we have seen some key frames and have
|
||||
// some idea how often they occur and they are reasonably frequent.
|
||||
if(m_nKeyFramePeriod>0) {
|
||||
// It would be crazy - but we could have a stream with key frames
|
||||
// a very long way apart - and if they are further than about
|
||||
// 3.5 minutes apart then we could get arithmetic overflow in
|
||||
// reference time units. Therefore we switch to mSec at this point
|
||||
int it = (itrFrame/10000)
|
||||
* (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1);
|
||||
MSR_INTEGER(m_idTimeTillKey, it);
|
||||
|
||||
// For debug - might want to see the details - dump them as scratch pad
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
MSR_INTEGER(0, m_nFramesSinceKeyFrame);
|
||||
MSR_INTEGER(0, m_nKeyFramePeriod);
|
||||
#endif
|
||||
if(m_itrLate/10000 > it) {
|
||||
m_bSkipping = TRUE;
|
||||
// Now we are committed. Once we start skipping, we
|
||||
// cannot stop until we hit a key frame.
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777770); // not near enough to next key
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777771); // Next key not predictable
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777772); // Less than one frame late
|
||||
MSR_INTEGER(0, m_itrLate);
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping
|
||||
MSR_INTEGER(0, m_itrAvgDecode);
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
++m_nFramesSinceKeyFrame;
|
||||
|
||||
if(m_bSkipping) {
|
||||
// We will count down the lateness as we skip each frame.
|
||||
// We re-assess each frame. The key frame might not arrive when expected.
|
||||
// We reset m_itrLate if we get a new Quality message, but actually that's
|
||||
// not likely because we're not sending frames on to the Renderer. In
|
||||
// fact if we DID get another one it would mean that there's a long
|
||||
// pipe between us and the renderer and we might need an altogether
|
||||
// better strategy to avoid hunting!
|
||||
m_itrLate = m_itrLate - itrFrame;
|
||||
}
|
||||
|
||||
MSR_INTEGER(m_idLate, (int)m_itrLate/10000); // Note how late we think we are
|
||||
if(m_bSkipping) {
|
||||
if(!m_bQualityChanged) {
|
||||
m_bQualityChanged = TRUE;
|
||||
NotifyEvent(EC_QUALITY_CHANGE,0,0);
|
||||
}
|
||||
}
|
||||
return m_bSkipping;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CVideoTransformFilter::AlterQuality(Quality q) {
|
||||
// to reduce the amount of 64 bit arithmetic, m_itrLate is an int.
|
||||
// +, -, >, == etc are not too bad, but * and / are painful.
|
||||
if(m_itrLate>300000000) {
|
||||
// Avoid overflow and silliness - more than 30 secs late is already silly
|
||||
m_itrLate = 300000000;
|
||||
}
|
||||
else {
|
||||
m_itrLate = (int)q.Late;
|
||||
}
|
||||
// We ignore the other fields
|
||||
|
||||
// We're actually not very good at handling this. In non-direct draw mode
|
||||
// most of the time can be spent in the renderer which can skip any frame.
|
||||
// In that case we'd rather the renderer handled things.
|
||||
// Nevertheless we will keep an eye on it and if we really start getting
|
||||
// a very long way behind then we will actually skip - but we'll still tell
|
||||
// the renderer (or whoever is downstream) that they should handle quality.
|
||||
|
||||
return E_FAIL; // Tell the renderer to do his thing.
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4
|
||||
#pragma warning(disable:4514)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Vtrans.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <measure.h>
|
||||
// #include <vtransfr.h> // now in precomp file streams.h
|
||||
|
||||
CVideoTransformFilter::CVideoTransformFilter
|
||||
( TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid)
|
||||
: CTransformFilter(pName, pUnk, clsid)
|
||||
, m_itrLate(0)
|
||||
, m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames
|
||||
, m_nFramesSinceKeyFrame(0)
|
||||
, m_bSkipping(FALSE)
|
||||
, m_tDecodeStart(0)
|
||||
, m_itrAvgDecode(300000) // 30mSec - probably allows skipping
|
||||
, m_bQualityChanged(FALSE) {
|
||||
#ifdef PERF
|
||||
RegisterPerfId();
|
||||
#endif // PERF
|
||||
}
|
||||
|
||||
|
||||
CVideoTransformFilter::~CVideoTransformFilter() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
// Reset our quality management state
|
||||
|
||||
HRESULT CVideoTransformFilter::StartStreaming() {
|
||||
m_itrLate = 0;
|
||||
m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames
|
||||
m_nFramesSinceKeyFrame = 0;
|
||||
m_bSkipping = FALSE;
|
||||
m_tDecodeStart = 0;
|
||||
m_itrAvgDecode = 300000; // 30mSec - probably allows skipping
|
||||
m_bQualityChanged = FALSE;
|
||||
m_bSampleSkipped = FALSE;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Overriden to reset quality management information
|
||||
|
||||
HRESULT CVideoTransformFilter::EndFlush() { {
|
||||
// Synchronize
|
||||
CAutoLock lck(&m_csReceive);
|
||||
|
||||
// Reset our stats
|
||||
//
|
||||
// Note - we don't want to call derived classes here,
|
||||
// we only want to reset our internal variables and this
|
||||
// is a convenient way to do it
|
||||
CVideoTransformFilter::StartStreaming();
|
||||
}
|
||||
return CTransformFilter::EndFlush();
|
||||
}
|
||||
|
||||
|
||||
HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) {
|
||||
NotifyEvent(EC_ERRORABORT, hr, 0);
|
||||
m_pOutput->DeliverEndOfStream();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Receive()
|
||||
//
|
||||
// Accept a sample from upstream, decide whether to process it
|
||||
// or drop it. If we process it then get a buffer from the
|
||||
// allocator of the downstream connection, transform it into the
|
||||
// new buffer and deliver it to the downstream filter.
|
||||
// If we decide not to process it then we do not get a buffer.
|
||||
|
||||
// Remember that although this code will notice format changes coming into
|
||||
// the input pin, it will NOT change its output format if that results
|
||||
// in the filter needing to make a corresponding output format change. Your
|
||||
// derived filter will have to take care of that. (eg. a palette change if
|
||||
// the input and output is an 8 bit format). If the input sample is discarded
|
||||
// and nothing is sent out for this Receive, please remember to put the format
|
||||
// change on the first output sample that you actually do send.
|
||||
// If your filter will produce the same output type even when the input type
|
||||
// changes, then this base class code will do everything you need.
|
||||
|
||||
HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) {
|
||||
// If the next filter downstream is the video renderer, then it may
|
||||
// be able to operate in DirectDraw mode which saves copying the data
|
||||
// and gives higher performance. In that case the buffer which we
|
||||
// get from GetDeliveryBuffer will be a DirectDraw buffer, and
|
||||
// drawing into this buffer draws directly onto the display surface.
|
||||
// This means that any waiting for the correct time to draw occurs
|
||||
// during GetDeliveryBuffer, and that once the buffer is given to us
|
||||
// the video renderer will count it in its statistics as a frame drawn.
|
||||
// This means that any decision to drop the frame must be taken before
|
||||
// calling GetDeliveryBuffer.
|
||||
|
||||
ASSERT(CritCheckIn(&m_csReceive));
|
||||
AM_MEDIA_TYPE *pmtOut, *pmt;
|
||||
#ifdef DEBUG
|
||||
FOURCCMap fccOut;
|
||||
#endif
|
||||
HRESULT hr;
|
||||
ASSERT(pSample);
|
||||
IMediaSample * pOutSample;
|
||||
|
||||
// If no output pin to deliver to then no point sending us data
|
||||
ASSERT(m_pOutput != NULL) ;
|
||||
|
||||
// The source filter may dynamically ask us to start transforming from a
|
||||
// different media type than the one we're using now. If we don't, we'll
|
||||
// draw garbage. (typically, this is a palette change in the movie,
|
||||
// but could be something more sinister like the compression type changing,
|
||||
// or even the video size changing)
|
||||
|
||||
#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource
|
||||
#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget
|
||||
|
||||
pSample->GetMediaType(&pmt);
|
||||
if(pmt != NULL && pmt->pbFormat != NULL) {
|
||||
|
||||
// spew some debug output
|
||||
ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL));
|
||||
#ifdef DEBUG
|
||||
fccOut.SetFOURCC(&pmt->subtype);
|
||||
LONG lCompression = HEADER(pmt->pbFormat)->biCompression;
|
||||
LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount;
|
||||
LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8;
|
||||
lStride = (lStride + 3) & ~3;
|
||||
DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to")));
|
||||
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
|
||||
fccOut.GetFOURCC(), lCompression, lBitCount));
|
||||
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
|
||||
HEADER(pmt->pbFormat)->biHeight,
|
||||
rcT1.left, rcT1.top, rcT1.right, rcT1.bottom));
|
||||
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
|
||||
rcS1.left, rcS1.top, rcS1.right, rcS1.bottom,
|
||||
lStride));
|
||||
#endif
|
||||
|
||||
// now switch to using the new format. I am assuming that the
|
||||
// derived filter will do the right thing when its media type is
|
||||
// switched and streaming is restarted.
|
||||
|
||||
StopStreaming();
|
||||
m_pInput->CurrentMediaType() = *pmt;
|
||||
DeleteMediaType(pmt);
|
||||
// if this fails, playback will stop, so signal an error
|
||||
hr = StartStreaming();
|
||||
if(FAILED(hr)) {
|
||||
return AbortPlayback(hr);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have noticed any format changes on the input sample, it's
|
||||
// OK to discard it.
|
||||
|
||||
if(ShouldSkipFrame(pSample)) {
|
||||
MSR_NOTE(m_idSkip);
|
||||
m_bSampleSkipped = TRUE;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Set up the output sample
|
||||
hr = InitializeOutputSample(pSample, &pOutSample);
|
||||
|
||||
if(FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_bSampleSkipped = FALSE;
|
||||
|
||||
// The renderer may ask us to on-the-fly to start transforming to a
|
||||
// different format. If we don't obey it, we'll draw garbage
|
||||
|
||||
#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource
|
||||
#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget
|
||||
|
||||
pOutSample->GetMediaType(&pmtOut);
|
||||
if(pmtOut != NULL && pmtOut->pbFormat != NULL) {
|
||||
|
||||
// spew some debug output
|
||||
ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL));
|
||||
#ifdef DEBUG
|
||||
fccOut.SetFOURCC(&pmtOut->subtype);
|
||||
LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression;
|
||||
LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount;
|
||||
LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8;
|
||||
lStride = (lStride + 3) & ~3;
|
||||
DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to")));
|
||||
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
|
||||
fccOut.GetFOURCC(), lCompression, lBitCount));
|
||||
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
|
||||
HEADER(pmtOut->pbFormat)->biHeight,
|
||||
rcT.left, rcT.top, rcT.right, rcT.bottom));
|
||||
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
|
||||
rcS.left, rcS.top, rcS.right, rcS.bottom,
|
||||
lStride));
|
||||
#endif
|
||||
|
||||
// now switch to using the new format. I am assuming that the
|
||||
// derived filter will do the right thing when its media type is
|
||||
// switched and streaming is restarted.
|
||||
|
||||
StopStreaming();
|
||||
m_pOutput->CurrentMediaType() = *pmtOut;
|
||||
DeleteMediaType(pmtOut);
|
||||
hr = StartStreaming();
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
// a new format, means a new empty buffer, so wait for a keyframe
|
||||
// before passing anything on to the renderer.
|
||||
// !!! a keyframe may never come, so give up after 30 frames
|
||||
DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe")));
|
||||
m_nWaitForKey = 30;
|
||||
|
||||
// if this fails, playback will stop, so signal an error
|
||||
}
|
||||
else {
|
||||
|
||||
// Must release the sample before calling AbortPlayback
|
||||
// because we might be holding the win16 lock or
|
||||
// ddraw lock
|
||||
pOutSample->Release();
|
||||
AbortPlayback(hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
// After a discontinuity, we need to wait for the next key frame
|
||||
if(pSample->IsDiscontinuity() == S_OK) {
|
||||
DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe")));
|
||||
m_nWaitForKey = 30;
|
||||
}
|
||||
|
||||
// Start timing the transform (and log it if PERF is defined)
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
m_tDecodeStart = timeGetTime();
|
||||
MSR_START(m_idTransform);
|
||||
|
||||
// have the derived class transform the data
|
||||
hr = Transform(pSample, pOutSample);
|
||||
|
||||
// Stop the clock (and log it if PERF is defined)
|
||||
MSR_STOP(m_idTransform);
|
||||
m_tDecodeStart = timeGetTime()-m_tDecodeStart;
|
||||
m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16);
|
||||
|
||||
// Maybe we're waiting for a keyframe still?
|
||||
if(m_nWaitForKey)
|
||||
m_nWaitForKey--;
|
||||
if(m_nWaitForKey && pSample->IsSyncPoint() == S_OK)
|
||||
m_nWaitForKey = FALSE;
|
||||
|
||||
// if so, then we don't want to pass this on to the renderer
|
||||
if(m_nWaitForKey && hr == NOERROR) {
|
||||
DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe")));
|
||||
hr = S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(FAILED(hr)) {
|
||||
DbgLog((LOG_TRACE,1,TEXT("Error from video transform")));
|
||||
}
|
||||
else {
|
||||
// the Transform() function can return S_FALSE to indicate that the
|
||||
// sample should not be delivered; we only deliver the sample if it's
|
||||
// really S_OK (same as NOERROR, of course.)
|
||||
// Try not to return S_FALSE to a direct draw buffer (it's wasteful)
|
||||
// Try to take the decision earlier - before you get it.
|
||||
|
||||
if(hr == NOERROR) {
|
||||
hr = m_pOutput->Deliver(pOutSample);
|
||||
}
|
||||
else {
|
||||
// S_FALSE returned from Transform is a PRIVATE agreement
|
||||
// We should return NOERROR from Receive() in this case because returning S_FALSE
|
||||
// from Receive() means that this is the end of the stream and no more data should
|
||||
// be sent.
|
||||
if(S_FALSE == hr) {
|
||||
|
||||
// We must Release() the sample before doing anything
|
||||
// like calling the filter graph because having the
|
||||
// sample means we may have the DirectDraw lock
|
||||
// (== win16 lock on some versions)
|
||||
pOutSample->Release();
|
||||
m_bSampleSkipped = TRUE;
|
||||
if(!m_bQualityChanged) {
|
||||
m_bQualityChanged = TRUE;
|
||||
NotifyEvent(EC_QUALITY_CHANGE,0,0);
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release the output buffer. If the connected pin still needs it,
|
||||
// it will have addrefed it itself.
|
||||
pOutSample->Release();
|
||||
ASSERT(CritCheckIn(&m_csReceive));
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) {
|
||||
REFERENCE_TIME trStart, trStopAt;
|
||||
HRESULT hr = pIn->GetTime(&trStart, &trStopAt);
|
||||
|
||||
// Don't skip frames with no timestamps
|
||||
if(hr != S_OK)
|
||||
return FALSE;
|
||||
|
||||
int itrFrame = (int)(trStopAt - trStart); // frame duration
|
||||
|
||||
if(S_OK==pIn->IsSyncPoint()) {
|
||||
MSR_INTEGER(m_idFrameType, 1);
|
||||
if(m_nKeyFramePeriod < m_nFramesSinceKeyFrame) {
|
||||
// record the max
|
||||
m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
|
||||
}
|
||||
m_nFramesSinceKeyFrame = 0;
|
||||
m_bSkipping = FALSE;
|
||||
}
|
||||
else {
|
||||
MSR_INTEGER(m_idFrameType, 2);
|
||||
if(m_nFramesSinceKeyFrame>m_nKeyFramePeriod
|
||||
&& m_nKeyFramePeriod>0) {
|
||||
// We haven't seen the key frame yet, but we were clearly being
|
||||
// overoptimistic about how frequent they are.
|
||||
m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Whatever we might otherwise decide,
|
||||
// if we are taking only a small fraction of the required frame time to decode
|
||||
// then any quality problems are actually coming from somewhere else.
|
||||
// Could be a net problem at the source for instance. In this case there's
|
||||
// no point in us skipping frames here.
|
||||
if(m_itrAvgDecode*4>itrFrame) {
|
||||
|
||||
// Don't skip unless we are at least a whole frame late.
|
||||
// (We would skip B frames if more than 1/2 frame late, but they're safe).
|
||||
if(m_itrLate > itrFrame) {
|
||||
|
||||
// Don't skip unless the anticipated key frame would be no more than
|
||||
// 1 frame early. If the renderer has not been waiting (we *guess*
|
||||
// it hasn't because we're late) then it will allow frames to be
|
||||
// played early by up to a frame.
|
||||
|
||||
// Let T = Stream time from now to anticipated next key frame
|
||||
// = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame)
|
||||
// So we skip if T - Late < one frame i.e.
|
||||
// (duration) * (freq - FramesSince) - Late < duration
|
||||
// or (duration) * (freq - FramesSince - 1) < Late
|
||||
|
||||
// We don't dare skip until we have seen some key frames and have
|
||||
// some idea how often they occur and they are reasonably frequent.
|
||||
if(m_nKeyFramePeriod>0) {
|
||||
// It would be crazy - but we could have a stream with key frames
|
||||
// a very long way apart - and if they are further than about
|
||||
// 3.5 minutes apart then we could get arithmetic overflow in
|
||||
// reference time units. Therefore we switch to mSec at this point
|
||||
int it = (itrFrame/10000)
|
||||
* (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1);
|
||||
MSR_INTEGER(m_idTimeTillKey, it);
|
||||
|
||||
// For debug - might want to see the details - dump them as scratch pad
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
MSR_INTEGER(0, m_nFramesSinceKeyFrame);
|
||||
MSR_INTEGER(0, m_nKeyFramePeriod);
|
||||
#endif
|
||||
if(m_itrLate/10000 > it) {
|
||||
m_bSkipping = TRUE;
|
||||
// Now we are committed. Once we start skipping, we
|
||||
// cannot stop until we hit a key frame.
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777770); // not near enough to next key
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777771); // Next key not predictable
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777772); // Less than one frame late
|
||||
MSR_INTEGER(0, m_itrLate);
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping
|
||||
MSR_INTEGER(0, m_itrAvgDecode);
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
++m_nFramesSinceKeyFrame;
|
||||
|
||||
if(m_bSkipping) {
|
||||
// We will count down the lateness as we skip each frame.
|
||||
// We re-assess each frame. The key frame might not arrive when expected.
|
||||
// We reset m_itrLate if we get a new Quality message, but actually that's
|
||||
// not likely because we're not sending frames on to the Renderer. In
|
||||
// fact if we DID get another one it would mean that there's a long
|
||||
// pipe between us and the renderer and we might need an altogether
|
||||
// better strategy to avoid hunting!
|
||||
m_itrLate = m_itrLate - itrFrame;
|
||||
}
|
||||
|
||||
MSR_INTEGER(m_idLate, (int)m_itrLate/10000); // Note how late we think we are
|
||||
if(m_bSkipping) {
|
||||
if(!m_bQualityChanged) {
|
||||
m_bQualityChanged = TRUE;
|
||||
NotifyEvent(EC_QUALITY_CHANGE,0,0);
|
||||
}
|
||||
}
|
||||
return m_bSkipping;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CVideoTransformFilter::AlterQuality(Quality q) {
|
||||
// to reduce the amount of 64 bit arithmetic, m_itrLate is an int.
|
||||
// +, -, >, == etc are not too bad, but * and / are painful.
|
||||
if(m_itrLate>300000000) {
|
||||
// Avoid overflow and silliness - more than 30 secs late is already silly
|
||||
m_itrLate = 300000000;
|
||||
}
|
||||
else {
|
||||
m_itrLate = (int)q.Late;
|
||||
}
|
||||
// We ignore the other fields
|
||||
|
||||
// We're actually not very good at handling this. In non-direct draw mode
|
||||
// most of the time can be spent in the renderer which can skip any frame.
|
||||
// In that case we'd rather the renderer handled things.
|
||||
// Nevertheless we will keep an eye on it and if we really start getting
|
||||
// a very long way behind then we will actually skip - but we'll still tell
|
||||
// the renderer (or whoever is downstream) that they should handle quality.
|
||||
|
||||
return E_FAIL; // Tell the renderer to do his thing.
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4
|
||||
#pragma warning(disable:4514)
|
||||
|
||||
|
||||
|
||||
+143
-143
@@ -1,143 +1,143 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: VTrans.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a video transform class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// This class is derived from CTransformFilter, but is specialised to handle
|
||||
// the requirements of video quality control by frame dropping.
|
||||
// This is a non-in-place transform, (i.e. it copies the data) such as a decoder.
|
||||
|
||||
class CVideoTransformFilter : public CTransformFilter
|
||||
{
|
||||
public:
|
||||
|
||||
CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
~CVideoTransformFilter();
|
||||
HRESULT EndFlush();
|
||||
|
||||
// =================================================================
|
||||
// ----- override these bits ---------------------------------------
|
||||
// =================================================================
|
||||
// The following methods are in CTransformFilter which is inherited.
|
||||
// They are mentioned here for completeness
|
||||
//
|
||||
// These MUST be supplied in a derived class
|
||||
//
|
||||
// NOTE:
|
||||
// virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
|
||||
// virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
|
||||
// virtual HRESULT CheckTransform
|
||||
// (const CMediaType* mtIn, const CMediaType* mtOut) PURE;
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
// virtual HRESULT DecideBufferSize
|
||||
// (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE;
|
||||
// virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
|
||||
//
|
||||
// These MAY also be overridden
|
||||
//
|
||||
// virtual HRESULT StopStreaming();
|
||||
// virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
|
||||
// virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
|
||||
// virtual HRESULT BreakConnect(PIN_DIRECTION dir);
|
||||
// virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
|
||||
// virtual HRESULT EndOfStream(void);
|
||||
// virtual HRESULT BeginFlush(void);
|
||||
// virtual HRESULT EndFlush(void);
|
||||
// virtual HRESULT NewSegment
|
||||
// (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate);
|
||||
#ifdef PERF
|
||||
|
||||
// If you override this - ensure that you register all these ids
|
||||
// as well as any of your own,
|
||||
virtual void RegisterPerfId() {
|
||||
m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame"));
|
||||
m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type"));
|
||||
m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness"));
|
||||
m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key"));
|
||||
CTransformFilter::RegisterPerfId();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
// =========== QUALITY MANAGEMENT IMPLEMENTATION ========================
|
||||
// Frames are assumed to come in three types:
|
||||
// Type 1: an AVI key frame or an MPEG I frame.
|
||||
// This frame can be decoded with no history.
|
||||
// Dropping this frame means that no further frame can be decoded
|
||||
// until the next type 1 frame.
|
||||
// Type 1 frames are sync points.
|
||||
// Type 2: an AVI non-key frame or an MPEG P frame.
|
||||
// This frame cannot be decoded unless the previous type 1 frame was
|
||||
// decoded and all type 2 frames since have been decoded.
|
||||
// Dropping this frame means that no further frame can be decoded
|
||||
// until the next type 1 frame.
|
||||
// Type 3: An MPEG B frame.
|
||||
// This frame cannot be decoded unless the previous type 1 or 2 frame
|
||||
// has been decoded AND the subsequent type 1 or 2 frame has also
|
||||
// been decoded. (This requires decoding the frames out of sequence).
|
||||
// Dropping this frame affects no other frames. This implementation
|
||||
// does not allow for these. All non-sync-point frames are treated
|
||||
// as being type 2.
|
||||
//
|
||||
// The spacing of frames of type 1 in a file is not guaranteed. There MUST
|
||||
// be a type 1 frame at (well, near) the start of the file in order to start
|
||||
// decoding at all. After that there could be one every half second or so,
|
||||
// there could be one at the start of each scene (aka "cut", "shot") or
|
||||
// there could be no more at all.
|
||||
// If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED
|
||||
// without losing all the rest of the movie. There is no way to tell whether
|
||||
// this is the case, so we find that we are in the gambling business.
|
||||
// To try to improve the odds, we record the greatest interval between type 1s
|
||||
// that we have seen and we bet on things being no worse than this in the
|
||||
// future.
|
||||
|
||||
// You can tell if it's a type 1 frame by calling IsSyncPoint().
|
||||
// there is no architected way to test for a type 3, so you should override
|
||||
// the quality management here if you have B-frames.
|
||||
|
||||
int m_nKeyFramePeriod; // the largest observed interval between type 1 frames
|
||||
// 1 means every frame is type 1, 2 means every other.
|
||||
|
||||
int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1.
|
||||
// becomes the new m_nKeyFramePeriod if greater.
|
||||
|
||||
BOOL m_bSkipping; // we are skipping to the next type 1 frame
|
||||
|
||||
#ifdef PERF
|
||||
int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key"
|
||||
int m_idSkip; // MSR id skipping
|
||||
int m_idLate; // MSR id lateness
|
||||
int m_idTimeTillKey; // MSR id for guessed time till next key frame.
|
||||
#endif
|
||||
|
||||
virtual HRESULT StartStreaming();
|
||||
|
||||
HRESULT AbortPlayback(HRESULT hr); // if something bad happens
|
||||
|
||||
HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
HRESULT AlterQuality(Quality q);
|
||||
|
||||
BOOL ShouldSkipFrame(IMediaSample * pIn);
|
||||
|
||||
int m_itrLate; // lateness from last Quality message
|
||||
// (this overflows at 214 secs late).
|
||||
int m_tDecodeStart; // timeGetTime when decode started.
|
||||
int m_itrAvgDecode; // Average decode time in reference units.
|
||||
|
||||
BOOL m_bNoSkip; // debug - no skipping.
|
||||
|
||||
// We send an EC_QUALITY_CHANGE notification to the app if we have to degrade.
|
||||
// We send one when we start degrading, not one for every frame, this means
|
||||
// we track whether we've sent one yet.
|
||||
BOOL m_bQualityChanged;
|
||||
|
||||
// When non-zero, don't pass anything to renderer until next keyframe
|
||||
// If there are few keys, give up and eventually draw something
|
||||
int m_nWaitForKey;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// File: VTrans.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a video transform class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// This class is derived from CTransformFilter, but is specialised to handle
|
||||
// the requirements of video quality control by frame dropping.
|
||||
// This is a non-in-place transform, (i.e. it copies the data) such as a decoder.
|
||||
|
||||
class CVideoTransformFilter : public CTransformFilter
|
||||
{
|
||||
public:
|
||||
|
||||
CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
~CVideoTransformFilter();
|
||||
HRESULT EndFlush();
|
||||
|
||||
// =================================================================
|
||||
// ----- override these bits ---------------------------------------
|
||||
// =================================================================
|
||||
// The following methods are in CTransformFilter which is inherited.
|
||||
// They are mentioned here for completeness
|
||||
//
|
||||
// These MUST be supplied in a derived class
|
||||
//
|
||||
// NOTE:
|
||||
// virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
|
||||
// virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
|
||||
// virtual HRESULT CheckTransform
|
||||
// (const CMediaType* mtIn, const CMediaType* mtOut) PURE;
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
// virtual HRESULT DecideBufferSize
|
||||
// (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE;
|
||||
// virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
|
||||
//
|
||||
// These MAY also be overridden
|
||||
//
|
||||
// virtual HRESULT StopStreaming();
|
||||
// virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
|
||||
// virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
|
||||
// virtual HRESULT BreakConnect(PIN_DIRECTION dir);
|
||||
// virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
|
||||
// virtual HRESULT EndOfStream(void);
|
||||
// virtual HRESULT BeginFlush(void);
|
||||
// virtual HRESULT EndFlush(void);
|
||||
// virtual HRESULT NewSegment
|
||||
// (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate);
|
||||
#ifdef PERF
|
||||
|
||||
// If you override this - ensure that you register all these ids
|
||||
// as well as any of your own,
|
||||
virtual void RegisterPerfId() {
|
||||
m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame"));
|
||||
m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type"));
|
||||
m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness"));
|
||||
m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key"));
|
||||
CTransformFilter::RegisterPerfId();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
// =========== QUALITY MANAGEMENT IMPLEMENTATION ========================
|
||||
// Frames are assumed to come in three types:
|
||||
// Type 1: an AVI key frame or an MPEG I frame.
|
||||
// This frame can be decoded with no history.
|
||||
// Dropping this frame means that no further frame can be decoded
|
||||
// until the next type 1 frame.
|
||||
// Type 1 frames are sync points.
|
||||
// Type 2: an AVI non-key frame or an MPEG P frame.
|
||||
// This frame cannot be decoded unless the previous type 1 frame was
|
||||
// decoded and all type 2 frames since have been decoded.
|
||||
// Dropping this frame means that no further frame can be decoded
|
||||
// until the next type 1 frame.
|
||||
// Type 3: An MPEG B frame.
|
||||
// This frame cannot be decoded unless the previous type 1 or 2 frame
|
||||
// has been decoded AND the subsequent type 1 or 2 frame has also
|
||||
// been decoded. (This requires decoding the frames out of sequence).
|
||||
// Dropping this frame affects no other frames. This implementation
|
||||
// does not allow for these. All non-sync-point frames are treated
|
||||
// as being type 2.
|
||||
//
|
||||
// The spacing of frames of type 1 in a file is not guaranteed. There MUST
|
||||
// be a type 1 frame at (well, near) the start of the file in order to start
|
||||
// decoding at all. After that there could be one every half second or so,
|
||||
// there could be one at the start of each scene (aka "cut", "shot") or
|
||||
// there could be no more at all.
|
||||
// If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED
|
||||
// without losing all the rest of the movie. There is no way to tell whether
|
||||
// this is the case, so we find that we are in the gambling business.
|
||||
// To try to improve the odds, we record the greatest interval between type 1s
|
||||
// that we have seen and we bet on things being no worse than this in the
|
||||
// future.
|
||||
|
||||
// You can tell if it's a type 1 frame by calling IsSyncPoint().
|
||||
// there is no architected way to test for a type 3, so you should override
|
||||
// the quality management here if you have B-frames.
|
||||
|
||||
int m_nKeyFramePeriod; // the largest observed interval between type 1 frames
|
||||
// 1 means every frame is type 1, 2 means every other.
|
||||
|
||||
int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1.
|
||||
// becomes the new m_nKeyFramePeriod if greater.
|
||||
|
||||
BOOL m_bSkipping; // we are skipping to the next type 1 frame
|
||||
|
||||
#ifdef PERF
|
||||
int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key"
|
||||
int m_idSkip; // MSR id skipping
|
||||
int m_idLate; // MSR id lateness
|
||||
int m_idTimeTillKey; // MSR id for guessed time till next key frame.
|
||||
#endif
|
||||
|
||||
virtual HRESULT StartStreaming();
|
||||
|
||||
HRESULT AbortPlayback(HRESULT hr); // if something bad happens
|
||||
|
||||
HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
HRESULT AlterQuality(Quality q);
|
||||
|
||||
BOOL ShouldSkipFrame(IMediaSample * pIn);
|
||||
|
||||
int m_itrLate; // lateness from last Quality message
|
||||
// (this overflows at 214 secs late).
|
||||
int m_tDecodeStart; // timeGetTime when decode started.
|
||||
int m_itrAvgDecode; // Average decode time in reference units.
|
||||
|
||||
BOOL m_bNoSkip; // debug - no skipping.
|
||||
|
||||
// We send an EC_QUALITY_CHANGE notification to the app if we have to degrade.
|
||||
// We send one when we start degrading, not one for every frame, this means
|
||||
// we track whether we've sent one yet.
|
||||
BOOL m_bQualityChanged;
|
||||
|
||||
// When non-zero, don't pass anything to renderer until next keyframe
|
||||
// If there are few keys, give up and eventually draw something
|
||||
int m_nWaitForKey;
|
||||
};
|
||||
|
||||
+1977
-1977
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user