Files
itgmania212121/stepmania/src/Sprite.cpp
T

408 lines
12 KiB
C++
Raw Normal View History

2001-11-03 10:52:42 +00:00
#include "stdafx.h"
/*
-----------------------------------------------------------------------------
File: Sprite.cpp
Desc: A bitmap actor that animates and moves around.
2002-05-19 01:59:48 +00:00
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
2002-06-27 17:49:10 +00:00
Chris Danford
-----------------------------------------------------------------------------
*/
2001-11-03 10:52:42 +00:00
#include "Sprite.h"
#include "RageTextureManager.h"
#include "IniFile.h"
#include <math.h>
2002-05-01 19:14:55 +00:00
#include "RageLog.h"
2002-06-14 22:25:22 +00:00
2002-05-27 08:23:27 +00:00
#include "PrefsManager.h"
2001-11-03 10:52:42 +00:00
Sprite::Sprite()
{
m_pTexture = NULL;
m_iNumStates = 0;
m_iCurState = 0;
2001-11-03 10:52:42 +00:00
m_bIsAnimating = TRUE;
m_fSecsIntoState = 0.0;
2001-12-28 10:15:59 +00:00
m_bUsingCustomTexCoords = false;
2001-11-03 10:52:42 +00:00
}
2002-01-16 10:01:32 +00:00
2001-11-03 10:52:42 +00:00
Sprite::~Sprite()
{
2002-05-01 19:14:55 +00:00
// LOG->WriteLine( "Sprite Destructor" );
2001-11-03 10:52:42 +00:00
2002-05-19 01:59:48 +00:00
TEXTUREMAN->UnloadTexture( m_sTexturePath );
2001-11-03 10:52:42 +00:00
}
2002-05-19 01:59:48 +00:00
bool Sprite::LoadFromTexture( CString sTexturePath, bool bForceReload, int iMipMaps, int iAlphaBits, bool bDither, bool bStretch )
2001-11-03 10:52:42 +00:00
{
2002-05-01 19:14:55 +00:00
LOG->WriteLine( ssprintf("Sprite::LoadFromTexture(%s)", sTexturePath) );
2001-11-03 10:52:42 +00:00
2002-01-16 10:01:32 +00:00
//Init();
2002-05-19 01:59:48 +00:00
return LoadTexture( sTexturePath, bForceReload, iMipMaps, iAlphaBits, bDither, bStretch );
2001-11-03 10:52:42 +00:00
}
// Sprite file has the format:
//
// [Sprite]
2001-12-19 01:50:57 +00:00
// Texture=Textures\Logo.bmp
2001-11-03 10:52:42 +00:00
// Frame0000=0
// Delay0000=1.0
// Frame0001=3
// Delay0000=2.0
2002-05-19 01:59:48 +00:00
bool Sprite::LoadFromSpriteFile( CString sSpritePath, bool bForceReload, int iMipMaps, int iAlphaBits, bool bDither, bool bStretch )
2001-11-03 10:52:42 +00:00
{
2002-05-01 19:14:55 +00:00
LOG->WriteLine( ssprintf("Sprite::LoadFromSpriteFile(%s)", sSpritePath) );
2001-11-03 10:52:42 +00:00
2002-01-16 10:01:32 +00:00
//Init();
2001-11-03 10:52:42 +00:00
m_sSpritePath = sSpritePath;
2002-01-16 10:01:32 +00:00
// Split for the directory. We'll need it below
CString sFontDir, sFontFileName, sFontExtension;
splitrelpath( m_sSpritePath, sFontDir, sFontFileName, sFontExtension );
2001-11-03 10:52:42 +00:00
// read sprite file
IniFile ini;
ini.SetPath( m_sSpritePath );
if( !ini.ReadFile() )
2002-06-14 22:25:22 +00:00
throw RageException( ssprintf("Error opening Sprite file '%s'.", m_sSpritePath) );
2001-11-03 10:52:42 +00:00
2002-05-20 08:59:37 +00:00
CString sTextureFile;
ini.GetValue( "Sprite", "Texture", sTextureFile );
2002-01-16 10:01:32 +00:00
if( sTextureFile == "" )
2002-06-14 22:25:22 +00:00
throw RageException( ssprintf("Error reading value 'Texture' from %s.", m_sSpritePath) );
2001-11-03 10:52:42 +00:00
2002-01-16 10:01:32 +00:00
CString sTexturePath = sFontDir + sTextureFile; // save the path of the new texture
2001-11-03 10:52:42 +00:00
// 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++ )
{
2002-07-23 01:41:40 +00:00
CString sFrameKey = ssprintf( "Frame%04d", i );
CString sDelayKey = ssprintf( "Delay%04d", i );
2001-11-03 10:52:42 +00:00
2002-05-20 08:59:37 +00:00
m_iStateToFrame[i] = 0;
if( !ini.GetValueI( "Sprite", sFrameKey, m_iStateToFrame[i] ) )
break;
if( m_iStateToFrame[i] >= m_pTexture->GetNumFrames() )
2002-06-14 22:25:22 +00:00
throw RageException( "In '%s', %s is %d, but the texture %s only has %d frames.",
2002-05-20 08:59:37 +00:00
m_sSpritePath, sFrameKey, m_iStateToFrame[i], sTexturePath, m_pTexture->GetNumFrames() );
m_fDelay[i] = 0.2f;
if( !ini.GetValueF( "Sprite", sDelayKey, m_fDelay[i] ) )
break;
2001-11-03 10:52:42 +00:00
if( m_iStateToFrame[i] == 0 && m_fDelay[i] > -0.00001f && m_fDelay[i] < 0.00001f ) // both values are empty
2001-11-03 10:52:42 +00:00
break;
m_iNumStates = i+1;
2001-11-03 10:52:42 +00:00
}
if( m_iNumStates == 0 )
2002-01-16 10:01:32 +00:00
{
m_iNumStates = 1;
m_iStateToFrame[0] = 0;
2002-01-16 10:01:32 +00:00
m_fDelay[0] = 10;
}
2001-11-03 10:52:42 +00:00
2002-01-16 10:01:32 +00:00
return true;
2001-11-03 10:52:42 +00:00
}
2002-04-16 17:31:00 +00:00
void Sprite::UnloadTexture()
2001-11-03 10:52:42 +00:00
{
if( m_pTexture != NULL ) // If there was a previous bitmap...
2002-05-19 01:59:48 +00:00
TEXTUREMAN->UnloadTexture( m_sTexturePath ); // Unload it.
2002-04-16 17:31:00 +00:00
m_pTexture = NULL;
m_sTexturePath = "";
}
2002-05-19 01:59:48 +00:00
bool Sprite::LoadTexture( CString sTexturePath, bool bForceReload, int iMipMaps, int iAlphaBits, bool bDither, bool bStretch )
2002-04-16 17:31:00 +00:00
{
if( m_pTexture != NULL ) // If there was a previous bitmap...
UnloadTexture();
2001-11-03 10:52:42 +00:00
m_sTexturePath = sTexturePath;
2002-05-19 01:59:48 +00:00
m_pTexture = TEXTUREMAN->LoadTexture( m_sTexturePath, bForceReload, iMipMaps, iAlphaBits, bDither, bStretch );
2001-11-03 10:52:42 +00:00
assert( m_pTexture != NULL );
2001-11-25 04:31:44 +00:00
// the size of the sprite is the size of the image before it was scaled
2001-11-28 20:26:45 +00:00
SetWidth( (float)m_pTexture->GetSourceFrameWidth() );
SetHeight( (float)m_pTexture->GetSourceFrameHeight() );
2001-11-03 10:52:42 +00:00
// Assume the frames of this animation play in sequential order with 0.2 second delay.
for( int i=0; i<m_pTexture->GetNumFrames(); i++ )
2001-11-03 10:52:42 +00:00
{
m_iStateToFrame[i] = i;
2001-11-03 10:52:42 +00:00
m_fDelay[i] = 0.1f;
m_iNumStates = i+1;
2001-11-03 10:52:42 +00:00
}
return TRUE;
}
void Sprite::Update( float fDeltaTime )
2001-11-03 10:52:42 +00:00
{
//PrintDebugInfo();
Actor::Update( fDeltaTime ); // do tweening
// update animation
if( m_bIsAnimating )
{
m_fSecsIntoState += fDeltaTime;
if( m_fSecsIntoState > m_fDelay[m_iCurState] ) // it's time to switch frames
2001-11-03 10:52:42 +00:00
{
// increment frame and reset the counter
m_fSecsIntoState -= m_fDelay[m_iCurState]; // leave the left over time for the next frame
m_iCurState ++;
if( m_iCurState >= m_iNumStates )
m_iCurState = 0;
2001-11-03 10:52:42 +00:00
}
}
2001-11-28 20:26:45 +00:00
2001-11-03 10:52:42 +00:00
}
2002-05-19 01:59:48 +00:00
void Sprite::DrawPrimitives()
2001-11-03 10:52:42 +00:00
{
2002-05-27 08:23:27 +00:00
// offset so that pixels are aligned to texels
2002-07-23 01:41:40 +00:00
DISPLAY->TranslateLocal( -0.5f, -0.5f, 0 );
2002-01-16 10:01:32 +00:00
if( m_pTexture == NULL )
return;
// use m_temp_* variables to draw the object
2001-11-03 10:52:42 +00:00
2001-11-25 04:31:44 +00:00
2002-01-16 10:01:32 +00:00
// make the object in logical units centered at the origin
2001-11-25 04:31:44 +00:00
2002-01-16 10:01:32 +00:00
FRECT quadVerticies;
2001-11-25 04:31:44 +00:00
2002-01-16 10:01:32 +00:00
switch( m_HorizAlign )
{
2002-01-16 10:01:32 +00:00
case align_top: quadVerticies.left = 0; quadVerticies.right = m_size.x; break;
case align_middle: quadVerticies.left = -m_size.x/2; quadVerticies.right = m_size.x/2; break;
case align_bottom: quadVerticies.left = -m_size.x; quadVerticies.right = 0; break;
2002-02-11 04:46:31 +00:00
default: ASSERT( false );
2002-01-16 10:01:32 +00:00
}
2001-11-25 04:31:44 +00:00
2002-01-16 10:01:32 +00:00
switch( m_VertAlign )
{
case align_bottom: quadVerticies.top = 0; quadVerticies.bottom = m_size.y; break;
case align_middle: quadVerticies.top = -m_size.y/2; quadVerticies.bottom = m_size.y/2; break;
case align_top: quadVerticies.top = -m_size.y; quadVerticies.bottom = 0; break;
2002-02-11 04:46:31 +00:00
default: ASSERT( false );
2002-01-16 10:01:32 +00:00
}
2001-11-25 04:31:44 +00:00
2002-05-19 01:59:48 +00:00
LPDIRECT3DVERTEXBUFFER8 pVB = DISPLAY->GetVertexBuffer();
RAGEVERTEX* v;
2002-01-16 10:01:32 +00:00
pVB->Lock( 0, 0, (BYTE**)&v, 0 );
2001-11-25 04:31:44 +00:00
2002-04-28 20:42:32 +00:00
v[0].p = D3DXVECTOR3( quadVerticies.left, quadVerticies.bottom, 0 ); // bottom left
v[1].p = D3DXVECTOR3( quadVerticies.left, quadVerticies.top, 0 ); // top left
v[2].p = D3DXVECTOR3( quadVerticies.right, quadVerticies.bottom, 0 ); // bottom right
v[3].p = D3DXVECTOR3( quadVerticies.right, quadVerticies.top, 0 ); // top right
2001-11-25 04:31:44 +00:00
2002-01-16 10:01:32 +00:00
if( m_bUsingCustomTexCoords )
{
2002-04-28 20:42:32 +00:00
v[0].t = D3DXVECTOR2( m_CustomTexCoords[0], m_CustomTexCoords[1] ); // bottom left
v[1].t = D3DXVECTOR2( m_CustomTexCoords[2], m_CustomTexCoords[3] ); // top left
v[2].t = D3DXVECTOR2( m_CustomTexCoords[4], m_CustomTexCoords[5] ); // bottom right
v[3].t = D3DXVECTOR2( m_CustomTexCoords[6], m_CustomTexCoords[7] ); // top right
2002-01-16 10:01:32 +00:00
}
else
{
UINT uFrameNo = m_iStateToFrame[m_iCurState];
2002-01-16 10:01:32 +00:00
FRECT* pTexCoordRect = m_pTexture->GetTextureCoordRect( uFrameNo );
2001-12-28 10:15:59 +00:00
2002-04-28 20:42:32 +00:00
v[0].t = D3DXVECTOR2( pTexCoordRect->left, pTexCoordRect->bottom ); // bottom left
v[1].t = D3DXVECTOR2( pTexCoordRect->left, pTexCoordRect->top ); // top left
v[2].t = D3DXVECTOR2( pTexCoordRect->right, pTexCoordRect->bottom ); // bottom right
v[3].t = D3DXVECTOR2( pTexCoordRect->right, pTexCoordRect->top ); // top right
2002-01-16 10:01:32 +00:00
}
2001-12-28 10:15:59 +00:00
2002-01-16 10:01:32 +00:00
pVB->Unlock();
2001-12-28 10:15:59 +00:00
2001-11-25 04:31:44 +00:00
2002-01-16 10:01:32 +00:00
// Set the stage...
2002-05-19 01:59:48 +00:00
LPDIRECT3DDEVICE8 pd3dDevice = DISPLAY->GetDevice();
2002-01-16 10:01:32 +00:00
pd3dDevice->SetTexture( 0, m_pTexture->GetD3DTexture() );
2002-01-16 10:01:32 +00:00
pd3dDevice->SetRenderState( D3DRS_SRCBLEND, m_bBlendAdd ? D3DBLEND_ONE : D3DBLEND_SRCALPHA );
pd3dDevice->SetRenderState( D3DRS_DESTBLEND, m_bBlendAdd ? D3DBLEND_ONE : D3DBLEND_INVSRCALPHA );
2002-05-19 01:59:48 +00:00
pd3dDevice->SetVertexShader( D3DFVF_RAGEVERTEX );
pd3dDevice->SetStreamSource( 0, pVB, sizeof(RAGEVERTEX) );
2001-12-19 01:50:57 +00:00
if( m_temp_colorDiffuse[0].a != 0 )
2002-01-16 10:01:32 +00:00
{
//////////////////////
// render the shadow
//////////////////////
2002-05-01 19:14:55 +00:00
if( m_bShadow )
2001-12-19 01:50:57 +00:00
{
2002-05-19 01:59:48 +00:00
DISPLAY->PushMatrix();
DISPLAY->TranslateLocal( m_fShadowLength, m_fShadowLength, 0 ); // shift by 5 units
2002-01-16 10:01:32 +00:00
2001-12-19 01:50:57 +00:00
pVB->Lock( 0, 0, (BYTE**)&v, 0 );
v[0].color = v[1].color = v[2].color = v[3].color = D3DXCOLOR(0,0,0,0.5f*m_temp_colorDiffuse[0].a); // semi-transparent black
2001-12-19 01:50:57 +00:00
pVB->Unlock();
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
2002-01-16 10:01:32 +00:00
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
2001-12-19 01:50:57 +00:00
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
2002-01-16 10:01:32 +00:00
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
2001-12-19 01:50:57 +00:00
pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
2002-01-16 10:01:32 +00:00
2002-05-19 01:59:48 +00:00
DISPLAY->PopMatrix();
2001-12-19 01:50:57 +00:00
}
//////////////////////
2002-01-16 10:01:32 +00:00
// render the diffuse pass
//////////////////////
2002-01-16 10:01:32 +00:00
pVB->Lock( 0, 0, (BYTE**)&v, 0 );
v[0].color = m_temp_colorDiffuse[2]; // bottom left
v[1].color = m_temp_colorDiffuse[0]; // top left
v[2].color = m_temp_colorDiffuse[3]; // bottom right
v[3].color = m_temp_colorDiffuse[1]; // top right
2002-01-16 10:01:32 +00:00
pVB->Unlock();
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );//bBlendAdd ? D3DTOP_ADD : D3DTOP_MODULATE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );//bBlendAdd ? D3DTOP_ADD : D3DTOP_MODULATE );
2001-12-19 01:50:57 +00:00
2002-01-16 10:01:32 +00:00
// finally! Pump those triangles!
pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
}
2001-11-03 10:52:42 +00:00
2002-01-16 10:01:32 +00:00
//////////////////////
// render the add pass
//////////////////////
if( m_temp_colorAdd.a != 0 )
2002-01-16 10:01:32 +00:00
{
pVB->Lock( 0, 0, (BYTE**)&v, 0 );
v[0].color = v[1].color = v[2].color = v[3].color = m_temp_colorAdd;
2002-01-16 10:01:32 +00:00
pVB->Unlock();
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
}
2001-11-03 10:52:42 +00:00
}
void Sprite::SetState( int iNewState )
2001-11-03 10:52:42 +00:00
{
ASSERT( iNewState >= 0 && iNewState < m_iNumStates );
2002-05-20 08:59:37 +00:00
if( iNewState < 0 ) iNewState = 0;
else if( iNewState >= m_iNumStates ) iNewState = m_iNumStates-1;
m_iCurState = iNewState;
2001-11-03 10:52:42 +00:00
m_fSecsIntoState = 0.0;
}
2002-01-29 21:56:14 +00:00
void Sprite::SetCustomTextureRect( FRECT new_texcoord_frect )
2001-11-03 10:52:42 +00:00
{
2001-12-28 10:15:59 +00:00
m_bUsingCustomTexCoords = true;
m_CustomTexCoords[0] = new_texcoord_frect.left; m_CustomTexCoords[1] = new_texcoord_frect.bottom; // bottom left
m_CustomTexCoords[2] = new_texcoord_frect.left; m_CustomTexCoords[3] = new_texcoord_frect.top; // top left
m_CustomTexCoords[4] = new_texcoord_frect.right; m_CustomTexCoords[5] = new_texcoord_frect.bottom; // bottom right
m_CustomTexCoords[6] = new_texcoord_frect.right; m_CustomTexCoords[7] = new_texcoord_frect.top; // top right
2001-11-25 04:31:44 +00:00
}
2001-11-03 10:52:42 +00:00
2002-01-29 21:56:14 +00:00
void Sprite::SetCustomTextureCoords( float fTexCoords[8] ) // order: bottom left, top left, bottom right, top right
2001-12-28 10:15:59 +00:00
{
m_bUsingCustomTexCoords = true;
for( int i=0; i<8; i++ )
m_CustomTexCoords[i] = fTexCoords[i];
}
2001-11-03 10:52:42 +00:00
2002-06-27 17:49:10 +00:00
void Sprite::GetCustomTextureCoords( float fTexCoordsOut[8] ) // order: bottom left, top left, bottom right, top right
{
for( int i=0; i<8; i++ )
fTexCoordsOut[i] = m_CustomTexCoords[i];
}
2002-01-29 21:56:14 +00:00
void Sprite::SetCustomImageRect( FRECT rectImageCoords )
{
// Convert to a rectangle in texture coordinate space.
rectImageCoords.left *= m_pTexture->GetImageWidth() / (float)m_pTexture->GetTextureWidth();
rectImageCoords.right *= m_pTexture->GetImageWidth() / (float)m_pTexture->GetTextureWidth();
rectImageCoords.top *= m_pTexture->GetImageHeight() / (float)m_pTexture->GetTextureHeight();
rectImageCoords.bottom *= m_pTexture->GetImageHeight() / (float)m_pTexture->GetTextureHeight();
SetCustomTextureRect( rectImageCoords );
}
void Sprite::SetCustomImageCoords( float fImageCoords[8] ) // order: bottom left, top left, bottom right, top right
{
// convert image coords to texture coords in place
for( int i=0; i<8; i+=2 )
{
fImageCoords[i+0] *= m_pTexture->GetImageWidth() / (float)m_pTexture->GetTextureWidth();
fImageCoords[i+1] *= m_pTexture->GetImageHeight() / (float)m_pTexture->GetTextureHeight();
}
SetCustomTextureCoords( fImageCoords );
}
2002-03-31 07:55:25 +00:00
void Sprite::StopUsingCustomCoords()
{
m_bUsingCustomTexCoords = false;
}