Files
itgmania212121/stepmania/src/Sprite.cpp
T
Chris Danford a40558031b Major rewrite of all classes related to gameplay (Song, Steps, Player,
WindowDancing and all its UI elements).  All of the dancing UI elements
have been consolidated into the Player class, which simplifies things a
great deal.  Steps and the classes that use them have been generalized
to use a variable number of panels (6 panel, 8 panel).  Only a little more
work is needed on the ColorArrows portion of Player to fully support these
panel modes.
2001-11-04 19:34:28 +00:00

379 lines
8.7 KiB
C++

#include "stdafx.h"
/*
-----------------------------------------------------------------------------
File: Sprite.cpp
Desc: A bitmap actor that animates and moves around.
Copyright (c) 2001 Chris Danford. All rights reserved.
-----------------------------------------------------------------------------
*/
#include "Sprite.h"
#include "RageTextureManager.h"
#include "IniFile.h"
#include <assert.h>
#include <math.h>
Sprite::Sprite()
{
Init();
}
void Sprite::Init()
{
Actor::Init();
m_pTexture = NULL;
m_uNumStates = 0;
m_uCurState = 0;
m_bIsAnimating = TRUE;
m_fSecsIntoState = 0.0;
m_bUsingCustomSrcRect = FALSE ;
m_Effect = no_effect ;
m_fPercentBetweenColors = 0.0f ;
m_bTweeningTowardEndColor = TRUE ;
m_fDeltaPercentPerSecond = 1.0 ;
m_fWagRadians = 0.2f ;
m_fWagPeriod = 2.0f ;
m_fWagTimer = 0.0f ;
m_fSpinSpeed = 2.0f ;
m_fVibrationDistance = 5.0f ;
m_bVisibleThisFrame = FALSE;
m_bBlendAdd = FALSE;
}
Sprite::~Sprite()
{
// RageLog( "Sprite Destructor" );
TM->UnloadTexture( m_sTexturePath );
}
BOOL Sprite::LoadFromTexture( CString sTexturePath )
{
RageLog( ssprintf("Sprite::LoadFromTexture(%s)", sTexturePath) );
Init();
return LoadTexture( sTexturePath );
}
// Sprite file has the format:
//
// [Sprite]
// Texture=Textures\Logo 1x1.bmp
// Frame0000=0
// Delay0000=1.0
// Frame0001=3
// Delay0000=2.0
BOOL Sprite::LoadFromSpriteFile( CString sSpritePath )
{
RageLog( ssprintf("Sprite::LoadFromSpriteFile(%s)", sSpritePath) );
Init();
m_sSpritePath = sSpritePath;
// read sprite file
IniFile ini;
ini.SetPath( m_sSpritePath );
if( !ini.ReadFile() )
RageError( ssprintf("Error opening Sprite file '%s'.", m_sSpritePath) );
CString sTexturePath = ini.GetValue( "Sprite", "Texture" );
if( sTexturePath == "" )
RageError( ssprintf("Error reading value 'Texture' from %s.", m_sSpritePath) );
// Load the texture
if( !LoadTexture( sTexturePath ) )
return FALSE;
// Read in frames and delays from the sprite file,
// overwriting the states that LoadFromTexture created.
for( UINT i=0; i<MAX_SPRITE_STATES; i++ )
{
CString sStateNo;
sStateNo.Format( "%u%u%u%u", (i%10000)/1000, (i%1000)/100, (i%100)/10, (i%10) ); // four digit state no
CString sFrameKey( CString("Frame") + sStateNo );
CString sDelayKey( CString("Delay") + sStateNo );
m_uFrame[i] = ini.GetValueI( "Sprite", sFrameKey );
if( m_uFrame[i] >= m_pTexture->GetNumFrames() )
RageError( ssprintf("In '%s', %s is %d, but the texture %s only has %d frames.",
m_sSpritePath, sFrameKey, m_uFrame[i], sTexturePath, m_pTexture->GetNumFrames()) );
m_fDelay[i] = (float)ini.GetValueF( "Sprite", sDelayKey );
if( m_uFrame[i] == 0 && m_fDelay[i] > -0.00001f && m_fDelay[i] < 0.00001f ) // both values are empty
break;
m_uNumStates = i+1;
}
if( m_uNumStates == 0 )
RageError( ssprintf("Failed to find at least one state in %s.", m_sSpritePath) );
return TRUE;
}
BOOL Sprite::LoadTexture( CString sTexturePath )
{
if( m_sTexturePath != "" ) // If there was a previous bitmap...
TM->UnloadTexture( m_sTexturePath ); // Unload it.
m_sTexturePath = sTexturePath;
m_pTexture = TM->LoadTexture( m_sTexturePath );
assert( m_pTexture != NULL );
SetWidth( (FLOAT)m_pTexture->GetFrameWidth() );
SetHeight( (FLOAT)m_pTexture->GetFrameHeight() );
// Assume the frames of this animation play in sequential order with 0.2 second delay.
for( UINT i=0; i<m_pTexture->GetNumFrames(); i++ )
{
m_uFrame[i] = i;
m_fDelay[i] = 0.1f;
m_uNumStates = i+1;
}
return TRUE;
}
void Sprite::PrintDebugInfo()
{
// Actor::PrintDebugInfo();
RageLog( "Sprite::PrintDebugInfo()" );
RageLog( "m_uNumStates: %u, m_uCurState: %u, m_fSecsIntoState: %f",
m_uNumStates, m_uCurState, m_fSecsIntoState );
}
void Sprite::Update( const FLOAT &fDeltaTime )
{
//PrintDebugInfo();
Actor::Update( fDeltaTime ); // do tweening
// update animation
if( m_bIsAnimating )
{
m_fSecsIntoState += fDeltaTime;
if( m_fSecsIntoState > m_fDelay[m_uCurState] ) // it's time to switch frames
{
// increment frame and reset the counter
m_fSecsIntoState -= m_fDelay[m_uCurState]; // leave the left over time for the next frame
m_uCurState ++;
if( m_uCurState >= m_uNumStates )
m_uCurState = 0;
}
}
// update SpriteEffect
switch( m_Effect )
{
case no_effect:
break;
case blinking:
case camelion:
case glowing:
if( m_bTweeningTowardEndColor ) {
m_fPercentBetweenColors += m_fDeltaPercentPerSecond * fDeltaTime;
if( m_fPercentBetweenColors > 1.0f ) {
m_fPercentBetweenColors = 1.0f;
m_bTweeningTowardEndColor = FALSE;
}
}
else { // !m_bTweeningTowardEndColor
m_fPercentBetweenColors -= m_fDeltaPercentPerSecond * fDeltaTime;
if( m_fPercentBetweenColors < 0.0f ) {
m_fPercentBetweenColors = 0.0f;
m_bTweeningTowardEndColor = TRUE;
}
}
case wagging:
m_fWagTimer += fDeltaTime;
if( m_fWagTimer > m_fWagPeriod )
m_fWagTimer -= m_fWagPeriod;
break;
case spinning:
FLOAT rotation;
rotation = GetRotation();
rotation += m_fSpinSpeed * fDeltaTime;
if( rotation > 2.0f * D3DX_PI )
rotation -= 2.0f * D3DX_PI;
else if( rotation < 0.0f )
rotation += 2.0f * D3DX_PI;
SetRotation( rotation );
break;
case vibrating:
break;
case flickering:
break;
}
}
void Sprite::Draw()
{
if( m_pTexture == NULL )
return;
UINT uFrameNo = m_uFrame[m_uCurState];
LPRECT pRectSrc;
if( m_bUsingCustomSrcRect )
pRectSrc = &m_rectCustomSrcRect;
else
pRectSrc = m_pTexture->GetFrameRect( uFrameNo );
//::SetRect( &rectSrc, 0, 0, m_pTexture->GetImageWidth(), m_pTexture->GetImageHeight() );
D3DXVECTOR2 scaling;
scaling.x = GetZoom();
scaling.y = GetZoom();
D3DXVECTOR2 translation;
translation.x = (float)GetLeftEdge();
translation.y = (float)GetTopEdge();
D3DXVECTOR3 rotation = m_rotation;
D3DXVECTOR2 rot_center;
rot_center.x = GetZoomedWidth()/2.0f;
rot_center.y = GetZoomedHeight()/2.0f;
D3DXCOLOR color = m_color;
// update SpriteEffect
switch( m_Effect )
{
case no_effect:
break;
case blinking:
color = m_bTweeningTowardEndColor ? m_start_color : m_end_color;
break;
case camelion:
case glowing:
color = m_start_color*m_fPercentBetweenColors + m_end_color*(1.0f-m_fPercentBetweenColors);
break;
case wagging:
rotation.z = m_fWagRadians * (FLOAT)sin(
(m_fWagTimer / m_fWagPeriod) // percent through wag
* 2.0 * D3DX_PI );
break;
case spinning:
// nothing special needed
break;
case vibrating:
translation.x += m_fVibrationDistance * randomf(-1.0f, 1.0f) * GetZoom();
translation.y += m_fVibrationDistance * randomf(-1.0f, 1.0f) * GetZoom();
break;
case flickering:
m_bVisibleThisFrame = !m_bVisibleThisFrame;
if( m_bVisibleThisFrame )
return; // don't draw the frame
break;
}
SCREEN->DrawQuad( m_pTexture,
pRectSrc,
&scaling, // scaling
&rot_center, // rotation center
&rotation, // rotation
&translation, // translation
color,
m_Effect == glowing ? op_add : op_modulate,
m_bBlendAdd );
}
void Sprite::SetState( UINT uNewState )
{
ASSERT( uNewState >= 0 && uNewState < m_uNumStates );
m_uCurState = uNewState;
m_fSecsIntoState = 0.0;
}
void Sprite::SetCustomSrcRect( RECT newRect )
{
m_bUsingCustomSrcRect = TRUE;
m_rectCustomSrcRect = newRect;
SetWidth( (FLOAT) RECTWIDTH(newRect) );
SetHeight( (FLOAT) RECTHEIGHT(newRect) );
};
VOID Sprite::SetEffectNone()
{
m_Effect = no_effect;
//m_color = D3DXCOLOR( 1.0,1.0,1.0,1.0 );
}
VOID Sprite::SetEffectBlinking( FLOAT fDeltaPercentPerSecond, D3DXCOLOR Color, D3DXCOLOR Color2 )
{
m_Effect = blinking;
m_start_color = Color;
m_end_color = Color2;
//m_fPercentBetweenColors = 0.0;
//m_bTweeningTowardEndColor = TRUE;
m_fDeltaPercentPerSecond = fDeltaPercentPerSecond;
}
VOID Sprite::SetEffectCamelion( FLOAT fDeltaPercentPerSecond, D3DXCOLOR Color, D3DXCOLOR Color2 )
{
m_Effect = camelion;
m_start_color = Color;
m_end_color = Color2;
//m_fPercentBetweenColors = 0.0;
//m_bTweeningTowardEndColor = TRUE;
m_fDeltaPercentPerSecond = fDeltaPercentPerSecond;
}
VOID Sprite::SetEffectGlowing( FLOAT fDeltaPercentPerSecond, D3DXCOLOR Color, D3DXCOLOR Color2 )
{
m_Effect = glowing;
m_start_color = Color;
m_end_color = Color2;
//m_fPercentBetweenColors = 0.0;
//m_bTweeningTowardEndColor = TRUE;
m_fDeltaPercentPerSecond = fDeltaPercentPerSecond;
}
VOID Sprite::SetEffectWagging( FLOAT fWagRadians, FLOAT fWagPeriod )
{
m_Effect = wagging;
m_fWagRadians = fWagRadians;
m_fWagPeriod = fWagPeriod;
}
VOID Sprite::SetEffectSpinning( FLOAT fSpinSpeed /*radians per second*/ )
{
m_Effect = spinning;
m_fSpinSpeed = fSpinSpeed;
}
VOID Sprite::SetEffectVibrating( FLOAT fVibrationDistance )
{
m_Effect = vibrating;
m_fVibrationDistance = fVibrationDistance;
}
VOID Sprite::SetEffectFlickering()
{
m_Effect = flickering;
}