2012-01-21 21:57:41 +01:00
# include "fanart.hpp"
# include "pngu.h"
# include "boxmesh.hpp"
# include "text.hpp"
2012-12-08 17:17:35 +01:00
# include "gecko/gecko.hpp"
2013-09-24 17:21:31 +02:00
# include "memory/mem2.hpp"
2012-01-21 21:57:41 +01:00
using namespace std ;
static guVector _GRRaxisx = ( guVector ) { 1 , 0 , 0 } ; // DO NOT MODIFY!!!
static guVector _GRRaxisy = ( guVector ) { 0 , 1 , 0 } ; // Even at runtime
static guVector _GRRaxisz = ( guVector ) { 0 , 0 , 1 } ; // NOT ever!
CFanart : : CFanart ( void )
: m_animationComplete ( false ) , m_loaded ( false ) , m_cfg ( ) , m_bg ( ) , m_bglq ( )
{
}
CFanart : : ~ CFanart ( void )
{
}
void CFanart : : unload ( )
{
m_cfg . unload ( ) ;
m_loaded = false ;
2012-11-14 17:58:14 +01:00
for ( vector < CFanartElement > : : iterator Elm = m_elms . begin ( ) ; Elm ! = m_elms . end ( ) ; Elm + + )
Elm - > Cleanup ( ) ;
2012-01-21 21:57:41 +01:00
m_elms . clear ( ) ;
2012-12-28 15:19:40 +01:00
TexHandle . Cleanup ( m_bg ) ;
TexHandle . Cleanup ( m_bglq ) ;
2012-01-21 21:57:41 +01:00
}
bool CFanart : : load ( Config & m_globalConfig , const char * path , const char * id )
{
bool retval = false ;
2012-09-29 19:32:31 +02:00
if ( ! m_globalConfig . getBool ( " FANART " , " enable_fanart " , true ) )
2012-01-21 21:57:41 +01:00
return retval ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
unload ( ) ;
2012-09-29 19:32:31 +02:00
char dir [ 64 ] ;
2012-11-14 17:58:14 +01:00
dir [ 63 ] = ' \0 ' ;
2012-09-29 19:32:31 +02:00
strncpy ( dir , fmt ( " %s/%s " , path , id ) , 63 ) ;
2012-12-28 15:19:40 +01:00
TexErr texErr = TexHandle . fromImageFile ( m_bg , fmt ( " %s/background.png " , dir ) ) ;
2012-11-11 19:28:03 +01:00
if ( texErr = = TE_ERROR )
2012-01-21 21:57:41 +01:00
{
2012-09-29 19:32:31 +02:00
strncpy ( dir , fmt ( " %s/%.3s " , path , id ) , 63 ) ;
2012-12-28 15:19:40 +01:00
texErr = TexHandle . fromImageFile ( m_bg , fmt ( " %s/background.png " , dir ) ) ;
2012-01-21 21:57:41 +01:00
}
2012-11-11 19:28:03 +01:00
if ( texErr = = TE_OK )
2012-01-21 21:57:41 +01:00
{
2012-09-29 19:32:31 +02:00
char cfg_char [ 64 ] ;
2012-11-14 17:58:14 +01:00
cfg_char [ 63 ] = ' \0 ' ;
2012-09-29 19:32:31 +02:00
strncpy ( cfg_char , fmt ( " %s/%s.ini " , dir , id ) , 63 ) ;
m_cfg . load ( cfg_char ) ;
if ( ! m_cfg . loaded ( ) )
{
strncpy ( cfg_char , fmt ( " %s/%.3s.ini " , dir , id ) , 63 ) ;
m_cfg . load ( cfg_char ) ;
}
2012-12-28 15:19:40 +01:00
TexHandle . fromImageFile ( m_bglq , fmt ( " %s/background_lq.png " , dir ) ) ;
2012-09-29 19:32:31 +02:00
for ( int i = 1 ; i < = 6 ; i + + )
2012-01-21 21:57:41 +01:00
{
CFanartElement elm ( m_cfg , dir , i ) ;
if ( elm . IsValid ( ) ) m_elms . push_back ( elm ) ;
}
m_loaded = true ;
retval = true ;
2012-09-29 19:32:31 +02:00
m_defaultDelay = m_globalConfig . getInt ( " FANART " , " delay_after_animation " , 200 ) ;
m_delayAfterAnimation = m_cfg . getInt ( " GENERAL " , " delay_after_animation " , m_defaultDelay ) ;
m_allowArtworkOnTop = m_globalConfig . getBool ( " FANART " , " allow_artwork_on_top " , true ) ;
m_globalHideCover = m_globalConfig . getOptBool ( " FANART " , " hidecover " , 2 ) ; // 0 is false, 1 is true, 2 is default
m_globalShowCoverAfterAnimation = m_globalConfig . getOptBool ( " FANART " , " show_cover_after_animation " , 2 ) ;
}
2012-01-21 21:57:41 +01:00
return retval ;
}
2012-12-28 15:19:40 +01:00
void CFanart : : getBackground ( const TexData * & hq , const TexData * & lq )
2012-01-21 21:57:41 +01:00
{
2012-09-29 19:32:31 +02:00
if ( m_loaded )
2012-01-21 21:57:41 +01:00
{
2012-11-16 23:40:20 +01:00
hq = & m_bg ;
lq = & m_bglq ;
2012-01-21 21:57:41 +01:00
}
2012-11-16 23:40:20 +01:00
if ( lq = = NULL | | lq - > data = = NULL )
lq = hq ;
2012-01-21 21:57:41 +01:00
}
CColor CFanart : : getTextColor ( CColor themeTxtColor )
{
return m_loaded ? m_cfg . getColor ( " GENERAL " , " textcolor " , CColor ( themeTxtColor ) ) : themeTxtColor ;
}
bool CFanart : : hideCover ( )
{
2012-09-29 19:32:31 +02:00
if ( ! m_loaded )
2012-01-21 21:57:41 +01:00
return false ; // If no fanart is loaded, return false
/*
fanart_hidecover defaults to True
fanart_showafter defaults to False
hideCover | fanart_hideCover | showAfter | fanart_showAfter | animating | hide
1 True * * * * True
2 False * * * * False
3 default False * * * False
4 default default / True True * True True
5 default default / True True * False False
6 default default / True False * * True
7 default default / True default True True True
8 default default / True default True False False
9 * * * * * True
*/
2012-09-29 19:32:31 +02:00
// rules 1 and 2
if ( m_globalHideCover ! = 2 )
2012-01-21 21:57:41 +01:00
return m_globalHideCover = = 1 ;
2012-09-29 19:32:31 +02:00
// rule 3
if ( ! m_cfg . getBool ( " GENERAL " , " hidecover " , true ) )
return false ;
// rules 4, 5 and 6
if ( m_globalShowCoverAfterAnimation ! = 2 )
return m_globalShowCoverAfterAnimation = = 0 | | ! isAnimationComplete ( ) ;
// rules 7 and 8
if ( m_cfg . getBool ( " GENERAL " , " show_cover_after_animation " , false ) )
return ! isAnimationComplete ( ) ;
// rule 9
return true ;
2012-01-21 21:57:41 +01:00
}
bool CFanart : : isLoaded ( )
{
return m_loaded ;
}
bool CFanart : : isAnimationComplete ( )
{
return m_animationComplete & & m_delayAfterAnimation < = 0 ;
}
void CFanart : : tick ( )
{
m_animationComplete = true ;
2012-09-29 19:32:31 +02:00
for ( u32 i = 0 ; i < m_elms . size ( ) ; + + i )
2012-01-21 21:57:41 +01:00
{
m_elms [ i ] . tick ( ) ;
2012-09-29 19:32:31 +02:00
if ( ! m_elms [ i ] . IsAnimationComplete ( ) )
2012-01-21 21:57:41 +01:00
m_animationComplete = false ;
}
2012-09-29 19:32:31 +02:00
if ( m_animationComplete & & m_delayAfterAnimation > 0 )
m_delayAfterAnimation - - ;
2012-01-21 21:57:41 +01:00
}
void CFanart : : draw ( bool front )
{
2012-09-29 19:32:31 +02:00
if ( ! m_loaded ) return ; //derp
if ( ! m_allowArtworkOnTop & & front )
2012-01-21 21:57:41 +01:00
return ; // It's not allowed to draw fanart on top, it has already been drawn
GX_SetNumChans ( 1 ) ;
GX_ClearVtxDesc ( ) ;
GX_SetVtxDesc ( GX_VA_POS , GX_DIRECT ) ;
GX_SetVtxAttrFmt ( GX_VTXFMT0 , GX_VA_POS , GX_POS_XYZ , GX_F32 , 0 ) ;
GX_SetVtxDesc ( GX_VA_CLR0 , GX_DIRECT ) ;
GX_SetVtxAttrFmt ( GX_VTXFMT0 , GX_VA_CLR0 , GX_CLR_RGBA , GX_RGBA8 , 0 ) ;
GX_SetVtxDesc ( GX_VA_TEX0 , GX_DIRECT ) ;
GX_SetVtxAttrFmt ( GX_VTXFMT0 , GX_VA_TEX0 , GX_TEX_ST , GX_F32 , 0 ) ;
GX_SetNumTexGens ( 1 ) ;
GX_SetTevOp ( GX_TEVSTAGE0 , GX_MODULATE ) ;
GX_SetTevOrder ( GX_TEVSTAGE0 , GX_TEXCOORD0 , GX_TEXMAP0 , GX_COLOR0A0 ) ;
GX_SetTexCoordGen ( GX_TEXCOORD0 , GX_TG_MTX2x4 , GX_TG_TEX0 , GX_IDENTITY ) ;
GX_SetBlendMode ( GX_BM_BLEND , GX_BL_SRCALPHA , GX_BL_INVSRCALPHA , GX_LO_CLEAR ) ;
GX_SetAlphaUpdate ( GX_TRUE ) ;
GX_SetCullMode ( GX_CULL_NONE ) ;
GX_SetZMode ( GX_DISABLE , GX_LEQUAL , GX_TRUE ) ;
2012-09-29 19:32:31 +02:00
for ( u32 i = 0 ; i < m_elms . size ( ) ; + + i )
if ( ! m_allowArtworkOnTop | | ( ( front & & m_elms [ i ] . ShowOnTop ( ) ) | | ! front ) )
2012-01-21 21:57:41 +01:00
m_elms [ i ] . draw ( ) ;
}
CFanartElement : : CFanartElement ( Config & cfg , const char * dir , int artwork )
: m_artwork ( artwork ) , m_isValid ( false )
{
2012-12-28 15:19:40 +01:00
m_isValid = ( TexHandle . fromImageFile ( m_art , fmt ( " %s/artwork%d.png " , dir , artwork ) ) = = TE_OK ) ;
2013-09-24 17:21:31 +02:00
if ( ! m_isValid )
return ;
2012-01-21 21:57:41 +01:00
2013-09-24 17:21:31 +02:00
char * section = fmt_malloc ( " artwork%d " , artwork ) ;
if ( section = = NULL )
return ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
m_show_on_top = cfg . getBool ( section , " show_on_top " , true ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
m_x = cfg . getInt ( section , " x " , 0 ) ;
m_y = cfg . getInt ( section , " y " , 0 ) ;
m_scaleX = cfg . getFloat ( section , " scale_x " , 1.f ) ;
m_scaleY = cfg . getFloat ( section , " scale_y " , 1.f ) ;
m_alpha = min ( cfg . getInt ( section , " alpha " , 255 ) , 255 ) ;
m_delay = ( int ) ( cfg . getFloat ( section , " delay " , 0.f ) * 50 ) ;
m_angle = cfg . getFloat ( section , " angle " , 0.f ) ;
m_event_duration = ( int ) ( cfg . getFloat ( section , " duration " , 0.f ) * 50 ) ;
m_event_x = m_event_duration = = 0 ? m_x : cfg . getInt ( section , " event_x " , m_x ) ;
m_event_y = m_event_duration = = 0 ? m_y : cfg . getInt ( section , " event_y " , m_y ) ;
m_event_scaleX = m_event_duration = = 0 ? m_scaleX : cfg . getInt ( section , " event_scale_x " , m_scaleX ) ;
m_event_scaleY = m_event_duration = = 0 ? m_scaleY : cfg . getInt ( section , " event_scale_y " , m_scaleY ) ;
m_event_alpha = m_event_duration = = 0 ? m_alpha : min ( cfg . getInt ( section , " event_alpha " , m_alpha ) , 255 ) ; // Not from m_alpha, because the animation can start less translucent than m_alpha
m_event_angle = m_event_duration = = 0 ? m_angle : cfg . getFloat ( section , " event_angle " , m_angle ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
m_step_x = m_event_duration = = 0 ? 0 : ( m_x - m_event_x ) / m_event_duration ;
m_step_y = m_event_duration = = 0 ? 0 : ( m_y - m_event_y ) / m_event_duration ;
m_step_scaleX = m_event_duration = = 0 ? 0 : ( m_scaleX - m_event_scaleX ) / m_event_duration ;
m_step_scaleY = m_event_duration = = 0 ? 0 : ( m_scaleY - m_event_scaleY ) / m_event_duration ;
m_step_alpha = m_event_duration = = 0 ? 0 : ( m_alpha - m_event_alpha ) / m_event_duration ;
m_step_angle = m_event_duration = = 0 ? 0 : ( m_angle - m_event_angle ) / m_event_duration ;
2013-09-24 17:21:31 +02:00
MEM2_free ( section ) ;
2012-01-21 21:57:41 +01:00
}
2012-11-14 17:58:14 +01:00
void CFanartElement : : Cleanup ( void )
2012-01-21 21:57:41 +01:00
{
2012-12-28 15:19:40 +01:00
TexHandle . Cleanup ( m_art ) ;
2012-01-21 21:57:41 +01:00
}
bool CFanartElement : : IsValid ( )
{
return m_isValid ;
}
bool CFanartElement : : IsAnimationComplete ( )
{
return m_event_duration = = 0 ;
}
bool CFanartElement : : ShowOnTop ( )
{
return m_show_on_top ;
}
void CFanartElement : : tick ( )
{
2012-09-29 19:32:31 +02:00
if ( m_delay > 0 )
2012-01-21 21:57:41 +01:00
{
m_delay - - ;
return ;
}
2012-09-29 19:32:31 +02:00
if ( ( m_step_x < 0 & & m_event_x > m_x ) | | ( m_step_x > 0 & & m_event_x < m_x ) )
2012-01-21 21:57:41 +01:00
m_event_x = ( int ) ( m_event_x + m_step_x ) ;
2012-09-29 19:32:31 +02:00
if ( ( m_step_y < 0 & & m_event_y > m_y ) | | ( m_step_y > 0 & & m_event_y < m_y ) )
2012-01-21 21:57:41 +01:00
m_event_y = ( int ) ( m_event_y + m_step_y ) ;
2012-09-29 19:32:31 +02:00
if ( ( m_step_alpha < 0 & & m_event_alpha > m_alpha ) | | ( m_step_alpha > 0 & & m_event_alpha < m_alpha ) )
2012-01-21 21:57:41 +01:00
m_event_alpha = ( int ) ( m_event_alpha + m_step_alpha ) ;
2012-09-29 19:32:31 +02:00
if ( ( m_step_scaleX < 0 & & m_event_scaleX > m_scaleX ) | | ( m_step_scaleX > 0 & & m_event_scaleX < m_scaleX ) )
2012-01-21 21:57:41 +01:00
m_event_scaleX + = m_step_scaleX ;
2012-09-29 19:32:31 +02:00
if ( ( m_step_scaleY < 0 & & m_event_scaleY > m_scaleY ) | | ( m_step_scaleY > 0 & & m_event_scaleY < m_scaleY ) )
2012-01-21 21:57:41 +01:00
m_event_scaleY + = m_step_scaleY ;
2012-09-29 19:32:31 +02:00
if ( ( m_step_angle < 0 & & m_event_angle > m_angle ) | | ( m_step_angle > 0 & & m_event_angle < m_angle ) )
2012-01-21 21:57:41 +01:00
m_event_angle = ( int ) ( m_event_angle + m_step_angle ) ;
2012-09-29 19:32:31 +02:00
if ( m_event_duration > 0 )
2012-01-21 21:57:41 +01:00
m_event_duration - - ;
}
void CFanartElement : : draw ( )
{
2012-09-29 19:32:31 +02:00
if ( m_event_alpha = = 0 | | m_event_scaleX = = 0.f | | m_event_scaleY = = 0.f | | m_delay > 0 )
2012-01-21 21:57:41 +01:00
return ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
GXTexObj artwork ;
Mtx modelViewMtx , idViewMtx , rotViewMtxZ ;
guMtxIdentity ( idViewMtx ) ;
guMtxScaleApply ( idViewMtx , idViewMtx , m_event_scaleX , m_event_scaleY , 1.f ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
guMtxRotAxisDeg ( rotViewMtxZ , & _GRRaxisz , m_event_angle ) ;
guMtxConcat ( rotViewMtxZ , idViewMtx , modelViewMtx ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
guMtxTransApply ( modelViewMtx , modelViewMtx , m_event_x , m_event_y , 0.f ) ;
GX_LoadPosMtxImm ( modelViewMtx , GX_PNMTX0 ) ;
2012-11-03 20:16:03 +01:00
GX_InitTexObj ( & artwork , m_art . data , m_art . width , m_art . height , m_art . format , GX_CLAMP , GX_CLAMP , GX_FALSE ) ;
2012-01-21 21:57:41 +01:00
GX_LoadTexObj ( & artwork , GX_TEXMAP0 ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
float w = ( float ) ( m_art . width / 2 ) ; // * m_event_scaleX;
float h = ( float ) ( m_art . height / 2 ) ; // * m_event_scaleY;
GX_Begin ( GX_QUADS , GX_VTXFMT0 , 4 ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
// Draw top left
GX_Position3f32 ( - w , - h , 0.f ) ;
GX_Color4u8 ( 0xFF , 0xFF , 0xFF , m_event_alpha ) ;
GX_TexCoord2f32 ( 0.f , 0.f ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
// Draw top right
GX_Position3f32 ( w , - h , 0.f ) ;
GX_Color4u8 ( 0xFF , 0xFF , 0xFF , m_event_alpha ) ;
GX_TexCoord2f32 ( 1.f , 0.f ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
// Draw bottom right
GX_Position3f32 ( w , h , 0.f ) ;
GX_Color4u8 ( 0xFF , 0xFF , 0xFF , m_event_alpha ) ;
GX_TexCoord2f32 ( 1.f , 1.f ) ;
2012-09-29 19:32:31 +02:00
2012-01-21 21:57:41 +01:00
// Draw bottom left
GX_Position3f32 ( - w , h , 0.f ) ;
GX_Color4u8 ( 0xFF , 0xFF , 0xFF , m_event_alpha ) ;
GX_TexCoord2f32 ( 0.f , 1.f ) ;
GX_End ( ) ;
}