2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <new>
|
|
|
|
#include <zlib.h>
|
|
|
|
#include <cwctype>
|
2016-05-19 01:15:19 +02:00
|
|
|
#include <sys/stat.h>
|
2012-01-21 21:57:41 +01:00
|
|
|
#include "coverflow.hpp"
|
|
|
|
#include "pngu.h"
|
|
|
|
#include "boxmesh.hpp"
|
|
|
|
#include "lockMutex.hpp"
|
|
|
|
#include "fonts.h"
|
2012-06-16 19:03:23 +02:00
|
|
|
#include "types.h"
|
2013-11-19 16:27:52 +01:00
|
|
|
#include "gui/fmt.h"
|
2012-12-08 17:17:35 +01:00
|
|
|
#include "gecko/gecko.hpp"
|
2013-03-28 14:02:50 +01:00
|
|
|
#include "menu/menu.hpp"
|
2013-04-21 13:59:58 +02:00
|
|
|
#include "plugin/plugin.hpp"
|
2012-11-03 20:16:03 +01:00
|
|
|
#include "memory/mem2.hpp"
|
2013-04-21 13:59:58 +02:00
|
|
|
#include "fileOps/fileOps.h"
|
2012-08-05 15:48:15 +02:00
|
|
|
#include "wstringEx/wstringEx.hpp"
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-07-08 17:41:58 +02:00
|
|
|
static const int black_len = 16;
|
|
|
|
static const char* black[black_len] = {"RZZJEL","RZNJ01","SEKJ99","SX3J01","SX3P01","R5WJA4","RUYJ99","S3HJ08","SJBJ01","CKBE88","CCPE01","SMMP01","MDUE01","SL2J01","APR","AFR"};
|
2012-02-02 18:21:10 +01:00
|
|
|
|
2012-02-16 20:36:50 +01:00
|
|
|
static const int red_len = 2;
|
|
|
|
static const char* red[red_len] = {"SMN","HBW"};
|
|
|
|
|
|
|
|
static const int yellow_len = 2;
|
|
|
|
static const char* yellow[yellow_len] = {"SIIE8P","SIIP8P"};
|
|
|
|
|
|
|
|
static const int greenOne_len = 1;
|
|
|
|
static const char* greenOne[greenOne_len] = {"SF8J01"};
|
|
|
|
|
|
|
|
static const int greenTwo_len = 1;
|
|
|
|
static const char* greenTwo[greenTwo_len] = {"PDUE01"};
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
static lwp_t coverLoaderThread = LWP_THREAD_NULL;
|
|
|
|
|
|
|
|
static inline int loopNum(int i, int s)
|
|
|
|
{
|
|
|
|
return i < 0 ? (s - (-i % s)) % s : i % s;
|
|
|
|
}
|
|
|
|
|
2012-11-11 19:28:03 +01:00
|
|
|
CCoverFlow CoverFlow;
|
|
|
|
|
2014-03-17 18:38:32 +01:00
|
|
|
u8 CCoverFlow::coverThreadStack[32768] ATTRIBUTE_ALIGN(32);
|
|
|
|
const u32 CCoverFlow::coverThreadStackSize = 32768;
|
|
|
|
|
2013-01-21 00:30:28 +01:00
|
|
|
CCoverFlow::CCover::CCover(void)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
index = 0;
|
|
|
|
txtAngle = 0.f;
|
|
|
|
txtTargetAngle = 0.f;
|
|
|
|
txtColor = 0;
|
|
|
|
txtTargetColor = 0;
|
|
|
|
color = 0x00FFFFFF;
|
|
|
|
targetColor = 0xFFFFFFFF;
|
|
|
|
shadowColor = 0x00000000;
|
|
|
|
targetShadowColor = 0x00000000;
|
|
|
|
scale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
targetScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
}
|
|
|
|
|
2013-03-28 14:02:50 +01:00
|
|
|
CCoverFlow::CItem::CItem(dir_discHdr *itemHdr, int playcount, unsigned int lastPlayed) :
|
2012-01-21 21:57:41 +01:00
|
|
|
hdr(itemHdr),
|
|
|
|
playcount(playcount),
|
2013-01-21 00:30:28 +01:00
|
|
|
lastPlayed(lastPlayed),
|
|
|
|
boxTexture(false),
|
|
|
|
state(STATE_Loading)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-03-28 14:02:50 +01:00
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline wchar_t upperCaseWChar(wchar_t c)
|
|
|
|
{
|
|
|
|
return c >= L'a' && c <= L'z' ? c & 0x00DF : c;
|
|
|
|
}
|
|
|
|
|
2012-05-12 18:03:14 +02:00
|
|
|
float m_normal_speed;
|
|
|
|
float m_selected_speed;
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
CCoverFlow::CCoverFlow(void)
|
|
|
|
{
|
|
|
|
m_loNormal.camera = Vector3D(0.f, 1.5f, 5.f);
|
|
|
|
m_loNormal.cameraAim = Vector3D(0.f, 0.f, -1.f);
|
|
|
|
m_loNormal.leftScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
m_loNormal.rightScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
m_loNormal.centerScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
m_loNormal.rowCenterScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
m_loNormal.leftPos = Vector3D(-1.6f, 0.f, 0.f);
|
|
|
|
m_loNormal.rightPos = Vector3D(1.6f, 0.f, 0.f);
|
|
|
|
m_loNormal.centerPos = Vector3D(0.f, 0.f, 1.f);
|
|
|
|
m_loNormal.rowCenterPos = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loNormal.leftAngle = Vector3D(0.f, 70.f, 0.f);
|
|
|
|
m_loNormal.rightAngle = Vector3D(0.f, -70.f, 0.f);
|
|
|
|
m_loNormal.centerAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loNormal.rowCenterAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loNormal.leftSpacer = Vector3D(-0.35f, 0.f, 0.f);
|
|
|
|
m_loNormal.rightSpacer = Vector3D(0.35f, 0.f, 0.f);
|
|
|
|
m_loNormal.leftDeltaAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loNormal.rightDeltaAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loNormal.txtLeftAngle = -55.f;
|
|
|
|
m_loNormal.txtRightAngle = 55.f;
|
|
|
|
m_loNormal.txtCenterAngle = 0.f;
|
|
|
|
m_loNormal.txtLeftPos = Vector3D(-4.f, 0.f, 1.3f);
|
|
|
|
m_loNormal.txtRightPos = Vector3D(4.f, 0.f, 1.3f);
|
|
|
|
m_loNormal.txtCenterPos = Vector3D(0.f, 0.f, 2.6f);
|
|
|
|
m_loNormal.txtSideWidth = 500.f;
|
|
|
|
m_loNormal.txtCenterWidth = 500.f;
|
|
|
|
m_loNormal.txtSideStyle = FTGX_ALIGN_BOTTOM | FTGX_JUSTIFY_CENTER;
|
|
|
|
m_loNormal.txtCenterStyle = FTGX_ALIGN_BOTTOM | FTGX_JUSTIFY_CENTER;
|
|
|
|
m_loNormal.endColor = CColor(0x3FFFFFFF);
|
|
|
|
m_loNormal.begColor = CColor(0xCFFFFFFF);
|
|
|
|
m_loNormal.mouseOffColor = CColor(0xFF00FF00);
|
|
|
|
m_loNormal.shadowColorCenter = CColor(0x00000000);
|
|
|
|
m_loNormal.shadowColorEnd = CColor(0x00000000);
|
|
|
|
m_loNormal.shadowColorBeg = CColor(0x00000000);
|
|
|
|
m_loNormal.shadowColorOff = CColor(0x00000000);
|
|
|
|
m_loNormal.topSpacer = Vector3D(0.f, 2.f, 0.f);
|
|
|
|
m_loNormal.bottomSpacer = Vector3D(0.f, -2.f, 0.f);
|
|
|
|
m_loNormal.topDeltaAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loNormal.bottomDeltaAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loNormal.topAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loNormal.bottomAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
//
|
|
|
|
m_loSelected.camera = Vector3D(0.f, 1.5f, 5.f);
|
|
|
|
m_loSelected.cameraAim = Vector3D(0.f, 0.f, -1.f);
|
|
|
|
m_loSelected.leftScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
m_loSelected.rightScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
m_loSelected.centerScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
m_loSelected.rowCenterScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
m_loSelected.leftPos = Vector3D(-4.6f, 2.f, 0.f);
|
|
|
|
m_loSelected.rightPos = Vector3D(4.6f, 2.f, 0.f);
|
|
|
|
m_loSelected.centerPos = Vector3D(-0.6f, 0.f, 2.6f);
|
|
|
|
m_loSelected.rowCenterPos = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loSelected.leftAngle = Vector3D(-45.f, 90.f, 0.f);
|
|
|
|
m_loSelected.rightAngle = Vector3D(-45.f, -90.f, 0.f);
|
|
|
|
m_loSelected.centerAngle = Vector3D(0.f, 380.f, 0.f);
|
|
|
|
m_loSelected.rowCenterAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loSelected.leftSpacer = Vector3D(-0.35f, 0.f, 0.f);
|
|
|
|
m_loSelected.rightSpacer = Vector3D(0.35f, 0.f, 0.f);
|
|
|
|
m_loSelected.leftDeltaAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loSelected.rightDeltaAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loSelected.txtLeftAngle = -55.f;
|
|
|
|
m_loSelected.txtRightAngle = 55.f;
|
|
|
|
m_loSelected.txtCenterAngle = 0.f;
|
|
|
|
m_loSelected.txtLeftPos = Vector3D(-4.35f, 0.f, 1.3f);
|
|
|
|
m_loSelected.txtRightPos = Vector3D(4.35f, 0.f, 1.3f);
|
|
|
|
m_loSelected.txtCenterPos = Vector3D(2.3f, 1.8f, 1.f);
|
|
|
|
m_loSelected.txtSideWidth = 500.f;
|
|
|
|
m_loSelected.txtCenterWidth = 310.f;
|
|
|
|
m_loSelected.txtSideStyle = FTGX_ALIGN_BOTTOM | FTGX_JUSTIFY_CENTER;
|
|
|
|
m_loSelected.txtCenterStyle = FTGX_ALIGN_TOP | FTGX_JUSTIFY_RIGHT;
|
|
|
|
m_loSelected.endColor = CColor(0x3FFFFFFF);
|
|
|
|
m_loSelected.begColor = CColor(0xCFFFFFFF);
|
|
|
|
m_loSelected.mouseOffColor = CColor(0xFF00FF00);
|
|
|
|
m_loSelected.shadowColorCenter = CColor(0x00000000);
|
|
|
|
m_loSelected.shadowColorEnd = CColor(0x00000000);
|
|
|
|
m_loSelected.shadowColorBeg = CColor(0x00000000);
|
|
|
|
m_loSelected.shadowColorOff = CColor(0x00000000);
|
|
|
|
m_loSelected.topSpacer = Vector3D(0.f, 2.f, 0.f);
|
|
|
|
m_loSelected.bottomSpacer = Vector3D(0.f, -2.f, 0.f);
|
|
|
|
m_loSelected.topDeltaAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loSelected.bottomDeltaAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loSelected.topAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_loSelected.bottomAngle = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
//
|
|
|
|
m_mirrorAlpha = 0.2f;
|
|
|
|
m_txtMirrorAlpha = 0.2f;
|
|
|
|
m_delay = 0;
|
|
|
|
m_minDelay = 5;
|
|
|
|
m_jump = 0;
|
|
|
|
m_mutex = 0;
|
2012-07-21 19:05:58 +02:00
|
|
|
m_dvdskin_loaded = false;
|
2013-01-13 16:45:05 +01:00
|
|
|
m_defcovers_loaded = false;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_loadingCovers = false;
|
2012-11-04 20:22:02 +01:00
|
|
|
m_coverThrdBusy = false;
|
2012-11-11 19:28:03 +01:00
|
|
|
m_renderTex = false;
|
|
|
|
m_renderingTex = NULL;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_moved = false;
|
|
|
|
m_selected = false;
|
|
|
|
m_hideCover = false;
|
|
|
|
m_tickCount = 0;
|
|
|
|
m_blurRadius = 3;
|
|
|
|
m_blurFactor = 1.f;
|
|
|
|
//
|
|
|
|
m_mirrorBlur = false;
|
|
|
|
m_effectTex.width = 96;
|
|
|
|
m_effectTex.height = 72;
|
|
|
|
m_effectTex.format = GX_TF_RGBA8;
|
|
|
|
m_shadowScale = 1.f;
|
|
|
|
m_shadowX = 0.f;
|
|
|
|
m_shadowY = 0.f;
|
|
|
|
m_flipCoverPos = Vector3D(0.f, 0.f, 0.f);
|
|
|
|
m_flipCoverAngle = Vector3D(0.f, 180.f, 0.f);
|
|
|
|
m_flipCoverScale = Vector3D(1.f, 1.f, 1.f);
|
|
|
|
// Settings
|
|
|
|
m_lodBias = -0.3f;
|
|
|
|
m_aniso = GX_ANISO_1;
|
|
|
|
m_edgeLOD = false;
|
2012-04-27 20:12:10 +02:00
|
|
|
m_numBufCovers = 20;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_compressTextures = true;
|
|
|
|
m_compressCache = false;
|
|
|
|
m_deletePicsAfterCaching = false;
|
2013-04-21 13:59:58 +02:00
|
|
|
m_pluginCacheFolders = false;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_box = true;
|
2016-12-14 19:47:13 +01:00
|
|
|
m_smallBox = false;
|
2012-05-04 16:08:44 +02:00
|
|
|
m_useHQcover = false;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_rows = 1;
|
|
|
|
m_columns = 11;
|
|
|
|
m_range = m_rows * m_columns;
|
|
|
|
for(int chan = WPAD_MAX_WIIMOTES-1; chan >= 0; chan--)
|
|
|
|
m_mouse[chan] = -1;
|
|
|
|
sndCopyNum = 0;
|
|
|
|
m_soundVolume = 0xFF;
|
|
|
|
m_sorting = SORT_ALPHA;
|
2012-05-12 18:03:14 +02:00
|
|
|
m_normal_speed = 0.1f;
|
|
|
|
m_selected_speed = 0.07f;
|
2012-01-21 21:57:41 +01:00
|
|
|
//
|
2012-11-07 23:27:41 +01:00
|
|
|
m_flipSound = NULL;
|
|
|
|
m_hoverSound = NULL;
|
|
|
|
m_selectSound = NULL;
|
|
|
|
m_cancelSound = NULL;
|
2013-01-13 16:45:05 +01:00
|
|
|
//
|
2013-01-21 00:30:28 +01:00
|
|
|
m_covers = NULL;
|
2012-01-21 21:57:41 +01:00
|
|
|
LWP_MutexInit(&m_mutex, 0);
|
|
|
|
}
|
|
|
|
|
2012-11-03 20:16:03 +01:00
|
|
|
bool CCoverFlow::init(const u8 *font, const u32 font_size, bool vid_50hz)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
// Load font
|
|
|
|
m_font.fromBuffer(font, font_size, TITLEFONT);
|
|
|
|
m_fontColor = CColor(0xFFFFFFFF);
|
2012-05-11 17:14:57 +02:00
|
|
|
|
2012-05-12 18:03:14 +02:00
|
|
|
if(vid_50hz)
|
2012-05-11 17:14:57 +02:00
|
|
|
{
|
|
|
|
gprintf("WiiFlow is in 50hz mode\n");
|
2012-05-12 18:03:14 +02:00
|
|
|
m_normal_speed = 0.12f;
|
|
|
|
m_selected_speed = 0.084f;
|
2012-05-11 17:14:57 +02:00
|
|
|
m_minDelay = 4;
|
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
if (CONF_GetAspectRatio() == CONF_ASPECT_16_9)
|
|
|
|
guPerspective(m_projMtx, 45, 16.f / 9.f, .1f, 300.f);
|
|
|
|
else
|
2019-07-03 12:00:18 +02:00
|
|
|
guPerspective(m_projMtx, RadToDeg(2.f * atan(tan(DegToRad(45 / 2)) / (4.f / 3.f) * (16.f / 9.f))), 4.f / 3.f, .1f, 300.f);
|
2012-01-21 21:57:41 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::simulateOtherScreenFormat(bool s)
|
|
|
|
{
|
|
|
|
if ((CONF_GetAspectRatio() == CONF_ASPECT_16_9) != s)
|
|
|
|
guPerspective(m_projMtx, 45, 16.f / 9.f, .1f, 300.f);
|
|
|
|
else
|
2019-07-03 12:00:18 +02:00
|
|
|
guPerspective(m_projMtx, RadToDeg(2.f * atan(tan(DegToRad(45 / 2)) / (4.f / 3.f) * (16.f / 9.f))), 4.f / 3.f, .1f, 300.f);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
CCoverFlow::~CCoverFlow(void)
|
|
|
|
{
|
2012-11-07 23:27:41 +01:00
|
|
|
shutdown();
|
2012-01-21 21:57:41 +01:00
|
|
|
LWP_MutexDestroy(m_mutex);
|
|
|
|
}
|
|
|
|
|
2018-11-12 21:38:37 +01:00
|
|
|
void CCoverFlow::setCachePath(const char *path, bool pluginCacheFolders)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
m_cachePath = path;
|
2013-04-21 13:59:58 +02:00
|
|
|
m_pluginCacheFolders = pluginCacheFolders;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setTextureQuality(float lodBias, int aniso, bool edgeLOD)
|
|
|
|
{
|
|
|
|
m_lodBias = min(max(-3.f, lodBias), 1.f);
|
|
|
|
switch (aniso)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
m_aniso = GX_ANISO_2;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_aniso = GX_ANISO_4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
m_aniso = GX_ANISO_1;
|
|
|
|
}
|
|
|
|
m_edgeLOD = edgeLOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setBoxMode(bool box)
|
|
|
|
{
|
|
|
|
m_box = box;
|
|
|
|
}
|
|
|
|
|
2016-12-14 19:47:13 +01:00
|
|
|
void CCoverFlow::setSmallBoxMode(bool smallBox)
|
|
|
|
{
|
|
|
|
m_smallBox = smallBox;
|
|
|
|
}
|
|
|
|
|
2012-05-04 16:08:44 +02:00
|
|
|
void CCoverFlow::setHQcover(bool HQ)
|
|
|
|
{
|
|
|
|
m_useHQcover = HQ;
|
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
void CCoverFlow::setBufferSize(u32 numCovers)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if(m_covers != NULL) return;
|
2018-05-08 15:49:43 +02:00
|
|
|
m_numBufCovers = min(max(4ul, numCovers / 2ul), 40ul);//8 to 80
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setTextures(const string &loadingPic, const string &loadingPicFlat, const string &noCoverPic, const string &noCoverPicFlat)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers != NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_pngLoadCover = loadingPic;
|
|
|
|
m_pngLoadCoverFlat = loadingPicFlat;
|
|
|
|
m_pngNoCover = noCoverPic;
|
|
|
|
m_pngNoCoverFlat = noCoverPicFlat;
|
|
|
|
}
|
|
|
|
|
2012-11-03 20:16:03 +01:00
|
|
|
void CCoverFlow::setFont(const SFont &font, const CColor &color)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-11-03 20:16:03 +01:00
|
|
|
if(m_font.font != NULL)
|
|
|
|
delete m_font.font;
|
|
|
|
m_font = font;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_fontColor = color;
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers != NULL)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
for (u32 i = 0; i < m_range; ++i)
|
|
|
|
_loadCover(i, m_covers[i].index);
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-21 00:30:28 +01:00
|
|
|
void CCoverFlow::_transposeCover(CCover* &dst, u32 rows, u32 columns, int pos)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
int i = pos - (int)(rows * columns / 2);
|
|
|
|
int j = rows >= 3 ? abs(i) - ((abs(i) + (int)rows / 2) / (int)rows) * 2 : abs(i);
|
|
|
|
if (m_rows >= 3)
|
|
|
|
j += ((j + ((int)m_rows - 2) / 2) / ((int)m_rows - 2)) * 2;
|
|
|
|
int k = m_range / 2 + (i < 0 ? -j : j);
|
|
|
|
if ((u32)k < m_range)
|
|
|
|
dst[pos] = m_covers[k];
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setRange(u32 rows, u32 columns)
|
|
|
|
{
|
2018-05-08 15:49:43 +02:00
|
|
|
rows = rows < 3ul ? 1ul : min(rows | 1ul, 9ul) + 2ul;
|
|
|
|
columns = min(max(3ul, columns | 1ul), 21ul) + 2ul;
|
2012-01-21 21:57:41 +01:00
|
|
|
u32 range = rows * columns;
|
|
|
|
if (rows == m_rows && columns == m_columns && range == m_range)
|
|
|
|
return;
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers != NULL)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
stopCoverLoader();
|
2018-06-27 14:47:03 +02:00
|
|
|
MEM2_free(m_covers);
|
2013-01-21 00:30:28 +01:00
|
|
|
CCover *tmpCovers = (CCover*)MEM2_alloc(sizeof(CCover) * range);
|
|
|
|
for(size_t i = 0; i < range; ++i)
|
2018-06-27 14:47:03 +02:00
|
|
|
{
|
|
|
|
// does not allocate memory -- calls: operator new (sizeof(CCover), tmpCovers+i)
|
|
|
|
// only constructs an object at tmpCovers+i
|
|
|
|
// delete is not needed
|
|
|
|
// this is the same as CCover tmpCovers[range] except the objects memory address is specified and won't go out of scope
|
|
|
|
tmpCovers[i] = *(new (tmpCovers+i) CCover);
|
|
|
|
}
|
2012-01-21 21:57:41 +01:00
|
|
|
if (rows >= 3)
|
|
|
|
for (u32 x = 0; x < columns; ++x)
|
|
|
|
for (u32 y = 1; y < rows - 1; ++y)
|
|
|
|
_transposeCover(tmpCovers, rows, columns, x * rows + y);
|
|
|
|
else
|
|
|
|
for (u32 x = 0; x < range; ++x)
|
|
|
|
_transposeCover(tmpCovers, rows, columns, x);
|
|
|
|
m_rows = rows;
|
|
|
|
m_columns = columns;
|
|
|
|
m_range = range;
|
2013-01-21 00:30:28 +01:00
|
|
|
m_covers = tmpCovers;
|
2012-01-21 21:57:41 +01:00
|
|
|
_loadAllCovers(m_covers[m_range / 2].index);
|
|
|
|
_updateAllTargets();
|
|
|
|
startCoverLoader();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_rows = rows;
|
|
|
|
m_columns = columns;
|
|
|
|
m_range = range;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setCameraPos(bool selected, const Vector3D &pos, const Vector3D &aim)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.camera = pos;
|
|
|
|
lo.cameraAim = aim;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setCameraOsc(bool selected, const Vector3D &speed, const Vector3D &)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.cameraOscSpeed = speed;
|
|
|
|
lo.cameraOscAmp = amp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setCoverScale(bool selected, const Vector3D &left, const Vector3D &right, const Vector3D ¢er, const Vector3D &rowCenter)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.leftScale = left;
|
|
|
|
lo.rightScale = right;
|
|
|
|
lo.centerScale = center;
|
|
|
|
lo.rowCenterScale = rowCenter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setCoverPos(bool selected, const Vector3D &left, const Vector3D &right, const Vector3D ¢er, const Vector3D &rowCenter)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.leftPos = left;
|
|
|
|
lo.rightPos = right;
|
|
|
|
lo.centerPos = center;
|
|
|
|
lo.rowCenterPos = rowCenter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setCoverAngleOsc(bool selected, const Vector3D &speed, const Vector3D &)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.coverOscASpeed = speed;
|
|
|
|
lo.coverOscAAmp = amp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setCoverPosOsc(bool selected, const Vector3D &speed, const Vector3D &)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.coverOscPSpeed = speed;
|
|
|
|
lo.coverOscPAmp = amp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setSpacers(bool selected, const Vector3D &left, const Vector3D &right)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.leftSpacer = left;
|
|
|
|
lo.rightSpacer = right;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setDeltaAngles(bool selected, const Vector3D &left, const Vector3D &right)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.leftDeltaAngle = left;
|
|
|
|
lo.rightDeltaAngle = right;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setAngles(bool selected, const Vector3D &left, const Vector3D &right, const Vector3D ¢er, const Vector3D &rowCenter)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.leftAngle = left;
|
|
|
|
lo.rightAngle = right;
|
|
|
|
lo.centerAngle = center;
|
|
|
|
lo.rowCenterAngle = rowCenter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setTitleAngles(bool selected, float left, float right, float center)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.txtLeftAngle = left;
|
|
|
|
lo.txtRightAngle = right;
|
|
|
|
lo.txtCenterAngle = center;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setTitlePos(bool selected, const Vector3D &left, const Vector3D &right, const Vector3D ¢er)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.txtLeftPos = left;
|
|
|
|
lo.txtRightPos= right;
|
|
|
|
lo.txtCenterPos= center;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setTitleWidth(bool selected, float side, float center)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.txtSideWidth = side;
|
|
|
|
lo.txtCenterWidth= center;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setTitleStyle(bool selected, u16 side, u16 center)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
lo.txtSideStyle = side;
|
|
|
|
lo.txtCenterStyle = center;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setColors(bool selected, const CColor &begColor, const CColor &endColor, const CColor &offColor)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
|
|
|
|
lo.begColor = begColor;
|
|
|
|
lo.endColor = endColor;
|
|
|
|
lo.mouseOffColor = offColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setMirrorAlpha(float cover, float title)
|
|
|
|
{
|
|
|
|
m_mirrorAlpha = cover;
|
|
|
|
m_txtMirrorAlpha = title;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setMirrorBlur(bool blur)
|
|
|
|
{
|
|
|
|
m_mirrorBlur = blur;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setShadowColors(bool selected, const CColor ¢erColor, const CColor &begColor, const CColor &endColor, const CColor &offColor)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
|
|
|
|
lo.shadowColorCenter = centerColor;
|
|
|
|
lo.shadowColorBeg = begColor;
|
|
|
|
lo.shadowColorEnd = endColor;
|
|
|
|
lo.shadowColorOff = offColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setShadowPos(float scale, float x, float y)
|
|
|
|
{
|
|
|
|
m_shadowScale = scale;
|
|
|
|
m_shadowX = x;
|
|
|
|
m_shadowY = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setRowSpacers(bool selected, const Vector3D &top, const Vector3D &bottom)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
|
|
|
|
lo.topSpacer = top;
|
|
|
|
lo.bottomSpacer = bottom;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setRowDeltaAngles(bool selected, const Vector3D &top, const Vector3D &bottom)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
|
|
|
|
lo.topDeltaAngle = top;
|
|
|
|
lo.bottomDeltaAngle = bottom;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setRowAngles(bool selected, const Vector3D &top, const Vector3D &bottom)
|
|
|
|
{
|
|
|
|
SLayout &lo = selected ? m_loSelected : m_loNormal;
|
|
|
|
|
|
|
|
lo.topAngle = top;
|
|
|
|
lo.bottomAngle = bottom;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setCoverFlipping(const Vector3D &pos, const Vector3D &angle, const Vector3D &scale)
|
|
|
|
{
|
|
|
|
m_flipCoverPos = pos;
|
|
|
|
m_flipCoverAngle = angle;
|
|
|
|
m_flipCoverScale = scale;
|
|
|
|
}
|
|
|
|
|
2016-06-20 23:03:40 +02:00
|
|
|
void CCoverFlow::setCoverFlipPos(const Vector3D &pos)
|
|
|
|
{
|
2016-06-22 21:34:58 +02:00
|
|
|
if(m_covers == NULL || !m_selected) return;
|
2016-06-20 23:03:40 +02:00
|
|
|
LockMutex lock(m_mutex);
|
2016-06-22 21:34:58 +02:00
|
|
|
m_covers[m_range / 2].targetPos = m_loSelected.centerPos + pos;
|
2016-06-20 23:03:40 +02:00
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
void CCoverFlow::setBlur(u32 blurResolution, u32 blurRadius, float blurFactor)
|
|
|
|
{
|
|
|
|
static const struct { u32 x; u32 y; } blurRes[] = {
|
|
|
|
{ 64, 48 }, { 96, 72 }, { 128, 96 }, { 192, 144 }
|
|
|
|
};
|
2018-11-26 00:37:55 +01:00
|
|
|
u32 i = min(max(0ul, blurResolution), sizeof blurRes / sizeof blurRes[0] - 1ul);
|
2012-01-21 21:57:41 +01:00
|
|
|
m_effectTex.width = blurRes[i].x;
|
|
|
|
m_effectTex.height = blurRes[i].y;
|
2012-11-03 20:16:03 +01:00
|
|
|
if(m_effectTex.data != NULL)
|
|
|
|
{
|
|
|
|
free(m_effectTex.data);
|
|
|
|
m_effectTex.data = NULL;
|
|
|
|
}
|
2018-11-26 00:37:55 +01:00
|
|
|
m_blurRadius = min(max(1ul, blurRadius), 3ul);
|
2012-01-21 21:57:41 +01:00
|
|
|
m_blurFactor = min(max(1.f, blurFactor), 2.f);
|
|
|
|
}
|
|
|
|
|
2012-11-03 20:16:03 +01:00
|
|
|
void CCoverFlow::setSorting(Sorting sorting)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
m_sorting = sorting;
|
|
|
|
}
|
|
|
|
|
2012-11-04 20:22:02 +01:00
|
|
|
void CCoverFlow::setSounds(GuiSound *flipSound, GuiSound *hoverSound, GuiSound *selectSound, GuiSound *cancelSound)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-11-03 20:16:03 +01:00
|
|
|
//for(u8 i = 0; i < 4; i++)
|
2012-11-04 20:22:02 +01:00
|
|
|
m_flipSound = flipSound;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_hoverSound = hoverSound;
|
|
|
|
m_selectSound = selectSound;
|
|
|
|
m_cancelSound = cancelSound;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setSoundVolume(u8 vol)
|
|
|
|
{
|
|
|
|
m_soundVolume = vol;
|
|
|
|
}
|
|
|
|
|
2012-11-04 20:22:02 +01:00
|
|
|
void CCoverFlow::_stopSound(GuiSound * &snd)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-11-03 20:16:03 +01:00
|
|
|
if(snd == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
snd->Stop();
|
|
|
|
}
|
|
|
|
|
2012-11-04 20:22:02 +01:00
|
|
|
void CCoverFlow::_playSound(GuiSound * &snd)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-11-03 20:16:03 +01:00
|
|
|
if(snd == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
snd->Play(m_soundVolume);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::stopSound(void)
|
|
|
|
{
|
2012-11-04 20:22:02 +01:00
|
|
|
//for(u8 i = 0; i < 4; i++)
|
|
|
|
_stopSound(m_flipSound);
|
2012-01-21 21:57:41 +01:00
|
|
|
_stopSound(m_hoverSound);
|
2012-11-04 20:22:02 +01:00
|
|
|
_stopSound(m_selectSound);
|
|
|
|
_stopSound(m_cancelSound);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::applySettings(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
2016-06-22 21:34:58 +02:00
|
|
|
_updateAllTargets(true);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::stopCoverLoader(bool empty)
|
|
|
|
{
|
|
|
|
m_loadingCovers = false;
|
2013-01-21 00:30:28 +01:00
|
|
|
m_moved = true;
|
2012-11-04 20:22:02 +01:00
|
|
|
if(coverLoaderThread != LWP_THREAD_NULL)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
if(LWP_ThreadIsSuspended(coverLoaderThread))
|
|
|
|
LWP_ResumeThread(coverLoaderThread);
|
2012-11-04 20:22:02 +01:00
|
|
|
while(m_coverThrdBusy)
|
|
|
|
usleep(50);
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
LWP_JoinThread(coverLoaderThread, NULL);
|
|
|
|
coverLoaderThread = LWP_THREAD_NULL;
|
2012-06-01 07:34:52 +02:00
|
|
|
if(empty)
|
2012-04-27 20:12:10 +02:00
|
|
|
{
|
2012-11-03 20:16:03 +01:00
|
|
|
for(u32 i = 0; i < m_items.size(); ++i)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-12-28 15:19:40 +01:00
|
|
|
TexHandle.Cleanup(m_items[i].texture);
|
2012-11-03 20:16:03 +01:00
|
|
|
m_items[i].state = STATE_Loading;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
2012-04-27 20:12:10 +02:00
|
|
|
}
|
2018-12-24 14:42:31 +01:00
|
|
|
//gprintf("Coverflow stopped!\n");
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::startCoverLoader(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if(m_covers == NULL || coverLoaderThread != LWP_THREAD_NULL || m_loadingCovers)
|
2012-06-01 07:34:52 +02:00
|
|
|
return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
m_loadingCovers = true;
|
2012-06-01 07:34:52 +02:00
|
|
|
m_moved = true;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2019-02-18 21:40:07 +01:00
|
|
|
LWP_CreateThread(&coverLoaderThread, _coverLoader, this, coverThreadStack, coverThreadStackSize, 40);
|
2018-12-24 14:42:31 +01:00
|
|
|
//gprintf("Coverflow started!\n");
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::clear(void)
|
|
|
|
{
|
|
|
|
stopCoverLoader(true);
|
2013-01-21 00:30:28 +01:00
|
|
|
if(m_covers != NULL)
|
|
|
|
MEM2_free(m_covers);
|
|
|
|
m_covers = NULL;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_items.clear();
|
-updating wiiflow lite to beta 4.3.0
-fixed using categories to hide GC disc 2's. Apparently this has never really worked right for some time or ever.
-fixed deleting the cached cover texture file for plugin games. Delete cover for plugins only deletes the cached texture file (.wfc)
-fixed favorites and adultonly (parental lock) for plugin games. Apparently I may have broke this a few revisions back.
-favorites and adultonly for plugin games now have their own domains in gamecfg1- [FAVORITES_PLUGINS] and [ADULTONLY_PLUGINS]. just makes it more organized.
-only wii, GC, channels are added to [PLAYCOUNT] and [LAST_PLAYED] in gamecfg1.
-now loading gamecfg1 at startup and leaving it loaded till exit. no more loading it and unloading all the time.
-fixed scrolling for game_info synopsis, credits, and help text.
-made source menu buttons wider for wiiflow default. old 80x80, now 100x80. looks better.
-display music info now defaults to off
-screensaver_disabled now defaults to yes
-show GC view button is now on by default no matter what. the only way it is disabled is if you edit wiiflow.ini manually. this is how all the view buttons work.
-removed hiding homebrew button but if wiiflow locked it won't work or in sourceflow it won't show.
-dump_list is now under [GENERAL] instead of each view. Also only works for Wii, GC, and channels.
-sorting only works for Wii, GC, and Channels now. disabled for sourceflow, plugins, homebrew, and combined view.
-now if no games are found a message is shown with the current path so you can see where wiiflow is looking. (except for plugins)
-removed auto create emuNAND for emuNAND view if gamelist is empty. just go to settings>NAND settings if you want to extract or disable it.
-now when no games are found all buttons at bottom are still accessible allowing you to change the view or go to settings and change current partition or path and even extract your NAND to create a EmuNAND. Or go to Home Menu and Install a Wii or GC game.
-removed auto extract NAND to emuNAND when launching a Wii game with EmuNAND save. Now a message is diplayed saying 'emuNAND for saves not found - using real NAND'.
-made the speed at which cover titles fade in/out almost instantly.
-removed update button from Home Menu. online update code is still there but not used and probably won't be used any more as there just isn't a need for it now.
-removed ftp button from Home Menu and all code for the FTP server. I just use WiiXplorer's FTP server. it seems to work better for me.
-disabled keep USB Alive thread for now. i think there's a possibilty it might be the cause of my SD/USB files getting corrupted.
-removed Btn B and - combo to switch partitions. didn't seem useful anymore.
-redid nand emulation settings menu. looks like this now:
pg1
Select EmuNAND
EmuNAND Enulation
Select SaveNAND
SaveNAND Emulation
pg2
Extract Saves All
Missing
Extract NAND
Select Saves Partition
-no longer blocking Select Plugin menu and View icons when using source menu combined view
-now Select Plugins Menu is like switching to plugin view but you get to choose the plugins first
-now [PLUGIN] partition= is the default partition for all plugins. to change individual plugins add 'romPartition=x' to the plugin ini. x is the partition number 0 thru 8 with SD being 0. this is how my usbloadergx plugin mod works.
2016-10-05 01:44:13 +02:00
|
|
|
//vector<CItem>().swap(m_items);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2012-07-21 19:05:58 +02:00
|
|
|
void CCoverFlow::shutdown(void)
|
|
|
|
{
|
|
|
|
gprintf("Cleanup Coverflow\n");
|
2012-12-28 15:19:40 +01:00
|
|
|
TexHandle.Cleanup(m_dvdSkin);
|
|
|
|
TexHandle.Cleanup(m_dvdSkin_Red);
|
|
|
|
TexHandle.Cleanup(m_dvdSkin_Black);
|
|
|
|
TexHandle.Cleanup(m_dvdSkin_Yellow);
|
|
|
|
TexHandle.Cleanup(m_dvdSkin_GreenOne);
|
|
|
|
TexHandle.Cleanup(m_dvdSkin_GreenTwo);
|
2020-11-16 22:11:04 +01:00
|
|
|
TexHandle.Cleanup(m_dvdSkin_Clear);
|
2012-11-07 23:27:41 +01:00
|
|
|
clear();
|
2012-11-04 20:22:02 +01:00
|
|
|
|
|
|
|
if(m_flipSound != NULL)
|
|
|
|
delete m_flipSound;
|
|
|
|
m_flipSound = NULL;
|
|
|
|
if(m_cancelSound != NULL)
|
|
|
|
delete m_cancelSound;
|
2012-11-03 20:16:03 +01:00
|
|
|
m_cancelSound = NULL;
|
2012-07-21 19:05:58 +02:00
|
|
|
LWP_MutexDestroy(m_mutex);
|
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
void CCoverFlow::reserve(u32 capacity)
|
|
|
|
{
|
|
|
|
m_items.reserve(capacity);
|
|
|
|
}
|
|
|
|
|
2013-03-28 14:02:50 +01:00
|
|
|
void CCoverFlow::addItem(dir_discHdr *hdr, int playcount, unsigned int lastPlayed)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers != NULL) return;
|
2013-03-28 14:02:50 +01:00
|
|
|
m_items.push_back(CCoverFlow::CItem(hdr, playcount, lastPlayed));
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Draws a plane in the Z-Buffer only.
|
|
|
|
void CCoverFlow::_drawMirrorZ(void)
|
|
|
|
{
|
|
|
|
GX_LoadPosMtxImm(m_viewMtx, GX_PNMTX0);
|
|
|
|
// GX setup
|
|
|
|
GX_SetNumChans(0);
|
|
|
|
GX_ClearVtxDesc();
|
|
|
|
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
|
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
|
|
|
GX_SetNumTexGens(0);
|
|
|
|
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
|
|
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_DISABLE, GX_COLORNULL);
|
|
|
|
GX_SetAlphaUpdate(GX_FALSE);
|
|
|
|
GX_SetColorUpdate(GX_FALSE);
|
|
|
|
GX_SetZMode(GX_ENABLE, GX_LEQUAL, GX_TRUE);
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
|
|
GX_Position3f32(-10000.f, 0.f, -10000.f);
|
|
|
|
GX_Position3f32(10000.f, 0.f, -10000.f);
|
|
|
|
GX_Position3f32(10000.f, 0.f, 10000.f);
|
|
|
|
GX_Position3f32(-10000.f, 0.f, 10000.f);
|
|
|
|
GX_End();
|
|
|
|
GX_SetAlphaUpdate(GX_TRUE);
|
|
|
|
GX_SetColorUpdate(GX_TRUE);
|
|
|
|
}
|
|
|
|
|
2012-12-28 15:19:40 +01:00
|
|
|
void CCoverFlow::_effectBg(const TexData * &tex)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
Mtx modelViewMtx;
|
|
|
|
GXTexObj texObj;
|
2012-11-16 23:40:20 +01:00
|
|
|
if(tex == NULL || tex->data == NULL)
|
|
|
|
return;
|
2012-01-21 21:57:41 +01:00
|
|
|
GX_ClearVtxDesc();
|
|
|
|
GX_SetNumTevStages(1);
|
|
|
|
GX_SetNumChans(0);
|
|
|
|
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
|
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 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_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
|
|
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
|
|
|
|
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
|
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
|
|
|
|
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
|
|
GX_SetAlphaUpdate(GX_TRUE);
|
|
|
|
GX_SetCullMode(GX_CULL_NONE);
|
|
|
|
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
|
|
|
|
guMtxIdentity(modelViewMtx);
|
|
|
|
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
|
2012-11-16 23:40:20 +01:00
|
|
|
GX_InitTexObj(&texObj, tex->data, tex->width, tex->height, tex->format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
2012-01-21 21:57:41 +01:00
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
|
|
GX_Position3f32(0.f, 0.f, 0.f);
|
|
|
|
GX_TexCoord2f32(0.f, 0.f);
|
|
|
|
GX_Position3f32(640.f, 0.f, 0.f);
|
|
|
|
GX_TexCoord2f32(1.f, 0.f);
|
|
|
|
GX_Position3f32(640.f, 480.f, 0.f);
|
|
|
|
GX_TexCoord2f32(1.f, 1.f);
|
|
|
|
GX_Position3f32(0.f, 480.f, 0.f);
|
|
|
|
GX_TexCoord2f32(0.f, 1.f);
|
|
|
|
GX_End();
|
|
|
|
}
|
|
|
|
|
2012-11-11 19:28:03 +01:00
|
|
|
void CCoverFlow::_effectBlur(bool vertical)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
int kSize = m_blurRadius * 2 + 1;
|
|
|
|
GXTexObj texObj;
|
|
|
|
Mtx mh1;
|
|
|
|
Mtx mh2;
|
|
|
|
Mtx mh3;
|
|
|
|
Mtx mh4;
|
|
|
|
Mtx mh5;
|
|
|
|
Mtx mh6;
|
|
|
|
Mtx modelViewMtx;
|
|
|
|
float pixDist = m_blurFactor;
|
|
|
|
float w = (float)m_effectTex.width;
|
|
|
|
float h = (float)m_effectTex.height;
|
|
|
|
float x = 0.f;
|
|
|
|
float y = 0.f;
|
|
|
|
CColor kGauss7(0xFF * 20 / 64, 0xFF * 15 / 64, 0xFF * 6 / 64, 0xFF * 1 / 64);
|
|
|
|
CColor kGauss5(0xFF * 6 / 16, 0xFF * 4 / 16, 0xFF * 1 / 16, 0);
|
|
|
|
CColor kGauss3(0xFF * 2 / 4, 0xFF * 1 / 4, 0, 0);
|
|
|
|
CColor kBox(0xFF / kSize, 0xFF / kSize, 0xFF / kSize, 0xFF / kSize);
|
|
|
|
Mtx44 projMtx;
|
|
|
|
|
|
|
|
GX_SetScissor(0, 0, m_effectTex.width, m_effectTex.height);
|
|
|
|
GX_SetPixelFmt(GX_PF_RGBA6_Z24, GX_ZC_LINEAR);
|
|
|
|
GX_InvVtxCache();
|
|
|
|
GX_InvalidateTexAll();
|
2012-11-03 20:16:03 +01:00
|
|
|
GX_InitTexObj(&texObj, m_effectTex.data, m_effectTex.width, m_effectTex.height, m_effectTex.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
2012-01-21 21:57:41 +01:00
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
GX_SetNumTevStages(kSize);
|
|
|
|
GX_SetNumTexGens(kSize);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
|
|
|
guMtxIdentity(mh1);
|
|
|
|
guMtxIdentity(mh2);
|
|
|
|
guMtxIdentity(mh3);
|
|
|
|
guMtxIdentity(mh4);
|
|
|
|
guMtxIdentity(mh5);
|
|
|
|
guMtxIdentity(mh6);
|
|
|
|
if (vertical)
|
|
|
|
{
|
|
|
|
guMtxRowCol(mh1, 0, 3) = pixDist * -1.f / w;
|
|
|
|
guMtxRowCol(mh2, 0, 3) = pixDist * 1.f / w;
|
|
|
|
guMtxRowCol(mh3, 0, 3) = pixDist * -2.f / w;
|
|
|
|
guMtxRowCol(mh4, 0, 3) = pixDist * 2.f / w;
|
|
|
|
guMtxRowCol(mh5, 0, 3) = pixDist * -3.f / w;
|
|
|
|
guMtxRowCol(mh6, 0, 3) = pixDist * 3.f / w;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
guMtxRowCol(mh1, 1, 3) = pixDist * -1.f / h;
|
|
|
|
guMtxRowCol(mh2, 1, 3) = pixDist * 1.f / h;
|
|
|
|
guMtxRowCol(mh3, 1, 3) = pixDist * -2.f / h;
|
|
|
|
guMtxRowCol(mh4, 1, 3) = pixDist * 2.f / h;
|
|
|
|
guMtxRowCol(mh5, 1, 3) = pixDist * -3.f / h;
|
|
|
|
guMtxRowCol(mh6, 1, 3) = pixDist * 3.f / h;
|
|
|
|
}
|
|
|
|
GX_LoadTexMtxImm(mh1, GX_TEXMTX1, GX_MTX2x4);
|
|
|
|
GX_LoadTexMtxImm(mh2, GX_TEXMTX2, GX_MTX2x4);
|
|
|
|
GX_LoadTexMtxImm(mh3, GX_TEXMTX3, GX_MTX2x4);
|
|
|
|
GX_LoadTexMtxImm(mh4, GX_TEXMTX4, GX_MTX2x4);
|
|
|
|
GX_LoadTexMtxImm(mh3, GX_TEXMTX5, GX_MTX2x4);
|
|
|
|
GX_LoadTexMtxImm(mh4, GX_TEXMTX6, GX_MTX2x4);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX1);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX2);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD3, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX3);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX4);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD5, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX5);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD6, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX6);
|
|
|
|
switch (m_blurRadius)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, kGauss3);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, kGauss5);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, kGauss7);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, kBox);
|
|
|
|
}
|
|
|
|
GX_SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0_R);
|
|
|
|
GX_SetTevKColorSel(GX_TEVSTAGE1, GX_TEV_KCSEL_K0_G);
|
|
|
|
GX_SetTevKColorSel(GX_TEVSTAGE2, GX_TEV_KCSEL_K0_G);
|
|
|
|
GX_SetTevKColorSel(GX_TEVSTAGE3, GX_TEV_KCSEL_K0_B);
|
|
|
|
GX_SetTevKColorSel(GX_TEVSTAGE4, GX_TEV_KCSEL_K0_B);
|
|
|
|
GX_SetTevKColorSel(GX_TEVSTAGE5, GX_TEV_KCSEL_K0_A);
|
|
|
|
GX_SetTevKColorSel(GX_TEVSTAGE6, GX_TEV_KCSEL_K0_A);
|
|
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K0_R);
|
|
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE1, GX_TEV_KASEL_K0_G);
|
|
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE2, GX_TEV_KASEL_K0_G);
|
|
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE3, GX_TEV_KASEL_K0_B);
|
|
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE4, GX_TEV_KASEL_K0_B);
|
|
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE5, GX_TEV_KASEL_K0_A);
|
|
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE6, GX_TEV_KASEL_K0_A);
|
|
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
|
|
|
|
GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_KONST, GX_CC_ZERO);
|
|
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_KONST, GX_CA_ZERO);
|
|
|
|
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
for (int i = 1; i < kSize; ++i)
|
|
|
|
{
|
|
|
|
GX_SetTevOrder(GX_TEVSTAGE0 + i, GX_TEXCOORD0 + i, GX_TEXMAP0, GX_COLORNULL);
|
|
|
|
GX_SetTevColorIn(GX_TEVSTAGE0 + i, GX_CC_ZERO, GX_CC_TEXC, GX_CC_KONST, GX_CC_CPREV);
|
|
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0 + i, GX_CA_ZERO, GX_CA_TEXA, GX_CA_KONST, GX_CA_APREV);
|
|
|
|
GX_SetTevColorOp(GX_TEVSTAGE0 + i, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0 + i, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
}
|
|
|
|
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
|
|
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
|
|
|
|
GX_SetViewport(0, 0, 640.f, 480.f, 0.f, 1.f);
|
|
|
|
guOrtho(projMtx, 0, 480.f + 0, 0, 640.f + 0, 0.f, 1000.0f);
|
|
|
|
GX_LoadProjectionMtx(projMtx, GX_ORTHOGRAPHIC);
|
|
|
|
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_TEX0, GX_DIRECT);
|
|
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
|
|
|
GX_SetAlphaUpdate(GX_TRUE);
|
|
|
|
GX_SetCullMode(GX_CULL_NONE);
|
|
|
|
guMtxIdentity(modelViewMtx);
|
|
|
|
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
|
|
GX_Position3f32(x, y, 0.f);
|
|
|
|
GX_TexCoord2f32(0.f, 0.f);
|
|
|
|
GX_Position3f32(x + w, y, 0.f);
|
|
|
|
GX_TexCoord2f32(1.f, 0.f);
|
|
|
|
GX_Position3f32(x + w, y + h, 0.f);
|
|
|
|
GX_TexCoord2f32(1.f, 1.f);
|
|
|
|
GX_Position3f32(x, y + h, 0.f);
|
|
|
|
GX_TexCoord2f32(0.f, 1.f);
|
|
|
|
GX_End();
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.renderToTexture(m_effectTex, true);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CCoverFlow::_effectVisible(void)
|
|
|
|
{
|
|
|
|
SLayout &lo = m_selected ? m_loSelected : m_loNormal;
|
|
|
|
return (m_mirrorAlpha > 0.01f && m_mirrorBlur)
|
|
|
|
|| lo.shadowColorCenter.a > 0 || lo.shadowColorBeg.a > 0
|
|
|
|
|| lo.shadowColorEnd.a > 0 || lo.shadowColorOff.a > 0;
|
|
|
|
}
|
|
|
|
|
2012-12-28 15:19:40 +01:00
|
|
|
void CCoverFlow::makeEffectTexture(const TexData * &bg)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
if (!_effectVisible()) return;
|
|
|
|
int aa = 8;
|
|
|
|
|
|
|
|
GX_SetDither(GX_DISABLE);
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.setAA(aa, true, m_effectTex.width, m_effectTex.height);
|
2012-01-21 21:57:41 +01:00
|
|
|
for (int i = 0; i < aa; ++i)
|
|
|
|
{
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.prepareAAPass(i);
|
|
|
|
m_vid.setup2DProjection(false, true);
|
2012-01-21 21:57:41 +01:00
|
|
|
_effectBg(bg);
|
|
|
|
if (m_mirrorBlur)
|
|
|
|
_draw(CCoverFlow::CFDR_NORMAL, true, false);
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.shiftViewPort(m_shadowX, m_shadowY);
|
2012-01-21 21:57:41 +01:00
|
|
|
_draw(CCoverFlow::CFDR_SHADOW, false, true);
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.renderAAPass(i);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
GX_SetPixelFmt(GX_PF_RGBA6_Z24, GX_ZC_LINEAR);
|
|
|
|
GX_InvVtxCache();
|
|
|
|
GX_InvalidateTexAll();
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.setup2DProjection(false, true);
|
2012-01-21 21:57:41 +01:00
|
|
|
GX_SetViewport(0.f, 0.f, (float)m_effectTex.width, (float)m_effectTex.height, 0.f, 1.f);
|
|
|
|
GX_SetScissor(0, 0, m_effectTex.width, m_effectTex.height);
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.drawAAScene();
|
|
|
|
m_vid.renderToTexture(m_effectTex, true);
|
|
|
|
_effectBlur(false);
|
|
|
|
_effectBlur(true);
|
2012-01-21 21:57:41 +01:00
|
|
|
GX_SetDither(GX_ENABLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::drawEffect(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
if (_effectVisible())
|
|
|
|
{
|
|
|
|
Mtx modelViewMtx;
|
|
|
|
GXTexObj texObj;
|
|
|
|
float w = 640.f;
|
|
|
|
float h = 480.f;
|
|
|
|
float x = 0.f;
|
|
|
|
float y = 0.f;
|
|
|
|
|
|
|
|
GX_SetNumTevStages(1);
|
|
|
|
GX_SetNumChans(0);
|
|
|
|
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_TEX0, GX_DIRECT);
|
|
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
|
|
|
GX_SetNumTexGens(1);
|
|
|
|
GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
|
|
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
|
|
|
|
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
|
|
|
|
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_FALSE);
|
|
|
|
GX_SetCullMode(GX_CULL_NONE);
|
|
|
|
GX_SetZMode(GX_ENABLE, GX_LEQUAL, GX_FALSE);
|
|
|
|
guMtxIdentity(modelViewMtx);
|
|
|
|
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
|
2012-11-03 20:16:03 +01:00
|
|
|
GX_InitTexObj(&texObj, m_effectTex.data, m_effectTex.width, m_effectTex.height, m_effectTex.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
2012-01-21 21:57:41 +01:00
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
|
|
GX_Position3f32(x, y, -999.f);
|
|
|
|
GX_TexCoord2f32(0.f, 0.f);
|
|
|
|
GX_Position3f32(x + w, y, -999.f);
|
|
|
|
GX_TexCoord2f32(1.f, 0.f);
|
|
|
|
GX_Position3f32(x + w, y + h, -999.f);
|
|
|
|
GX_TexCoord2f32(1.f, 1.f);
|
|
|
|
GX_Position3f32(x, y + h, -999.f);
|
|
|
|
GX_TexCoord2f32(0.f, 1.f);
|
|
|
|
GX_End();
|
|
|
|
}
|
|
|
|
if (!m_mirrorBlur)
|
|
|
|
_draw(CCoverFlow::CFDR_NORMAL, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::draw(void)
|
|
|
|
{
|
|
|
|
_draw();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::drawText(bool withRectangle)
|
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
Vector3D up(0.f, 1.f, 0.f);
|
|
|
|
Vector3D dir(m_cameraAim);
|
|
|
|
Vector3D pos(m_cameraPos);
|
|
|
|
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
if (m_fontColor.a == 0) return;
|
|
|
|
|
|
|
|
pos += _cameraMoves();
|
|
|
|
// Camera
|
|
|
|
GX_LoadProjectionMtx(m_projMtx, GX_PERSPECTIVE);
|
|
|
|
guLookAt(m_viewMtx, &pos, &up, &dir);
|
|
|
|
// Text
|
|
|
|
GX_SetNumChans(1);
|
|
|
|
GX_SetCullMode(GX_CULL_NONE);
|
|
|
|
GX_SetZMode(GX_DISABLE, GX_LEQUAL, GX_FALSE);
|
|
|
|
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
|
|
for (u32 i = 0; i < m_range; ++i)
|
|
|
|
{
|
|
|
|
_drawTitle(loopNum((i & 1) != 0 ? m_range / 2 - (i + 1) / 2 : m_range / 2 + i / 2, m_range), true, withRectangle);
|
|
|
|
_drawTitle(loopNum((i & 1) != 0 ? m_range / 2 - (i + 1) / 2 : m_range / 2 + i / 2, m_range), false, withRectangle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::hideCover(void)
|
|
|
|
{
|
|
|
|
m_hideCover = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::showCover(void)
|
|
|
|
{
|
|
|
|
m_hideCover = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int innerToOuter(int i, int range)
|
|
|
|
{
|
|
|
|
return loopNum((i & 1) != 0 ? range / 2 - (i + 1) / 2 : range / 2 + i / 2, range);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_draw(DrawMode dm, bool mirror, bool blend)
|
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
Vector3D up(0.f, 1.f, 0.f);
|
|
|
|
Vector3D dir(m_cameraAim);
|
|
|
|
Vector3D pos(m_cameraPos);
|
|
|
|
|
|
|
|
if (mirror && m_mirrorAlpha <= 0.f) return;
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
pos += _cameraMoves();
|
|
|
|
// GX setup
|
|
|
|
GX_ClearVtxDesc();
|
|
|
|
GX_SetNumTevStages(1);
|
|
|
|
if (dm == CCoverFlow::CFDR_NORMAL)
|
|
|
|
{
|
|
|
|
GX_SetNumChans(0);
|
|
|
|
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
|
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 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_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_KONST, GX_CC_TEXC, GX_CC_ZERO);
|
|
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_KONST, GX_CA_TEXA, GX_CA_ZERO);
|
|
|
|
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
|
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GX_SetNumChans(1);
|
|
|
|
GX_SetNumTexGens(0);
|
|
|
|
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
|
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
|
|
|
GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_KONST);
|
|
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST);
|
|
|
|
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLORNULL);
|
|
|
|
}
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, CColor(0xFF, 0xFF, 0xFF, 0xFF));
|
|
|
|
GX_SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0);
|
|
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K0_A);
|
|
|
|
if (blend)
|
|
|
|
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
|
|
else
|
|
|
|
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
|
|
GX_SetAlphaUpdate(GX_TRUE);
|
|
|
|
// Camera
|
|
|
|
GX_LoadProjectionMtx(m_projMtx, GX_PERSPECTIVE);
|
|
|
|
guLookAt(m_viewMtx, &pos, &up, &dir);
|
|
|
|
// Covers
|
|
|
|
GX_SetCullMode(m_box ? (mirror ? GX_CULL_BACK : GX_CULL_FRONT) : GX_CULL_NONE);
|
|
|
|
if (dm == CCoverFlow::CFDR_SHADOW)
|
|
|
|
{
|
|
|
|
// Shadow
|
|
|
|
GX_SetZMode(GX_DISABLE, GX_LEQUAL, GX_FALSE);
|
|
|
|
for (int x = (int)m_columns - 3; x >= 0; --x)
|
|
|
|
{
|
|
|
|
int xx = innerToOuter(x, m_columns);
|
|
|
|
if (m_rows >= 3)
|
|
|
|
for (int y = (int)m_rows - 3; y >= 0; --y)
|
|
|
|
_drawCover(xx * m_rows + innerToOuter(y, m_rows), mirror, dm);
|
|
|
|
else
|
|
|
|
_drawCover(xx, mirror, dm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Normal
|
|
|
|
GX_SetZMode(GX_ENABLE, GX_LEQUAL, GX_TRUE);
|
|
|
|
for (int x = 0; x < (int)m_columns - 2; ++x)
|
|
|
|
{
|
|
|
|
int xx = innerToOuter(x, m_columns);
|
|
|
|
if (m_rows >= 3)
|
|
|
|
for (int y = 0; y < (int)m_rows - 2; ++y)
|
|
|
|
_drawCover(xx * m_rows + innerToOuter(y, m_rows), mirror, dm);
|
|
|
|
else
|
|
|
|
_drawCover(xx, mirror, dm);
|
|
|
|
}
|
|
|
|
// Vanishing covers
|
|
|
|
GX_SetZMode(GX_ENABLE, GX_LEQUAL, GX_FALSE);
|
|
|
|
for (u32 y = 0; y < m_rows; ++y)
|
|
|
|
{
|
|
|
|
_drawCover(y, mirror, dm);
|
|
|
|
_drawCover((m_columns - 1) * m_rows + y, mirror, dm);
|
|
|
|
}
|
|
|
|
if (m_rows >= 3)
|
|
|
|
for (u32 x = 1; x < m_columns - 1; ++x)
|
|
|
|
{
|
|
|
|
_drawCover(x * m_rows, mirror, dm);
|
|
|
|
_drawCover(x * m_rows + m_rows - 1, mirror, dm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3D CCoverFlow::_cameraMoves(void)
|
|
|
|
{
|
|
|
|
SLayout &lo = m_selected ? m_loSelected : m_loNormal;
|
|
|
|
float tick = (float)m_tickCount * 0.005f;
|
|
|
|
return Vector3D(cos(tick * lo.cameraOscSpeed.x) * lo.cameraOscAmp.x,
|
|
|
|
cos(tick * lo.cameraOscSpeed.y) * lo.cameraOscAmp.y,
|
|
|
|
cos(tick * lo.cameraOscSpeed.z) * lo.cameraOscAmp.z);
|
|
|
|
}
|
|
|
|
|
- PHASE 2 (finally!)
- New Coverflow theme format. no more emuflow, coverflow, brewflow. now we have coverflow, shortflow, sideflow, and smallflow.
- coverflow is the normal coverflow.
- shortflow is automatically used for plugins if all selected plugins require a short CD style cover such as GB, GBC, GBA, and playstation. if there's more let me know and i can add them.
- sideflow is automatically used for plugins if all selected plugins require a cover on its side such as SNES and Nintendo 64.
- smallflow is used if smallbox is set for homebrew and sourceflow.
- no more need for emuflow= with a source btn in the source menu. it is done automatically now using the plugins magic#
- each flow has its own number of modes/layouts. so now coveflow can have 8, smallfow 1, sideflow, 6, and shortflow 4 or whatever you want.
- adjust coverflow works with no problems. just choose the view first before entering the adjust coverflow menu.
- other minor code changes here and there.
- remember themes are now in themes_lite and the coverflow part is seperated and put in the coverflows folder with the same name as the theme or you can use a default coverflow named default.ini for all themes.
2016-05-11 19:58:36 +02:00
|
|
|
Vector3D CCoverFlow::_coverMovesA(void)//angle
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
SLayout &lo = m_selected ? m_loSelected : m_loNormal;
|
|
|
|
float tick = (float)m_tickCount * 0.005f;
|
|
|
|
return Vector3D(cos(tick * lo.coverOscASpeed.x) * lo.coverOscAAmp.x,
|
|
|
|
sin(tick * lo.coverOscASpeed.y) * lo.coverOscAAmp.y,
|
|
|
|
cos(tick * lo.coverOscASpeed.z) * lo.coverOscAAmp.z);
|
|
|
|
}
|
|
|
|
|
- PHASE 2 (finally!)
- New Coverflow theme format. no more emuflow, coverflow, brewflow. now we have coverflow, shortflow, sideflow, and smallflow.
- coverflow is the normal coverflow.
- shortflow is automatically used for plugins if all selected plugins require a short CD style cover such as GB, GBC, GBA, and playstation. if there's more let me know and i can add them.
- sideflow is automatically used for plugins if all selected plugins require a cover on its side such as SNES and Nintendo 64.
- smallflow is used if smallbox is set for homebrew and sourceflow.
- no more need for emuflow= with a source btn in the source menu. it is done automatically now using the plugins magic#
- each flow has its own number of modes/layouts. so now coveflow can have 8, smallfow 1, sideflow, 6, and shortflow 4 or whatever you want.
- adjust coverflow works with no problems. just choose the view first before entering the adjust coverflow menu.
- other minor code changes here and there.
- remember themes are now in themes_lite and the coverflow part is seperated and put in the coverflows folder with the same name as the theme or you can use a default coverflow named default.ini for all themes.
2016-05-11 19:58:36 +02:00
|
|
|
Vector3D CCoverFlow::_coverMovesP(void)//position
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
SLayout &lo = m_selected ? m_loSelected : m_loNormal;
|
|
|
|
float tick = (float)m_tickCount * 0.005f;
|
|
|
|
return Vector3D(cos(tick * lo.coverOscPSpeed.x) * lo.coverOscPAmp.x,
|
|
|
|
sin(tick * lo.coverOscPSpeed.y) * lo.coverOscPAmp.y,
|
|
|
|
cos(tick * lo.coverOscPSpeed.z) * lo.coverOscPAmp.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_drawTitle(int i, bool mirror, bool rectangle)
|
|
|
|
{
|
|
|
|
Mtx modelMtx;
|
|
|
|
Mtx modelViewMtx;
|
|
|
|
Vector3D rotAxis(0.f, 1.f, 0.f);
|
2018-10-25 00:05:02 +02:00
|
|
|
CColor color(m_fontColor);
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
if (m_hideCover) return;
|
|
|
|
if (m_covers[i].txtColor == 0) return;
|
|
|
|
|
|
|
|
color.a = mirror ? (u8)((float)m_covers[i].txtColor * m_txtMirrorAlpha) : m_covers[i].txtColor;
|
2018-07-09 16:53:35 +02:00
|
|
|
|
|
|
|
// rectangle is never used. in menu.cpp _mainLoopCommon() adjusting is never set true
|
|
|
|
// but if it would be. rectangle is the same as using a frame for the text as when the gui draws a label.
|
|
|
|
// when using a frame the text style is used. otherwise it is not used.
|
|
|
|
if (rectangle && !mirror)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
// GX setup
|
|
|
|
GX_SetNumTevStages(1);
|
|
|
|
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_SetNumTexGens(0);
|
|
|
|
GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
|
|
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA);
|
|
|
|
GX_SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0);
|
|
|
|
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
|
|
//
|
|
|
|
Mtx rotMtx;
|
|
|
|
guMtxIdentity(modelMtx);
|
|
|
|
guMtxScaleApply(modelMtx, modelMtx, 0.005f, 0.005f, 0.005f);
|
|
|
|
guMtxRotDeg(rotMtx, 'Y', m_covers[i].txtAngle);
|
|
|
|
guMtxConcat(rotMtx, modelMtx, modelMtx);
|
|
|
|
guMtxTransApply(modelMtx, modelMtx, m_covers[i].txtPos.x, mirror ? -m_covers[i].txtPos.y : m_covers[i].txtPos.y, m_covers[i].txtPos.z);
|
|
|
|
guMtxConcat(m_viewMtx, modelMtx, modelViewMtx);
|
|
|
|
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
|
|
|
|
const SLayout &lo = m_selected ? m_loSelected : m_loNormal;
|
|
|
|
u16 s = (u32)i == m_range / 2 ? lo.txtCenterStyle : lo.txtSideStyle;
|
|
|
|
float x;
|
|
|
|
float y;
|
|
|
|
float w = (u32)i == m_range / 2 ? lo.txtCenterWidth : lo.txtSideWidth;
|
|
|
|
float h = m_font.lineSpacing;
|
|
|
|
if ((s & FTGX_JUSTIFY_CENTER) != 0)
|
|
|
|
x = -w * 0.5f;
|
|
|
|
else if ((s & FTGX_JUSTIFY_RIGHT) != 0)
|
|
|
|
x = -w;
|
|
|
|
else
|
|
|
|
x = 0.f;
|
|
|
|
if ((s & FTGX_ALIGN_MIDDLE) != 0)
|
|
|
|
y = -h * 0.5f;
|
|
|
|
else if ((s & FTGX_ALIGN_TOP) != 0)
|
|
|
|
y = -h;
|
|
|
|
else
|
|
|
|
y = 0.f;
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
|
|
GX_Position3f32(x, y, 0.f);
|
|
|
|
GX_Color4u8(color.r, color.g, color.b, color.a / 2);
|
|
|
|
GX_Position3f32(x + w, y, 0.f);
|
|
|
|
GX_Color4u8(color.r, color.g, color.b, color.a / 2);
|
|
|
|
GX_Position3f32(x + w, y + h, 0.f);
|
|
|
|
GX_Color4u8(color.r, color.g, color.b, color.a / 2);
|
|
|
|
GX_Position3f32(x, y + h, 0.f);
|
|
|
|
GX_Color4u8(color.r, color.g, color.b, color.a / 2);
|
|
|
|
GX_End();
|
|
|
|
}
|
|
|
|
m_covers[i].title.setColor(color);
|
|
|
|
m_font.font->reset();
|
|
|
|
m_font.font->setXScale(0.005f);
|
|
|
|
m_font.font->setYScale(mirror ? 0.005f : -0.005f);
|
|
|
|
GX_ClearVtxDesc();
|
|
|
|
GX_SetNumTevStages(1);
|
|
|
|
GX_SetNumChans(1);
|
|
|
|
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_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
|
|
//
|
|
|
|
guMtxIdentity(modelMtx);
|
|
|
|
guMtxRotAxisDeg(modelMtx, &rotAxis, m_covers[i].txtAngle);
|
|
|
|
guMtxTransApply(modelMtx, modelMtx, m_covers[i].txtPos.x, mirror ? -m_covers[i].txtPos.y : m_covers[i].txtPos.y, m_covers[i].txtPos.z);
|
|
|
|
guMtxConcat(m_viewMtx, modelMtx, modelViewMtx);
|
|
|
|
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
|
|
|
|
m_covers[i].title.draw();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_drawCover(int i, bool mirror, CCoverFlow::DrawMode dm)
|
|
|
|
{
|
|
|
|
Mtx modelMtx;
|
|
|
|
Mtx rotMtx;
|
|
|
|
Mtx modelViewMtx;
|
|
|
|
Vector3D osc;
|
|
|
|
Vector3D oscP;
|
|
|
|
|
|
|
|
if (m_hideCover)
|
|
|
|
return;
|
|
|
|
if (m_covers[i].color.a == 0 || (dm == CCoverFlow::CFDR_SHADOW && m_covers[i].shadowColor.a == 0))
|
|
|
|
return;
|
|
|
|
if (dm == CCoverFlow::CFDR_STENCIL && (i > 0xFF || _invisibleCover(i / m_rows, i % m_rows)))
|
|
|
|
return;
|
|
|
|
if ((u32)i == m_range / 2)
|
|
|
|
{
|
|
|
|
osc = _coverMovesA();
|
|
|
|
oscP = _coverMovesP();
|
|
|
|
}
|
|
|
|
//
|
|
|
|
guMtxIdentity(modelMtx);
|
|
|
|
guMtxScaleApply(modelMtx, modelMtx, m_covers[i].scale.x, m_covers[i].scale.y, m_covers[i].scale.z);
|
|
|
|
if (dm == CCoverFlow::CFDR_SHADOW)
|
|
|
|
guMtxScaleApply(modelMtx, modelMtx, 1.f + (m_shadowScale - 1.f) * g_boxSize.y / g_boxSize.x, m_shadowScale, m_shadowScale);
|
|
|
|
guMtxRotDeg(rotMtx, 'Z', m_covers[i].angle.z + osc.z);
|
|
|
|
guMtxConcat(rotMtx, modelMtx, modelMtx);
|
|
|
|
guMtxRotDeg(rotMtx, 'X', m_covers[i].angle.x + osc.x);
|
|
|
|
guMtxConcat(rotMtx, modelMtx, modelMtx);
|
|
|
|
guMtxRotDeg(rotMtx, 'Y', m_covers[i].angle.y + osc.y);
|
|
|
|
guMtxConcat(rotMtx, modelMtx, modelMtx);
|
|
|
|
guMtxTransApply(modelMtx, modelMtx, m_covers[i].pos.x + oscP.x, m_covers[i].pos.y + oscP.y + g_coverYCenter, m_covers[i].pos.z + oscP.z);
|
|
|
|
if (mirror)
|
|
|
|
guMtxScaleApply(modelMtx, modelMtx, 1.f, -1.f, 1.f);
|
|
|
|
guMtxConcat(m_viewMtx, modelMtx, modelViewMtx);
|
|
|
|
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
|
|
|
|
// Cover
|
|
|
|
if (m_box)
|
|
|
|
_drawCoverBox(i, mirror, dm);
|
|
|
|
else
|
|
|
|
_drawCoverFlat(i, mirror, dm);
|
|
|
|
}
|
|
|
|
|
2013-01-13 16:45:05 +01:00
|
|
|
const TexData *CCoverFlow::_coverTexture(int i)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-11-03 20:16:03 +01:00
|
|
|
if(m_items[i].texture.data == NULL)
|
2019-02-26 22:49:47 +01:00
|
|
|
{
|
|
|
|
if(m_box)
|
|
|
|
return (m_items[i].state == STATE_Loading) ? &m_boxLoadingTexture : &m_boxNoCoverTexture;
|
|
|
|
else
|
|
|
|
return (m_items[i].state == STATE_Loading) ? &m_flatLoadingTexture : &m_flatNoCoverTexture;
|
|
|
|
}
|
2013-01-13 16:45:05 +01:00
|
|
|
return &m_items[i].texture;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_drawCoverFlat(int i, bool mirror, CCoverFlow::DrawMode dm)
|
|
|
|
{
|
|
|
|
GXTexObj texObj;
|
2013-01-13 16:45:05 +01:00
|
|
|
const TexData *tex = _coverTexture(m_covers[i].index);
|
2012-01-21 21:57:41 +01:00
|
|
|
bool boxTex = m_items[m_covers[i].index].boxTexture && !!m_items[m_covers[i].index].texture.data;
|
|
|
|
|
|
|
|
switch (dm)
|
|
|
|
{
|
|
|
|
case CCoverFlow::CFDR_NORMAL:
|
|
|
|
{
|
|
|
|
CColor color(m_covers[i].color);
|
|
|
|
if (mirror)
|
|
|
|
color.a = (u8)((float)color.a * m_mirrorAlpha);
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, color);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CCoverFlow::CFDR_STENCIL:
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, CColor(i + 1, 0xFF, 0xFF, 0xFF));
|
|
|
|
break;
|
|
|
|
case CCoverFlow::CFDR_SHADOW:
|
|
|
|
{
|
|
|
|
CColor color(m_covers[i].shadowColor);
|
|
|
|
if (mirror)
|
|
|
|
color.a = (u8)((float)color.a * m_mirrorAlpha);
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, color);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-01-13 16:45:05 +01:00
|
|
|
if(dm == CCoverFlow::CFDR_NORMAL)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-01-13 16:45:05 +01:00
|
|
|
GX_InitTexObj(&texObj, tex->data, tex->width, tex->height, tex->format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
if(tex->maxLOD > 0)
|
|
|
|
GX_InitTexObjLOD(&texObj, GX_LIN_MIP_LIN, GX_LINEAR, 0.f, (float)tex->maxLOD, mirror ? 1.f : m_lodBias, GX_FALSE, m_edgeLOD ? GX_TRUE : GX_FALSE, m_aniso);
|
2012-01-21 21:57:41 +01:00
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
}
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, g_flatCoverMeshSize);
|
|
|
|
for (u32 j = 0; j < g_flatCoverMeshSize; ++j)
|
2012-03-14 21:00:01 +01:00
|
|
|
{
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_Position3f32(g_flatCoverMesh[j].pos.x, g_flatCoverMesh[j].pos.y, g_flatCoverMesh[j].pos.z);
|
|
|
|
if (dm == CCoverFlow::CFDR_NORMAL)
|
2012-03-14 21:00:01 +01:00
|
|
|
{
|
2012-04-08 17:54:34 +02:00
|
|
|
if (boxTex)
|
|
|
|
GX_TexCoord2f32(g_flatCoverBoxTex[j].x, g_flatCoverBoxTex[j].y);
|
|
|
|
else
|
|
|
|
GX_TexCoord2f32(g_flatCoverMesh[j].texCoord.x, g_flatCoverMesh[j].texCoord.y);
|
2012-03-14 21:00:01 +01:00
|
|
|
}
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_End();
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2013-01-13 16:45:05 +01:00
|
|
|
bool CCoverFlow::checkCoverColor(const char *gameID, const char *checkID[], u32 len)
|
2012-02-02 18:21:10 +01:00
|
|
|
{
|
2013-01-13 16:45:05 +01:00
|
|
|
for(u32 num = 0; num < len; ++num)
|
2012-02-02 18:21:10 +01:00
|
|
|
{
|
|
|
|
if (strncmp(gameID, checkID[num], strlen(checkID[num])) == 0)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-13 16:45:05 +01:00
|
|
|
u32 CCoverFlow::InternalCoverColor(const char *ID, u32 DefCaseColor)
|
|
|
|
{
|
|
|
|
if(checkCoverColor(ID, red, red_len))
|
|
|
|
return 0xFF0000;
|
|
|
|
else if(checkCoverColor(ID, black, black_len))
|
|
|
|
return 0x000000;
|
|
|
|
else if(checkCoverColor(ID, yellow, yellow_len))
|
|
|
|
return 0xFCFF00;
|
|
|
|
else if(checkCoverColor(ID, greenOne, greenOne_len))
|
|
|
|
return 0x01A300;
|
|
|
|
else if(checkCoverColor(ID, greenTwo, greenTwo_len))
|
|
|
|
return 0x00E360;
|
|
|
|
return DefCaseColor;
|
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
void CCoverFlow::_drawCoverBox(int i, bool mirror, CCoverFlow::DrawMode dm)
|
|
|
|
{
|
|
|
|
CColor color;
|
2013-01-13 16:45:05 +01:00
|
|
|
GXTexObj texObj;
|
|
|
|
const TexData *tex = _coverTexture(m_covers[i].index);
|
2012-01-21 21:57:41 +01:00
|
|
|
bool flatTex = !m_items[m_covers[i].index].boxTexture && !!m_items[m_covers[i].index].texture.data;
|
|
|
|
|
|
|
|
switch (dm)
|
|
|
|
{
|
|
|
|
case CCoverFlow::CFDR_NORMAL:
|
|
|
|
color = m_covers[i].color;
|
|
|
|
if (mirror)
|
|
|
|
color.a = (u8)((float)color.a * m_mirrorAlpha);
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, color);
|
|
|
|
break;
|
|
|
|
case CCoverFlow::CFDR_STENCIL:
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, CColor(i + 1, 0xFF, 0xFF, 0xFF));
|
|
|
|
break;
|
|
|
|
case CCoverFlow::CFDR_SHADOW:
|
|
|
|
color = m_covers[i].shadowColor;
|
|
|
|
if (mirror)
|
|
|
|
color.a = (u8)((float)color.a * m_mirrorAlpha);
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, color);
|
|
|
|
break;
|
|
|
|
}
|
2019-02-26 22:49:47 +01:00
|
|
|
/* this draws the colored spine of the box */
|
2013-01-13 16:45:05 +01:00
|
|
|
if(dm == CCoverFlow::CFDR_NORMAL)
|
2012-02-02 18:21:10 +01:00
|
|
|
{
|
2019-02-26 22:49:47 +01:00
|
|
|
// set dvd spine color texture, depending on game
|
2013-01-13 16:45:05 +01:00
|
|
|
switch(m_items[m_covers[i].index].hdr->casecolor)
|
2012-02-17 14:26:57 +01:00
|
|
|
{
|
2013-01-13 16:45:05 +01:00
|
|
|
case 0x000000:
|
|
|
|
case 0x181919:
|
|
|
|
GX_InitTexObj(&texObj, m_dvdSkin_Black.data, m_dvdSkin_Black.width, m_dvdSkin_Black.height, m_dvdSkin_Black.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
break;
|
|
|
|
case 0xFF0000:
|
|
|
|
GX_InitTexObj(&texObj, m_dvdSkin_Red.data, m_dvdSkin_Red.width, m_dvdSkin_Red.height, m_dvdSkin_Red.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
break;
|
|
|
|
case 0xFCFF00:
|
|
|
|
GX_InitTexObj(&texObj, m_dvdSkin_Yellow.data, m_dvdSkin_Yellow.width, m_dvdSkin_Yellow.height, m_dvdSkin_Yellow.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
break;
|
|
|
|
case 0x01A300:
|
|
|
|
GX_InitTexObj(&texObj, m_dvdSkin_GreenOne.data, m_dvdSkin_GreenOne.width, m_dvdSkin_GreenOne.height, m_dvdSkin_GreenOne.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
break;
|
|
|
|
case 0x00E360:
|
|
|
|
GX_InitTexObj(&texObj, m_dvdSkin_GreenTwo.data, m_dvdSkin_GreenTwo.width, m_dvdSkin_GreenTwo.height, m_dvdSkin_GreenTwo.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
break;
|
2020-11-16 22:11:04 +01:00
|
|
|
case 0x111111:
|
|
|
|
GX_InitTexObj(&texObj, m_dvdSkin_Clear.data, m_dvdSkin_Clear.width, m_dvdSkin_Clear.height, m_dvdSkin_Clear.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
break;
|
2013-01-13 16:45:05 +01:00
|
|
|
default:
|
|
|
|
GX_InitTexObj(&texObj, m_dvdSkin.data, m_dvdSkin.width, m_dvdSkin.height, m_dvdSkin.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
break;
|
2012-02-17 14:26:57 +01:00
|
|
|
}
|
2012-01-21 21:57:41 +01:00
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
}
|
2019-02-26 22:49:47 +01:00
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, g_boxMeshQSize);// Quads
|
2012-04-08 17:54:34 +02:00
|
|
|
for (u32 j = 0; j < g_boxMeshQSize; ++j)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_Position3f32(g_boxMeshQ[j].pos.x, g_boxMeshQ[j].pos.y, g_boxMeshQ[j].pos.z);
|
2012-01-21 21:57:41 +01:00
|
|
|
if (dm == CCoverFlow::CFDR_NORMAL)
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_TexCoord2f32(g_boxMeshQ[j].texCoord.x, g_boxMeshQ[j].texCoord.y);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_End();
|
2019-02-26 22:49:47 +01:00
|
|
|
GX_Begin(GX_TRIANGLES, GX_VTXFMT0, g_boxMeshTSize);// triangles
|
2012-04-08 17:54:34 +02:00
|
|
|
for (u32 j = 0; j < g_boxMeshTSize; ++j)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_Position3f32(g_boxMeshT[j].pos.x, g_boxMeshT[j].pos.y, g_boxMeshT[j].pos.z);
|
|
|
|
if (dm == CCoverFlow::CFDR_NORMAL)
|
|
|
|
GX_TexCoord2f32(g_boxMeshT[j].texCoord.x, g_boxMeshT[j].texCoord.y);
|
|
|
|
}
|
|
|
|
GX_End();
|
2019-02-26 22:49:47 +01:00
|
|
|
/* draw back of cover and title spine texture */
|
2012-04-08 17:54:34 +02:00
|
|
|
if (dm == CCoverFlow::CFDR_NORMAL)
|
|
|
|
{
|
2013-01-13 16:45:05 +01:00
|
|
|
const TexData *myTex = tex;
|
2019-02-26 22:49:47 +01:00
|
|
|
/* if we have front cover texture only then draw back and spine textures using the default box no cover texture */
|
2013-01-13 16:45:05 +01:00
|
|
|
if(flatTex)
|
2019-02-26 22:49:47 +01:00
|
|
|
myTex = &m_boxNoCoverTexture;
|
2012-11-03 20:16:03 +01:00
|
|
|
GX_InitTexObj(&texObj, myTex->data, myTex->width, myTex->height, myTex->format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
2012-04-08 17:54:34 +02:00
|
|
|
if (myTex->maxLOD > 0)
|
|
|
|
GX_InitTexObjLOD(&texObj, GX_LIN_MIP_LIN, GX_LINEAR, 0.f, (float)myTex->maxLOD, mirror ? 1.f : m_lodBias, GX_FALSE, m_edgeLOD ? GX_TRUE : GX_FALSE, m_aniso);
|
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
}
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, g_boxBackCoverMeshSize);
|
|
|
|
for (u32 j = 0; j < g_boxBackCoverMeshSize; ++j)
|
|
|
|
{
|
|
|
|
GX_Position3f32(g_boxBackCoverMesh[j].pos.x, g_boxBackCoverMesh[j].pos.y, g_boxBackCoverMesh[j].pos.z);
|
|
|
|
if (dm == CCoverFlow::CFDR_NORMAL)
|
|
|
|
GX_TexCoord2f32(g_boxBackCoverMesh[j].texCoord.x, g_boxBackCoverMesh[j].texCoord.y);
|
|
|
|
}
|
|
|
|
GX_End();
|
2019-02-26 22:49:47 +01:00
|
|
|
/* draw front of cover texture */
|
|
|
|
/* if front cover only we need to change texObj from box no cover texture to the front cover texture */
|
2012-04-08 17:54:34 +02:00
|
|
|
if (dm == CCoverFlow::CFDR_NORMAL && flatTex)
|
|
|
|
{
|
2013-01-13 16:45:05 +01:00
|
|
|
GX_InitTexObj(&texObj, tex->data, tex->width, tex->height, tex->format, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
if (tex->maxLOD > 0)
|
|
|
|
GX_InitTexObjLOD(&texObj, GX_LIN_MIP_LIN, GX_LINEAR, 0.f, (float)tex->maxLOD, mirror ? 1.f : m_lodBias, GX_FALSE, m_edgeLOD ? GX_TRUE : GX_FALSE, m_aniso);
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
}
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, g_boxCoverMeshSize);
|
|
|
|
for (u32 j = 0; j < g_boxCoverMeshSize; ++j)
|
|
|
|
{
|
|
|
|
GX_Position3f32(g_boxCoverMesh[j].pos.x, g_boxCoverMesh[j].pos.y, g_boxCoverMesh[j].pos.z);
|
2012-01-21 21:57:41 +01:00
|
|
|
if (dm == CCoverFlow::CFDR_NORMAL)
|
|
|
|
{
|
|
|
|
if (flatTex)
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_TexCoord2f32(g_boxCoverFlatTex[j].x, g_boxCoverFlatTex[j].y);
|
|
|
|
else
|
|
|
|
GX_TexCoord2f32(g_boxCoverMesh[j].texCoord.x, g_boxCoverMesh[j].texCoord.y);
|
2012-03-14 21:00:01 +01:00
|
|
|
}
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
2012-04-08 17:54:34 +02:00
|
|
|
GX_End();
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_loadCover(int i, int item)
|
|
|
|
{
|
|
|
|
m_covers[i].index = item;
|
|
|
|
m_covers[i].title.setText(m_font, m_items[item].hdr->title);
|
|
|
|
}
|
|
|
|
|
2012-12-27 21:22:40 +01:00
|
|
|
const char *CCoverFlow::getId(void) const
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL || m_items.empty()) return "";
|
2012-12-27 21:22:40 +01:00
|
|
|
return m_items[loopNum(m_covers[m_range / 2].index + m_jump, m_items.size())].hdr->id;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2012-12-27 21:22:40 +01:00
|
|
|
const char *CCoverFlow::getNextId(void) const
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL || m_items.empty()) return "";
|
2012-12-27 21:22:40 +01:00
|
|
|
return m_items[loopNum(m_covers[m_range / 2].index + m_jump + 1, m_items.size())].hdr->id;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2013-01-21 00:30:28 +01:00
|
|
|
const dir_discHdr * CCoverFlow::getHdr(void) const
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL || m_items.empty()) return NULL;
|
2012-01-21 21:57:41 +01:00
|
|
|
return m_items[loopNum(m_covers[m_range / 2].index + m_jump, m_items.size())].hdr;
|
|
|
|
}
|
|
|
|
|
2013-01-21 00:30:28 +01:00
|
|
|
const dir_discHdr * CCoverFlow::getNextHdr(void) const
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL || m_items.empty()) return NULL;
|
2012-01-21 21:57:41 +01:00
|
|
|
return m_items[loopNum(m_covers[m_range / 2].index + m_jump + 1, m_items.size())].hdr;
|
|
|
|
}
|
|
|
|
|
2013-03-31 01:57:42 +01:00
|
|
|
const dir_discHdr * CCoverFlow::getSpecificHdr(u32 place) const
|
|
|
|
{
|
|
|
|
if (m_covers == NULL || m_items.empty() || place >= m_items.size()) return NULL;
|
|
|
|
return m_items[place].hdr;
|
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
wstringEx CCoverFlow::getTitle(void) const
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return L"";
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
return m_items[m_covers[m_range / 2].index].hdr->title;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 CCoverFlow::getChanTitle(void) const
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL || m_items.empty()) return 0;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-06-17 12:22:00 +02:00
|
|
|
return TITLE_ID(m_items[loopNum(m_covers[m_range / 2].index + m_jump, m_items.size())].hdr->settings[0],
|
|
|
|
m_items[loopNum(m_covers[m_range / 2].index + m_jump, m_items.size())].hdr->settings[1]);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2020-04-20 15:16:18 +02:00
|
|
|
bool CCoverFlow::getRenderTex(void)
|
|
|
|
{
|
|
|
|
return m_renderTex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::setRenderTex(bool val)
|
|
|
|
{
|
|
|
|
m_renderTex = val;
|
|
|
|
}
|
|
|
|
|
2020-04-08 19:06:21 +02:00
|
|
|
/* this is used for smallbox homebrew icon png's that have alpha transparency */
|
|
|
|
/* cover textures can't have transparency. this creates a new texture by filling the transparent parts */
|
|
|
|
void CCoverFlow::RenderTex(void)
|
|
|
|
{
|
|
|
|
if(m_renderingTex != NULL && m_renderingTex->data != NULL)
|
|
|
|
{
|
|
|
|
DrawTexture(m_renderingTex);
|
|
|
|
m_vid.renderToTexture(*m_renderingTex, true);
|
|
|
|
}
|
2020-04-20 15:16:18 +02:00
|
|
|
setRenderTex(false);
|
2020-04-08 19:06:21 +02:00
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
bool CCoverFlow::select(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL || m_jump != 0) return false;
|
2012-01-21 21:57:41 +01:00
|
|
|
if (m_selected) return true;
|
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
int curPos = (int)m_range / 2;
|
|
|
|
for(int chan = WPAD_MAX_WIIMOTES-1; chan >= 0; chan--)
|
|
|
|
if ((u32)m_mouse[chan] < m_range && m_mouse[chan] != curPos)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
if (m_rows >= 3)
|
|
|
|
j = ((m_mouse[chan] / m_rows - 1) * (m_rows - 2) + m_mouse[chan] % m_rows - 1)
|
|
|
|
- ((curPos / m_rows - 1) * (m_rows - 2) + curPos % m_rows - 1);
|
|
|
|
else
|
|
|
|
j = m_mouse[chan] - (int)(m_range / 2);
|
|
|
|
_setJump(j);
|
|
|
|
}
|
|
|
|
m_cameraPos += _cameraMoves();
|
|
|
|
m_covers[m_range / 2].angle += _coverMovesA();
|
|
|
|
m_covers[m_range / 2].pos += _coverMovesP();
|
|
|
|
m_selected = true;
|
|
|
|
m_covers[m_range / 2].angle -= _coverMovesA();
|
|
|
|
m_covers[m_range / 2].pos -= _coverMovesP();
|
|
|
|
m_cameraPos -= _cameraMoves();
|
|
|
|
_updateAllTargets();
|
|
|
|
_playSound(m_selectSound);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::cancel(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
_unselect();
|
|
|
|
_updateAllTargets();
|
|
|
|
_playSound(m_cancelSound);
|
|
|
|
}
|
|
|
|
|
2019-02-18 21:40:07 +01:00
|
|
|
u32 CCoverFlow::_currentPos(void) const
|
|
|
|
{
|
|
|
|
if (m_covers == NULL) return 0;
|
|
|
|
|
|
|
|
return m_covers[m_range / 2].index;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_setCurPos(u32 index)
|
2012-12-27 21:22:40 +01:00
|
|
|
{
|
2019-02-18 21:40:07 +01:00
|
|
|
_loadAllCovers(index);
|
2016-06-22 21:34:58 +02:00
|
|
|
_updateAllTargets(true);
|
2012-12-27 21:22:40 +01:00
|
|
|
}
|
|
|
|
|
2019-10-17 01:22:40 +02:00
|
|
|
bool CCoverFlow::_setCurPosToCurItem(const char *id, const char *filename, u32 sourceNumber, bool instant)
|
2019-02-18 21:40:07 +01:00
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
u32 i, curPos = _currentPos();
|
|
|
|
|
2019-10-17 01:22:40 +02:00
|
|
|
if(m_items.empty() || (instant && m_covers == NULL))
|
2019-02-18 21:40:07 +01:00
|
|
|
return false;
|
|
|
|
//
|
|
|
|
for(i = 0; i < m_items.size(); ++i)
|
|
|
|
{
|
2019-10-17 01:22:40 +02:00
|
|
|
if(strlen(filename) > 0)
|
2019-02-18 21:40:07 +01:00
|
|
|
{
|
|
|
|
//homebrew folder or rom title.ext
|
|
|
|
const char *name = strrchr(m_items[i].hdr->path, '/');
|
2019-10-17 01:22:40 +02:00
|
|
|
if(name != NULL && strcasecmp(name + 1, filename) == 0)
|
2019-02-18 21:40:07 +01:00
|
|
|
break;
|
2019-10-17 01:22:40 +02:00
|
|
|
else if(strcmp(m_items[i].hdr->path, filename) == 0)// scummvm
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if(strlen(id) > 0)
|
|
|
|
{
|
|
|
|
if(strcasecmp(m_items[i].hdr->id, id) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(m_items[i].hdr->settings[0] == sourceNumber)
|
2019-02-18 21:40:07 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(i >= m_items.size())
|
|
|
|
return false;
|
|
|
|
m_jump = 0;
|
|
|
|
if (instant)
|
|
|
|
{
|
|
|
|
_loadAllCovers(i);
|
|
|
|
_updateAllTargets(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int j = (int)i - (int)curPos;
|
|
|
|
if (abs(j) <= (int)m_items.size() / 2)
|
|
|
|
_setJump(j);
|
|
|
|
else
|
|
|
|
_setJump(j < 0 ? j + (int)m_items.size() : j - (int)m_items.size());
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
void CCoverFlow::_updateAllTargets(bool instant)
|
|
|
|
{
|
|
|
|
m_targetCameraPos = m_selected ? m_loSelected.camera : m_loNormal.camera;
|
|
|
|
m_targetCameraAim = m_selected ? m_loSelected.cameraAim : m_loNormal.cameraAim;
|
|
|
|
for (u32 i = 0; i < m_range; ++i)
|
|
|
|
_updateTarget(i, instant);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_updateTarget(int i, bool instant)
|
|
|
|
{
|
|
|
|
SLayout &lo = m_selected ? m_loSelected : m_loNormal;
|
|
|
|
int hcenter = m_columns / 2;
|
|
|
|
int vcenter = m_rows / 2;
|
|
|
|
int x = i / m_rows;
|
|
|
|
int y = i % m_rows;
|
|
|
|
CCover &cvr = m_covers[i];
|
|
|
|
|
|
|
|
// Left covers
|
|
|
|
if (x < hcenter)
|
|
|
|
{
|
|
|
|
Vector3D deltaAngle(lo.leftDeltaAngle * (float)(hcenter - 1 - x));
|
|
|
|
cvr.targetAngle = lo.leftAngle + deltaAngle;
|
|
|
|
cvr.targetPos = lo.leftPos + lo.leftSpacer.rotateY(deltaAngle.y * 0.5f) * (float)(hcenter - 1 - x);
|
|
|
|
cvr.targetScale = lo.leftScale;
|
|
|
|
if (_invisibleCover(x, y))
|
|
|
|
{
|
|
|
|
cvr.targetColor = CColor(lo.endColor.r, lo.endColor.g, lo.endColor.b, 0);
|
|
|
|
cvr.targetShadowColor = CColor(lo.shadowColorEnd.r, lo.shadowColorEnd.g, lo.shadowColorEnd.b, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u8 a = (x - 1) * 0xFF / max(1, hcenter - 2);
|
|
|
|
cvr.targetColor = CColor::interpolate(lo.endColor, lo.begColor, a);
|
|
|
|
cvr.targetShadowColor = CColor::interpolate(lo.shadowColorEnd, lo.shadowColorBeg, a);
|
|
|
|
}
|
|
|
|
cvr.txtTargetAngle = lo.txtLeftAngle;
|
|
|
|
cvr.txtTargetPos = lo.txtLeftPos;
|
|
|
|
cvr.txtTargetColor = 0;
|
2016-11-07 16:06:00 +01:00
|
|
|
cvr.txtColor = 0;//instant fade out if was displayed
|
2012-01-21 21:57:41 +01:00
|
|
|
cvr.title.setFrame(lo.txtSideWidth, lo.txtSideStyle, false, instant);
|
|
|
|
}
|
|
|
|
// Right covers
|
|
|
|
else if (x > hcenter)
|
|
|
|
{
|
|
|
|
Vector3D deltaAngle(lo.rightDeltaAngle * (float)(x - hcenter - 1));
|
|
|
|
cvr.targetAngle = lo.rightAngle + deltaAngle;
|
|
|
|
cvr.targetPos = lo.rightPos + lo.rightSpacer.rotateY(deltaAngle.y * 0.5f) * (float)(x - hcenter - 1);
|
|
|
|
cvr.targetScale = lo.rightScale;
|
|
|
|
if (_invisibleCover(x, y))
|
|
|
|
{
|
|
|
|
cvr.targetColor = CColor(lo.endColor.r, lo.endColor.g, lo.endColor.b, 0);
|
|
|
|
cvr.targetShadowColor = CColor(lo.shadowColorEnd.r, lo.shadowColorEnd.g, lo.shadowColorEnd.b, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u8 a = (m_columns - x - 2) * 0xFF / max(1, hcenter - 2);
|
|
|
|
cvr.targetColor = CColor::interpolate(lo.endColor, lo.begColor, a);
|
|
|
|
cvr.targetShadowColor = CColor::interpolate(lo.shadowColorEnd, lo.shadowColorBeg, a);
|
|
|
|
}
|
|
|
|
cvr.txtTargetAngle = lo.txtRightAngle;
|
|
|
|
cvr.txtTargetPos = lo.txtRightPos;
|
|
|
|
cvr.txtTargetColor = 0;
|
2016-11-07 16:06:00 +01:00
|
|
|
cvr.txtColor = 0;//instant fade out if was displayed
|
2012-01-21 21:57:41 +01:00
|
|
|
cvr.title.setFrame(lo.txtSideWidth, lo.txtSideStyle, false, instant);
|
|
|
|
}
|
|
|
|
// New center cover
|
|
|
|
else if (y == vcenter)
|
|
|
|
{
|
|
|
|
cvr.targetColor = 0xFFFFFFFF;
|
|
|
|
cvr.targetShadowColor = lo.shadowColorCenter;
|
|
|
|
cvr.targetAngle = lo.centerAngle;
|
|
|
|
cvr.targetPos = lo.centerPos;
|
|
|
|
cvr.targetScale = lo.centerScale;
|
|
|
|
cvr.txtTargetColor = 0xFF;
|
|
|
|
cvr.txtTargetAngle = lo.txtCenterAngle;
|
|
|
|
cvr.txtTargetPos = lo.txtCenterPos;
|
2016-11-07 16:06:00 +01:00
|
|
|
cvr.title.setFrame(lo.txtCenterWidth, lo.txtCenterStyle, false, true);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
else // Center of a row
|
|
|
|
{
|
|
|
|
cvr.targetColor = lo.begColor;
|
|
|
|
cvr.targetShadowColor = lo.shadowColorBeg;
|
|
|
|
cvr.targetAngle = lo.rowCenterAngle;
|
|
|
|
cvr.targetPos = lo.rowCenterPos;
|
|
|
|
cvr.targetScale = lo.rowCenterScale;
|
|
|
|
cvr.txtTargetColor = 0;
|
2016-11-07 16:06:00 +01:00
|
|
|
cvr.txtColor = 0;//instant fade out if was displayed
|
2012-01-21 21:57:41 +01:00
|
|
|
if (y < vcenter)
|
|
|
|
{
|
|
|
|
cvr.txtTargetAngle = lo.txtLeftAngle;
|
|
|
|
cvr.txtTargetPos = lo.txtLeftPos;
|
|
|
|
}
|
|
|
|
else // (y > vcenter)
|
|
|
|
{
|
|
|
|
cvr.txtTargetAngle = lo.txtRightAngle;
|
|
|
|
cvr.txtTargetPos = lo.txtRightPos;
|
|
|
|
}
|
|
|
|
cvr.title.setFrame(lo.txtSideWidth, lo.txtSideStyle, false, instant);
|
|
|
|
}
|
|
|
|
// Top row
|
|
|
|
if (y < vcenter)
|
|
|
|
{
|
|
|
|
Vector3D deltaAngle(lo.topDeltaAngle * (float)(vcenter - y - 1));
|
|
|
|
cvr.targetAngle += lo.topAngle + deltaAngle;
|
|
|
|
cvr.targetPos += lo.topSpacer.rotateX(deltaAngle.x * 0.5f) * (float)(vcenter - y);
|
|
|
|
if (_invisibleCover(x, y))
|
|
|
|
{
|
|
|
|
cvr.targetColor = CColor(lo.endColor.r, lo.endColor.g, lo.endColor.b, 0);
|
|
|
|
cvr.targetShadowColor = CColor(lo.shadowColorEnd.r, lo.shadowColorEnd.g, lo.shadowColorEnd.b, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u8 a = (y - 1) * 0xFF / max(1, vcenter - 2);
|
|
|
|
CColor c1(CColor::interpolate(lo.endColor, lo.begColor, a));
|
|
|
|
cvr.targetColor = CColor::interpolate(c1, cvr.targetColor, 0x7F);
|
|
|
|
CColor c2(CColor::interpolate(lo.shadowColorEnd, lo.shadowColorBeg, a));
|
|
|
|
cvr.targetShadowColor = CColor::interpolate(c2, cvr.targetShadowColor, 0x7F);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Bottom row
|
|
|
|
else if (y > vcenter)
|
|
|
|
{
|
|
|
|
Vector3D deltaAngle(lo.bottomDeltaAngle * (float)(y - vcenter - 1));
|
|
|
|
cvr.targetAngle += lo.bottomAngle + deltaAngle;
|
|
|
|
cvr.targetPos += lo.bottomSpacer.rotateX(deltaAngle.x * 0.5f) * (float)(y - vcenter);
|
|
|
|
if (_invisibleCover(x, y))
|
|
|
|
{
|
|
|
|
cvr.targetColor = CColor(lo.endColor.r, lo.endColor.g, lo.endColor.b, 0);
|
|
|
|
cvr.targetShadowColor = CColor(lo.shadowColorEnd.r, lo.shadowColorEnd.g, lo.shadowColorEnd.b, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u8 a = (m_rows - y - 2) * 0xFF / max(1, vcenter - 2);
|
|
|
|
CColor c1(CColor::interpolate(lo.endColor, lo.begColor, a));
|
|
|
|
cvr.targetColor = CColor::interpolate(c1, cvr.targetColor, 0x7F);
|
|
|
|
CColor c2(CColor::interpolate(lo.shadowColorEnd, lo.shadowColorBeg, a));
|
|
|
|
cvr.targetShadowColor = CColor::interpolate(c2, cvr.targetShadowColor, 0x7F);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (vcenter > 0 && !_invisibleCover(x, y) && x != hcenter)
|
|
|
|
{
|
|
|
|
cvr.targetColor = CColor::interpolate(lo.begColor, cvr.targetColor, 0x7F);
|
|
|
|
cvr.targetShadowColor = CColor::interpolate(lo.shadowColorBeg, cvr.targetShadowColor, 0x7F);
|
|
|
|
}
|
|
|
|
// Mouse selection
|
|
|
|
for(int chan = WPAD_MAX_WIIMOTES-1; chan >= 0; chan--)
|
|
|
|
if (!m_selected && (u32)m_mouse[chan] < m_range)
|
|
|
|
{
|
|
|
|
if (i == m_mouse[chan])
|
|
|
|
{
|
|
|
|
cvr.targetColor = 0xFFFFFFFF;
|
|
|
|
cvr.targetShadowColor = lo.shadowColorCenter;
|
|
|
|
cvr.txtTargetAngle = lo.txtCenterAngle;
|
|
|
|
cvr.txtTargetPos = lo.txtCenterPos;
|
|
|
|
cvr.txtTargetColor = 0xFF;
|
2016-11-07 16:06:00 +01:00
|
|
|
cvr.title.setFrame(lo.txtCenterWidth, lo.txtCenterStyle, false, true);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cvr.targetColor = lo.mouseOffColor;
|
|
|
|
cvr.targetShadowColor = lo.shadowColorOff;
|
|
|
|
cvr.txtTargetAngle = m_mouse[chan] > i ? lo.txtLeftAngle : lo.txtRightAngle;
|
|
|
|
cvr.txtTargetPos = m_mouse[chan] > i ? lo.txtLeftPos : lo.txtRightPos;
|
|
|
|
cvr.txtTargetColor = 0;
|
2016-11-07 16:06:00 +01:00
|
|
|
cvr.txtColor = 0;//instant fade out if was displayed
|
2012-01-21 21:57:41 +01:00
|
|
|
cvr.title.setFrame(lo.txtSideWidth, lo.txtSideStyle, false, instant);
|
|
|
|
}
|
|
|
|
if (_invisibleCover(x, y))
|
|
|
|
{
|
|
|
|
cvr.targetColor.a = 0;
|
|
|
|
cvr.targetShadowColor.a = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
if (instant)
|
|
|
|
_instantTarget(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_instantTarget(int i)
|
|
|
|
{
|
|
|
|
CCover &cvr = m_covers[i];
|
|
|
|
|
|
|
|
cvr.angle = cvr.targetAngle;
|
|
|
|
cvr.pos = cvr.targetPos;
|
|
|
|
cvr.scale = cvr.targetScale;
|
|
|
|
cvr.color = cvr.targetColor;
|
|
|
|
cvr.shadowColor = cvr.targetShadowColor;
|
|
|
|
cvr.txtAngle = cvr.txtTargetAngle;
|
|
|
|
cvr.txtPos = cvr.txtTargetPos;
|
|
|
|
cvr.txtColor = cvr.txtTargetColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCoverFlow::_sortByPlayCount(CItem item1, CItem item2)
|
|
|
|
{
|
|
|
|
return (item1.playcount == item2.playcount) ? _sortByAlpha(item1, item2) : item1.playcount > item2.playcount;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCoverFlow::_sortByLastPlayed(CItem item1, CItem item2)
|
|
|
|
{
|
|
|
|
return (item1.lastPlayed == item2.lastPlayed) ? _sortByPlayCount(item1, item2) : item1.lastPlayed > item2.lastPlayed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCoverFlow::_sortByGameID(CItem item1, CItem item2)
|
|
|
|
{
|
2012-11-14 17:58:14 +01:00
|
|
|
u32 s = min(strlen(item1.hdr->id), strlen(item2.hdr->id));
|
|
|
|
for(u32 k = 0; k < s; ++k)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-11-14 17:58:14 +01:00
|
|
|
if(toupper(item1.hdr->id[k]) > toupper(item2.hdr->id[k]))
|
2012-01-21 21:57:41 +01:00
|
|
|
return false;
|
2012-11-14 17:58:14 +01:00
|
|
|
else if(toupper(item1.hdr->id[k]) < toupper(item2.hdr->id[k]))
|
2012-01-21 21:57:41 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-14 17:58:14 +01:00
|
|
|
return strlen(item1.hdr->id) < strlen(item2.hdr->id);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CCoverFlow::_sortByAlpha(CItem item1, CItem item2)
|
|
|
|
{
|
2013-04-10 01:24:42 +02:00
|
|
|
const wchar_t *first = item1.hdr->title;
|
|
|
|
const wchar_t *second = item2.hdr->title;
|
|
|
|
return wchar_cmp(first, second, wcslen(first), wcslen(second));
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CCoverFlow::_sortByPlayers(CItem item1, CItem item2)
|
|
|
|
{
|
2012-06-16 19:03:23 +02:00
|
|
|
if(item1.hdr->players == item2.hdr->players) return _sortByAlpha(item1, item2);
|
|
|
|
return item1.hdr->players < item2.hdr->players;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CCoverFlow::_sortByWifiPlayers(CItem item1, CItem item2)
|
|
|
|
{
|
2012-06-16 19:03:23 +02:00
|
|
|
if(item1.hdr->wifi == item2.hdr->wifi) return _sortByAlpha(item1, item2);
|
|
|
|
return item1.hdr->wifi < item2.hdr->wifi;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2018-10-01 13:48:52 +02:00
|
|
|
bool CCoverFlow::_sortByBtnNumbers(CItem item1, CItem item2)
|
|
|
|
{
|
|
|
|
if(item1.hdr->settings[0] == item2.hdr->settings[0]) return _sortByAlpha(item1, item2);
|
|
|
|
return item1.hdr->settings[0] < item2.hdr->settings[0];
|
|
|
|
}
|
|
|
|
|
2013-11-19 16:27:52 +01:00
|
|
|
bool CCoverFlow::start(const string &m_imgsDir)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
if (m_items.empty()) return true;
|
|
|
|
|
2019-10-17 01:22:40 +02:00
|
|
|
/* sort coverflow items list based on sort type */
|
2012-01-21 21:57:41 +01:00
|
|
|
if (m_sorting == SORT_ALPHA)
|
|
|
|
sort(m_items.begin(), m_items.end(), CCoverFlow::_sortByAlpha);
|
|
|
|
else if (m_sorting == SORT_PLAYCOUNT)
|
|
|
|
sort(m_items.begin(), m_items.end(), CCoverFlow::_sortByPlayCount);
|
|
|
|
else if (m_sorting == SORT_LASTPLAYED)
|
|
|
|
sort(m_items.begin(), m_items.end(), CCoverFlow::_sortByLastPlayed);
|
|
|
|
else if (m_sorting == SORT_GAMEID)
|
|
|
|
sort(m_items.begin(), m_items.end(), CCoverFlow::_sortByGameID);
|
|
|
|
else if (m_sorting == SORT_PLAYERS)
|
|
|
|
sort(m_items.begin(), m_items.end(), CCoverFlow::_sortByPlayers);
|
|
|
|
else if (m_sorting == SORT_WIFIPLAYERS)
|
|
|
|
sort(m_items.begin(), m_items.end(), CCoverFlow::_sortByWifiPlayers);
|
2018-10-01 13:48:52 +02:00
|
|
|
else if (m_sorting == SORT_BTN_NUMBERS)
|
|
|
|
sort(m_items.begin(), m_items.end(), CCoverFlow::_sortByBtnNumbers);
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2019-10-17 01:22:40 +02:00
|
|
|
/* load the colored skin/spine images if not already done */
|
2012-07-21 19:05:58 +02:00
|
|
|
if(!m_dvdskin_loaded)
|
|
|
|
{
|
2020-04-12 20:35:57 +02:00
|
|
|
if(TexHandle.fromImageFile(m_dvdSkin, fmt("%s/dvdskin.png", m_imgsDir.c_str())) != TE_OK)
|
2012-07-21 19:05:58 +02:00
|
|
|
return false;
|
2020-04-12 20:35:57 +02:00
|
|
|
if(TexHandle.fromImageFile(m_dvdSkin_Red, fmt("%s/dvdskin_red.png", m_imgsDir.c_str())) != TE_OK)
|
2012-07-21 19:05:58 +02:00
|
|
|
return false;
|
2020-04-12 20:35:57 +02:00
|
|
|
if(TexHandle.fromImageFile(m_dvdSkin_Black, fmt("%s/dvdskin_black.png", m_imgsDir.c_str())) != TE_OK)
|
2012-07-21 19:05:58 +02:00
|
|
|
return false;
|
2020-04-12 20:35:57 +02:00
|
|
|
if(TexHandle.fromImageFile(m_dvdSkin_Yellow, fmt("%s/dvdskin_yellow.png", m_imgsDir.c_str())) != TE_OK)
|
2012-07-21 19:05:58 +02:00
|
|
|
return false;
|
2020-04-12 20:35:57 +02:00
|
|
|
if(TexHandle.fromImageFile(m_dvdSkin_GreenOne, fmt("%s/dvdskin_greenone.png", m_imgsDir.c_str())) != TE_OK)
|
2012-07-21 19:05:58 +02:00
|
|
|
return false;
|
2020-04-12 20:35:57 +02:00
|
|
|
if(TexHandle.fromImageFile(m_dvdSkin_GreenTwo, fmt("%s/dvdskin_greentwo.png", m_imgsDir.c_str())) != TE_OK)
|
2012-07-21 19:05:58 +02:00
|
|
|
return false;
|
2020-11-16 22:11:04 +01:00
|
|
|
if(TexHandle.fromImageFile(m_dvdSkin_Clear, fmt("%s/dvdskin_clear.png", m_imgsDir.c_str())) != TE_OK)
|
|
|
|
return false;
|
2012-07-21 19:05:58 +02:00
|
|
|
m_dvdskin_loaded = true;
|
|
|
|
}
|
2019-10-17 01:22:40 +02:00
|
|
|
/* load the no pic or loading cover images if not already done */
|
2013-01-13 16:45:05 +01:00
|
|
|
if(!m_defcovers_loaded)
|
2012-08-20 21:15:52 +02:00
|
|
|
{
|
2013-01-13 16:45:05 +01:00
|
|
|
if(m_pngLoadCover.empty() || TexHandle.fromImageFile(m_boxLoadingTexture, m_pngLoadCover.c_str(), GX_TF_CMPR, 32, 512) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
{
|
2020-04-12 20:35:57 +02:00
|
|
|
if(TexHandle.fromImageFile(m_boxLoadingTexture, fmt("%s/loading.png", m_imgsDir.c_str()), GX_TF_CMPR, 32, 512) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
return false;
|
|
|
|
}
|
2013-01-13 16:45:05 +01:00
|
|
|
if(m_pngNoCover.empty() || TexHandle.fromImageFile(m_boxNoCoverTexture, m_pngNoCover.c_str(), GX_TF_CMPR, 32, 512) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
{
|
2013-11-19 16:27:52 +01:00
|
|
|
if(TexHandle.fromImageFile(m_boxNoCoverTexture, fmt("%s/nopic.png", m_imgsDir.c_str()), GX_TF_CMPR, 32, 512) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
return false;
|
|
|
|
}
|
2013-01-13 16:45:05 +01:00
|
|
|
if(m_pngLoadCoverFlat.empty() || TexHandle.fromImageFile(m_flatLoadingTexture, m_pngLoadCoverFlat.c_str(), GX_TF_CMPR, 32, 512) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
{
|
2020-04-12 20:35:57 +02:00
|
|
|
if(TexHandle.fromImageFile(m_flatLoadingTexture, fmt("%s/flatloading.png", m_imgsDir.c_str()), GX_TF_CMPR, 32, 512) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
return false;
|
|
|
|
}
|
2013-01-13 16:45:05 +01:00
|
|
|
if(m_pngNoCoverFlat.empty() || TexHandle.fromImageFile(m_flatNoCoverTexture, m_pngNoCoverFlat.c_str(), GX_TF_CMPR, 32, 512) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
{
|
2013-11-19 16:27:52 +01:00
|
|
|
if(TexHandle.fromImageFile(m_flatNoCoverTexture, fmt("%s/flatnopic.png", m_imgsDir.c_str()), GX_TF_CMPR, 32, 512) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
return false;
|
|
|
|
}
|
2020-11-11 20:24:29 +01:00
|
|
|
m_defcovers_loaded = true;
|
2012-08-20 21:15:52 +02:00
|
|
|
}
|
2013-01-13 16:45:05 +01:00
|
|
|
|
2019-10-17 01:22:40 +02:00
|
|
|
/* allocate enough memory for the covers list (m_covers) based on rows * columns (m_range) */
|
2013-01-21 00:30:28 +01:00
|
|
|
if(m_covers != NULL)
|
|
|
|
MEM2_free(m_covers);
|
|
|
|
m_covers = NULL;
|
|
|
|
if(m_range > 0)
|
|
|
|
{
|
2018-06-27 14:47:03 +02:00
|
|
|
m_covers = (CCover*)MEM2_alloc(sizeof(CCover) * m_range);
|
2013-01-21 00:30:28 +01:00
|
|
|
for(size_t i = 0; i < m_range; ++i)
|
|
|
|
m_covers[i] = *(new(m_covers+i) CCover);
|
|
|
|
}
|
2012-01-21 21:57:41 +01:00
|
|
|
m_jump = 0;
|
|
|
|
m_selected = false;
|
2012-04-27 20:12:10 +02:00
|
|
|
m_moved = true;
|
2012-01-21 21:57:41 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::up(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
if (m_jump != 0) return;
|
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
_left(m_minDelay, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::down(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
if (m_jump != 0) return;
|
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
_right(m_minDelay, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::left(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
if (m_jump != 0) return;
|
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
_left(m_minDelay, m_rows >= 3 ? m_rows - 2 : 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::right(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
if (m_jump != 0) return;
|
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
_right(m_minDelay, m_rows >= 3 ? m_rows - 2 : 1);
|
|
|
|
}
|
2012-02-02 18:21:10 +01:00
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
void CCoverFlow::_left(int repeatDelay, u32 step)
|
|
|
|
{
|
|
|
|
int prev, arrStep;
|
|
|
|
|
|
|
|
if (m_delay > 0) return;
|
|
|
|
|
|
|
|
m_moved = true;
|
|
|
|
m_delay = repeatDelay;
|
|
|
|
m_covers[m_range / 2].angle += _coverMovesA();
|
|
|
|
m_covers[m_range / 2].pos += _coverMovesP();
|
|
|
|
if (m_rows >= 3)
|
|
|
|
{
|
|
|
|
prev = m_covers[m_range / 2].index;
|
|
|
|
// Shift the array to the right
|
|
|
|
arrStep = step % (m_rows - 2) + (step / (m_rows - 2)) * m_rows;
|
|
|
|
for (int i = (int)m_range - 1; i >= arrStep; --i)
|
|
|
|
m_covers[i] = m_covers[i - arrStep];
|
|
|
|
_loadAllCovers(loopNum((int)prev - step, m_items.size()));
|
|
|
|
_updateAllTargets();
|
|
|
|
if (arrStep % m_rows != 0)
|
|
|
|
for (u32 i = 0; i < m_columns; ++i)
|
|
|
|
_instantTarget(i * m_rows);
|
|
|
|
if (arrStep / m_rows != 0)
|
|
|
|
for (u32 i = 0; i < m_rows; ++i)
|
|
|
|
_instantTarget(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prev = m_covers[0].index;
|
|
|
|
// Shift the array to the right
|
|
|
|
for (int i = (int)m_range - 1; i > 0; --i)
|
|
|
|
m_covers[i] = m_covers[i - 1];
|
|
|
|
_loadCover(0, loopNum(prev - step, m_items.size()));
|
|
|
|
_updateAllTargets();
|
|
|
|
_instantTarget(0);
|
|
|
|
}
|
2012-11-07 23:27:41 +01:00
|
|
|
_playSound(m_flipSound);
|
2012-01-21 21:57:41 +01:00
|
|
|
m_covers[m_range / 2].angle -= _coverMovesA();
|
|
|
|
m_covers[m_range / 2].pos -= _coverMovesP();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_right(int repeatDelay, u32 step)
|
|
|
|
{
|
|
|
|
int prev, arrStep;
|
|
|
|
|
|
|
|
if (m_delay > 0) return;
|
|
|
|
|
|
|
|
m_moved = true;
|
|
|
|
m_delay = repeatDelay;
|
|
|
|
m_covers[m_range / 2].angle += _coverMovesA();
|
|
|
|
m_covers[m_range / 2].pos += _coverMovesP();
|
|
|
|
if (m_rows >= 3)
|
|
|
|
{
|
|
|
|
prev = m_covers[m_range / 2].index;
|
|
|
|
// Shift the array to the left
|
|
|
|
arrStep = step % (m_rows - 2) + (step / (m_rows - 2)) * m_rows;
|
|
|
|
for (u32 i = 0; i < m_range - arrStep; ++i)
|
|
|
|
m_covers[i] = m_covers[i + arrStep];
|
|
|
|
_loadAllCovers(loopNum(prev + step, m_items.size()));
|
|
|
|
_updateAllTargets();
|
|
|
|
if (arrStep % m_rows != 0)
|
|
|
|
for (u32 i = 0; i < m_columns; ++i)
|
|
|
|
_instantTarget(i * m_rows + m_rows - 1);
|
|
|
|
if (arrStep / m_rows != 0)
|
|
|
|
for (u32 i = 0; i < m_rows; ++i)
|
|
|
|
_instantTarget(i + (m_columns - 1) * m_rows);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prev = m_covers[m_range - 1].index;
|
|
|
|
// Shift the array to the left
|
|
|
|
for (u32 i = 0; i < m_range - 1; ++i)
|
|
|
|
m_covers[i] = m_covers[i + 1];
|
|
|
|
_loadCover(m_range - 1, loopNum(prev + step, m_items.size()));
|
|
|
|
_updateAllTargets();
|
|
|
|
_instantTarget(m_range - 1);
|
|
|
|
}
|
2012-11-07 23:27:41 +01:00
|
|
|
_playSound(m_flipSound);
|
2012-01-21 21:57:41 +01:00
|
|
|
m_covers[m_range / 2].angle -= _coverMovesA();
|
|
|
|
m_covers[m_range / 2].pos -= _coverMovesP();
|
|
|
|
}
|
|
|
|
|
2012-11-11 19:28:03 +01:00
|
|
|
void CCoverFlow::mouse(int chan, int x, int y)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
int m = m_mouse[chan];
|
|
|
|
if (x < 0 || y < 0)
|
|
|
|
m_mouse[chan] = -1;
|
|
|
|
else
|
|
|
|
{
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.prepareStencil();
|
2012-01-21 21:57:41 +01:00
|
|
|
_draw(CCoverFlow::CFDR_STENCIL, false, false);
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.renderStencil();
|
|
|
|
m_mouse[chan] = m_vid.stencilVal(x, y) - 1;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
if (m != m_mouse[chan])
|
|
|
|
{
|
2016-11-07 16:06:00 +01:00
|
|
|
if ((u32)m_mouse[chan] < m_range && m_mouse[chan] >= 0)
|
2012-01-21 21:57:41 +01:00
|
|
|
_playSound(m_hoverSound);
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-11 19:28:03 +01:00
|
|
|
bool CCoverFlow::mouseOver(int x, int y)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return false;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.prepareStencil();
|
2012-01-21 21:57:41 +01:00
|
|
|
_draw(CCoverFlow::CFDR_STENCIL, false, false);
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.renderStencil();
|
|
|
|
m_vid.prepareStencil();
|
2012-01-21 21:57:41 +01:00
|
|
|
_draw(CCoverFlow::CFDR_STENCIL, false, false);
|
2012-11-11 19:28:03 +01:00
|
|
|
m_vid.renderStencil();
|
|
|
|
return m_vid.stencilVal(x, y) == (int)m_range / 2 + 1;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2017-09-22 00:03:41 +02:00
|
|
|
void CCoverFlow::setSelected(int i)
|
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
m_moved = true;
|
|
|
|
_loadAllCovers(i);
|
|
|
|
_updateAllTargets(true);
|
|
|
|
select();
|
|
|
|
}
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
void CCoverFlow::pageUp(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
int n, j;
|
|
|
|
if (m_rows >= 3)
|
|
|
|
{
|
|
|
|
j = m_jump - max(1, (int)m_columns - 2);
|
|
|
|
if (m_jump != 0)
|
|
|
|
{
|
|
|
|
n = ((int)m_items.size() - 1) / (m_rows - 2) + 1;
|
|
|
|
j = j < 0 ? -(-j % n) : j % n;
|
|
|
|
}
|
|
|
|
j *= (int)m_rows - 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
j = m_jump - max(1, (int)m_range / 2);
|
|
|
|
if (m_jump != 0)
|
|
|
|
{
|
|
|
|
n = (int)m_items.size();
|
|
|
|
j = j < 0 ? -(-j % n) : j % n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_setJump(j);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::pageDown(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
int n, j;
|
|
|
|
if (m_rows >= 3)
|
|
|
|
{
|
|
|
|
j = m_jump + max(1, (int)m_columns - 2);
|
|
|
|
if (m_jump != 0)
|
|
|
|
{
|
|
|
|
n = ((int)m_items.size() - 1) / (m_rows - 2) + 1;
|
|
|
|
j = j < 0 ? -(-j % n) : j % n;
|
|
|
|
}
|
|
|
|
j *= (int)m_rows - 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
j = m_jump + max(1, (int)m_range / 2);
|
|
|
|
if (m_jump != 0)
|
|
|
|
{
|
|
|
|
n = (int)m_items.size();
|
|
|
|
j = j < 0 ? -(-j % n) : j % n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_setJump(j);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::flip(bool force, bool f)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL || !m_selected) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
|
|
|
|
CCoverFlow::CCover &cvr = m_covers[m_range / 2];
|
|
|
|
if (!force)
|
|
|
|
f = m_loSelected.centerAngle == cvr.targetAngle && m_loSelected.centerPos == cvr.targetPos && m_loSelected.centerScale == cvr.targetScale;
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
cvr.targetPos = m_loSelected.centerPos + m_flipCoverPos;
|
|
|
|
cvr.targetAngle = m_loSelected.centerAngle + m_flipCoverAngle;
|
|
|
|
cvr.targetScale = m_loSelected.centerScale * m_flipCoverScale;
|
|
|
|
cvr.txtTargetColor = m_flipCoverPos == Vector3D(0.f, 0.f, 0.f) ? 0xFF : 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cvr.targetPos = m_loSelected.centerPos;
|
|
|
|
cvr.targetAngle = m_loSelected.centerAngle;
|
|
|
|
cvr.targetScale = m_loSelected.centerScale;
|
|
|
|
cvr.txtTargetColor = 0xFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CCoverFlow::_invisibleCover(u32 x, u32 y)
|
|
|
|
{
|
|
|
|
return (m_rows > 1 && (y == 0 || y == m_rows - 1)) || x == 0 || x == m_columns - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_loadAllCovers(int i)
|
|
|
|
{
|
|
|
|
int r = (int)m_rows;
|
|
|
|
int c = (int)m_columns;
|
|
|
|
int s = (int)m_items.size();
|
|
|
|
|
|
|
|
if (m_rows >= 3)
|
|
|
|
for (int j = 0; j < r; ++j)
|
|
|
|
for (int k = 0; k < c; ++k)
|
|
|
|
_loadCover(j + k * r, loopNum(i + (j - r / 2) + (k - c / 2) * (r - 2), s));
|
|
|
|
else
|
|
|
|
for (int k = 0; k < (int)m_range; ++k)
|
|
|
|
_loadCover(k, loopNum(i + k - (int)m_range / 2, s));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_setJump(int j)
|
|
|
|
{
|
|
|
|
_loadAllCovers(_currentPos());
|
|
|
|
m_jump = j;
|
|
|
|
if (m_jump == 0)
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_completeJump(void)
|
|
|
|
{
|
|
|
|
if (m_rows >= 3)
|
|
|
|
_loadAllCovers((int)m_covers[m_range / 2].index + m_jump);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (m_jump < 0)
|
|
|
|
_loadAllCovers((int)m_covers[0].index + m_jump + (int)m_range / 2);
|
|
|
|
else
|
|
|
|
_loadAllCovers((int)m_covers[m_range - 1].index + m_jump - ((int)m_range - 1) / 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::nextLetter(wchar_t *c)
|
|
|
|
{
|
2018-10-01 13:48:52 +02:00
|
|
|
if (m_covers == NULL || m_sorting == SORT_BTN_NUMBERS)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
c[0] = L'\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_sorting == SORT_WIFIPLAYERS || m_sorting == SORT_PLAYERS)
|
|
|
|
return nextPlayers(m_sorting == SORT_WIFIPLAYERS, c);
|
|
|
|
|
|
|
|
if (m_sorting == SORT_GAMEID)
|
|
|
|
return nextID(c);
|
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
|
|
|
|
u32 i, j = 0, k = 0, n = m_items.size();
|
|
|
|
|
|
|
|
_completeJump();
|
|
|
|
u32 curPos = _currentPos();
|
|
|
|
|
|
|
|
while (!iswalnum(m_items[curPos].hdr->title[j]) && m_items[curPos].hdr->title[j+1] != L'\0') j++;
|
|
|
|
c[0] = upperCaseWChar(m_items[curPos].hdr->title[j]);
|
|
|
|
|
|
|
|
for (i = 1; i < n; ++i)
|
|
|
|
{
|
|
|
|
k = 0;
|
|
|
|
while (!iswalnum(m_items[loopNum(curPos + i, n)].hdr->title[k]) && m_items[loopNum(curPos + i, n)].hdr->title[k+1] != L'\0') k++;
|
|
|
|
if (upperCaseWChar(m_items[loopNum(curPos + i, n)].hdr->title[k]) != c[0])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i < n)
|
|
|
|
{
|
|
|
|
_setJump(i);
|
|
|
|
c[0] = upperCaseWChar(m_items[loopNum(curPos + i, n)].hdr->title[k]);
|
|
|
|
}
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::prevLetter(wchar_t *c)
|
|
|
|
{
|
2018-10-01 13:48:52 +02:00
|
|
|
if (m_covers == NULL || m_sorting == SORT_BTN_NUMBERS)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
c[0] = L'\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_sorting == SORT_WIFIPLAYERS || m_sorting == SORT_PLAYERS)
|
|
|
|
return prevPlayers(m_sorting == SORT_WIFIPLAYERS, c);
|
|
|
|
|
|
|
|
if (m_sorting == SORT_GAMEID)
|
|
|
|
return prevID(c);
|
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
u32 i, j = 0, k = 0, n = m_items.size();
|
|
|
|
|
|
|
|
_completeJump();
|
|
|
|
u32 curPos = _currentPos();
|
|
|
|
|
|
|
|
while (!iswalnum(m_items[curPos].hdr->title[j]) && m_items[curPos].hdr->title[j+1] != L'\0') j++;
|
|
|
|
c[0] = upperCaseWChar(m_items[curPos].hdr->title[j]);
|
|
|
|
|
|
|
|
for (i = 1; i < n; ++i)
|
|
|
|
{
|
|
|
|
k = 0;
|
|
|
|
while (!iswalnum(m_items[loopNum(curPos - i, n)].hdr->title[k]) && m_items[loopNum(curPos - i, n)].hdr->title[k+1] != L'\0') k++;
|
|
|
|
if (upperCaseWChar(m_items[loopNum(curPos - i, n)].hdr->title[k]) != c[0])
|
|
|
|
{
|
|
|
|
c[0] = upperCaseWChar(m_items[loopNum(curPos - i, n)].hdr->title[k]);
|
|
|
|
while(i < n)
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
k = 0;
|
|
|
|
while (!iswalnum(m_items[loopNum(curPos - i, n)].hdr->title[k]) && m_items[loopNum(curPos - i, n)].hdr->title[k+1] != L'\0') k++;
|
|
|
|
if(upperCaseWChar(m_items[loopNum(curPos - i, n)].hdr->title[k]) != c[0])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < n)
|
|
|
|
{
|
|
|
|
_setJump(-i);
|
|
|
|
k = 0;
|
|
|
|
while (!iswalnum(m_items[loopNum(curPos - i, n)].hdr->title[k]) && m_items[loopNum(curPos - i, n)].hdr->title[k+1] != L'\0') k++;
|
|
|
|
c[0] = upperCaseWChar(m_items[loopNum(curPos - i, n)].hdr->title[k]);
|
|
|
|
}
|
|
|
|
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::nextPlayers(bool wifi, wchar_t *c)
|
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
u32 i, n = m_items.size();
|
|
|
|
|
|
|
|
_completeJump();
|
|
|
|
u32 curPos = _currentPos();
|
2012-06-16 19:03:23 +02:00
|
|
|
int players = wifi ? m_items[curPos].hdr->wifi : m_items[curPos].hdr->players;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
for (i = 1; i < n; ++i)
|
2012-06-16 19:03:23 +02:00
|
|
|
if ((wifi ? m_items[loopNum(curPos + i, n)].hdr->wifi : m_items[loopNum(curPos + i, n)].hdr->players) != players)
|
2012-01-21 21:57:41 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (i < n)
|
|
|
|
{
|
|
|
|
_setJump(i);
|
2012-06-16 19:03:23 +02:00
|
|
|
players = wifi ? m_items[loopNum(curPos + i, n)].hdr->wifi : m_items[loopNum(curPos + i, n)].hdr->players;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
char p[4] = {0 ,0 ,0 ,0};
|
|
|
|
sprintf(p, "%d", players);
|
|
|
|
mbstowcs(c, p, strlen(p));
|
|
|
|
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::prevPlayers(bool wifi, wchar_t *c)
|
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
u32 i, n = m_items.size();
|
|
|
|
|
|
|
|
_completeJump();
|
|
|
|
u32 curPos = _currentPos();
|
2012-06-16 19:03:23 +02:00
|
|
|
int players = wifi ? m_items[curPos].hdr->wifi : m_items[curPos].hdr->players;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
for (i = 1; i < n; ++i)
|
2012-06-16 19:03:23 +02:00
|
|
|
if ((wifi ? m_items[loopNum(curPos - i, n)].hdr->wifi : m_items[loopNum(curPos - i, n)].hdr->players) != players)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-06-16 19:03:23 +02:00
|
|
|
players = wifi ? m_items[loopNum(curPos - i, n)].hdr->wifi : m_items[loopNum(curPos - i, n)].hdr->players;
|
|
|
|
while(i < n && (wifi ? m_items[loopNum(curPos - i, n)].hdr->wifi : m_items[loopNum(curPos - i, n)].hdr->players) == players) ++i;
|
2012-01-21 21:57:41 +01:00
|
|
|
i--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < n)
|
|
|
|
{
|
|
|
|
_setJump(-i);
|
2012-06-16 19:03:23 +02:00
|
|
|
players = wifi ? m_items[loopNum(curPos - i, n)].hdr->wifi : m_items[loopNum(curPos - i, n)].hdr->players;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
char p[4] = {0 ,0 ,0 ,0};
|
|
|
|
sprintf(p, "%d", players);
|
|
|
|
mbstowcs(c, p, strlen(p));
|
|
|
|
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::nextID(wchar_t *c)
|
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
u32 i, n = m_items.size();
|
|
|
|
|
|
|
|
_completeJump();
|
|
|
|
u32 curPos = _currentPos();
|
2012-11-14 17:58:14 +01:00
|
|
|
char *system = m_items[curPos].hdr->id;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
for (i = 1; i < n; ++i)
|
2012-11-14 17:58:14 +01:00
|
|
|
if (m_items[loopNum(curPos + i, n)].hdr->id[0] != system[0])
|
2012-01-21 21:57:41 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (i < n)
|
|
|
|
{
|
|
|
|
_setJump(i);
|
2012-11-14 17:58:14 +01:00
|
|
|
system = m_items[loopNum(curPos + i, n)].hdr->id;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
system[1] = '\0';
|
|
|
|
mbstowcs(c, system, 1);
|
|
|
|
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::prevID(wchar_t *c)
|
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
u32 i, n = m_items.size();
|
|
|
|
|
|
|
|
_completeJump();
|
|
|
|
u32 curPos = _currentPos();
|
2012-11-14 17:58:14 +01:00
|
|
|
char *system = m_items[curPos].hdr->id;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-11-14 17:58:14 +01:00
|
|
|
for(i = 1; i < n; ++i)
|
|
|
|
if(m_items[loopNum(curPos - i, n)].hdr->id[0] != system[0])
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-11-14 17:58:14 +01:00
|
|
|
system = m_items[loopNum(curPos - i, n)].hdr->id;
|
|
|
|
while(i < n && m_items[loopNum(curPos - i, n)].hdr->id[0] == system[0]) ++i;
|
2012-01-21 21:57:41 +01:00
|
|
|
i--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i < n)
|
|
|
|
{
|
|
|
|
_setJump(-i);
|
2012-11-14 17:58:14 +01:00
|
|
|
system = m_items[loopNum(curPos - i, n)].hdr->id;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
system[1] = '\0';
|
2012-11-14 17:58:14 +01:00
|
|
|
mbstowcs(c, system, 1);
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
_updateAllTargets();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_coverTick(int i)
|
|
|
|
{
|
2012-05-12 18:03:14 +02:00
|
|
|
float speed = m_selected ? m_selected_speed : m_normal_speed;
|
2012-01-21 21:57:41 +01:00
|
|
|
Vector3D posDist(m_covers[i].targetPos - m_covers[i].pos);
|
|
|
|
|
|
|
|
if (posDist.sqNorm() < 0.5f)
|
|
|
|
speed *= 0.5f;
|
|
|
|
m_covers[i].angle += (m_covers[i].targetAngle - m_covers[i].angle) * speed;
|
|
|
|
m_covers[i].pos += posDist * speed;
|
|
|
|
m_covers[i].scale += (m_covers[i].targetScale - m_covers[i].scale) * speed;
|
|
|
|
if (m_covers[i].color != m_covers[i].targetColor)
|
|
|
|
{
|
|
|
|
CColor c(m_covers[i].color);
|
|
|
|
m_covers[i].color = CColor::interpolate(c, m_covers[i].targetColor, 0x20);
|
|
|
|
if (m_covers[i].color == c) // If the interpolation doesn't do anything because of numerical approximation, force the target color
|
|
|
|
m_covers[i].color = m_covers[i].targetColor;
|
|
|
|
}
|
|
|
|
if (m_covers[i].shadowColor != m_covers[i].targetShadowColor)
|
|
|
|
{
|
|
|
|
CColor c(m_covers[i].shadowColor);
|
|
|
|
m_covers[i].shadowColor = CColor::interpolate(c, m_covers[i].targetShadowColor, 0x20);
|
|
|
|
if (m_covers[i].shadowColor == c) // If the interpolation doesn't do anything because of numerical approximation, force the target color
|
|
|
|
m_covers[i].shadowColor = m_covers[i].targetShadowColor;
|
|
|
|
}
|
|
|
|
m_covers[i].txtAngle += (m_covers[i].txtTargetAngle - m_covers[i].txtAngle) * speed;
|
|
|
|
m_covers[i].txtPos += (m_covers[i].txtTargetPos - m_covers[i].txtPos) * speed;
|
|
|
|
int colorDist = (int)m_covers[i].txtTargetColor - (int)m_covers[i].txtColor;
|
2016-11-07 16:06:00 +01:00
|
|
|
m_covers[i].txtColor += abs(colorDist) >= 8 ? (u8)(colorDist / 8) : (u8)colorDist;
|
2012-01-21 21:57:41 +01:00
|
|
|
m_covers[i].title.tick();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_unselect(void)
|
|
|
|
{
|
|
|
|
if (m_selected)
|
|
|
|
{
|
|
|
|
m_cameraPos += _cameraMoves();
|
|
|
|
m_covers[m_range / 2].angle += _coverMovesA();
|
|
|
|
m_covers[m_range / 2].pos += _coverMovesP();
|
|
|
|
m_selected = false;
|
|
|
|
m_covers[m_range / 2].angle -= _coverMovesA();
|
|
|
|
m_covers[m_range / 2].pos -= _coverMovesP();
|
|
|
|
m_cameraPos -= _cameraMoves();
|
|
|
|
m_targetCameraPos = m_loNormal.camera;
|
|
|
|
m_targetCameraAim = m_loNormal.cameraAim;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_jump(void)
|
|
|
|
{
|
|
|
|
int step, delay = 2;
|
|
|
|
|
|
|
|
if (m_rows >= 3)
|
|
|
|
step = (u32)abs(m_jump) <= (m_rows - 2) / 2 ? 1 : m_rows - 2;
|
|
|
|
else
|
|
|
|
// Cheat and skip covers we wouldn't see anyway
|
|
|
|
// This means the jump shouldn't be modified before it's done completely
|
|
|
|
step = (u32)abs(m_jump) > m_range + 1 ? abs(m_jump) - (m_range + 1) : 1;
|
|
|
|
if (m_jump < 0)
|
|
|
|
{
|
|
|
|
_left(delay, step);
|
|
|
|
m_jump += step;
|
|
|
|
}
|
|
|
|
else if (m_jump > 0)
|
|
|
|
{
|
|
|
|
_right(delay, step);
|
|
|
|
m_jump -= step;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::tick(void)
|
|
|
|
{
|
2013-01-21 00:30:28 +01:00
|
|
|
if (m_covers == NULL) return;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
++m_tickCount;
|
|
|
|
if (m_delay > 0)
|
|
|
|
--m_delay;
|
|
|
|
else
|
|
|
|
_jump();
|
|
|
|
for (u32 i = 0; i < m_range; ++i)
|
|
|
|
_coverTick(i);
|
|
|
|
m_cameraPos += (m_targetCameraPos - m_cameraPos) * 0.2f;
|
|
|
|
m_cameraAim += (m_targetCameraAim - m_cameraAim) * 0.2f;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SWFCHeader
|
|
|
|
{
|
|
|
|
u8 newFmt : 1; // Was 0 in beta
|
|
|
|
u8 full : 1;
|
|
|
|
u8 cmpr : 1;
|
|
|
|
u8 zipped : 1;
|
|
|
|
u8 backCover : 1;
|
|
|
|
u16 width;
|
|
|
|
u16 height;
|
|
|
|
u8 maxLOD;
|
|
|
|
u16 backWidth;
|
|
|
|
u16 backHeight;
|
|
|
|
u8 backMaxLOD;
|
|
|
|
public:
|
|
|
|
u32 getWidth(void) const { return width * 4; }
|
|
|
|
u32 getHeight(void) const { return height * 4; }
|
|
|
|
u32 getBackWidth(void) const { return backWidth * 4; }
|
|
|
|
u32 getBackHeight(void) const { return backHeight * 4; }
|
|
|
|
SWFCHeader(void)
|
|
|
|
{
|
|
|
|
memset(this, 0, sizeof *this);
|
|
|
|
}
|
2012-12-28 15:19:40 +01:00
|
|
|
SWFCHeader(const TexData &tex, bool f, bool z, const TexData &backTex = TexData())
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
newFmt = 1;
|
|
|
|
full = f ? 1 : 0;
|
|
|
|
cmpr = tex.format == GX_TF_CMPR ? 1 : 0;
|
|
|
|
zipped = z ? 1 : 0;
|
|
|
|
width = tex.width / 4;
|
|
|
|
height = tex.height / 4;
|
|
|
|
maxLOD = tex.maxLOD;
|
|
|
|
backCover = !!backTex.data ? 1 : 0;
|
|
|
|
backWidth = backTex.width / 4;
|
|
|
|
backHeight = backTex.height / 4;
|
|
|
|
backMaxLOD = backTex.maxLOD;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-11-12 21:38:37 +01:00
|
|
|
bool CCoverFlow::cacheCoverFile(const char *wfcPath, const char *coverPath, bool full)
|
2018-06-12 23:27:52 +02:00
|
|
|
{
|
|
|
|
TexData tex;
|
2020-04-08 19:06:21 +02:00
|
|
|
tex.thread = true;// lets TexHandle know this texture is a cover image and in case its a homebrew icon.png
|
|
|
|
m_renderingTex = &tex;// only used if cover has alpha transparency - homebrew icon.png and sourceflow smallbox
|
2020-06-26 01:11:58 +02:00
|
|
|
u8 textureFmt = m_compressTextures ? GX_TF_CMPR : GX_TF_RGB565;// always GX_TF_CMPR
|
2018-06-12 23:27:52 +02:00
|
|
|
if(TexHandle.fromImageFile(tex, coverPath, textureFmt, 32) != TE_OK)
|
2020-04-08 19:06:21 +02:00
|
|
|
{
|
|
|
|
m_renderingTex = NULL;
|
2018-06-12 23:27:52 +02:00
|
|
|
return false;
|
2020-04-08 19:06:21 +02:00
|
|
|
}
|
|
|
|
m_renderingTex = NULL;
|
|
|
|
tex.thread = false;
|
2018-06-12 23:27:52 +02:00
|
|
|
u32 bufSize = fixGX_GetTexBufferSize(tex.width, tex.height, tex.format, tex.maxLOD > 0 ? GX_TRUE : GX_FALSE, tex.maxLOD);
|
2018-11-12 21:38:37 +01:00
|
|
|
if(tex.data != NULL)
|
2018-06-12 23:27:52 +02:00
|
|
|
{
|
|
|
|
FILE *file = fopen(wfcPath, "wb");
|
|
|
|
if(file != NULL)
|
|
|
|
{
|
2018-11-12 21:38:37 +01:00
|
|
|
SWFCHeader header(tex, full, false);
|
2018-06-12 23:27:52 +02:00
|
|
|
fwrite(&header, 1, sizeof(header), file);
|
2018-11-12 21:38:37 +01:00
|
|
|
fwrite(tex.data, 1, bufSize, file);
|
2018-06-12 23:27:52 +02:00
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TexHandle.Cleanup(tex);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-12 21:38:37 +01:00
|
|
|
bool CCoverFlow::cacheCoverBuffer(const char *wfcPath, const u8 *png, bool full)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-12-28 15:19:40 +01:00
|
|
|
TexData tex;
|
2020-04-08 19:06:21 +02:00
|
|
|
u8 textureFmt = m_compressTextures ? GX_TF_CMPR : GX_TF_RGB565;// always GX_TF_CMPR
|
2012-12-28 15:19:40 +01:00
|
|
|
if(TexHandle.fromPNG(tex, png, textureFmt, 32) != TE_OK)
|
2012-11-11 19:28:03 +01:00
|
|
|
return false;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
u32 bufSize = fixGX_GetTexBufferSize(tex.width, tex.height, tex.format, tex.maxLOD > 0 ? GX_TRUE : GX_FALSE, tex.maxLOD);
|
2018-11-12 21:38:37 +01:00
|
|
|
if(tex.data != NULL)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2018-11-12 21:38:37 +01:00
|
|
|
FILE *file = fopen(wfcPath, "wb");
|
2012-11-11 19:28:03 +01:00
|
|
|
if(file != NULL)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2018-11-12 21:38:37 +01:00
|
|
|
SWFCHeader header(tex, full, false);
|
|
|
|
fwrite(&header, 1, sizeof(header), file);
|
|
|
|
fwrite(tex.data, 1, bufSize, file);
|
2012-05-13 17:13:33 +02:00
|
|
|
fclose(file);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
}
|
2012-12-28 15:19:40 +01:00
|
|
|
TexHandle.Cleanup(tex);
|
2012-01-21 21:57:41 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-12 23:27:52 +02:00
|
|
|
bool CCoverFlow::fullCoverCached(const char *wfcPath)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
|
2018-06-12 23:27:52 +02:00
|
|
|
FILE *file = fopen(wfcPath, "rb");
|
2012-11-11 19:28:03 +01:00
|
|
|
if(file != NULL)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
SWFCHeader header;
|
|
|
|
found = fread(&header, 1, sizeof header, file) == sizeof header
|
|
|
|
&& header.full != 0 && m_compressTextures == (header.cmpr != 0)
|
|
|
|
&& header.getWidth() >= 8 && header.getHeight() >= 8
|
2012-05-05 12:46:01 +02:00
|
|
|
&& header.getWidth() <= 1090 && header.getHeight() <= 1090;
|
2012-05-13 17:13:33 +02:00
|
|
|
fclose(file);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2012-12-28 15:19:40 +01:00
|
|
|
bool CCoverFlow::_calcTexLQLOD(TexData &tex)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
while (tex.width > 512 && tex.height > 512 && tex.maxLOD > 0)
|
|
|
|
{
|
|
|
|
--tex.maxLOD;
|
2018-11-12 21:38:37 +01:00
|
|
|
tex.width >>= 1;// divide by 2
|
|
|
|
tex.height >>= 1;// divide by 2
|
2012-01-21 21:57:41 +01:00
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
return done;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCoverFlow::_dropHQLOD(int i)
|
|
|
|
{
|
|
|
|
if ((u32)i >= m_items.size()) return;
|
|
|
|
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
|
2012-12-28 15:19:40 +01:00
|
|
|
const TexData &prevTex = m_items[i].texture;
|
2012-11-03 20:16:03 +01:00
|
|
|
if(prevTex.data == NULL)
|
|
|
|
return;
|
2012-12-28 15:19:40 +01:00
|
|
|
TexData newTex;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
|
|
|
newTex.maxLOD = prevTex.maxLOD;
|
|
|
|
newTex.width = prevTex.width;
|
|
|
|
newTex.height = prevTex.height;
|
|
|
|
newTex.format = prevTex.format;
|
|
|
|
|
|
|
|
if (!CCoverFlow::_calcTexLQLOD(newTex)) return;
|
|
|
|
|
|
|
|
u32 prevTexLen = fixGX_GetTexBufferSize(prevTex.width, prevTex.height, prevTex.format, prevTex.maxLOD > 0 ? GX_TRUE : GX_FALSE, prevTex.maxLOD);
|
|
|
|
u32 newTexLen = fixGX_GetTexBufferSize(newTex.width, newTex.height, newTex.format, newTex.maxLOD > 0 ? GX_TRUE : GX_FALSE, newTex.maxLOD);
|
2012-11-03 20:16:03 +01:00
|
|
|
newTex.data = (u8*)MEM2_alloc(newTexLen);
|
|
|
|
if(newTex.data == NULL)
|
|
|
|
return;
|
|
|
|
memcpy(newTex.data, prevTex.data + (prevTexLen - newTexLen), newTexLen);
|
|
|
|
DCFlushRange(newTex.data, newTexLen);
|
2012-12-28 15:19:40 +01:00
|
|
|
TexHandle.Cleanup(m_items[i].texture);
|
2012-11-03 20:16:03 +01:00
|
|
|
m_items[i].texture = newTex;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2019-02-11 21:55:44 +01:00
|
|
|
const char *CCoverFlow::getFilenameId(const dir_discHdr *curHdr)
|
2014-03-18 03:39:42 +01:00
|
|
|
{
|
|
|
|
if(NoGameID(curHdr->type))
|
|
|
|
{
|
|
|
|
if(strrchr(curHdr->path, '/') != NULL)
|
2019-02-11 21:55:44 +01:00
|
|
|
return strrchr(curHdr->path, '/') + 1;// app folder or rom name.ext
|
2014-03-18 03:39:42 +01:00
|
|
|
else
|
2019-02-11 21:55:44 +01:00
|
|
|
return curHdr->path;// title for scummvm
|
2014-03-18 03:39:42 +01:00
|
|
|
}
|
2019-02-11 21:55:44 +01:00
|
|
|
return curHdr->id;// ID for Wii, GC, & Channels
|
2014-03-18 03:39:42 +01:00
|
|
|
}
|
|
|
|
|
2012-11-01 19:38:22 +01:00
|
|
|
CCoverFlow::CLRet CCoverFlow::_loadCoverTex(u32 i, bool box, bool hq, bool blankBoxCover)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2016-04-06 18:43:51 +02:00
|
|
|
if(!m_loadingCovers)
|
2012-04-08 17:54:34 +02:00
|
|
|
return CL_ERROR;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2019-03-28 00:29:34 +01:00
|
|
|
if(box && m_smallBox)// prevent smallbox from loading full box cover
|
|
|
|
return CL_ERROR;
|
|
|
|
|
|
|
|
if(blankBoxCover && m_items[i].hdr->type == TYPE_SOURCE)// blank covers not used for sourceflow
|
2016-12-14 19:47:13 +01:00
|
|
|
return CL_ERROR;
|
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
bool allocFailed = false;
|
|
|
|
|
2018-11-13 23:08:25 +01:00
|
|
|
/* try to find the wfc texture file in the cache folder */
|
2012-06-14 22:59:18 +02:00
|
|
|
if(!m_cachePath.empty())
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2019-04-29 15:14:54 +02:00
|
|
|
char wfcTitle[128];
|
|
|
|
wfcTitle[127] = '\0';
|
2018-11-13 23:08:25 +01:00
|
|
|
const char *wfcCoverDir = NULL;
|
2016-07-22 01:40:12 +02:00
|
|
|
char *full_path = (char*)MEM2_alloc(MAX_FAT_PATH+1);
|
|
|
|
if(full_path == NULL)
|
|
|
|
return CL_NOMEM;
|
|
|
|
memset(full_path, 0, MAX_FAT_PATH+1);
|
|
|
|
|
2018-11-13 23:08:25 +01:00
|
|
|
/* get title for wfc file */
|
2012-11-01 19:38:22 +01:00
|
|
|
if(blankBoxCover)
|
2013-03-28 14:02:50 +01:00
|
|
|
{
|
2016-04-21 02:05:28 +02:00
|
|
|
const char *blankCoverPath = mainMenu.getBlankCoverPath(m_items[i].hdr);
|
|
|
|
if(blankCoverPath != NULL && strrchr(blankCoverPath, '/') != NULL)
|
2019-03-27 17:45:43 +01:00
|
|
|
strncpy(wfcTitle, strrchr(blankCoverPath, '/') + 1, sizeof(wfcTitle) - 1);
|
2018-11-13 23:08:25 +01:00
|
|
|
else
|
|
|
|
return CL_ERROR;
|
2013-03-28 14:02:50 +01:00
|
|
|
}
|
2014-03-18 03:39:42 +01:00
|
|
|
else
|
2019-03-27 17:45:43 +01:00
|
|
|
strncpy(wfcTitle, getFilenameId(m_items[i].hdr), sizeof(wfcTitle) - 1);
|
2016-07-22 01:40:12 +02:00
|
|
|
|
2019-03-27 17:45:43 +01:00
|
|
|
/* get coverfolder for plugins, sourceflow, and homebrew */
|
2019-03-28 00:29:34 +01:00
|
|
|
if(m_items[i].hdr->type == TYPE_PLUGIN && m_pluginCacheFolders)
|
2018-11-13 23:08:25 +01:00
|
|
|
wfcCoverDir = m_plugin.GetCoverFolderName(m_items[i].hdr->settings[0]);
|
2019-03-28 00:29:34 +01:00
|
|
|
if(m_items[i].hdr->type == TYPE_SOURCE)
|
2018-11-13 23:08:25 +01:00
|
|
|
wfcCoverDir = "sourceflow";
|
2019-03-27 17:45:43 +01:00
|
|
|
if(m_items[i].hdr->type == TYPE_HOMEBREW)
|
|
|
|
wfcCoverDir = "homebrew";
|
2018-11-13 23:08:25 +01:00
|
|
|
|
|
|
|
/* set full path of wfc file */
|
|
|
|
if(wfcCoverDir != NULL)
|
2019-03-04 21:29:46 +01:00
|
|
|
{
|
|
|
|
if(m_smallBox)
|
|
|
|
strncpy(full_path, fmt("%s/%s/%s_small.wfc", m_cachePath.c_str(), wfcCoverDir, wfcTitle), MAX_FAT_PATH);
|
|
|
|
else
|
|
|
|
strncpy(full_path, fmt("%s/%s/%s.wfc", m_cachePath.c_str(), wfcCoverDir, wfcTitle), MAX_FAT_PATH);
|
|
|
|
}
|
2016-07-22 01:40:12 +02:00
|
|
|
else
|
2019-03-04 21:29:46 +01:00
|
|
|
{
|
|
|
|
if(m_smallBox)
|
|
|
|
strncpy(full_path, fmt("%s/%s_small.wfc", m_cachePath.c_str(), wfcTitle), MAX_FAT_PATH);
|
|
|
|
else
|
|
|
|
strncpy(full_path, fmt("%s/%s.wfc", m_cachePath.c_str(), wfcTitle), MAX_FAT_PATH);
|
|
|
|
}
|
2016-07-22 01:40:12 +02:00
|
|
|
DCFlushRange(full_path, MAX_FAT_PATH+1);
|
2018-11-13 23:08:25 +01:00
|
|
|
|
|
|
|
/* load wfc file */
|
2016-07-22 01:40:12 +02:00
|
|
|
FILE *fp;
|
|
|
|
fp = fopen(full_path, "rb");
|
|
|
|
free(full_path);
|
|
|
|
|
2016-04-03 02:51:40 +02:00
|
|
|
if(fp != NULL)//if wfc chache file is found
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
|
|
|
bool success = false;
|
2019-03-27 17:45:43 +01:00
|
|
|
if(fseek(fp, 0, SEEK_END) != 0)
|
|
|
|
{
|
|
|
|
fclose(fp);
|
|
|
|
return CL_ERROR;
|
|
|
|
}
|
|
|
|
u32 fileSize = ftell(fp);
|
|
|
|
if(fseek(fp, 0, SEEK_SET) != 0)
|
2016-05-19 01:15:19 +02:00
|
|
|
{
|
|
|
|
fclose(fp);
|
2019-03-27 17:45:43 +01:00
|
|
|
return CL_ERROR;
|
2016-05-19 01:15:19 +02:00
|
|
|
}
|
2016-07-22 01:40:12 +02:00
|
|
|
|
2012-01-21 21:57:41 +01:00
|
|
|
SWFCHeader header;
|
-updating wiiflow lite to beta 4.3.0
-fixed using categories to hide GC disc 2's. Apparently this has never really worked right for some time or ever.
-fixed deleting the cached cover texture file for plugin games. Delete cover for plugins only deletes the cached texture file (.wfc)
-fixed favorites and adultonly (parental lock) for plugin games. Apparently I may have broke this a few revisions back.
-favorites and adultonly for plugin games now have their own domains in gamecfg1- [FAVORITES_PLUGINS] and [ADULTONLY_PLUGINS]. just makes it more organized.
-only wii, GC, channels are added to [PLAYCOUNT] and [LAST_PLAYED] in gamecfg1.
-now loading gamecfg1 at startup and leaving it loaded till exit. no more loading it and unloading all the time.
-fixed scrolling for game_info synopsis, credits, and help text.
-made source menu buttons wider for wiiflow default. old 80x80, now 100x80. looks better.
-display music info now defaults to off
-screensaver_disabled now defaults to yes
-show GC view button is now on by default no matter what. the only way it is disabled is if you edit wiiflow.ini manually. this is how all the view buttons work.
-removed hiding homebrew button but if wiiflow locked it won't work or in sourceflow it won't show.
-dump_list is now under [GENERAL] instead of each view. Also only works for Wii, GC, and channels.
-sorting only works for Wii, GC, and Channels now. disabled for sourceflow, plugins, homebrew, and combined view.
-now if no games are found a message is shown with the current path so you can see where wiiflow is looking. (except for plugins)
-removed auto create emuNAND for emuNAND view if gamelist is empty. just go to settings>NAND settings if you want to extract or disable it.
-now when no games are found all buttons at bottom are still accessible allowing you to change the view or go to settings and change current partition or path and even extract your NAND to create a EmuNAND. Or go to Home Menu and Install a Wii or GC game.
-removed auto extract NAND to emuNAND when launching a Wii game with EmuNAND save. Now a message is diplayed saying 'emuNAND for saves not found - using real NAND'.
-made the speed at which cover titles fade in/out almost instantly.
-removed update button from Home Menu. online update code is still there but not used and probably won't be used any more as there just isn't a need for it now.
-removed ftp button from Home Menu and all code for the FTP server. I just use WiiXplorer's FTP server. it seems to work better for me.
-disabled keep USB Alive thread for now. i think there's a possibilty it might be the cause of my SD/USB files getting corrupted.
-removed Btn B and - combo to switch partitions. didn't seem useful anymore.
-redid nand emulation settings menu. looks like this now:
pg1
Select EmuNAND
EmuNAND Enulation
Select SaveNAND
SaveNAND Emulation
pg2
Extract Saves All
Missing
Extract NAND
Select Saves Partition
-no longer blocking Select Plugin menu and View icons when using source menu combined view
-now Select Plugins Menu is like switching to plugin view but you get to choose the plugins first
-now [PLUGIN] partition= is the default partition for all plugins. to change individual plugins add 'romPartition=x' to the plugin ini. x is the partition number 0 thru 8 with SD being 0. this is how my usbloadergx plugin mod works.
2016-10-05 01:44:13 +02:00
|
|
|
if(fileSize > sizeof(header))
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2016-11-07 16:06:00 +01:00
|
|
|
if(fread(&header, 1, sizeof(header), fp) != sizeof(header))
|
|
|
|
{
|
|
|
|
fclose(fp);
|
2019-03-27 17:45:43 +01:00
|
|
|
return CL_ERROR;
|
2016-11-07 16:06:00 +01:00
|
|
|
}
|
2019-02-18 21:40:07 +01:00
|
|
|
DCFlushRange(&header, sizeof(header));
|
2016-04-06 18:43:51 +02:00
|
|
|
//make sure wfc cache file matches what we want
|
2016-04-21 02:05:28 +02:00
|
|
|
if(header.newFmt == 1 && (header.full != 0) == box && (header.cmpr != 0) == m_compressTextures)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-12-28 15:19:40 +01:00
|
|
|
TexData tex;
|
2012-01-21 21:57:41 +01:00
|
|
|
tex.format = header.cmpr != 0 ? GX_TF_CMPR : GX_TF_RGB565;
|
|
|
|
tex.width = header.getWidth();
|
|
|
|
tex.height = header.getHeight();
|
|
|
|
tex.maxLOD = header.maxLOD;
|
|
|
|
|
2018-11-13 23:08:25 +01:00
|
|
|
/* note bufSize and texLen will be the same if cover is HQ */
|
2012-01-21 21:57:41 +01:00
|
|
|
u32 bufSize = fixGX_GetTexBufferSize(tex.width, tex.height, tex.format, tex.maxLOD > 0 ? GX_TRUE : GX_FALSE, tex.maxLOD);
|
2012-11-03 20:16:03 +01:00
|
|
|
if(!hq)
|
|
|
|
CCoverFlow::_calcTexLQLOD(tex);
|
2012-01-21 21:57:41 +01:00
|
|
|
u32 texLen = fixGX_GetTexBufferSize(tex.width, tex.height, tex.format, tex.maxLOD > 0 ? GX_TRUE : GX_FALSE, tex.maxLOD);
|
|
|
|
|
2012-11-03 20:16:03 +01:00
|
|
|
tex.data = (u8*)MEM2_alloc(texLen);
|
2018-11-12 21:38:37 +01:00
|
|
|
if(tex.data == NULL)
|
|
|
|
allocFailed = true;
|
2016-04-21 02:05:28 +02:00
|
|
|
else
|
|
|
|
{
|
2018-11-13 23:08:25 +01:00
|
|
|
/* if not HQ cover then skip (bufSize - texLen) texture data after header */
|
2018-11-12 21:38:37 +01:00
|
|
|
fseek(fp, sizeof(header) + (bufSize - texLen), SEEK_SET);
|
2019-03-27 17:45:43 +01:00
|
|
|
if(fread(tex.data, 1, texLen, fp) == texLen)
|
2012-11-03 20:16:03 +01:00
|
|
|
{
|
2019-03-27 17:45:43 +01:00
|
|
|
DCFlushRange(tex.data, texLen);
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
TexHandle.Cleanup(m_items[i].texture);
|
|
|
|
m_items[i].texture = tex;
|
|
|
|
m_items[i].state = STATE_Ready;
|
|
|
|
m_items[i].boxTexture = header.full != 0;
|
|
|
|
success = true;
|
2012-11-03 20:16:03 +01:00
|
|
|
}
|
2016-04-21 02:05:28 +02:00
|
|
|
}
|
2013-01-13 16:45:05 +01:00
|
|
|
if(!success && tex.data != NULL)
|
|
|
|
{
|
|
|
|
free(tex.data);
|
|
|
|
tex.data = NULL;
|
|
|
|
}
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
}
|
2012-11-03 20:16:03 +01:00
|
|
|
fclose(fp);
|
2012-07-27 20:53:33 +02:00
|
|
|
if(success)
|
2012-11-03 20:16:03 +01:00
|
|
|
return CL_OK;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
}
|
2012-07-27 20:53:33 +02:00
|
|
|
if(allocFailed)
|
2012-11-03 20:16:03 +01:00
|
|
|
return CL_NOMEM;
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2019-03-27 17:45:43 +01:00
|
|
|
return CL_ERROR;
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
|
2018-05-29 11:59:57 +02:00
|
|
|
void * CCoverFlow::_coverLoader(void *obj)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2018-05-29 11:59:57 +02:00
|
|
|
CCoverFlow *cf = static_cast<CCoverFlow *>(obj);
|
2012-11-04 20:22:02 +01:00
|
|
|
cf->m_coverThrdBusy = true;
|
2012-11-03 20:16:03 +01:00
|
|
|
CLRet ret;
|
2013-01-17 19:52:56 +01:00
|
|
|
u32 firstItem;
|
2012-04-27 20:12:10 +02:00
|
|
|
bool update;
|
2013-01-17 19:52:56 +01:00
|
|
|
u32 i, j;
|
2013-09-11 20:11:23 +02:00
|
|
|
bool hq_req = cf->m_useHQcover;
|
|
|
|
bool cur_pos_hq = false;
|
2018-11-26 00:37:55 +01:00
|
|
|
u32 bufferSize = min(cf->m_numBufCovers * max(2ul, cf->m_rows), 80ul);
|
2012-01-21 21:57:41 +01:00
|
|
|
|
2012-05-04 16:08:44 +02:00
|
|
|
while(cf->m_loadingCovers)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-04-27 20:12:10 +02:00
|
|
|
update = cf->m_moved;
|
2012-01-21 21:57:41 +01:00
|
|
|
cf->m_moved = false;
|
2016-07-22 01:40:12 +02:00
|
|
|
firstItem = cf->m_covers[cf->m_range / 2].index;
|
|
|
|
for(j = cf->m_items.size(); j >= bufferSize && !cf->m_moved && update; --j)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2012-04-27 20:12:10 +02:00
|
|
|
i = loopNum((j & 1) ? firstItem - (j + 1) / 2 : firstItem + j / 2, cf->m_items.size());
|
2013-09-11 20:11:23 +02:00
|
|
|
if(cf->m_items[i].state != STATE_Loading)
|
|
|
|
{
|
|
|
|
LWP_MutexLock(cf->m_mutex);
|
|
|
|
TexHandle.Cleanup(cf->m_items[i].texture);
|
|
|
|
cf->m_items[i].state = STATE_Loading;
|
|
|
|
LWP_MutexUnlock(cf->m_mutex);
|
|
|
|
}
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
2012-11-03 20:16:03 +01:00
|
|
|
ret = CL_OK;
|
2019-03-27 17:45:43 +01:00
|
|
|
bool hq_done = false;
|
|
|
|
/* we try 3 passes to get the full cover. because the cover loader randomly skips the wfc file for unknown reasons */
|
|
|
|
/* first time is full cover only */
|
|
|
|
/* second time is full then front */
|
|
|
|
/* third is full then front then custom blank cover */
|
|
|
|
for(u8 k = 1; k < 4 && !cf->m_moved && update && ret != CL_NOMEM; k++)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2019-03-27 17:45:43 +01:00
|
|
|
for(j = 0; j <= bufferSize && !cf->m_moved && update && ret != CL_NOMEM; ++j)
|
2012-01-21 21:57:41 +01:00
|
|
|
{
|
2019-03-27 17:45:43 +01:00
|
|
|
i = loopNum((j & 1) ? firstItem - (j + 1) / 2 : firstItem + j / 2, cf->m_items.size());
|
|
|
|
cur_pos_hq = (hq_req && i == firstItem);
|
|
|
|
if(!cur_pos_hq && cf->m_items[i].state != STATE_Loading)
|
|
|
|
continue;
|
|
|
|
if(cur_pos_hq && hq_done)
|
|
|
|
continue;
|
|
|
|
if(((ret = cf->_loadCoverTex(i, true, cur_pos_hq, false)) == CL_ERROR) && k > 1)
|
2012-11-01 19:38:22 +01:00
|
|
|
{
|
2019-03-27 17:45:43 +01:00
|
|
|
if(((ret = cf->_loadCoverTex(i, false, cur_pos_hq, false)) == CL_ERROR) && k > 2)
|
|
|
|
{
|
|
|
|
if((ret = cf->_loadCoverTex(i, true, cur_pos_hq, true)) == CL_ERROR)
|
|
|
|
cf->m_items[i].state = STATE_NoCover;
|
|
|
|
}
|
2012-11-01 19:38:22 +01:00
|
|
|
}
|
2019-03-27 17:45:43 +01:00
|
|
|
hq_done = (hq_done == false && ret == CL_OK && cur_pos_hq);
|
2012-01-21 21:57:41 +01:00
|
|
|
}
|
|
|
|
}
|
2012-11-03 20:16:03 +01:00
|
|
|
if(ret == CL_NOMEM && bufferSize > 3)
|
2012-01-21 21:57:41 +01:00
|
|
|
bufferSize -= 2;
|
|
|
|
}
|
2012-11-04 20:22:02 +01:00
|
|
|
cf->m_coverThrdBusy = false;
|
2012-01-21 21:57:41 +01:00
|
|
|
return 0;
|
|
|
|
}
|