mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-11-01 17:15:06 +01:00
301 lines
9.8 KiB
C++
301 lines
9.8 KiB
C++
|
#include "fanart.hpp"
|
||
|
#include "pngu.h"
|
||
|
#include "boxmesh.hpp"
|
||
|
#include "text.hpp"
|
||
|
#include "gecko.h"
|
||
|
|
||
|
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;
|
||
|
m_elms.clear();
|
||
|
}
|
||
|
|
||
|
bool CFanart::load(Config &m_globalConfig, const char *path, const char *id)
|
||
|
{
|
||
|
bool retval = false;
|
||
|
|
||
|
if (!m_globalConfig.getBool("FANART", "enable_fanart", true))
|
||
|
return retval;
|
||
|
|
||
|
unload();
|
||
|
|
||
|
const char *dir = fmt("%s/%s", path, id);
|
||
|
STexture fanBg, fanBgLq;
|
||
|
|
||
|
STexture::TexErr texErr = fanBg.fromPNGFile(sfmt("%s/background.png", dir).c_str(), GX_TF_RGBA8);
|
||
|
if (texErr == STexture::TE_ERROR)
|
||
|
{
|
||
|
dir = fmt("%s/%.3s", path, id);
|
||
|
texErr = fanBg.fromPNGFile(sfmt("%s/background.png", dir).c_str(), GX_TF_RGBA8);
|
||
|
}
|
||
|
|
||
|
if (texErr == STexture::TE_OK)
|
||
|
{
|
||
|
m_cfg.load(sfmt("%s/%s.ini", dir, id).c_str());
|
||
|
if (!m_cfg.loaded()) m_cfg.load(sfmt("%s/%.3s.ini", dir, id).c_str());
|
||
|
|
||
|
fanBgLq.fromPNGFile(sfmt("%s/background_lq.png", dir).c_str(), GX_TF_RGBA8);
|
||
|
|
||
|
for (int i = 1; i <= 6; i++)
|
||
|
{
|
||
|
CFanartElement elm(m_cfg, dir, i);
|
||
|
if (elm.IsValid()) m_elms.push_back(elm);
|
||
|
}
|
||
|
|
||
|
m_loaded = true;
|
||
|
retval = true;
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
m_bg = fanBg;
|
||
|
m_bglq = fanBgLq;
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
void CFanart::getBackground(STexture &hq, STexture &lq)
|
||
|
{
|
||
|
if (m_loaded)
|
||
|
{
|
||
|
hq = m_bg;
|
||
|
lq = m_bglq;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CColor CFanart::getTextColor(CColor themeTxtColor)
|
||
|
{
|
||
|
return m_loaded ? m_cfg.getColor("GENERAL", "textcolor", CColor(themeTxtColor)) : themeTxtColor;
|
||
|
}
|
||
|
|
||
|
bool CFanart::hideCover()
|
||
|
{
|
||
|
if (!isLoaded())
|
||
|
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
|
||
|
*/
|
||
|
// rules 1 and 2
|
||
|
if (m_globalHideCover != 2)
|
||
|
return m_globalHideCover == 1;
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
bool CFanart::isLoaded()
|
||
|
{
|
||
|
return m_loaded;
|
||
|
}
|
||
|
|
||
|
bool CFanart::isAnimationComplete()
|
||
|
{
|
||
|
return m_animationComplete && m_delayAfterAnimation <= 0;
|
||
|
}
|
||
|
|
||
|
void CFanart::tick()
|
||
|
{
|
||
|
m_animationComplete = true;
|
||
|
for (u32 i = 0; i < m_elms.size(); ++i)
|
||
|
{
|
||
|
m_elms[i].tick();
|
||
|
if (!m_elms[i].IsAnimationComplete())
|
||
|
m_animationComplete = false;
|
||
|
}
|
||
|
if (m_animationComplete && m_delayAfterAnimation > 0)
|
||
|
m_delayAfterAnimation--;
|
||
|
}
|
||
|
|
||
|
void CFanart::draw(bool front)
|
||
|
{
|
||
|
if (!m_allowArtworkOnTop && front)
|
||
|
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);
|
||
|
|
||
|
for (u32 i = 0; i < m_elms.size(); ++i)
|
||
|
if (!m_allowArtworkOnTop || ((front && m_elms[i].ShowOnTop()) || !front))
|
||
|
m_elms[i].draw();
|
||
|
}
|
||
|
|
||
|
CFanartElement::CFanartElement(Config &cfg, const char *dir, int artwork)
|
||
|
: m_artwork(artwork), m_isValid(false)
|
||
|
{
|
||
|
m_isValid = m_art.fromPNGFile(sfmt("%s/artwork%d.png", dir, artwork).c_str(), GX_TF_RGBA8) == STexture::TE_OK;
|
||
|
if (!m_isValid) return;
|
||
|
|
||
|
const char *section = fmt("artwork%d", artwork);
|
||
|
|
||
|
m_show_on_top = cfg.getBool(section, "show_on_top", true);
|
||
|
|
||
|
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);
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
CFanartElement::~CFanartElement(void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
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()
|
||
|
{
|
||
|
if (m_delay > 0)
|
||
|
{
|
||
|
m_delay--;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((m_step_x < 0 && m_event_x > m_x) || (m_step_x > 0 && m_event_x < m_x))
|
||
|
m_event_x = (int) (m_event_x + m_step_x);
|
||
|
if ((m_step_y < 0 && m_event_y > m_y) || (m_step_y > 0 && m_event_y < m_y))
|
||
|
m_event_y = (int) (m_event_y + m_step_y);
|
||
|
if ((m_step_alpha < 0 && m_event_alpha > m_alpha) || (m_step_alpha > 0 && m_event_alpha < m_alpha))
|
||
|
m_event_alpha = (int) (m_event_alpha + m_step_alpha);
|
||
|
if ((m_step_scaleX < 0 && m_event_scaleX > m_scaleX) || (m_step_scaleX > 0 && m_event_scaleX < m_scaleX))
|
||
|
m_event_scaleX += m_step_scaleX;
|
||
|
if ((m_step_scaleY < 0 && m_event_scaleY > m_scaleY) || (m_step_scaleY > 0 && m_event_scaleY < m_scaleY))
|
||
|
m_event_scaleY += m_step_scaleY;
|
||
|
if ((m_step_angle < 0 && m_event_angle > m_angle) || (m_step_angle > 0 && m_event_angle < m_angle))
|
||
|
m_event_angle = (int) (m_event_angle + m_step_angle);
|
||
|
|
||
|
if (m_event_duration > 0)
|
||
|
{
|
||
|
m_event_duration--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CFanartElement::draw()
|
||
|
{
|
||
|
if (m_event_alpha == 0 || m_event_scaleX == 0.f || m_event_scaleY == 0.f || m_delay > 0)
|
||
|
return;
|
||
|
|
||
|
GXTexObj artwork;
|
||
|
Mtx modelViewMtx, idViewMtx, rotViewMtxZ;
|
||
|
|
||
|
guMtxIdentity(idViewMtx);
|
||
|
guMtxScaleApply(idViewMtx, idViewMtx, m_event_scaleX, m_event_scaleY, 1.f);
|
||
|
|
||
|
guMtxRotAxisDeg(rotViewMtxZ, &_GRRaxisz, m_event_angle);
|
||
|
guMtxConcat(rotViewMtxZ, idViewMtx, modelViewMtx);
|
||
|
|
||
|
guMtxTransApply(modelViewMtx, modelViewMtx, m_event_x, m_event_y, 0.f);
|
||
|
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
|
||
|
|
||
|
GX_InitTexObj(&artwork, m_art.data.get(), m_art.width, m_art.height, m_art.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||
|
GX_LoadTexObj(&artwork, GX_TEXMAP0);
|
||
|
|
||
|
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);
|
||
|
|
||
|
// Draw top left
|
||
|
GX_Position3f32(-w, -h, 0.f);
|
||
|
GX_Color4u8(0xFF, 0xFF, 0xFF, m_event_alpha);
|
||
|
GX_TexCoord2f32(0.f, 0.f);
|
||
|
|
||
|
// Draw top right
|
||
|
GX_Position3f32(w, -h, 0.f);
|
||
|
GX_Color4u8(0xFF, 0xFF, 0xFF, m_event_alpha);
|
||
|
GX_TexCoord2f32(1.f, 0.f);
|
||
|
|
||
|
// Draw bottom right
|
||
|
GX_Position3f32(w, h, 0.f);
|
||
|
GX_Color4u8(0xFF, 0xFF, 0xFF, m_event_alpha);
|
||
|
GX_TexCoord2f32(1.f, 1.f);
|
||
|
|
||
|
// 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();
|
||
|
}
|