2003-02-16 04:01:45 +00:00
# include "global.h"
2001-11-04 19:34:28 +00:00
/*
-----------------------------------------------------------------------------
2002-08-18 16:19:26 +00:00
Class: Sprite
2001-11-04 19:34:28 +00:00
2002-08-18 16:19:26 +00:00
Desc: See header.
2001-11-04 19:34:28 +00:00
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-04 19:34:28 +00:00
-----------------------------------------------------------------------------
*/
2001-11-03 10:52:42 +00:00
2002-08-23 01:06:36 +00:00
# include <math.h>
# include <assert.h>
2001-11-03 10:52:42 +00:00
# include "Sprite.h"
# include "RageTextureManager.h"
# include "IniFile.h"
2002-05-01 19:14:55 +00:00
# include "RageLog.h"
2002-07-27 19:29:51 +00:00
# include "RageException.h"
2002-05-27 08:23:27 +00:00
# include "PrefsManager.h"
2002-11-11 04:53:31 +00:00
# include "RageDisplay.h"
# include "GameConstantsAndTypes.h"
2003-02-14 06:31:09 +00:00
# include "SDL_utils.h"
2003-07-11 03:15:28 +00:00
# include "arch/ArchHooks/ArchHooks.h"
2001-11-03 10:52:42 +00:00
Sprite : : Sprite ( )
{
m_pTexture = NULL ;
2002-11-11 04:53:31 +00:00
m_bDrawIfTextureNull = false ;
2002-03-30 20:00:13 +00:00
m_iCurState = 0 ;
2001-11-03 10:52:42 +00:00
m_fSecsIntoState = 0.0 ;
2001-12-28 10:15:59 +00:00
m_bUsingCustomTexCoords = false ;
2003-07-03 06:38:57 +00:00
m_fRememberedClipWidth = - 1 ;
m_fRememberedClipHeight = - 1 ;
m_fTexCoordVelocityX = 0 ;
m_fTexCoordVelocityY = 0 ;
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-12-30 02:43:52 +00:00
UnloadTexture ( ) ;
2001-11-03 10:52:42 +00:00
}
2003-03-23 18:52:18 +00:00
bool Sprite : : LoadBG ( RageTextureID ID )
{
ID . iMipMaps = 1 ;
2003-07-22 07:47:27 +00:00
// ID.bDither = true;
2003-03-23 18:52:18 +00:00
return Load ( ID ) ;
}
bool Sprite : : Load ( RageTextureID ID )
{
if ( ID . filename = = " " ) return true ;
if ( ID . filename . Right ( 7 ) = = " .sprite " )
return LoadFromSpriteFile ( ID ) ;
else
return LoadFromTexture ( ID ) ;
} ;
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
2003-02-06 07:32:57 +00:00
// BaseRotationXDegrees=0
// BaseRotationYDegrees=0
// BaseRotationZDegrees=0
// BaseZoomX=1
// BaseZoomY=1
// BaseZoomZ=1
2002-12-30 02:43:52 +00:00
bool Sprite : : LoadFromSpriteFile ( RageTextureID ID )
2001-11-03 10:52:42 +00:00
{
2003-04-25 00:01:35 +00:00
LOG - > Trace ( ssprintf ( " Sprite::LoadFromSpriteFile(%s) " , ID . filename . c_str ( ) ) ) ;
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
2002-12-30 02:43:52 +00:00
m_sSpritePath = ID . filename ;
2001-11-03 10:52:42 +00:00
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 ( ) )
2003-04-25 00:01:35 +00:00
RageException : : Throw ( " Error opening Sprite file '%s'. " , m_sSpritePath . c_str ( ) ) ;
2001-11-03 10:52:42 +00:00
2002-05-20 08:59:37 +00:00
CString sTextureFile ;
ini . GetValue ( " Sprite " , " Texture " , sTextureFile ) ;
2002-09-24 03:12:04 +00:00
if ( sTextureFile = = " " )
2003-04-25 00:01:35 +00:00
RageException : : Throw ( " Error reading value 'Texture' from %s. " , m_sSpritePath . c_str ( ) ) ;
2001-11-03 10:52:42 +00:00
2002-12-30 02:43:52 +00:00
ID . filename = sFontDir + sTextureFile ; // save the path of the real texture
2003-05-05 08:26:30 +00:00
{
vector < CString > asElementPaths ;
GetDirListing ( ID . filename + " * " , asElementPaths , false , true ) ;
if ( asElementPaths . size ( ) = = 0 )
RageException : : Throw ( " The sprite file '%s' points to a texture '%s' which doesn't exist. " , m_sSpritePath . c_str ( ) , ID . filename . c_str ( ) ) ;
if ( asElementPaths . size ( ) > 1 )
{
CString message = ssprintf (
" There is more than one file that matches "
" '%s/%s'. Please remove all but one of these matches. " ,
ID . filename . c_str ( ) ) ;
RageException : : Throw ( message ) ;
}
ID . filename = asElementPaths [ 0 ] ;
}
2002-09-24 03:12:04 +00:00
2001-11-03 10:52:42 +00:00
// Load the texture
2002-12-30 02:43:52 +00:00
LoadFromTexture ( ID ) ;
2001-11-03 10:52:42 +00:00
// Read in frames and delays from the sprite file,
// overwriting the states that LoadFromTexture created.
2003-05-22 05:28:37 +00:00
// If the .sprite file doesn't define any states, leave
// frames and delays created during LoadFromTexture().
for ( int i = 0 ; true ; i + + )
2001-11-03 10:52:42 +00:00
{
2002-07-23 01:41:40 +00:00
CString sFrameKey = ssprintf ( " Frame%04d " , i ) ;
CString sDelayKey = ssprintf ( " Delay%04d " , i ) ;
2003-05-22 05:28:37 +00:00
State newState ;
2003-10-02 02:03:29 +00:00
if ( ! ini . GetValue ( " Sprite " , sFrameKey , newState . iFrameIndex ) )
2002-05-20 08:59:37 +00:00
break ;
2003-05-22 05:28:37 +00:00
if ( newState . iFrameIndex > = m_pTexture - > GetNumFrames ( ) )
2002-12-21 19:34:02 +00:00
RageException : : Throw ( " In '%s', %s is %d, but the texture %s only has %d frames. " ,
2003-05-22 05:28:37 +00:00
m_sSpritePath . c_str ( ) , sFrameKey . c_str ( ) , newState . iFrameIndex , ID . filename . c_str ( ) , m_pTexture - > GetNumFrames ( ) ) ;
2001-11-03 10:52:42 +00:00
2003-10-02 02:03:29 +00:00
if ( ! ini . GetValue ( " Sprite " , sDelayKey , newState . fDelay ) )
2001-11-03 10:52:42 +00:00
break ;
2003-05-22 05:28:37 +00:00
if ( i = = 0 ) // the ini file defines at least one frame
m_States . clear ( ) ; // clear before adding
2001-11-03 10:52:42 +00:00
2003-05-22 05:28:37 +00:00
m_States . push_back ( newState ) ;
2002-01-16 10:01:32 +00:00
}
2001-11-03 10:52:42 +00:00
2003-02-06 07:32:57 +00:00
float f ;
2003-10-02 02:03:29 +00:00
if ( ini . GetValue ( " Sprite " , " BaseRotationXDegrees " , f ) ) Actor : : SetBaseRotationX ( f ) ;
if ( ini . GetValue ( " Sprite " , " BaseRotationYDegrees " , f ) ) Actor : : SetBaseRotationY ( f ) ;
if ( ini . GetValue ( " Sprite " , " BaseRotationZDegrees " , f ) ) Actor : : SetBaseRotationZ ( f ) ;
if ( ini . GetValue ( " Sprite " , " BaseZoomX " , f ) ) Actor : : SetBaseZoomX ( f ) ;
if ( ini . GetValue ( " Sprite " , " BaseZoomY " , f ) ) Actor : : SetBaseZoomY ( f ) ;
if ( ini . GetValue ( " Sprite " , " BaseZoomZ " , f ) ) Actor : : SetBaseZoomZ ( f ) ;
2003-02-06 07:32:57 +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
{
2002-03-30 20:00:13 +00:00
if ( m_pTexture ! = NULL ) // If there was a previous bitmap...
2002-12-30 02:43:52 +00:00
TEXTUREMAN - > UnloadTexture ( m_pTexture ) ; // Unload it.
2002-04-16 17:31:00 +00:00
m_pTexture = NULL ;
}
2003-03-23 18:52:18 +00:00
void Sprite : : EnableAnimation ( bool bEnable )
{
Actor : : EnableAnimation ( bEnable ) ;
if ( m_pTexture )
bEnable ? m_pTexture - > Play ( ) : m_pTexture - > Pause ( ) ;
}
2002-12-30 02:43:52 +00:00
bool Sprite : : LoadFromTexture ( RageTextureID ID )
2002-04-16 17:31:00 +00:00
{
2003-07-22 07:47:27 +00:00
LOG - > Trace ( " Sprite::LoadFromTexture( %s ) " , ID . filename . c_str ( ) ) ;
2003-03-16 00:45:06 +00:00
if ( ! m_pTexture | | ! ( m_pTexture - > GetID ( ) = = ID ) )
{
/* Load the texture if it's not already loaded. We still need
* to do the rest, even if it's the same texture, since we need
* to reset Sprite::m_size, etc. */
UnloadTexture ( ) ;
m_pTexture = TEXTUREMAN - > LoadTexture ( ID ) ;
2003-05-22 05:28:37 +00:00
ASSERT ( m_pTexture - > GetTextureWidth ( ) > = 0 ) ;
ASSERT ( m_pTexture - > GetTextureHeight ( ) > = 0 ) ;
2003-03-16 00:45:06 +00:00
}
2001-11-03 10:52:42 +00:00
2002-12-30 02:43:52 +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
2002-09-02 21:59:58 +00:00
Sprite : : m_size . x = ( float ) m_pTexture - > GetSourceFrameWidth ( ) ;
Sprite : : m_size . y = ( 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.
2003-05-22 05:28:37 +00:00
m_States . clear ( ) ;
2002-03-30 20:00:13 +00:00
for ( int i = 0 ; i < m_pTexture - > GetNumFrames ( ) ; i + + )
2001-11-03 10:52:42 +00:00
{
2003-05-22 05:28:37 +00:00
State newState = { i , 0.1f } ;
m_States . push_back ( newState ) ;
2001-11-03 10:52:42 +00:00
}
2003-02-07 05:48:30 +00:00
2003-07-03 06:38:57 +00:00
// apply clipping (if any)
if ( m_fRememberedClipWidth ! = - 1 & & m_fRememberedClipHeight ! = - 1 )
ScaleToClipped ( m_fRememberedClipWidth , m_fRememberedClipHeight ) ;
2002-08-23 08:26:11 +00:00
return true ;
2001-11-03 10:52:42 +00:00
}
2003-07-03 06:38:57 +00:00
void Sprite : : Update ( float fDelta )
2001-11-03 10:52:42 +00:00
{
2003-07-03 06:38:57 +00:00
Actor : : Update ( fDelta ) ; // do tweening
2001-11-03 10:52:42 +00:00
2002-10-16 00:28:01 +00:00
if ( ! m_bIsAnimating )
return ;
2001-11-03 10:52:42 +00:00
2003-05-22 05:28:37 +00:00
if ( ! m_pTexture ) // no texture, nothing to animate
return ;
2003-07-03 06:38:57 +00:00
//
// update animation frame
//
m_fSecsIntoState + = fDelta ;
2002-10-16 00:28:01 +00:00
2003-05-22 05:28:37 +00:00
while ( m_fSecsIntoState > m_States [ m_iCurState ] . fDelay ) // it's time to switch frames
2001-11-03 10:52:42 +00:00
{
2002-10-16 00:28:01 +00:00
// increment frame and reset the counter
2003-05-22 05:28:37 +00:00
m_fSecsIntoState - = m_States [ m_iCurState ] . fDelay ; // leave the left over time for the next frame
m_iCurState = ( m_iCurState + 1 ) % m_States . size ( ) ;
2001-11-03 10:52:42 +00:00
}
2003-07-03 06:38:57 +00:00
//
// update scrolling
//
if ( m_fTexCoordVelocityX ! = 0 | | m_fTexCoordVelocityY ! = 0 )
{
float fTexCoords [ 8 ] ;
Sprite : : GetActiveTextureCoords ( fTexCoords ) ;
// top left, bottom left, bottom right, top right
fTexCoords [ 0 ] + = fDelta * m_fTexCoordVelocityX ;
fTexCoords [ 1 ] + = fDelta * m_fTexCoordVelocityY ;
fTexCoords [ 2 ] + = fDelta * m_fTexCoordVelocityX ;
fTexCoords [ 3 ] + = fDelta * m_fTexCoordVelocityY ;
fTexCoords [ 4 ] + = fDelta * m_fTexCoordVelocityX ;
fTexCoords [ 5 ] + = fDelta * m_fTexCoordVelocityY ;
fTexCoords [ 6 ] + = fDelta * m_fTexCoordVelocityX ;
fTexCoords [ 7 ] + = fDelta * m_fTexCoordVelocityY ;
Sprite : : SetCustomTextureCoords ( fTexCoords ) ;
}
2001-11-03 10:52:42 +00:00
}
2003-07-07 01:29:18 +00:00
static void TexCoordsFromArray ( RageSpriteVertex * v , const float * f )
2003-04-21 01:35:37 +00:00
{
2003-04-21 02:45:00 +00:00
v [ 0 ] . t = RageVector2 ( f [ 0 ] , f [ 1 ] ) ; // top left
v [ 1 ] . t = RageVector2 ( f [ 2 ] , f [ 3 ] ) ; // bottom left
v [ 2 ] . t = RageVector2 ( f [ 4 ] , f [ 5 ] ) ; // bottom right
v [ 3 ] . t = RageVector2 ( f [ 6 ] , f [ 7 ] ) ; // top right
}
void TexCoordArrayFromRect ( float fImageCoords [ 8 ] , const RectF & rect )
{
fImageCoords [ 0 ] = rect . left ; fImageCoords [ 1 ] = rect . top ; // top left
fImageCoords [ 2 ] = rect . left ; fImageCoords [ 3 ] = rect . bottom ; // bottom left
fImageCoords [ 4 ] = rect . right ; fImageCoords [ 5 ] = rect . bottom ; // bottom right
fImageCoords [ 6 ] = rect . right ; fImageCoords [ 7 ] = rect . top ; // top right
2003-04-21 01:35:37 +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-11-11 04:53:31 +00:00
if ( m_pTexture = = NULL & & ! m_bDrawIfTextureNull )
2002-08-18 16:19:26 +00:00
return ;
2003-06-23 04:49:28 +00:00
// bail if cropped all the way
2003-10-07 04:26:14 +00:00
if ( m_pTempState - > crop . left + m_pTempState - > crop . right > 1 | |
m_pTempState - > crop . top + m_pTempState - > crop . bottom > 1 )
2003-06-23 04:49:28 +00:00
return ;
2002-03-30 20:00:13 +00:00
// use m_temp_* variables to draw the object
2002-10-31 06:00:30 +00:00
RectF quadVerticies ;
2001-11-25 04:31:44 +00:00
2002-01-16 10:01:32 +00:00
switch ( m_HorizAlign )
2001-12-11 11:25:37 +00:00
{
2003-02-17 12:19:42 +00:00
case align_left : quadVerticies . left = 0 ; quadVerticies . right = m_size . x ; break ;
case align_center : quadVerticies . left = - m_size . x / 2 ; quadVerticies . right = m_size . x / 2 ; break ;
case align_right : 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 )
{
2003-07-09 02:27:05 +00:00
// FIXME: Top and bottom are flipped, but changing them now breaks a lot
// in our themes. -Chris
2003-02-17 12:19:42 +00:00
case align_top : quadVerticies . top = 0 ; quadVerticies . bottom = m_size . y ; break ;
2002-01-16 10:01:32 +00:00
case align_middle : quadVerticies . top = - m_size . y / 2 ; quadVerticies . bottom = m_size . y / 2 ; break ;
2003-02-17 12:19:42 +00:00
case align_bottom : quadVerticies . top = - m_size . y ; quadVerticies . bottom = 0 ; break ;
2003-05-15 06:09:19 +00:00
default : ASSERT ( 0 ) ;
2002-01-16 10:01:32 +00:00
}
2001-11-25 04:31:44 +00:00
2003-06-23 04:49:28 +00:00
RectF croppedQuadVerticies = quadVerticies ;
2003-10-07 04:26:14 +00:00
# define IF_CROP_POS(side,opp_side) if(m_pTempState->crop.side>0) croppedQuadVerticies.side = SCALE( m_pTempState->crop.side, 0.f, 1.f, quadVerticies.side, quadVerticies.opp_side );
2003-06-23 04:49:28 +00:00
IF_CROP_POS ( left , right ) ;
IF_CROP_POS ( top , bottom ) ;
IF_CROP_POS ( right , left ) ;
IF_CROP_POS ( bottom , top ) ;
2003-06-20 23:04:11 +00:00
2003-07-07 01:29:18 +00:00
static RageSpriteVertex v [ 4 ] ;
2003-06-20 23:04:11 +00:00
v [ 0 ] . p = RageVector3 ( croppedQuadVerticies . left , croppedQuadVerticies . top , 0 ) ; // top left
v [ 1 ] . p = RageVector3 ( croppedQuadVerticies . left , croppedQuadVerticies . bottom , 0 ) ; // bottom left
v [ 2 ] . p = RageVector3 ( croppedQuadVerticies . right , croppedQuadVerticies . bottom , 0 ) ; // bottom right
v [ 3 ] . p = RageVector3 ( croppedQuadVerticies . right , croppedQuadVerticies . top , 0 ) ; // top right
2001-11-25 04:31:44 +00:00
2002-11-21 22:25:00 +00:00
DISPLAY - > SetTexture ( m_pTexture ) ;
2001-11-25 04:31:44 +00:00
2003-05-15 06:09:19 +00:00
// Must call this after setting the texture or else texture
// parameters have no effect.
Actor : : SetRenderStates ( ) ; // set Actor-specified render states
2002-11-11 04:53:31 +00:00
if ( m_pTexture )
2002-01-16 10:01:32 +00:00
{
2003-06-23 04:49:28 +00:00
float f [ 8 ] ;
2003-07-03 06:38:57 +00:00
GetActiveTextureCoords ( f ) ;
2003-06-23 04:49:28 +00:00
TexCoordsFromArray ( v , f ) ;
RageVector2 texCoords [ 4 ] = {
RageVector2 ( f [ 0 ] , f [ 1 ] ) , // top left
RageVector2 ( f [ 2 ] , f [ 3 ] ) , // bottom left
RageVector2 ( f [ 4 ] , f [ 5 ] ) , // bottom right
RageVector2 ( f [ 6 ] , f [ 7 ] ) // top right
} ;
2003-10-07 04:26:14 +00:00
if ( m_pTempState - > crop . left > 0 )
2003-06-23 04:49:28 +00:00
{
2003-10-07 04:26:14 +00:00
v [ 0 ] . t . x = SCALE ( m_pTempState - > crop . left , 0.f , 1.f , texCoords [ 0 ] . x , texCoords [ 3 ] . x ) ;
v [ 1 ] . t . x = SCALE ( m_pTempState - > crop . left , 0.f , 1.f , texCoords [ 1 ] . x , texCoords [ 2 ] . x ) ;
2003-06-23 04:49:28 +00:00
}
2003-10-07 04:26:14 +00:00
if ( m_pTempState - > crop . right > 0 )
2003-06-23 04:49:28 +00:00
{
2003-10-07 04:26:14 +00:00
v [ 2 ] . t . x = SCALE ( m_pTempState - > crop . right , 0.f , 1.f , texCoords [ 2 ] . x , texCoords [ 1 ] . x ) ;
v [ 3 ] . t . x = SCALE ( m_pTempState - > crop . right , 0.f , 1.f , texCoords [ 3 ] . x , texCoords [ 0 ] . x ) ;
2003-06-23 04:49:28 +00:00
}
2003-10-07 04:26:14 +00:00
if ( m_pTempState - > crop . top > 0 )
2003-06-23 04:49:28 +00:00
{
2003-10-07 04:26:14 +00:00
v [ 0 ] . t . y = SCALE ( m_pTempState - > crop . top , 0.f , 1.f , texCoords [ 0 ] . y , texCoords [ 1 ] . y ) ;
v [ 3 ] . t . y = SCALE ( m_pTempState - > crop . top , 0.f , 1.f , texCoords [ 3 ] . y , texCoords [ 2 ] . y ) ;
2003-06-23 04:49:28 +00:00
}
2003-10-07 04:26:14 +00:00
if ( m_pTempState - > crop . bottom > 0 )
2003-06-23 04:49:28 +00:00
{
2003-10-07 04:26:14 +00:00
v [ 1 ] . t . y = SCALE ( m_pTempState - > crop . bottom , 0.f , 1.f , texCoords [ 1 ] . y , texCoords [ 0 ] . y ) ;
v [ 2 ] . t . y = SCALE ( m_pTempState - > crop . bottom , 0.f , 1.f , texCoords [ 2 ] . y , texCoords [ 3 ] . y ) ;
2003-06-23 04:49:28 +00:00
}
2002-01-16 10:01:32 +00:00
}
2001-12-28 10:15:59 +00:00
2002-11-11 04:53:31 +00:00
DISPLAY - > SetTextureModeModulate ( ) ;
2001-12-11 11:25:37 +00:00
2003-05-15 06:09:19 +00:00
/* Draw if we're not fully transparent */
2003-10-07 04:26:14 +00:00
if ( m_pTempState - > diffuse [ 0 ] . a > 0 | |
m_pTempState - > diffuse [ 1 ] . a > 0 | |
m_pTempState - > diffuse [ 2 ] . a > 0 | |
m_pTempState - > diffuse [ 3 ] . 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 ( ) ;
2003-05-22 05:28:37 +00:00
DISPLAY - > TranslateWorld ( m_fShadowLength , m_fShadowLength , 0 ) ; // shift by 5 units
2003-10-07 04:26:14 +00:00
v [ 0 ] . c = v [ 1 ] . c = v [ 2 ] . c = v [ 3 ] . c = RageColor ( 0 , 0 , 0 , 0.5f * m_pTempState - > diffuse [ 0 ] . a ) ; // semi-transparent black
2002-11-11 04:53:31 +00:00
DISPLAY - > DrawQuad ( v ) ;
2002-05-19 01:59:48 +00:00
DISPLAY - > PopMatrix ( ) ;
2001-12-19 01:50:57 +00:00
}
2001-12-11 11:25:37 +00:00
//////////////////////
2002-01-16 10:01:32 +00:00
// render the diffuse pass
2001-12-11 11:25:37 +00:00
//////////////////////
2003-10-07 04:26:14 +00:00
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
2002-11-11 04:53:31 +00:00
DISPLAY - > DrawQuad ( v ) ;
2003-05-04 05:13:30 +00:00
// glEnable(GL_BLEND);
2001-12-11 11:25:37 +00:00
}
2001-11-03 10:52:42 +00:00
2002-01-16 10:01:32 +00:00
//////////////////////
2002-08-18 16:19:26 +00:00
// render the glow pass
2002-01-16 10:01:32 +00:00
//////////////////////
2003-10-07 04:26:14 +00:00
if ( m_pTempState - > glow . a > 0.0001f )
2002-01-16 10:01:32 +00:00
{
2003-10-07 04:26:14 +00:00
DISPLAY - > SetTextureModeGlow ( m_pTempState - > glowmode ) ;
v [ 0 ] . c = v [ 1 ] . c = v [ 2 ] . c = v [ 3 ] . c = m_pTempState - > glow ;
2002-11-11 04:53:31 +00:00
DISPLAY - > DrawQuad ( v ) ;
2002-01-16 10:01:32 +00:00
}
2001-11-03 10:52:42 +00:00
}
2002-03-30 20:00:13 +00:00
void Sprite : : SetState ( int iNewState )
2001-11-03 10:52:42 +00:00
{
2003-04-24 06:16:04 +00:00
// This assert will likely trigger if the "missing" theme element graphic
// is loaded in place of a multi-frame sprite. We want to know about these
// problems in debug builds, but they're not fatal.
2003-05-22 05:28:37 +00:00
DEBUG_ASSERT ( iNewState > = 0 & & iNewState < ( int ) m_States . size ( ) ) ;
2003-04-24 06:16:04 +00:00
2003-05-22 05:28:37 +00:00
CLAMP ( iNewState , 0 , ( int ) m_States . size ( ) - 1 ) ;
2002-03-30 20:00:13 +00:00
m_iCurState = iNewState ;
2001-11-03 10:52:42 +00:00
m_fSecsIntoState = 0.0 ;
}
2003-06-23 04:49:28 +00:00
void Sprite : : SetCustomTextureRect ( const RectF & new_texcoord_frect )
2001-12-28 10:15:59 +00:00
{
m_bUsingCustomTexCoords = true ;
2003-04-21 02:45:00 +00:00
m_bTextureWrapping = true ;
2003-06-23 04:49:28 +00:00
TexCoordArrayFromRect ( m_CustomTexCoords , new_texcoord_frect ) ;
2001-12-28 10:15:59 +00:00
}
2001-11-03 10:52:42 +00:00
2003-06-23 04:49:28 +00:00
void Sprite : : SetCustomTextureCoords ( float fTexCoords [ 8 ] ) // order: top left, bottom left, bottom right, top right
2002-06-27 17:49:10 +00:00
{
2003-06-23 04:49:28 +00:00
m_bUsingCustomTexCoords = true ;
m_bTextureWrapping = true ;
for ( int i = 0 ; i < 8 ; i + + )
m_CustomTexCoords [ i ] = fTexCoords [ i ] ;
}
void Sprite : : SetCustomImageRect ( RectF rectImageCoords )
2002-01-29 21:56:14 +00:00
{
// Convert to a rectangle in texture coordinate space.
2003-06-23 04:49:28 +00:00
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 ( ) ;
2002-01-29 21:56:14 +00:00
2003-06-23 04:49:28 +00:00
SetCustomTextureRect ( rectImageCoords ) ;
2002-01-29 21:56:14 +00:00
}
2003-06-23 04:49:28 +00:00
void Sprite : : SetCustomImageCoords ( float fImageCoords [ 8 ] ) // order: top left, bottom 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 ) ;
}
const RectF * Sprite : : GetCurrentTextureCoordRect ( ) const
2003-02-08 23:45:06 +00:00
{
2003-05-22 05:28:37 +00:00
unsigned int uFrameNo = m_States [ m_iCurState ] . iFrameIndex ;
2003-02-08 23:45:06 +00:00
return m_pTexture - > GetTextureCoordRect ( uFrameNo ) ;
}
2003-06-23 04:49:28 +00:00
2003-04-21 02:45:00 +00:00
/* If we're using custom coordinates, return them; otherwise return the coordinates
* for the current state. */
2003-07-03 06:38:57 +00:00
void Sprite : : GetActiveTextureCoords ( float fTexCoordsOut [ 8 ] ) const
2003-04-21 02:45:00 +00:00
{
2003-07-03 06:38:57 +00:00
if ( m_bUsingCustomTexCoords )
{
// GetCustomTextureCoords
for ( int i = 0 ; i < 8 ; i + + )
fTexCoordsOut [ i ] = m_CustomTexCoords [ i ] ;
}
else
{
// GetCurrentTextureCoords
const RectF * pTexCoordRect = GetCurrentTextureCoordRect ( ) ;
TexCoordArrayFromRect ( fTexCoordsOut , * pTexCoordRect ) ;
}
2003-04-21 02:45:00 +00:00
}
2002-03-31 07:55:25 +00:00
void Sprite : : StopUsingCustomCoords ( )
{
m_bUsingCustomTexCoords = false ;
}
2003-07-03 06:38:57 +00:00
void Sprite : : ScaleToClipped ( float fWidth , float fHeight )
{
m_fRememberedClipWidth = fWidth ;
m_fRememberedClipHeight = fHeight ;
if ( ! m_pTexture )
return ;
int iSourceWidth = m_pTexture - > GetSourceWidth ( ) ;
int iSourceHeight = m_pTexture - > GetSourceHeight ( ) ;
// save the original X&Y. We're going to resore them later.
float fOriginalX = GetX ( ) ;
float fOriginalY = GetY ( ) ;
if ( IsDiagonalBanner ( iSourceWidth , iSourceHeight ) ) // this is a SSR/DWI CroppedSprite
{
float fCustomImageCoords [ 8 ] = {
0.02f , 0.78f , // top left
0.22f , 0.98f , // bottom left
0.98f , 0.22f , // bottom right
0.78f , 0.02f , // top right
} ;
Sprite : : SetCustomImageCoords ( fCustomImageCoords ) ;
if ( fWidth ! = - 1 & & fHeight ! = - 1 )
m_size = RageVector2 ( fWidth , fHeight ) ;
else
{
/* If no crop size is set, then we're only being used to crop diagonal
* banners so they look like regular ones. We don't actually care about
* the size of the image, only that it has an aspect ratio of 4:1. */
m_size = RageVector2 ( 256 , 64 ) ;
}
SetZoom ( 1 ) ;
}
else if ( m_pTexture - > GetID ( ) . filename . find ( " (was rotated) " ) ! = m_pTexture - > GetID ( ) . filename . npos & &
fWidth ! = - 1 & & fHeight ! = - 1 )
{
/* Dumb hack. Normally, we crop all sprites except for diagonal banners,
* which are stretched. Low-res versions of banners need to do the same
* thing as their full resolution counterpart, so the crossfade looks right.
* However, low-res diagonal banners are un-rotated, to save space. BannerCache
* drops the above text into the "filename" (which is otherwise unused for
* these banners) to tell us this.
*/
Sprite : : StopUsingCustomCoords ( ) ;
m_size = RageVector2 ( fWidth , fHeight ) ;
SetZoom ( 1 ) ;
}
else if ( fWidth ! = - 1 & & fHeight ! = - 1 )
{
// this is probably a background graphic or something not intended to be a CroppedSprite
Sprite : : StopUsingCustomCoords ( ) ;
// first find the correct zoom
Sprite : : ScaleToCover ( RectI ( 0 , 0 ,
( int ) fWidth ,
( int ) fHeight )
) ;
// find which dimension is larger
bool bXDimNeedsToBeCropped = GetZoomedWidth ( ) > fWidth + 0.01 ;
if ( bXDimNeedsToBeCropped ) // crop X
{
float fPercentageToCutOff = ( this - > GetZoomedWidth ( ) - fWidth ) / this - > GetZoomedWidth ( ) ;
float fPercentageToCutOffEachSide = fPercentageToCutOff / 2 ;
// generate a rectangle with new texture coordinates
RectF fCustomImageRect (
fPercentageToCutOffEachSide ,
0 ,
1 - fPercentageToCutOffEachSide ,
1 ) ;
SetCustomImageRect ( fCustomImageRect ) ;
}
else // crop Y
{
float fPercentageToCutOff = ( this - > GetZoomedHeight ( ) - fHeight ) / this - > GetZoomedHeight ( ) ;
float fPercentageToCutOffEachSide = fPercentageToCutOff / 2 ;
// generate a rectangle with new texture coordinates
RectF fCustomImageRect (
0 ,
fPercentageToCutOffEachSide ,
1 ,
1 - fPercentageToCutOffEachSide ) ;
SetCustomImageRect ( fCustomImageRect ) ;
}
m_size = RageVector2 ( fWidth , fHeight ) ;
SetZoom ( 1 ) ;
}
// restore original XY
SetXY ( fOriginalX , fOriginalY ) ;
}
bool Sprite : : IsDiagonalBanner ( int iWidth , int iHeight )
{
/* A diagonal banner is a square. Give a couple pixels of leeway. */
return iWidth > = 100 & & abs ( iWidth - iHeight ) < 2 ;
}
2003-07-07 01:29:18 +00:00
inline CString GetParam ( const CStringArray & sParams , int iIndex , int & iMaxIndexAccessed )
{
iMaxIndexAccessed = max ( iIndex , iMaxIndexAccessed ) ;
if ( iIndex < int ( sParams . size ( ) ) )
return sParams [ iIndex ] ;
else
return " " ;
}
void Sprite : : HandleCommand ( const CStringArray & asTokens )
{
int iMaxIndexAccessed = 0 ;
# define sParam(i) (GetParam(asTokens,i,iMaxIndexAccessed))
# define fParam(i) ((float)atof(sParam(i)))
# define iParam(i) (atoi(sParam(i)))
# define bParam(i) (iParam(i)!=0)
const CString & sName = asTokens [ 0 ] ;
// Commands that go in the tweening queue:
/* Add left/right/top/bottom for alpha if needed. */
// Commands that take effect immediately (ignoring the tweening queue):
if ( sName = = " customtexturerect " ) SetCustomTextureRect ( RectF ( fParam ( 1 ) , fParam ( 2 ) , fParam ( 3 ) , fParam ( 4 ) ) ) ;
else if ( sName = = " texcoordvelocity " ) SetTexCoordVelocity ( fParam ( 1 ) , fParam ( 2 ) ) ;
else if ( sName = = " scaletoclipped " ) ScaleToClipped ( fParam ( 1 ) , fParam ( 2 ) ) ;
else
{
Actor : : HandleCommand ( asTokens ) ;
return ;
}
if ( iMaxIndexAccessed ! = ( int ) asTokens . size ( ) - 1 )
{
CString sError = ssprintf ( " Actor::HandleCommand: Wrong number of parameters in command '%s'. Expected %d but there are %d. " , join ( " , " , asTokens ) . c_str ( ) , iMaxIndexAccessed + 1 , ( int ) asTokens . size ( ) ) ;
LOG - > Warn ( sError ) ;
if ( DISPLAY - > IsWindowed ( ) )
HOOKS - > MessageBoxOK ( sError ) ;
}
}