WiiFlow_Lite/source/menu/menu.cpp
2012-10-06 16:38:21 +00:00

2667 lines
93 KiB
C++

#include <fstream>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>
#include <wchar.h>
#include <network.h>
#include <errno.h>
#include "menu.hpp"
#include "types.h"
#include "fonts.h"
#include "banner/BannerWindow.hpp"
#include "channel/nand.hpp"
#include "fileOps/fileOps.h"
#include "gc/gc.hpp"
#include "gui/Gekko.h"
#include "gui/GameTDB.hpp"
#include "loader/alt_ios.h"
#include "loader/cios.h"
#include "loader/fs.h"
#include "loader/nk.h"
#include "loader/playlog.h"
#include "loader/sys.h"
#include "loader/wbfs.h"
#include "music/SoundHandler.hpp"
#include "network/gcard.h"
#include "unzip/U8Archive.h"
// Sounds
extern const u8 click_wav[];
extern const u32 click_wav_size;
extern const u8 hover_wav[];
extern const u32 hover_wav_size;
extern const u8 camera_wav[];
extern const u32 camera_wav_size;
// Pics
extern const u8 btnplus_png[];
extern const u8 btnpluss_png[];
extern const u8 btnminus_png[];
extern const u8 btnminuss_png[];
extern const u8 background_jpg[];
extern const u32 background_jpg_size;
extern const u8 butleft_png[];
extern const u8 butcenter_png[];
extern const u8 butright_png[];
extern const u8 butsleft_png[];
extern const u8 butscenter_png[];
extern const u8 butsright_png[];
extern const u8 buthleft_png[];
extern const u8 buthcenter_png[];
extern const u8 buthright_png[];
extern const u8 buthsleft_png[];
extern const u8 buthscenter_png[];
extern const u8 buthsright_png[];
extern const u8 pbarleft_png[];
extern const u8 pbarcenter_png[];
extern const u8 pbarright_png[];
extern const u8 pbarlefts_png[];
extern const u8 pbarcenters_png[];
extern const u8 pbarrights_png[];
extern const u8 butauon_png[];
extern const u8 butauons_png[];
extern const u8 butauoff_png[];
extern const u8 butauoffs_png[];
extern const u8 butenon_png[];
extern const u8 butenons_png[];
extern const u8 butenoff_png[];
extern const u8 butenoffs_png[];
extern const u8 butjaon_png[];
extern const u8 butjaons_png[];
extern const u8 butjaoff_png[];
extern const u8 butjaoffs_png[];
extern const u8 butfron_png[];
extern const u8 butfrons_png[];
extern const u8 butfroff_png[];
extern const u8 butfroffs_png[];
extern const u8 butdeon_png[];
extern const u8 butdeons_png[];
extern const u8 butdeoff_png[];
extern const u8 butdeoffs_png[];
extern const u8 buteson_png[];
extern const u8 butesons_png[];
extern const u8 butesoff_png[];
extern const u8 butesoffs_png[];
extern const u8 butiton_png[];
extern const u8 butitons_png[];
extern const u8 butitoff_png[];
extern const u8 butitoffs_png[];
extern const u8 butnlon_png[];
extern const u8 butnlons_png[];
extern const u8 butnloff_png[];
extern const u8 butnloffs_png[];
extern const u8 butpton_png[];
extern const u8 butptons_png[];
extern const u8 butptoff_png[];
extern const u8 butptoffs_png[];
extern const u8 butruon_png[];
extern const u8 butruons_png[];
extern const u8 butruoff_png[];
extern const u8 butruoffs_png[];
extern const u8 butkoon_png[];
extern const u8 butkoons_png[];
extern const u8 butkooff_png[];
extern const u8 butkooffs_png[];
extern const u8 butzhcnon_png[];
extern const u8 butzhcnons_png[];
extern const u8 butzhcnoff_png[];
extern const u8 butzhcnoffs_png[];
extern const u8 checkbox_png[];
extern const u8 checkboxs_png[];
extern const u8 checkboxhid_png[];
extern const u8 checkboxreq_png[];
CMenu::CMenu(CVideo &vid) :
m_vid(vid)
{
m_aa = 0;
m_thrdWorking = false;
m_thrdStop = false;
m_thrdProgress = 0.f;
m_thrdStep = 0.f;
m_thrdStepLen = 0.f;
m_locked = false;
m_favorites = false;
m_networkInit = false;
m_thrdNetwork = false;
m_mutex = 0;
m_showtimer = 0;
m_gameSoundThread = LWP_THREAD_NULL;
m_gameSoundHdr = NULL;
m_numCFVersions = 0;
m_bgCrossFade = 0;
m_bnrSndVol = 0;
m_bnr_settings = true;
m_directLaunch = false;
m_exit = false;
m_reload = false;
m_gamesound_changed = false;
m_video_playing = false;
m_base_font = NULL;
m_base_font_size = 0;
m_wbf1_font = NULL;
m_wbf2_font = NULL;
m_current_view = COVERFLOW_USB;
m_Emulator_boot = false;
m_banner = new BannerWindow;
m_gameSound.SetVoice(1);
m_music_info = true;
}
void CMenu::init(void)
{
const char *drive = "empty";
const char *check = "empty";
struct stat dummy;
/* Clear Playlog */
Playlog_Delete();
for(int i = SD; i <= USB8; i++) //Find the first partition with a wiiflow.ini
if (DeviceHandle.IsInserted(i) && DeviceHandle.GetFSType(i) != PART_FS_WBFS && stat(fmt("%s:/%s/" CFG_FILENAME, DeviceName[i], APPDATA_DIR2), &dummy) == 0)
{
drive = DeviceName[i];
break;
}
if(drive == check) //No wiiflow.ini found
for(int i = SD; i <= USB8; i++) //Find the first partition with a boot.dol
if (DeviceHandle.IsInserted(i) && DeviceHandle.GetFSType(i) != PART_FS_WBFS && stat(fmt("%s:/%s/boot.dol", DeviceName[i], APPDATA_DIR2), &dummy) == 0)
{
drive = DeviceName[i];
break;
}
if(drive == check) //No boot.dol found
for(int i = SD; i <= USB8; i++) //Find the first partition with apps/wiiflow folder
if (DeviceHandle.IsInserted(i) && DeviceHandle.GetFSType(i) != PART_FS_WBFS && stat(fmt("%s:/%s", DeviceName[i], APPDATA_DIR2), &dummy) == 0)
{
drive = DeviceName[i];
break;
}
if(drive == check) //No apps/wiiflow folder found
for(int i = SD; i <= USB8; i++) // Find the first writable partition
if (DeviceHandle.IsInserted(i) && DeviceHandle.GetFSType(i) != PART_FS_WBFS)
{
drive = DeviceName[i];
fsop_MakeFolder((char *)fmt("%s:/%s", DeviceName[i], APPDATA_DIR2)); //Make the apps dir, so saving wiiflow.ini does not fail.
break;
}
_loadDefaultFont(CONF_GetLanguage() == CONF_LANG_KOREAN);
if(drive == check) // Should not happen
{
_buildMenus();
error(_fmt("errboot4", L"No available partitions found!"));
m_exit = true;
return;
}
m_appDir = sfmt("%s:/%s", drive, APPDATA_DIR2);
m_cfg.load(sfmt("%s/" CFG_FILENAME, m_appDir.c_str()).c_str());
m_use_wifi_gecko = m_cfg.getBool("DEBUG", "wifi_gecko");
if (m_cfg.getBool("GENERAL", "async_network") || has_enabled_providers() || m_use_wifi_gecko)
_reload_wifi_gecko();
gprintf("Wiiflow boot.dol Location: %s\n", m_appDir.c_str());
//Gecko Output to SD
if(!WriteToSD)
{
WriteToSD = m_cfg.getBool("DEBUG", "sd_write_log", false);
bufferMessages = WriteToSD;
}
useMainIOS = m_cfg.getBool("GENERAL", "force_cios_load", false);
bool onUSB = m_cfg.getBool("GENERAL", "data_on_usb", strncmp(drive, "usb", 3) == 0);
drive = check; //reset the drive variable for the check
if (onUSB)
{
for(int i = USB1; i <= USB8; i++) //Look for first partition with a wiiflow folder in root
if (DeviceHandle.IsInserted(i) && DeviceHandle.GetFSType(i) != PART_FS_WBFS && stat(fmt("%s:/%s", DeviceName[i], APPDATA_DIR), &dummy) == 0)
{
drive = DeviceName[i];
break;
}
}
else if(DeviceHandle.IsInserted(SD)) drive = DeviceName[SD];
if(drive == check && onUSB) //No wiiflow folder found in root of any usb partition, and data_on_usb=yes
for(int i = USB1; i <= USB8; i++) // Try first USB partition with wbfs folder.
if (DeviceHandle.IsInserted(i) && DeviceHandle.GetFSType(i) != PART_FS_WBFS && stat(fmt(GAMES_DIR, DeviceName[i]), &dummy) == 0)
{
drive = DeviceName[i];
break;
}
if(drive == check && onUSB) // No wbfs folder found and data_on_usb=yes
for(int i = USB1; i <= USB8; i++) // Try first available USB partition.
if (DeviceHandle.IsInserted(i) && DeviceHandle.GetFSType(i) != PART_FS_WBFS)
{
drive = DeviceName[i];
break;
}
if(drive == check)
{
_buildMenus();
if(DeviceHandle.IsInserted(SD))
{
error(_fmt("errboot5", L"data_on_usb=yes and No available usb partitions for data!\nUsing SD."));
drive = DeviceName[SD];
}
else
{
error(_fmt("errboot6", L"No available usb partitions for data and no SD inserted!\nExiting."));
m_exit = true;
return;
}
}
if(m_cfg.getBool("DML", "always_show_button", false))
{
gprintf("Force enabling DML view\n");
m_show_dml = true;
}
else
m_show_dml = MIOSisDML();
m_new_dml = m_cfg.getBool("DML", "dml_r52+", true);
m_new_dm_cfg = m_cfg.getBool("DML", "dm_r2.1+", true);
m_DMLgameDir = sfmt("%%s:/%s", m_cfg.getString("DML", "dir_usb_games", "games").c_str());
m_cfg.getString("NAND", "path", "");
m_cfg.getInt("NAND", "partition", 1);
m_cfg.getBool("NAND", "disable", true);
_installed_cios.clear();
if(!neek2o())
_load_installed_cioses();
else
_installed_cios[CurrentIOS.Version] = CurrentIOS.Version;
snprintf(m_app_update_drive, sizeof(m_app_update_drive), "%s:/", drive);
m_dataDir = sfmt("%s:/%s", drive, APPDATA_DIR);
gprintf("Data Directory: %s\n", m_dataDir.c_str());
m_dol = sfmt("%s/boot.dol", m_appDir.c_str());
m_ver = sfmt("%s/versions", m_appDir.c_str());
m_app_update_zip = sfmt("%s/update.zip", m_appDir.c_str());
m_data_update_zip = sfmt("%s/update.zip", m_dataDir.c_str());
m_customBnrDir = m_cfg.getString("GENERAL", "dir_custom_banners", sfmt("%s/custom_banners", m_dataDir.c_str()));
m_pluginsDir = m_cfg.getString("GENERAL", "dir_plugins", sfmt("%s/plugins", m_dataDir.c_str()));
m_cacheDir = m_cfg.getString("GENERAL", "dir_cache", sfmt("%s/cache", m_dataDir.c_str()));
m_listCacheDir = m_cfg.getString("GENERAL", "dir_list_cache", sfmt("%s/lists", m_cacheDir.c_str()));
m_bnrCacheDir = m_cfg.getString("GENERAL", "dir_banner_cache", sfmt("%s/banners", m_cacheDir.c_str()));
m_txtCheatDir = m_cfg.getString("GENERAL", "dir_txtcheat", sfmt("%s/codes", m_dataDir.c_str()));
m_cheatDir = m_cfg.getString("GENERAL", "dir_cheat", sfmt("%s/gct", m_txtCheatDir.c_str()));
m_wipDir = m_cfg.getString("GENERAL", "dir_wip", sfmt("%s/wip", m_txtCheatDir.c_str()));
m_settingsDir = m_cfg.getString("GENERAL", "dir_settings", sfmt("%s/settings", m_dataDir.c_str()));
m_languagesDir = m_cfg.getString("GENERAL", "dir_languages", sfmt("%s/languages", m_dataDir.c_str()));
m_boxPicDir = m_cfg.getString("GENERAL", "dir_box_covers", sfmt("%s/boxcovers", m_dataDir.c_str()));
m_picDir = m_cfg.getString("GENERAL", "dir_flat_covers", sfmt("%s/covers", m_dataDir.c_str()));
m_themeDir = m_cfg.getString("GENERAL", "dir_themes", sfmt("%s/themes", m_dataDir.c_str()));
m_musicDir = m_cfg.getString("GENERAL", "dir_music", sfmt("%s/music", m_dataDir.c_str()));
m_videoDir = m_cfg.getString("GENERAL", "dir_trailers", sfmt("%s/trailers", m_dataDir.c_str()));
m_fanartDir = m_cfg.getString("GENERAL", "dir_fanart", sfmt("%s/fanart", m_dataDir.c_str()));
m_screenshotDir = m_cfg.getString("GENERAL", "dir_screenshot", sfmt("%s/screenshots", m_dataDir.c_str()));
m_helpDir = m_cfg.getString("GENERAL", "dir_help", sfmt("%s/help", m_dataDir.c_str()));
//DeviceHandler::SetWatchdog(m_cfg.getUInt("GENERAL", "watchdog_timeout", 10));
const char *domain = _domainFromView();
const char *checkDir = m_current_view == COVERFLOW_HOMEBREW ? HOMEBREW_DIR : GAMES_DIR;
u8 partition = m_cfg.getInt(domain, "partition", 0); //Auto find a valid partition and fix old ini partition settings.
if(m_current_view != COVERFLOW_CHANNEL && (partition > USB8 || !DeviceHandle.IsInserted(partition)))
{
m_cfg.remove(domain, "partition");
for(int i = SD; i <= USB8+1; i++) // Find a usb partition with the wbfs folder or wbfs file system, else leave it blank (defaults to 1 later)
{
if(i > USB8)
{
m_current_view = COVERFLOW_CHANNEL;
break;
}
if (DeviceHandle.IsInserted(i)
&& ((m_current_view == COVERFLOW_USB && DeviceHandle.GetFSType(i) == PART_FS_WBFS)
|| stat(fmt(checkDir, DeviceName[i]), &dummy) == 0))
{
gprintf("Setting Emu NAND to Partition: %i\n",currentPartition);
m_cfg.setInt(domain, "partition", i);
break;
}
}
}
m_cf.init(m_base_font, m_base_font_size, m_vid.vid_50hz());
//Make important folders first.
fsop_MakeFolder((char *)m_dataDir.c_str()); //D'OH!
fsop_MakeFolder((char *)m_customBnrDir.c_str());
fsop_MakeFolder((char *)m_pluginsDir.c_str());
fsop_MakeFolder((char *)m_cacheDir.c_str());
fsop_MakeFolder((char *)m_listCacheDir.c_str());
fsop_MakeFolder((char *)m_bnrCacheDir.c_str());
fsop_MakeFolder((char *)m_txtCheatDir.c_str());
fsop_MakeFolder((char *)m_cheatDir.c_str());
fsop_MakeFolder((char *)m_wipDir.c_str());
fsop_MakeFolder((char *)m_settingsDir.c_str());
fsop_MakeFolder((char *)m_languagesDir.c_str());
fsop_MakeFolder((char *)m_boxPicDir.c_str());
fsop_MakeFolder((char *)m_picDir.c_str());
fsop_MakeFolder((char *)m_themeDir.c_str());
fsop_MakeFolder((char *)m_musicDir.c_str());
fsop_MakeFolder((char *)m_videoDir.c_str());
fsop_MakeFolder((char *)m_fanartDir.c_str());
fsop_MakeFolder((char *)m_screenshotDir.c_str());
fsop_MakeFolder((char *)m_helpDir.c_str());
// INI files
m_cat.load(fmt("%s/" CAT_FILENAME, m_settingsDir.c_str()));
string themeName = m_cfg.getString("GENERAL", "theme", "default");
m_themeDataDir = sfmt("%s/%s", m_themeDir.c_str(), themeName.c_str());
m_theme.load(fmt("%s.ini", m_themeDataDir.c_str()));
m_plugin.init(m_pluginsDir);
m_devo_installed = DEVO_Installed(m_dataDir.c_str());
u8 defaultMenuLanguage = 7; //English
switch (CONF_GetLanguage())
{
case CONF_LANG_JAPANESE:
defaultMenuLanguage = 14; //Japanese
break;
case CONF_LANG_GERMAN:
defaultMenuLanguage = 11; //German
break;
case CONF_LANG_FRENCH:
defaultMenuLanguage = 9; //French
break;
case CONF_LANG_SPANISH:
defaultMenuLanguage = 19; //Spanish
break;
case CONF_LANG_ITALIAN:
defaultMenuLanguage = 13; //Italian
break;
case CONF_LANG_DUTCH:
defaultMenuLanguage = 6; //Dutch
break;
case CONF_LANG_SIMP_CHINESE:
defaultMenuLanguage = 3; //Chinese_S
break;
case CONF_LANG_TRAD_CHINESE:
defaultMenuLanguage = 4; //Chinese_T
break;
case CONF_LANG_KOREAN:
defaultMenuLanguage = 7; // No Korean translation has been done for wiiflow, so the menu will use english in this case.
break;
}
if (CONF_GetArea() == CONF_AREA_BRA)
defaultMenuLanguage = 2; //Brazilian
m_curLanguage = CMenu::_translations[m_cfg.getInt("GENERAL", "language", defaultMenuLanguage)];
if (!m_loc.load(fmt("%s/%s.ini", m_languagesDir.c_str(), m_curLanguage.c_str())))
{
m_cfg.setInt("GENERAL", "language", 0);
m_curLanguage = CMenu::_translations[0];
m_loc.load(fmt("%s/%s.ini", m_languagesDir.c_str(), m_curLanguage.c_str()));
}
m_tempView = false;
m_gameList.Init(m_settingsDir.c_str(), m_loc.getString(m_curLanguage, "gametdb_code", "EN").c_str());
m_aa = 3;
CColor pShadowColor = m_theme.getColor("GENERAL", "pointer_shadow_color", CColor(0x3F000000));
float pShadowX = m_theme.getFloat("GENERAL", "pointer_shadow_x", 3.f);
float pShadowY = m_theme.getFloat("GENERAL", "pointer_shadow_y", 3.f);
bool pShadowBlur = m_theme.getBool("GENERAL", "pointer_shadow_blur", false);
for(int chan = WPAD_MAX_WIIMOTES-2; chan >= 0; chan--)
{
m_cursor[chan].init(fmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString("GENERAL", fmt("pointer%i", chan+1)).c_str()),
m_vid.wide(), pShadowColor, pShadowX, pShadowY, pShadowBlur, chan);
WPAD_SetVRes(chan, m_vid.width() + m_cursor[chan].width(), m_vid.height() + m_cursor[chan].height());
}
m_btnMgr.init(m_vid);
MusicPlayer.Init(m_cfg, m_musicDir, sfmt("%s/music", m_themeDataDir.c_str()));
m_music_info = m_cfg.getBool("GENERAL", "display_music_info", true);
_buildMenus();
m_locked = m_cfg.getString("GENERAL", "parent_code", "").size() >= 4;
m_btnMgr.setRumble(m_cfg.getBool("GENERAL", "rumble", true));
int exit_to = m_cfg.getInt("GENERAL", "exit_to", 0);
if(exit_to == EXIT_TO_BOOTMII && (!DeviceHandle.IsInserted(SD) ||
stat(fmt("%s:/bootmii/armboot.bin",DeviceName[SD]), &dummy) != 0 ||
stat(fmt("%s:/bootmii/ppcboot.elf", DeviceName[SD]), &dummy) != 0))
exit_to = EXIT_TO_HBC;
Sys_ExitTo(exit_to);
LWP_MutexInit(&m_mutex, 0);
m_cf.setSoundVolume(m_cfg.getInt("GENERAL", "sound_volume_coverflow", 255));
m_btnMgr.setSoundVolume(m_cfg.getInt("GENERAL", "sound_volume_gui", 255));
m_bnrSndVol = m_cfg.getInt("GENERAL", "sound_volume_bnr", 255);
m_bnr_settings = m_cfg.getBool("GENERAL", "banner_in_settings", true);
m_cfg.setString("GAMERCARD", "gamercards", "wiinnertag|dutag");
m_cfg.getString("GAMERCARD", "wiinnertag_url", WIINNERTAG_URL);
m_cfg.getString("GAMERCARD", "wiinnertag_key", "");
m_cfg.getString("GAMERCARD", "dutag_url", DUTAG_URL);
m_cfg.getString("GAMERCARD", "dutag_key", "");
if (m_cfg.getBool("GAMERCARD", "gamercards_enable", false))
{
vector<string> gamercards = stringToVector(m_cfg.getString("GAMERCARD", "gamercards"), '|');
if (gamercards.size() == 0)
{
gamercards.push_back("wiinnertag");
gamercards.push_back("dutag");
}
for (vector<string>::iterator itr = gamercards.begin(); itr != gamercards.end(); itr++)
{
gprintf("Found gamercard provider: %s\n",(*itr).c_str());
register_card_provider(
m_cfg.getString("GAMERCARD", fmt("%s_url", (*itr).c_str())).c_str(),
m_cfg.getString("GAMERCARD", fmt("%s_key", (*itr).c_str())).c_str()
);
}
}
}
bool cleaned_up = false;
void CMenu::cleanup()
{
if(cleaned_up)
return;
//gprintf("MEM1_freesize(): %i\nMEM2_freesize(): %i\n", MEM1_freesize(), MEM2_freesize());
m_btnMgr.hide(m_mainLblCurMusic);
_cleanupDefaultFont();
m_banner->DeleteBanner();
m_plugin.Cleanup();
_stopSounds();
MusicPlayer.Cleanup();
m_cameraSound.release();
ClearGameSoundThreadStack();
SoundHandler::DestroyInstance();
soundDeinit();
m_vid.cleanup();
m_cf.shutdown();
wiiLightOff();
_deinitNetwork();
Close_Inputs();
LWP_MutexDestroy(m_mutex);
m_mutex = 0;
for(TexSet::iterator texture = theme.texSet.begin(); texture != theme.texSet.end(); texture++)
{
if(texture->second.data.get())
texture->second.data.release();
}
theme.texSet.clear();
for(FontSet::iterator font = theme.fontSet.begin(); font != theme.fontSet.end(); font++)
{
if(font->second.data.get())
font->second.data.release();
}
theme.fontSet.clear();
for(SoundSet::iterator sound = theme.soundSet.begin(); sound != theme.soundSet.end(); sound++)
{
if(sound->second.get())
sound->second.release();
}
theme.soundSet.clear();
cleaned_up = true;
//gprintf(" \nMemory cleaned up\n");
gprintf("MEM1_freesize(): %i\nMEM2_freesize(): %i\n", MEM1_freesize(), MEM2_freesize());
}
void CMenu::_reload_wifi_gecko(void)
{
if(m_use_wifi_gecko)
{
_initAsyncNetwork();
while(net_get_status() == -EBUSY)
usleep(100);
}
}
void CMenu::_setAA(int aa)
{
switch (aa)
{
case 2:
case 3:
case 4:
case 5:
case 6:
case 8:
m_aa = aa;
break;
case 7:
m_aa = 6;
break;
default:
m_aa = 0;
}
}
void CMenu::_loadCFCfg(SThemeData &theme)
{
const char *domain = "_COVERFLOW";
//gprintf("Preparing to load sounds from %s\n", m_themeDataDir.c_str());
m_cf.setCachePath(m_cacheDir.c_str(), !m_cfg.getBool("GENERAL", "keep_png", true), m_cfg.getBool("GENERAL", "compress_cache", false));
m_cf.setBufferSize(m_cfg.getInt("GENERAL", "cover_buffer", 20));
// Coverflow Sounds
m_cf.setSounds(
SmartGuiSound(new GuiSound(sfmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "sound_flip").c_str()))),
_sound(theme.soundSet, domain, "sound_hover", hover_wav, hover_wav_size, string("default_btn_hover"), false),
_sound(theme.soundSet, domain, "sound_select", click_wav, click_wav_size, string("default_btn_click"), false),
SmartGuiSound(new GuiSound(sfmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "sound_cancel").c_str())))
);
// Textures
string texLoading = sfmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "loading_cover_box").c_str());
string texNoCover = sfmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "missing_cover_box").c_str());
string texLoadingFlat = sfmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "loading_cover_flat").c_str());
string texNoCoverFlat = sfmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString(domain, "missing_cover_flat").c_str());
m_cf.setTextures(texLoading, texLoadingFlat, texNoCover, texNoCoverFlat);
// Font
m_cf.setFont(_font(theme.fontSet, domain, "font", TITLEFONT), m_theme.getColor(domain, "font_color", CColor(0xFFFFFFFF)));
// Coverflow Count
m_numCFVersions = min(max(2, m_theme.getInt("_COVERFLOW", "number_of_modes", 2)), 15);
}
Vector3D CMenu::_getCFV3D(const string &domain, const string &key, const Vector3D &def, bool otherScrnFmt)
{
string key169(key);
string key43(key);
key43 += "_4_3";
if (m_vid.wide() == otherScrnFmt)
swap(key169, key43);
if (m_theme.has(domain, key169))
{
Vector3D v(m_theme.getVector3D(domain, key169));
m_theme.getVector3D(domain, key43, v);
return v;
}
return m_theme.getVector3D(domain, key169, m_theme.getVector3D(domain, key43, def));
}
int CMenu::_getCFInt(const string &domain, const string &key, int def, bool otherScrnFmt)
{
string key169(key);
string key43(key);
key43 += "_4_3";
if (m_vid.wide() == otherScrnFmt)
swap(key169, key43);
if (m_theme.has(domain, key169))
{
int v = m_theme.getInt(domain, key169);
m_theme.getInt(domain, key43, v);
return v;
}
return m_theme.getInt(domain, key169, m_theme.getInt(domain, key43, def));
}
float CMenu::_getCFFloat(const string &domain, const string &key, float def, bool otherScrnFmt)
{
string key169(key);
string key43(key);
key43 += "_4_3";
if (m_vid.wide() == otherScrnFmt)
swap(key169, key43);
if (m_theme.has(domain, key169))
{
float v = m_theme.getFloat(domain, key169);
m_theme.getFloat(domain, key43, v);
return v;
}
return m_theme.getFloat(domain, key169, m_theme.getFloat(domain, key43, def));
}
void CMenu::_loadCFLayout(int version, bool forceAA, bool otherScrnFmt)
{
bool homebrew = m_current_view == COVERFLOW_HOMEBREW;
bool smallbox = (homebrew || m_current_view == COVERFLOW_PLUGIN) && m_cfg.getBool(_domainFromView(), "smallbox", true);
string domain(homebrew ? fmt("_BREWFLOW_%i", version) : m_current_view == COVERFLOW_PLUGIN ? fmt("_EMUFLOW_%i", version) : fmt("_COVERFLOW_%i", version));
string domainSel(homebrew ? fmt("_BREWFLOW_%i_S", version) : m_current_view == COVERFLOW_PLUGIN ? fmt("_EMUFLOW_%i_S", version) : fmt("_COVERFLOW_%i_S", version));
bool sf = otherScrnFmt;
int max_fsaa = m_theme.getInt(domain, "max_fsaa", 3);
_setAA(forceAA ? max_fsaa : min(max_fsaa, m_cfg.getInt("GENERAL", "max_fsaa", 3)));
m_cf.setTextureQuality(m_theme.getFloat(domain, "tex_lod_bias", -3.f),
m_theme.getInt(domain, "tex_aniso", 2),
m_theme.getBool(domain, "tex_edge_lod", true));
m_cf.setRange(_getCFInt(domain, "rows", (smallbox && homebrew) ? 5 : 1, sf), _getCFInt(domain, "columns", 9, sf));
m_cf.setCameraPos(false,
_getCFV3D(domain, "camera_pos", Vector3D(0.f, 1.5f, 5.f), sf),
_getCFV3D(domain, "camera_aim", Vector3D(0.f, 0.f, -1.f), sf));
m_cf.setCameraPos(true,
_getCFV3D(domainSel, "camera_pos", Vector3D(0.f, 1.5f, 5.f), sf),
_getCFV3D(domainSel, "camera_aim", Vector3D(0.f, 0.f, -1.f), sf));
m_cf.setCameraOsc(false,
_getCFV3D(domain, "camera_osc_speed", Vector3D(2.f, 1.1f, 1.3f), sf),
_getCFV3D(domain, "camera_osc_amp", Vector3D(0.1f, 0.2f, 0.1f), sf));
m_cf.setCameraOsc(true,
_getCFV3D(domainSel, "camera_osc_speed", Vector3D(), sf),
_getCFV3D(domainSel, "camera_osc_amp", Vector3D(), sf));
float def_cvr_posX = (smallbox && homebrew) ? 1.f : 1.6f;
float def_cvr_posY = (smallbox && homebrew) ? -0.6f : 0.f;
m_cf.setCoverPos(false,
_getCFV3D(domain, "left_pos", Vector3D(-def_cvr_posX, def_cvr_posY, 0.f), sf),
_getCFV3D(domain, "right_pos", Vector3D(def_cvr_posX, def_cvr_posY, 0.f), sf),
_getCFV3D(domain, "center_pos", Vector3D(0.f, def_cvr_posY, 1.f), sf),
_getCFV3D(domain, "row_center_pos", Vector3D(0.f, def_cvr_posY, 0.f), sf));
def_cvr_posX = (smallbox && homebrew) ? 1.f : 4.6f;
float def_cvr_posX1 = (smallbox && homebrew) ? 0.f : -0.6f;
m_cf.setCoverPos(true,
_getCFV3D(domainSel, "left_pos", Vector3D(-def_cvr_posX, def_cvr_posY, 0.f), sf),
_getCFV3D(domainSel, "right_pos", Vector3D(def_cvr_posX, def_cvr_posY, 0.f), sf),
_getCFV3D(domainSel, "center_pos", Vector3D(def_cvr_posX1, 0.f, 2.6f), sf),
_getCFV3D(domainSel, "row_center_pos", Vector3D(0.f, def_cvr_posY, 0.f), sf));
m_cf.setCoverAngleOsc(false,
m_theme.getVector3D(domain, "cover_osc_speed", Vector3D(2.f, 2.f, 0.f)),
m_theme.getVector3D(domain, "cover_osc_amp", Vector3D(5.f, 10.f, 0.f)));
m_cf.setCoverAngleOsc(true,
m_theme.getVector3D(domainSel, "cover_osc_speed", Vector3D(2.1f, 2.1f, 0.f)),
m_theme.getVector3D(domainSel, "cover_osc_amp", Vector3D(2.f, 5.f, 0.f)));
m_cf.setCoverPosOsc(false,
m_theme.getVector3D(domain, "cover_pos_osc_speed"),
m_theme.getVector3D(domain, "cover_pos_osc_amp"));
m_cf.setCoverPosOsc(true,
m_theme.getVector3D(domainSel, "cover_pos_osc_speed"),
m_theme.getVector3D(domainSel, "cover_pos_osc_amp"));
float spacerX = (smallbox && homebrew) ? 1.f : 0.35f;
m_cf.setSpacers(false,
m_theme.getVector3D(domain, "left_spacer", Vector3D(-spacerX, 0.f, 0.f)),
m_theme.getVector3D(domain, "right_spacer", Vector3D(spacerX, 0.f, 0.f)));
m_cf.setSpacers(true,
m_theme.getVector3D(domainSel, "left_spacer", Vector3D(-spacerX, 0.f, 0.f)),
m_theme.getVector3D(domainSel, "right_spacer", Vector3D(spacerX, 0.f, 0.f)));
m_cf.setDeltaAngles(false,
m_theme.getVector3D(domain, "left_delta_angle"),
m_theme.getVector3D(domain, "right_delta_angle"));
m_cf.setDeltaAngles(true,
m_theme.getVector3D(domainSel, "left_delta_angle"),
m_theme.getVector3D(domainSel, "right_delta_angle"));
float angleY = (smallbox && homebrew) ? 0.f : 70.f;
m_cf.setAngles(false,
m_theme.getVector3D(domain, "left_angle", Vector3D(0.f, angleY, 0.f)),
m_theme.getVector3D(domain, "right_angle", Vector3D(0.f, -angleY, 0.f)),
m_theme.getVector3D(domain, "center_angle"),
m_theme.getVector3D(domain, "row_center_angle"));
angleY = (smallbox && homebrew) ? 0.f : 90.f;
float angleY1 = (smallbox && homebrew) ? 0.f : 380.f;
float angleX = (smallbox && homebrew) ? 0.f : -45.f;
m_cf.setAngles(true,
m_theme.getVector3D(domainSel, "left_angle", Vector3D(angleX, angleY, 0.f)),
m_theme.getVector3D(domainSel, "right_angle", Vector3D(angleX, -angleY, 0.f)),
m_theme.getVector3D(domainSel, "center_angle", Vector3D(0.f, angleY1, 0.f)),
m_theme.getVector3D(domainSel, "row_center_angle"));
angleX = smallbox ? 0.f : 55.f;
m_cf.setTitleAngles(false,
_getCFFloat(domain, "text_left_angle", -angleX, sf),
_getCFFloat(domain, "text_right_angle", angleX, sf),
_getCFFloat(domain, "text_center_angle", 0.f, sf));
m_cf.setTitleAngles(true,
_getCFFloat(domainSel, "text_left_angle", -angleX, sf),
_getCFFloat(domainSel, "text_right_angle", angleX, sf),
_getCFFloat(domainSel, "text_center_angle", 0.f, sf));
m_cf.setTitlePos(false,
_getCFV3D(domain, "text_left_pos", Vector3D(-4.f, 0.f, 1.3f), sf),
_getCFV3D(domain, "text_right_pos", Vector3D(4.f, 0.f, 1.3f), sf),
_getCFV3D(domain, "text_center_pos", Vector3D(0.f, 0.f, 2.6f), sf));
m_cf.setTitlePos(true,
_getCFV3D(domainSel, "text_left_pos", Vector3D(-4.f, 0.f, 1.3f), sf),
_getCFV3D(domainSel, "text_right_pos", Vector3D(4.f, 0.f, 1.3f), sf),
_getCFV3D(domainSel, "text_center_pos", Vector3D(1.7f, 1.8f, 1.6f), sf));
m_cf.setTitleWidth(false,
_getCFFloat(domain, "text_side_wrap_width", 500.f, sf),
_getCFFloat(domain, "text_center_wrap_width", 500.f, sf));
m_cf.setTitleWidth(true,
_getCFFloat(domainSel, "text_side_wrap_width", 500.f, sf),
_getCFFloat(domainSel, "text_center_wrap_width", 310.f, sf));
m_cf.setTitleStyle(false,
_textStyle(domain.c_str(), "text_side_style", FTGX_ALIGN_MIDDLE | FTGX_JUSTIFY_CENTER),
_textStyle(domain.c_str(), "text_center_style", FTGX_ALIGN_MIDDLE | FTGX_JUSTIFY_CENTER));
m_cf.setTitleStyle(true,
_textStyle(domainSel.c_str(), "text_side_style", FTGX_ALIGN_MIDDLE | FTGX_JUSTIFY_CENTER),
_textStyle(domainSel.c_str(), "text_center_style", FTGX_ALIGN_TOP | FTGX_JUSTIFY_RIGHT));
m_cf.setColors(false,
m_theme.getColor(domain, "color_beg", 0xCFFFFFFF),
m_theme.getColor(domain, "color_end", 0x3FFFFFFF),
m_theme.getColor(domain, "color_off", 0x7FFFFFFF));
m_cf.setColors(true,
m_theme.getColor(domainSel, "color_beg", 0x7FFFFFFF),
m_theme.getColor(domainSel, "color_end", 0x1FFFFFFF),
m_theme.getColor(domain, "color_off", 0x7FFFFFFF)); // Mouse not used once a selection has been made
m_cf.setMirrorAlpha(m_theme.getFloat(domain, "mirror_alpha", 0.25f), m_theme.getFloat(domain, "title_mirror_alpha", 0.2f)); // Doesn't depend on selection
m_cf.setMirrorBlur(m_theme.getBool(domain, "mirror_blur", true)); // Doesn't depend on selection
m_cf.setShadowColors(false,
m_theme.getColor(domain, "color_shadow_center", 0x00000000),
m_theme.getColor(domain, "color_shadow_beg", 0x00000000),
m_theme.getColor(domain, "color_shadow_end", 0x00000000),
m_theme.getColor(domain, "color_shadow_off", 0x00000000));
m_cf.setShadowColors(true,
m_theme.getColor(domainSel, "color_shadow_center", 0x0000007F),
m_theme.getColor(domainSel, "color_shadow_beg", 0x0000007F),
m_theme.getColor(domainSel, "color_shadow_end", 0x0000007F),
m_theme.getColor(domainSel, "color_shadow_off", 0x0000007F));
m_cf.setShadowPos(m_theme.getFloat(domain, "shadow_scale", 1.1f),
m_theme.getFloat(domain, "shadow_x"),
m_theme.getFloat(domain, "shadow_y"));
float spacerY = (smallbox && homebrew) ? 0.60f : 2.f;
m_cf.setRowSpacers(false,
m_theme.getVector3D(domain, "top_spacer", Vector3D(0.f, spacerY, 0.f)),
m_theme.getVector3D(domain, "bottom_spacer", Vector3D(0.f, -spacerY, 0.f)));
m_cf.setRowSpacers(true,
m_theme.getVector3D(domainSel, "top_spacer", Vector3D(0.f, spacerY, 0.f)),
m_theme.getVector3D(domainSel, "bottom_spacer", Vector3D(0.f, -spacerY, 0.f)));
m_cf.setRowDeltaAngles(false,
m_theme.getVector3D(domain, "top_delta_angle"),
m_theme.getVector3D(domain, "bottom_delta_angle"));
m_cf.setRowDeltaAngles(true,
m_theme.getVector3D(domainSel, "top_delta_angle"),
m_theme.getVector3D(domainSel, "bottom_delta_angle"));
m_cf.setRowAngles(false,
m_theme.getVector3D(domain, "top_angle"),
m_theme.getVector3D(domain, "bottom_angle"));
m_cf.setRowAngles(true,
m_theme.getVector3D(domainSel, "top_angle"),
m_theme.getVector3D(domainSel, "bottom_angle"));
Vector3D def_cvr_scale =
smallbox
? (homebrew
? Vector3D(0.667f, 0.25f, 1.f)
: Vector3D(1.f, 0.5f, 1.f))
: Vector3D(1.f, 1.f, 1.f);
m_cf.setCoverScale(false,
m_theme.getVector3D(domain, "left_scale", def_cvr_scale),
m_theme.getVector3D(domain, "right_scale", def_cvr_scale),
m_theme.getVector3D(domain, "center_scale", def_cvr_scale),
m_theme.getVector3D(domain, "row_center_scale", def_cvr_scale));
m_cf.setCoverScale(true,
m_theme.getVector3D(domainSel, "left_scale", def_cvr_scale),
m_theme.getVector3D(domainSel, "right_scale", def_cvr_scale),
m_theme.getVector3D(domainSel, "center_scale", def_cvr_scale),
m_theme.getVector3D(domainSel, "row_center_scale", def_cvr_scale));
float flipX = (smallbox && homebrew) ? 359.f : 180.f;
m_cf.setCoverFlipping(
_getCFV3D(domainSel, "flip_pos", Vector3D(), sf),
_getCFV3D(domainSel, "flip_angle", Vector3D(0.f, flipX, 0.f), sf),
_getCFV3D(domainSel, "flip_scale", def_cvr_scale, sf));
m_cf.setBlur(
m_theme.getInt(domain, "blur_resolution", 1),
m_theme.getInt(domain, "blur_radius", 2),
m_theme.getFloat(domain, "blur_factor", 1.f));
}
void CMenu::_buildMenus(void)
{
if(!m_base_font)
_loadDefaultFont(CONF_GetLanguage() == CONF_LANG_KOREAN);
// Default fonts
theme.btnFont = _font(theme.fontSet, "GENERAL", "button_font", BUTTONFONT);
theme.btnFontColor = m_theme.getColor("GENERAL", "button_font_color", 0xD0BFDFFF);
theme.lblFont = _font(theme.fontSet, "GENERAL", "label_font", LABELFONT);
theme.lblFontColor = m_theme.getColor("GENERAL", "label_font_color", 0xD0BFDFFF);
theme.titleFont = _font(theme.fontSet, "GENERAL", "title_font", TITLEFONT);
theme.titleFontColor = m_theme.getColor("GENERAL", "title_font_color", 0xFFFFFFFF);
theme.txtFont = _font(theme.fontSet, "GENERAL", "text_font", TEXTFONT);
theme.txtFontColor = m_theme.getColor("GENERAL", "text_font_color", 0xFFFFFFFF);
theme.selsbtnFontColor = m_theme.getColor("GENERAL", "selsbtn_font_color", 0xFA5882FF);
theme.selubtnFontColor = m_theme.getColor("GENERAL", "selubtn_font_color", 0xD0BFDFFF);
// Default Sounds
theme.clickSound = _sound(theme.soundSet, "GENERAL", "click_sound", click_wav, click_wav_size, string("default_btn_click"), false);
theme.hoverSound = _sound(theme.soundSet, "GENERAL", "hover_sound", hover_wav, hover_wav_size, string("default_btn_hover"), false);
theme.cameraSound = _sound(theme.soundSet, "GENERAL", "camera_sound", camera_wav, camera_wav_size, string("default_camera"), false);
m_cameraSound = theme.cameraSound;
// Default textures
theme.btnTexL.fromPNG(butleft_png);
theme.btnTexL = _texture(theme.texSet, "GENERAL", "button_texture_left", theme.btnTexL);
theme.btnTexR.fromPNG(butright_png);
theme.btnTexR = _texture(theme.texSet, "GENERAL", "button_texture_right", theme.btnTexR);
theme.btnTexC.fromPNG(butcenter_png);
theme.btnTexC = _texture(theme.texSet, "GENERAL", "button_texture_center", theme.btnTexC);
theme.btnTexLS.fromPNG(butsleft_png);
theme.btnTexLS = _texture(theme.texSet, "GENERAL", "button_texture_left_selected", theme.btnTexLS);
theme.btnTexRS.fromPNG(butsright_png);
theme.btnTexRS = _texture(theme.texSet, "GENERAL", "button_texture_right_selected", theme.btnTexRS);
theme.btnTexCS.fromPNG(butscenter_png);
theme.btnTexCS = _texture(theme.texSet, "GENERAL", "button_texture_center_selected", theme.btnTexCS);
theme.btnTexLH.fromPNG(buthleft_png);
theme.btnTexLH = _texture(theme.texSet, "GENERAL", "button_texture_hlleft", theme.btnTexLH);
theme.btnTexRH.fromPNG(buthright_png);
theme.btnTexRH = _texture(theme.texSet, "GENERAL", "button_texture_hlright", theme.btnTexRH);
theme.btnTexCH.fromPNG(buthcenter_png);
theme.btnTexCH = _texture(theme.texSet, "GENERAL", "button_texture_hlcenter", theme.btnTexCH);
theme.btnTexLSH.fromPNG(buthsleft_png);
theme.btnTexLSH = _texture(theme.texSet, "GENERAL", "button_texture_hlleft_selected", theme.btnTexLSH);
theme.btnTexRSH.fromPNG(buthsright_png);
theme.btnTexRSH = _texture(theme.texSet, "GENERAL", "button_texture_hlright_selected", theme.btnTexRSH);
theme.btnTexCSH.fromPNG(buthscenter_png);
theme.btnTexCSH = _texture(theme.texSet, "GENERAL", "button_texture_hlcenter_selected", theme.btnTexCSH);
theme.btnAUOn.fromPNG(butauon_png);
theme.btnAUOn = _texture(theme.texSet, "GENERAL", "button_au_on", theme.btnAUOn);
theme.btnAUOns.fromPNG(butauons_png);
theme.btnAUOns = _texture(theme.texSet, "GENERAL", "button_au_on_selected", theme.btnAUOns);
theme.btnAUOff.fromPNG(butauoff_png);
theme.btnAUOff = _texture(theme.texSet, "GENERAL", "button_au_off", theme.btnAUOff);
theme.btnAUOffs.fromPNG(butauoffs_png);
theme.btnAUOffs = _texture(theme.texSet, "GENERAL", "button_au_off_selected", theme.btnAUOffs);
theme.btnENOn.fromPNG(butenon_png);
theme.btnENOn = _texture(theme.texSet, "GENERAL", "button_en_on", theme.btnENOn);
theme.btnENOns.fromPNG(butenons_png);
theme.btnENOns = _texture(theme.texSet, "GENERAL", "button_en_on_selected", theme.btnENOns);
theme.btnENOff.fromPNG(butenoff_png);
theme.btnENOff = _texture(theme.texSet, "GENERAL", "button_en_off", theme.btnENOff);
theme.btnENOffs.fromPNG(butenoffs_png);
theme.btnENOffs = _texture(theme.texSet, "GENERAL", "button_en_off_selected", theme.btnENOffs);
theme.btnJAOn.fromPNG(butjaon_png);
theme.btnJAOn = _texture(theme.texSet, "GENERAL", "button_ja_on", theme.btnJAOn);
theme.btnJAOns.fromPNG(butjaons_png);
theme.btnJAOns = _texture(theme.texSet, "GENERAL", "button_ja_on_selected", theme.btnJAOns);
theme.btnJAOff.fromPNG(butjaoff_png);
theme.btnJAOff = _texture(theme.texSet, "GENERAL", "button_ja_off", theme.btnJAOff);
theme.btnJAOffs.fromPNG(butjaoffs_png);
theme.btnJAOffs = _texture(theme.texSet, "GENERAL", "button_ja_off_selected", theme.btnJAOffs);
theme.btnFROn.fromPNG(butfron_png);
theme.btnFROn = _texture(theme.texSet, "GENERAL", "button_fr_on", theme.btnFROn);
theme.btnFROns.fromPNG(butfrons_png);
theme.btnFROns = _texture(theme.texSet, "GENERAL", "button_fr_on_selected", theme.btnFROns);
theme.btnFROff.fromPNG(butfroff_png);
theme.btnFROff = _texture(theme.texSet, "GENERAL", "button_fr_off", theme.btnFROff);
theme.btnFROffs.fromPNG(butfroffs_png);
theme.btnFROffs = _texture(theme.texSet, "GENERAL", "button_fr_off_selected", theme.btnFROffs);
theme.btnDEOn.fromPNG(butdeon_png);
theme.btnDEOn = _texture(theme.texSet, "GENERAL", "button_de_on", theme.btnDEOn);
theme.btnDEOns.fromPNG(butdeons_png);
theme.btnDEOns = _texture(theme.texSet, "GENERAL", "button_de_on_selected", theme.btnDEOns);
theme.btnDEOff.fromPNG(butdeoff_png);
theme.btnDEOff = _texture(theme.texSet, "GENERAL", "button_de_off", theme.btnDEOff);
theme.btnDEOffs.fromPNG(butdeoffs_png);
theme.btnDEOffs = _texture(theme.texSet, "GENERAL", "button_de_off_selected", theme.btnDEOffs);
theme.btnESOn.fromPNG(buteson_png);
theme.btnESOn = _texture(theme.texSet, "GENERAL", "button_es_on", theme.btnESOn);
theme.btnESOns.fromPNG(butesons_png);
theme.btnESOns = _texture(theme.texSet, "GENERAL", "button_es_on_selected", theme.btnESOns);
theme.btnESOff.fromPNG(butesoff_png);
theme.btnESOff = _texture(theme.texSet, "GENERAL", "button_es_off", theme.btnESOff);
theme.btnESOffs.fromPNG(butesoffs_png);
theme.btnESOffs = _texture(theme.texSet, "GENERAL", "button_es_off_selected", theme.btnESOffs);
theme.btnITOn.fromPNG(butiton_png);
theme.btnITOn = _texture(theme.texSet, "GENERAL", "button_it_on", theme.btnITOn);
theme.btnITOns.fromPNG(butitons_png);
theme.btnITOns = _texture(theme.texSet, "GENERAL", "button_it_on_selected", theme.btnITOns);
theme.btnITOff.fromPNG(butitoff_png);
theme.btnITOff = _texture(theme.texSet, "GENERAL", "button_it_off", theme.btnITOff);
theme.btnITOffs.fromPNG(butitoffs_png);
theme.btnITOffs = _texture(theme.texSet, "GENERAL", "button_it_off_selected", theme.btnITOffs);
theme.btnNLOn.fromPNG(butnlon_png);
theme.btnNLOn = _texture(theme.texSet, "GENERAL", "button_nl_on", theme.btnNLOn);
theme.btnNLOns.fromPNG(butnlons_png);
theme.btnNLOns = _texture(theme.texSet, "GENERAL", "button_nl_on_selected", theme.btnNLOns);
theme.btnNLOff.fromPNG(butnloff_png);
theme.btnNLOff = _texture(theme.texSet, "GENERAL", "button_nl_off", theme.btnNLOff);
theme.btnNLOffs.fromPNG(butnloffs_png);
theme.btnNLOffs = _texture(theme.texSet, "GENERAL", "button_nl_off_selected", theme.btnNLOffs);
theme.btnPTOn.fromPNG(butpton_png);
theme.btnPTOn = _texture(theme.texSet, "GENERAL", "button_pt_on", theme.btnPTOn);
theme.btnPTOns.fromPNG(butptons_png);
theme.btnPTOns = _texture(theme.texSet, "GENERAL", "button_pt_on_selected", theme.btnPTOns);
theme.btnPTOff.fromPNG(butptoff_png);
theme.btnPTOff = _texture(theme.texSet, "GENERAL", "button_pt_off", theme.btnPTOff);
theme.btnPTOffs.fromPNG(butptoffs_png);
theme.btnPTOffs = _texture(theme.texSet, "GENERAL", "button_pt_off_selected", theme.btnPTOffs);
theme.btnRUOn.fromPNG(butruon_png);
theme.btnRUOn = _texture(theme.texSet, "GENERAL", "button_ru_on", theme.btnRUOn);
theme.btnRUOns.fromPNG(butruons_png);
theme.btnRUOns = _texture(theme.texSet, "GENERAL", "button_ru_on_selected", theme.btnRUOns);
theme.btnRUOff.fromPNG(butruoff_png);
theme.btnRUOff = _texture(theme.texSet, "GENERAL", "button_ru_off", theme.btnRUOff);
theme.btnRUOffs.fromPNG(butruoffs_png);
theme.btnRUOffs = _texture(theme.texSet, "GENERAL", "button_ru_off_selected", theme.btnRUOffs);
theme.btnKOOn.fromPNG(butkoon_png);
theme.btnKOOn = _texture(theme.texSet, "GENERAL", "button_ko_on", theme.btnKOOn);
theme.btnKOOns.fromPNG(butkoons_png);
theme.btnKOOns = _texture(theme.texSet, "GENERAL", "button_ko_on_selected", theme.btnKOOns);
theme.btnKOOff.fromPNG(butkooff_png);
theme.btnKOOff = _texture(theme.texSet, "GENERAL", "button_ko_off", theme.btnKOOff);
theme.btnKOOffs.fromPNG(butkooffs_png);
theme.btnKOOffs = _texture(theme.texSet, "GENERAL", "button_ko_off_selected", theme.btnKOOffs);
theme.btnZHCNOn.fromPNG(butzhcnon_png);
theme.btnZHCNOn = _texture(theme.texSet, "GENERAL", "button_zhcn_on", theme.btnZHCNOn);
theme.btnZHCNOns.fromPNG(butzhcnons_png);
theme.btnZHCNOns = _texture(theme.texSet, "GENERAL", "button_zhcn_on_selected", theme.btnZHCNOns);
theme.btnZHCNOff.fromPNG(butzhcnoff_png);
theme.btnZHCNOff = _texture(theme.texSet, "GENERAL", "button_zhcn_off", theme.btnZHCNOff);
theme.btnZHCNOffs.fromPNG(butzhcnoffs_png);
theme.btnZHCNOffs = _texture(theme.texSet, "GENERAL", "button_zhcn_off_selected", theme.btnZHCNOffs);
theme.checkboxoff.fromPNG(checkbox_png);
theme.checkboxoff = _texture(theme.texSet, "GENERAL", "checkbox_off", theme.checkboxoff);
theme.checkboxoffs.fromPNG(checkbox_png);
theme.checkboxoffs = _texture(theme.texSet, "GENERAL", "checkbox_off_selected", theme.checkboxoffs);
theme.checkboxon.fromPNG(checkboxs_png);
theme.checkboxon = _texture(theme.texSet, "GENERAL", "checkbox_on", theme.checkboxon);
theme.checkboxons.fromPNG(checkboxs_png);
theme.checkboxons = _texture(theme.texSet, "GENERAL", "checkbox_on_selected", theme.checkboxons);
theme.checkboxHid.fromPNG(checkboxhid_png);
theme.checkboxHid = _texture(theme.texSet, "GENERAL", "checkbox_Hid", theme.checkboxHid);
theme.checkboxHids.fromPNG(checkboxhid_png);
theme.checkboxHids = _texture(theme.texSet, "GENERAL", "checkbox_Hid_selected", theme.checkboxHids);
theme.checkboxReq.fromPNG(checkboxreq_png);
theme.checkboxReq = _texture(theme.texSet, "GENERAL", "checkbox_Req", theme.checkboxReq);
theme.checkboxReqs.fromPNG(checkboxreq_png);
theme.checkboxReqs = _texture(theme.texSet, "GENERAL", "checkbox_Req_selected", theme.checkboxReqs);
theme.pbarTexL.fromPNG(pbarleft_png);
theme.pbarTexL = _texture(theme.texSet, "GENERAL", "progressbar_texture_left", theme.pbarTexL);
theme.pbarTexR.fromPNG(pbarright_png);
theme.pbarTexR = _texture(theme.texSet, "GENERAL", "progressbar_texture_right", theme.pbarTexR);
theme.pbarTexC.fromPNG(pbarcenter_png);
theme.pbarTexC = _texture(theme.texSet, "GENERAL", "progressbar_texture_center", theme.pbarTexC);
theme.pbarTexLS.fromPNG(pbarlefts_png);
theme.pbarTexLS = _texture(theme.texSet, "GENERAL", "progressbar_texture_left_selected", theme.pbarTexLS);
theme.pbarTexRS.fromPNG(pbarrights_png);
theme.pbarTexRS = _texture(theme.texSet, "GENERAL", "progressbar_texture_right_selected", theme.pbarTexRS);
theme.pbarTexCS.fromPNG(pbarcenters_png);
theme.pbarTexCS = _texture(theme.texSet, "GENERAL", "progressbar_texture_center_selected", theme.pbarTexCS);
theme.btnTexPlus.fromPNG(btnplus_png);
theme.btnTexPlus = _texture(theme.texSet, "GENERAL", "plus_button_texture", theme.btnTexPlus);
theme.btnTexPlusS.fromPNG(btnpluss_png);
theme.btnTexPlusS = _texture(theme.texSet, "GENERAL", "plus_button_texture_selected", theme.btnTexPlusS);
theme.btnTexMinus.fromPNG(btnminus_png);
theme.btnTexMinus = _texture(theme.texSet, "GENERAL", "minus_button_texture", theme.btnTexMinus);
theme.btnTexMinusS.fromPNG(btnminuss_png);
theme.btnTexMinusS = _texture(theme.texSet, "GENERAL", "minus_button_texture_selected", theme.btnTexMinusS);
// Default background
theme.bg.fromJPG(background_jpg, background_jpg_size);
m_mainBgLQ.fromJPG(background_jpg, background_jpg_size, GX_TF_CMPR, ALLOC_MEM2, 64, 64);
m_gameBgLQ = m_mainBgLQ;
// Build menus
_initMainMenu(theme);
_initErrorMenu(theme);
_initConfigAdvMenu(theme);
_initConfigSndMenu(theme);
_initConfig4Menu(theme);
_initConfigScreenMenu(theme);
_initConfig3Menu(theme);
_initConfigMenu(theme);
_initGameMenu(theme);
_initDownloadMenu(theme);
_initCodeMenu(theme);
_initAboutMenu(theme);
_initWBFSMenu(theme);
_initCFThemeMenu(theme);
_initGameSettingsMenu(theme);
_initCheatSettingsMenu(theme);
_initSourceMenu(theme);
_initPluginSettingsMenu(theme);
_initCategorySettingsMenu(theme);
_initSystemMenu(theme);
_initGameInfoMenu(theme);
_initNandEmuMenu(theme);
_initHomeAndExitToMenu(theme);
_loadCFCfg(theme);
}
typedef struct
{
string ext;
u32 min;
u32 max;
u32 def;
u32 res;
} FontHolder;
SFont CMenu::_font(CMenu::FontSet &fontSet, const char *domain, const char *key, u32 fontSize, u32 lineSpacing, u32 weight, u32 index, const char *genKey)
{
string filename = "";
bool general = strncmp(domain, "GENERAL", 7) == 0;
FontHolder fonts[3] = {{ "_size", 6u, 300u, fontSize, 0 }, { "_line_height", 6u, 300u, lineSpacing, 0 }, { "_weight", 1u, 32u, weight, 0 }};
if(!general)
filename = m_theme.getString(domain, key);
if(filename.empty())
filename = m_theme.getString("GENERAL", genKey, genKey);
bool useDefault = filename == genKey;
for(u32 i = 0; i < 3; i++)
{
string defValue = genKey;
defValue += fonts[i].ext;
string value = key;
value += fonts[i].ext;
if(!general)
fonts[i].res = (u32)m_theme.getInt(domain, value);
if(fonts[i].res <= 0)
fonts[i].res = (u32)m_theme.getInt("GENERAL", defValue);
fonts[i].res = min(max(fonts[i].min, fonts[i].res <= 0 ? fonts[i].def : fonts[i].res), fonts[i].max);
}
// Try to find the same font with the same size
CMenu::FontSet::iterator i = fontSet.find(CMenu::FontDesc(upperCase(filename.c_str()), fonts[0].res));
if (i != fontSet.end()) return i->second;
// TTF not found in memory, load it to create a new font
SFont retFont;
if (!useDefault && retFont.fromFile(fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str()), fonts[0].res, fonts[1].res, fonts[2].res, index))
{
// Theme Font
fontSet[CMenu::FontDesc(upperCase(filename.c_str()), fonts[0].res)] = retFont;
return retFont;
}
if(!m_base_font) _loadDefaultFont(CONF_GetLanguage() == CONF_LANG_KOREAN);
if(retFont.fromBuffer(m_base_font, m_base_font_size, fonts[0].res, fonts[1].res, fonts[2].res, index))
{
// Default font
fontSet[CMenu::FontDesc(upperCase(filename.c_str()), fonts[0].res)] = retFont;
return retFont;
}
return retFont;
}
vector<STexture> CMenu::_textures(TexSet &texSet, const char *domain, const char *key)
{
vector<STexture> textures;
if (m_theme.loaded())
{
vector<string> filenames = m_theme.getStrings(domain, key);
if (filenames.size() > 0)
{
for (vector<string>::iterator itr = filenames.begin(); itr != filenames.end(); itr++)
{
string filename = *itr;
CMenu::TexSet::iterator i = texSet.find(filename);
if (i != texSet.end())
{
textures.push_back(i->second);
}
STexture tex;
if (STexture::TE_OK == tex.fromImageFile(fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str())))
{
texSet[filename] = tex;
textures.push_back(tex);
}
}
}
}
return textures;
}
STexture CMenu::_texture(CMenu::TexSet &texSet, const char *domain, const char *key, STexture def)
{
string filename;
if (m_theme.loaded())
{
filename = m_theme.getString(domain, key);
if (!filename.empty())
{
CMenu::TexSet::iterator i = texSet.find(filename);
if (i != texSet.end())
return i->second;
STexture tex;
if (STexture::TE_OK == tex.fromImageFile(fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str())))
{
def.data.release();
texSet[filename] = tex;
return tex;
}
}
}
texSet[filename] = def;
return def;
}
// Only for loading defaults and GENERAL domains!!
SmartGuiSound CMenu::_sound(CMenu::SoundSet &soundSet, const char *domain, const char *key, const u8 * snd, u32 len, string name, bool isAllocated)
{
string filename = m_theme.getString(domain, key, "");
if (filename.empty()) filename = name;
CMenu::SoundSet::iterator i = soundSet.find(upperCase(filename.c_str()));
if (i == soundSet.end())
{
if(strncmp(filename.c_str(), name.c_str(), name.size()) != 0)
soundSet[upperCase(filename.c_str())] = SmartGuiSound(new GuiSound(fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str())));
else
soundSet[upperCase(filename.c_str())] = SmartGuiSound(new GuiSound(snd, len, filename, isAllocated));
return soundSet[upperCase(filename.c_str())];
}
return i->second;
}
//For buttons and labels only!!
SmartGuiSound CMenu::_sound(CMenu::SoundSet &soundSet, const char *domain, const char *key, string name)
{
string filename = m_theme.getString(domain, key);
if (filename.empty())
{
if(name.find_last_of('/') != string::npos)
name = name.substr(name.find_last_of('/')+1);
return soundSet[upperCase(name.c_str())]; // General/Default are already cached!
}
CMenu::SoundSet::iterator i = soundSet.find(upperCase(filename.c_str()));
if (i == soundSet.end())
{
soundSet[upperCase(filename.c_str())] = SmartGuiSound(new GuiSound(fmt("%s/%s", m_themeDataDir.c_str(), filename.c_str())));
return soundSet[upperCase(filename.c_str())];
}
return i->second;
}
u16 CMenu::_textStyle(const char *domain, const char *key, u16 def)
{
u16 textStyle = 0;
string style(m_theme.getString(domain, key));
if (style.empty()) return def;
if (style.find_first_of("Cc") != string::npos)
textStyle |= FTGX_JUSTIFY_CENTER;
else if (style.find_first_of("Rr") != string::npos)
textStyle |= FTGX_JUSTIFY_RIGHT;
else
textStyle |= FTGX_JUSTIFY_LEFT;
if (style.find_first_of("Mm") != string::npos)
textStyle |= FTGX_ALIGN_MIDDLE;
else if (style.find_first_of("Bb") != string::npos)
textStyle |= FTGX_ALIGN_BOTTOM;
else
textStyle |= FTGX_ALIGN_TOP;
return textStyle;
}
s16 CMenu::_addButton(CMenu::SThemeData &theme, const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color)
{
SButtonTextureSet btnTexSet;
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
btnTexSet.left = _texture(theme.texSet, domain, "texture_left", theme.btnTexL);
btnTexSet.right = _texture(theme.texSet, domain, "texture_right", theme.btnTexR);
btnTexSet.center = _texture(theme.texSet, domain, "texture_center", theme.btnTexC);
btnTexSet.leftSel = _texture(theme.texSet, domain, "texture_left_selected", theme.btnTexLS);
btnTexSet.rightSel = _texture(theme.texSet, domain, "texture_right_selected", theme.btnTexRS);
btnTexSet.centerSel = _texture(theme.texSet, domain, "texture_center_selected", theme.btnTexCS);
font = _font(theme.fontSet, domain, "font", BUTTONFONT);
SmartGuiSound clickSound = _sound(theme.soundSet, domain, "click_sound", theme.clickSound->GetName());
SmartGuiSound hoverSound = _sound(theme.soundSet, domain, "hover_sound", theme.hoverSound->GetName());
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
x = m_vid.width() - x - width;
if (btnPos & FTGX_ALIGN_BOTTOM)
y = m_vid.height() - y - height;
return m_btnMgr.addButton(font, text, x, y, width, height, c, btnTexSet, clickSound, hoverSound);
}
s16 CMenu::_addSelButton(CMenu::SThemeData &theme, const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color)
{
SButtonTextureSet btnTexSet;
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
btnTexSet.left = _texture(theme.texSet, domain, "texture_left", theme.btnTexLH);
btnTexSet.right = _texture(theme.texSet, domain, "texture_right", theme.btnTexRH);
btnTexSet.center = _texture(theme.texSet, domain, "texture_center", theme.btnTexCH);
btnTexSet.leftSel = _texture(theme.texSet, domain, "texture_left_selected", theme.btnTexLSH);
btnTexSet.rightSel = _texture(theme.texSet, domain, "texture_right_selected", theme.btnTexRSH);
btnTexSet.centerSel = _texture(theme.texSet, domain, "texture_center_selected", theme.btnTexCSH);
font = _font(theme.fontSet, domain, "font", BUTTONFONT);
SmartGuiSound clickSound = _sound(theme.soundSet, domain, "click_sound", theme.clickSound->GetName());
SmartGuiSound hoverSound = _sound(theme.soundSet, domain, "hover_sound", theme.hoverSound->GetName());
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
x = m_vid.width() - x - width;
if (btnPos & FTGX_ALIGN_BOTTOM)
y = m_vid.height() - y - height;
return m_btnMgr.addButton(font, text, x, y, width, height, c, btnTexSet, clickSound, hoverSound);
}
s16 CMenu::_addPicButton(CMenu::SThemeData &theme, const char *domain, STexture &texNormal, STexture &texSelected, int x, int y, u32 width, u32 height)
{
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
STexture tex1 = _texture(theme.texSet, domain, "texture_normal", texNormal);
STexture tex2 = _texture(theme.texSet, domain, "texture_selected", texSelected);
SmartGuiSound clickSound = _sound(theme.soundSet, domain, "click_sound", theme.clickSound->GetName());
SmartGuiSound hoverSound = _sound(theme.soundSet, domain, "hover_sound", theme.hoverSound->GetName());
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
x = m_vid.width() - x - width;
if (btnPos & FTGX_ALIGN_BOTTOM)
y = m_vid.height() - y - height;
return m_btnMgr.addPicButton(tex1, tex2, x, y, width, height, clickSound, hoverSound);
}
s16 CMenu::_addTitle(CMenu::SThemeData &theme, const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color, s16 style)
{
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
font = _font(theme.fontSet, domain, "font", TITLEFONT);
style = _textStyle(domain, "style", style);
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
x = m_vid.width() - x - width;
if (btnPos & FTGX_ALIGN_BOTTOM)
y = m_vid.height() - y - height;
return m_btnMgr.addLabel(font, text, x, y, width, height, c, style);
}
s16 CMenu::_addText(CMenu::SThemeData &theme, const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color, s16 style)
{
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
font = _font(theme.fontSet, domain, "font", TEXTFONT);
style = _textStyle(domain, "style", style);
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
x = m_vid.width() - x - width;
if (btnPos & FTGX_ALIGN_BOTTOM)
y = m_vid.height() - y - height;
return m_btnMgr.addLabel(font, text, x, y, width, height, c, style);
}
s16 CMenu::_addLabel(CMenu::SThemeData &theme, const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color, s16 style)
{
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
font = _font(theme.fontSet, domain, "font", LABELFONT);
style = _textStyle(domain, "style", style);
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
x = m_vid.width() - x - width;
if (btnPos & FTGX_ALIGN_BOTTOM)
y = m_vid.height() - y - height;
return m_btnMgr.addLabel(font, text, x, y, width, height, c, style);
}
s16 CMenu::_addLabel(CMenu::SThemeData &theme, const char *domain, SFont font, const wstringEx &text, int x, int y, u32 width, u32 height, const CColor &color, s16 style, STexture &bg)
{
CColor c(color);
c = m_theme.getColor(domain, "color", c);
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
font = _font(theme.fontSet, domain, "font", BUTTONFONT);
STexture texBg = _texture(theme.texSet, domain, "background_texture", bg);
style = _textStyle(domain, "style", style);
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
x = m_vid.width() - x - width;
if (btnPos & FTGX_ALIGN_BOTTOM)
y = m_vid.height() - y - height;
return m_btnMgr.addLabel(font, text, x, y, width, height, c, style, texBg);
}
s16 CMenu::_addProgressBar(CMenu::SThemeData &theme, const char *domain, int x, int y, u32 width, u32 height)
{
SButtonTextureSet btnTexSet;
x = m_theme.getInt(domain, "x", x);
y = m_theme.getInt(domain, "y", y);
width = m_theme.getInt(domain, "width", width);
height = m_theme.getInt(domain, "height", height);
btnTexSet.left = _texture(theme.texSet, domain, "texture_left", theme.pbarTexL);
btnTexSet.right = _texture(theme.texSet, domain, "texture_right", theme.pbarTexR);
btnTexSet.center = _texture(theme.texSet, domain, "texture_center", theme.pbarTexC);
btnTexSet.leftSel = _texture(theme.texSet, domain, "texture_left_selected", theme.pbarTexLS);
btnTexSet.rightSel = _texture(theme.texSet, domain, "texture_right_selected", theme.pbarTexRS);
btnTexSet.centerSel = _texture(theme.texSet, domain, "texture_center_selected", theme.pbarTexCS);
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
x = m_vid.width() - x - width;
if (btnPos & FTGX_ALIGN_BOTTOM)
y = m_vid.height() - y - height;
return m_btnMgr.addProgressBar(x, y, width, height, btnTexSet);
}
void CMenu::_setHideAnim(s16 id, const char *domain, int dx, int dy, float scaleX, float scaleY)
{
dx = m_theme.getInt(domain, "effect_x", dx);
dy = m_theme.getInt(domain, "effect_y", dy);
scaleX = m_theme.getFloat(domain, "effect_scale_x", scaleX);
scaleY = m_theme.getFloat(domain, "effect_scale_y", scaleY);
int x, y;
u32 width, height;
m_btnMgr.getDimensions(id, x, y, width, height);
u16 btnPos = _textStyle(domain, "elmstyle", FTGX_JUSTIFY_LEFT | FTGX_ALIGN_TOP);
if (btnPos & FTGX_JUSTIFY_RIGHT)
{
dx = m_vid.width() - dx - width;
scaleX = m_vid.width() - scaleX - width;
}
if (btnPos & FTGX_ALIGN_BOTTOM)
{
dy = m_vid.height() - dy - height;
scaleY = m_vid.height() - scaleY - height;
}
m_btnMgr.hide(id, dx, dy, scaleX, scaleY, true);
}
void CMenu::_addUserLabels(CMenu::SThemeData &theme, s16 *ids, u32 size, const char *domain)
{
_addUserLabels(theme, ids, 0, size, domain);
}
void CMenu::_addUserLabels(CMenu::SThemeData &theme, s16 *ids, u32 start, u32 size, const char *domain)
{
for(u32 i = start; i < start + size; ++i)
{
string dom(sfmt("%s/USER%i", domain, i + 1));
if (m_theme.hasDomain(dom))
{
STexture emptyTex;
ids[i] = _addLabel(theme, dom.c_str(), theme.lblFont, L"", 40, 200, 64, 64, CColor(0xFFFFFFFF), 0, emptyTex);
_setHideAnim(ids[i], dom.c_str(), -50, 0, 0.f, 0.f);
}
else
ids[i] = -1;
}
}
void CMenu::_initCF(void)
{
Config dump, gameAgeList;
GameTDB gametdb;
const char *domain = _domainFromView();
m_cf.clear();
m_cf.reserve(m_gameList.size());
const vector<bool> *EnabledPlugins;
if(m_current_view == COVERFLOW_PLUGIN)
EnabledPlugins = m_plugin.GetEnabledPlugins(m_cfg);
bool dumpGameLst = m_cfg.getBool(domain, "dump_list", true);
if(dumpGameLst) dump.load(fmt("%s/" TITLES_DUMP_FILENAME, m_settingsDir.c_str()));
m_gcfg1.load(fmt("%s/" GAME_SETTINGS1_FILENAME, m_settingsDir.c_str()));
int ageLock = m_cfg.getInt("GENERAL", "age_lock");
if (ageLock < 2 || ageLock > 19)
ageLock = 19;
if (ageLock < 19)
{
gameAgeList.load(fmt("%s/" AGE_LOCK_FILENAME, m_settingsDir.c_str()));
if (m_current_view == COVERFLOW_USB || m_current_view == COVERFLOW_CHANNEL)
{
gametdb.OpenFile(sfmt("%s/wiitdb.xml", m_settingsDir.c_str()).c_str());
gametdb.SetLanguageCode(m_loc.getString(m_curLanguage, "gametdb_code", "EN").c_str());
}
}
// check for single plugin selected
u8 pos = 0;
u8 enabledPluginsCount = 0;
if(m_current_view == COVERFLOW_PLUGIN && EnabledPlugins->size() != 0)
{
char PluginMagicWord[9];
for(u8 i = 0; i < EnabledPlugins->size(); i++)
{
snprintf(PluginMagicWord, sizeof(PluginMagicWord), "%08x", m_plugin.getPluginMagic(i));
if(m_cfg.getBool("PLUGIN", PluginMagicWord, true))
{
pos = i;
enabledPluginsCount++;
}
}
}
for (u32 i = 0; i < m_gameList.size(); ++i)
{
string id;
string tempname(m_gameList[i].path);
u64 chantitle = TITLE_ID(m_gameList[i].settings[0],m_gameList[i].settings[1]);
if(m_gameList[i].type == TYPE_HOMEBREW)
{
tempname.assign(&tempname[tempname.find_last_of('/') + 1]);
id = tempname;
}
else if(m_gameList[i].type == TYPE_PLUGIN)
{
if(tempname.find(':') != string::npos)
{
if(tempname.empty() || tempname.find_first_of('/') == string::npos)
continue;
tempname.erase(0, tempname.find_first_of('/')+1);
string dirName = tempname.substr(0, tempname.find_first_of('/')+1);
if (tempname.find_first_of('/') == string::npos)
{
continue;
}
tempname.assign(&tempname[tempname.find_last_of('/') + 1]);
if(tempname.find_last_of('.') == string::npos)
{
continue;
}
tempname.erase(tempname.find_last_of('.'), tempname.size() - tempname.find_last_of('.'));
id = dirName+tempname;
}
else
id = tempname;
}
else
{
if(m_gameList[i].type == TYPE_CHANNEL && chantitle == HBC_108)
strncpy(m_gameList[i].id, "JODI", 6);
id = string(m_gameList[i].id);
}
bool ageLocked = false;
if (ageLock < 19)
{
int ageRated = min(max(gameAgeList.getInt(domain, id), 0), 19);
if(ageRated == 0 && (m_gameList[i].type == TYPE_WII_GAME || m_gameList[i].type == TYPE_CHANNEL))
{
GameXMLInfo gameinfo;
if(gametdb.IsLoaded() && gametdb.GetGameXMLInfo(id.c_str(), &gameinfo))
{
switch(gameinfo.RatingType)
{
case GAMETDB_RATING_TYPE_CERO:
if (gameinfo.RatingValue == "A")
ageRated = 3;
else if (gameinfo.RatingValue == "B")
ageRated = 12;
else if (gameinfo.RatingValue == "D")
ageRated = 15;
else if (gameinfo.RatingValue == "C")
ageRated = 17;
else if (gameinfo.RatingValue == "Z")
ageRated = 18;
break;
case GAMETDB_RATING_TYPE_ESRB:
if (gameinfo.RatingValue == "E")
ageRated = 6;
else if (gameinfo.RatingValue == "EC")
ageRated = 3;
else if (gameinfo.RatingValue == "E10+")
ageRated = 10;
else if (gameinfo.RatingValue == "T")
ageRated = 13;
else if (gameinfo.RatingValue == "M")
ageRated = 17;
else if (gameinfo.RatingValue == "AO")
ageRated = 18;
break;
case GAMETDB_RATING_TYPE_PEGI:
if (gameinfo.RatingValue == "3")
ageRated = 3;
else if (gameinfo.RatingValue == "7")
ageRated = 7;
else if (gameinfo.RatingValue == "12")
ageRated = 12;
else if (gameinfo.RatingValue == "16")
ageRated = 16;
else if (gameinfo.RatingValue == "18")
ageRated = 18;
break;
case GAMETDB_RATING_TYPE_GRB:
if (gameinfo.RatingValue == "A")
ageRated = 3;
else if (gameinfo.RatingValue == "12")
ageRated = 12;
else if (gameinfo.RatingValue == "15")
ageRated = 15;
else if (gameinfo.RatingValue == "18")
ageRated = 18;
break;
default:
break;
}
}
}
if(ageRated == 0)
ageRated = min(max(m_cfg.getInt("GENERAL", "age_lock_default", AGE_LOCK_DEFAULT), 2), 19);
if(ageRated == 0)
ageRated = AGE_LOCK_DEFAULT;
if(ageRated > ageLock)
ageLocked = true;
}
if((!m_favorites || m_gcfg1.getBool("FAVORITES", id, false))
&& (!m_locked || !m_gcfg1.getBool("ADULTONLY", id, false))
&& !ageLocked)
{
string catDomain;
switch(m_gameList[i].type)
{
case TYPE_CHANNEL:
catDomain = "NAND";
break;
case TYPE_HOMEBREW:
catDomain = "HOMEBREW";
break;
case TYPE_GC_GAME:
catDomain = "DML";
break;
case TYPE_PLUGIN:
catDomain = "EMULATOR";
break;
default:
catDomain = "GAMES";
}
if(enabledPluginsCount == 1)
{
catDomain = (m_plugin.GetPluginName(pos)).toUTF8();
if(m_gameList[i].settings[0] != m_plugin.getPluginMagic(pos))
continue;
}
const char *requiredCats = m_cat.getString(fmt("%s/GENERAL", catDomain.c_str()), "required_categories").c_str();
const char *selectedCats = m_cat.getString(fmt("%s/GENERAL", catDomain.c_str()), "selected_categories").c_str();
const char *hiddenCats = m_cat.getString(fmt("%s/GENERAL", catDomain.c_str()), "hidden_categories").c_str();
u8 numReqCats = strlen(requiredCats);
u8 numSelCats = strlen(selectedCats);
u8 numHidCats = strlen(hiddenCats);
if(numReqCats != 0 || numSelCats != 0 || numHidCats != 0) // if all 0 skip checking cats and show all games
{
const char *idCats = m_cat.getString(catDomain, id).c_str();
u8 numIdCats = strlen(idCats);
bool inaCat = false;
bool inHiddenCat = false;
int reqMatch = 0;
if(numIdCats != 0)
{
for(u8 j = 0; j < numIdCats; ++j)
{
int k = (static_cast<int>(idCats[j])) - 32;
if(k <= 0)
continue;
bool match = false;
if(numReqCats != 0)
{
for(u8 l = 0; l < numReqCats; ++l)
{
if(k == (static_cast<int>(requiredCats[l]) - 32))
{
match = true;
reqMatch++;
inaCat = true;
}
}
}
if(match)
continue;
if(numSelCats != 0)
{
for(u8 l = 0; l < numSelCats; ++l)
{
if(k == (static_cast<int>(selectedCats[l]) - 32))
{
match = true;
inaCat = true;
}
}
}
if(match)
continue;
if(numHidCats != 0)
{
for(u8 l = 0; l < numHidCats; ++l)
{
if(k == (static_cast<int>(hiddenCats[l]) - 32))
inHiddenCat = true;
}
}
}
}
//continue; means don't add game to list (don't show)
if(inHiddenCat)
continue;
if(numReqCats != reqMatch)
continue;
if(!inaCat)
{
if(numHidCats == 0)
continue;
else if(numSelCats > 0)
continue;
}
}
int playcount = m_gcfg1.getInt("PLAYCOUNT", id, 0);
unsigned int lastPlayed = m_gcfg1.getUInt("LASTPLAYED", id, 0);
if(dumpGameLst)
dump.setWString(domain, id, m_gameList[i].title);
if(m_gameList[i].type == TYPE_PLUGIN)
{
string tempname(m_gameList[i].path);
if(tempname.find_last_of("/") != string::npos)
tempname.assign(&tempname[tempname.find_last_of("/") + 1]);
string coverFolder(m_plugin.GetCoverFolderName(m_gameList[i].settings[0]));
if(EnabledPlugins->size() == 0) //all plugins
{
if(coverFolder.size() > 0)
m_cf.addItem(&m_gameList[i], fmt("%s/%s/%s.png", m_picDir.c_str(), coverFolder.c_str(), tempname.c_str()), fmt("%s/%s/%s.png", m_boxPicDir.c_str(), coverFolder.c_str(), tempname.c_str()), playcount, lastPlayed);
else
m_cf.addItem(&m_gameList[i], fmt("%s/%s.png", m_picDir.c_str(), tempname.c_str()), fmt("%s/%s.png", m_boxPicDir.c_str(), tempname.c_str()), playcount, lastPlayed);
}
else
{
for(u8 j = 0; j < EnabledPlugins->size(); j++)
{
if(EnabledPlugins->at(j) == true && m_gameList[i].settings[0] == m_plugin.getPluginMagic(j))
{
if(coverFolder.size() > 0)
m_cf.addItem(&m_gameList[i], fmt("%s/%s/%s.png", m_picDir.c_str(), coverFolder.c_str(), tempname.c_str()), fmt("%s/%s/%s.png", m_boxPicDir.c_str(), coverFolder.c_str(), tempname.c_str()), playcount, lastPlayed);
else
m_cf.addItem(&m_gameList[i], fmt("%s/%s.png", m_picDir.c_str(), tempname.c_str()), fmt("%s/%s.png", m_boxPicDir.c_str(), tempname.c_str()), playcount, lastPlayed);
break;
}
}
}
}
else if(m_gameList[i].type == TYPE_HOMEBREW)
m_cf.addItem(&m_gameList[i], fmt("%s/icon.png", m_gameList[i].path), fmt("%s/%s.png", m_boxPicDir.c_str(), id.c_str()), playcount, lastPlayed);
else
m_cf.addItem(&m_gameList[i], fmt("%s/%s.png", m_picDir.c_str(), id.c_str()), fmt("%s/%s.png", m_boxPicDir.c_str(), id.c_str()), playcount, lastPlayed);
}
}
m_gcfg1.unload();
if (dumpGameLst)
{
dump.save(true);
m_cfg.setBool(domain, "dump_list", false);
}
m_cf.setBoxMode(m_cfg.getBool("GENERAL", "box_mode", true));
m_cf.setCompression(m_cfg.getBool("GENERAL", "allow_texture_compression", true));
m_cf.setBufferSize(m_cfg.getInt("GENERAL", "cover_buffer", 20));
m_cf.setSorting((Sorting)m_cfg.getInt(domain, "sort", 0));
m_cf.setHQcover(m_cfg.getBool("GENERAL", "cover_use_hq", false));
if (m_curGameId.empty() || !m_cf.findId(m_curGameId.c_str(), true))
m_cf.findId(m_cfg.getString(domain, "current_item").c_str(), true);
m_cf.startCoverLoader();
}
void CMenu::_mainLoopCommon(bool withCF, bool adjusting)
{
if(withCF)
m_cf.tick();
m_btnMgr.tick();
m_fa.tick();
m_cf.setFanartPlaying(m_fa.isLoaded());
m_cf.setFanartTextColor(m_fa.getTextColor(m_theme.getColor("_COVERFLOW", "font_color", CColor(0xFFFFFFFF))));
_updateBg();
m_fa.hideCover() ? m_cf.hideCover() : m_cf.showCover();
if(withCF)
m_cf.makeEffectTexture(m_vid, m_lqBg);
if(withCF && m_aa > 0)
{
m_vid.setAA(m_aa, true);
for(int i = 0; i < m_aa; ++i)
{
m_vid.prepareAAPass(i);
m_vid.setup2DProjection(false, true);
_drawBg();
m_fa.draw(false);
m_cf.draw();
m_vid.setup2DProjection(false, true);
m_cf.drawEffect();
if(!m_banner->GetSelectedGame())
m_cf.drawText(adjusting);
m_vid.renderAAPass(i);
}
m_vid.setup2DProjection();
m_vid.drawAAScene();
}
else
{
m_vid.prepare();
m_vid.setup2DProjection();
_drawBg();
m_fa.draw(false);
if(withCF)
{
m_cf.draw();
m_vid.setup2DProjection();
m_cf.drawEffect();
if(!m_banner->GetSelectedGame())
m_cf.drawText(adjusting);
}
}
if(m_fa.isLoaded())
m_fa.draw();
else if(m_banner->GetSelectedGame() && (!m_banner->GetInGameSettings() || (m_banner->GetInGameSettings() && m_bnr_settings)))
m_banner->Draw();
m_btnMgr.draw();
ScanInput();
if(!m_vid.showingWaitMessage())
m_vid.render();
if(Sys_Exiting())
exitHandler(BUTTON_CALLBACK);
if(withCF && m_gameSelected && m_gamesound_changed && (m_gameSoundHdr == NULL) && !m_gameSound.IsPlaying() && MusicPlayer.GetVolume() == 0)
{
CheckGameSoundThread();
m_gameSound.Play(m_bnrSndVol);
m_gamesound_changed = false;
}
else if(!m_gameSelected)
m_gameSound.Stop();
MusicPlayer.Tick(m_video_playing || (m_gameSelected &&
m_gameSound.IsLoaded()) || m_gameSound.IsPlaying());
if(MusicPlayer.SongChanged() && m_music_info)
{
m_btnMgr.setText(m_mainLblCurMusic, MusicPlayer.GetFileName(), true);
m_btnMgr.show(m_mainLblCurMusic);
MusicPlayer.DisplayTime = time(NULL);
}
else if(MusicPlayer.DisplayTime > 0 && time(NULL) - MusicPlayer.DisplayTime > 3)
{
MusicPlayer.DisplayTime = 0;
m_btnMgr.hide(m_mainLblCurMusic);
}
//Take Screenshot
if(gc_btnsPressed & PAD_TRIGGER_Z)
{
time_t rawtime;
struct tm *timeinfo;
char buffer[80];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer,80,"%b-%d-20%y-%Hh%Mm%Ss.png",timeinfo);
gprintf("Screenshot taken and saved to: %s/%s\n", m_screenshotDir.c_str(), buffer);
m_vid.TakeScreenshot(fmt("%s/%s", m_screenshotDir.c_str(), buffer));
if(!!m_cameraSound)
m_cameraSound->Play(255);
}
#ifdef SHOWMEM
m_btnMgr.setText(m_mem2FreeSize, wfmt(L"Mem2 Free:%u, Mem1 Free:%u", MEM2_freesize(), MEM1_freesize()), true);
#endif
#ifdef SHOWMEMGECKO
mem1 = MEM1_freesize();
mem2 = MEM2_freesize();
if(mem1 != mem1old)
{
mem1old = mem1;
gprintf("Mem1 Free: %u\n", mem1);
}
if(mem2 != mem2old)
{
mem2old = mem2;
gprintf("Mem2 Free: %u\n", mem2);
}
#endif
}
void CMenu::_setBg(const STexture &tex, const STexture &lqTex)
{
m_lqBg = lqTex;
if (tex.data.get() == m_nextBg.data.get()) return;
m_prevBg = m_curBg;
m_nextBg = tex;
m_bgCrossFade = 0xFF;
}
void CMenu::_updateBg(void)
{
Mtx modelViewMtx;
GXTexObj texObj;
GXTexObj texObj2;
Mtx44 projMtx;
if (m_bgCrossFade == 0) return;
m_bgCrossFade = max(0, (int)m_bgCrossFade - 14);
if (m_bgCrossFade == 0)
{
m_curBg = m_nextBg;
return;
}
if (m_curBg.data.get() == m_prevBg.data.get())
m_curBg.data.release();
m_vid.prepare();
GX_SetViewport(0.f, 0.f, 640.f, 480.f, 0.f, 1.f);
guOrtho(projMtx, 0.f, 480.f, 0.f, 640.f, 0.f, 1000.0f);
GX_LoadProjectionMtx(projMtx, GX_ORTHOGRAPHIC);
GX_ClearVtxDesc();
GX_SetNumTevStages(!m_prevBg.data ? 1 : 2);
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(!m_prevBg.data ? 1 : 2);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTevKColor(GX_KCOLOR0, CColor(m_bgCrossFade, 0xFF - m_bgCrossFade, 0, 0));
GX_SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0_R);
GX_SetTevColorIn(GX_TEVSTAGE0, GX_CC_TEXC, GX_CC_ZERO, GX_CC_KONST, GX_CC_ZERO);
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_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL);
GX_SetTevKColorSel(GX_TEVSTAGE1, GX_TEV_KCSEL_K0_G);
GX_SetTevColorIn(GX_TEVSTAGE1, GX_CC_TEXC, GX_CC_ZERO, GX_CC_KONST, GX_CC_CPREV);
GX_SetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO);
GX_SetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GX_SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLORNULL);
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaUpdate(GX_FALSE);
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_InitTexObj(&texObj, m_nextBg.data.get(), m_nextBg.width, m_nextBg.height, m_nextBg.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj, GX_TEXMAP0);
if (!!m_prevBg.data)
{
GX_InitTexObj(&texObj2, m_prevBg.data.get(), m_prevBg.width, m_prevBg.height, m_prevBg.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_LoadTexObj(&texObj2, GX_TEXMAP1);
}
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();
GX_SetNumTevStages(1);
m_curBg.width = 640;
m_curBg.height = 480;
m_curBg.format = GX_TF_RGBA8;
m_curBg.maxLOD = 0;
m_vid.renderToTexture(m_curBg, true);
if (!m_curBg.data)
{
m_curBg = m_nextBg;
m_bgCrossFade = 0;
}
}
void CMenu::_drawBg(void)
{
Mtx modelViewMtx;
GXTexObj texObj;
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_FALSE);
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
guMtxIdentity(modelViewMtx);
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
GX_InitTexObj(&texObj, m_curBg.data.get(), m_curBg.width, m_curBg.height, m_curBg.format, GX_CLAMP, GX_CLAMP, GX_FALSE);
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();
}
void CMenu::_updateText(void)
{
_textMain();
_textError();
_textConfig();
_textConfig3();
_textConfigScreen();
_textConfig4();
_textConfigSnd();
_textConfigAdv();
_textDownload();
_textGame();
_textCode();
_textWBFS();
_textGameSettings();
_textCategorySettings();
_textSystem();
}
const wstringEx CMenu::_fmt(const char *key, const wchar_t *def)
{
wstringEx ws = m_loc.getWString(m_curLanguage, key, def);
if (checkFmt(def, ws)) return ws;
return def;
}
bool CMenu::_loadChannelList(void)
{
string emuPath;
int emuPartition = -1;
bool disable_emu = (m_cfg.getBool("NAND", "disable", true) || neek2o());
static bool last_emu_state = disable_emu;
if(!disable_emu)
{
m_partRequest = m_cfg.getInt("NAND", "partition", 1);
emuPartition = _FindEmuPart(&emuPath, m_partRequest, false);
if(emuPartition < 0)
emuPartition = _FindEmuPart(&emuPath, m_partRequest, true);
if(emuPartition < 0)
return false;
else
currentPartition = emuPartition;
}
static u8 lastPartition = currentPartition;
static bool first = true;
bool changed = lastPartition != currentPartition || last_emu_state != disable_emu || first;
if(changed)
UpdateCache(COVERFLOW_CHANNEL);
if(first && !disable_emu)
{
char basepath[64];
snprintf(basepath, sizeof(basepath), "%s:%s", DeviceName[currentPartition], emuPath.c_str());
Nand::Instance()->PreNandCfg(basepath, m_cfg.getBool("NAND", "real_nand_miis", false), m_cfg.getBool("NAND", "real_nand_config", false));
first = false;
}
string nandpath = sfmt("%s:%s/", DeviceName[currentPartition], emuPath.empty() ? "" : emuPath.c_str());
Nand::Instance()->Disable_Emu();
if(!disable_emu)
{
MusicPlayer.Stop();
_TempLoadIOS();
if(!DeviceHandle.IsInserted(lastPartition))
DeviceHandle.Mount(lastPartition);
DeviceHandle.UnMount(currentPartition);
Nand::Instance()->Init(emuPath.c_str(), currentPartition, disable_emu);
if(Nand::Instance()->Enable_Emu() < 0)
Nand::Instance()->Disable_Emu();
gprintf("Using path: \"%s\" for NAND emulation\n", nandpath.c_str());
}
if(!DeviceHandle.IsInserted(currentPartition))
DeviceHandle.Mount(currentPartition);
if(Nand::Instance()->EmulationEnabled() || disable_emu)
{
string cacheDir;
if(!disable_emu)
cacheDir = fmt("%s/%s_channels.db", m_listCacheDir.c_str(), DeviceName[currentPartition]);
bool updateCache = m_cfg.getBool(_domainFromView(), "update_cache");
vector<string> NullVector;
m_gameList.CreateList(m_current_view, currentPartition, std::string(),
NullVector, cacheDir, updateCache);
}
lastPartition = currentPartition;
last_emu_state = disable_emu;
return m_gameList.size() > 0 ? true : false;
}
bool CMenu::_loadList(void)
{
m_cf.clear();
if((m_current_view == COVERFLOW_CHANNEL && m_cfg.getBool("NAND", "disable", true))
|| (m_current_view != COVERFLOW_CHANNEL && Nand::Instance()->EmulationEnabled()))
{
MusicPlayer.Stop();
Nand::Instance()->Disable_Emu();
_TempLoadIOS(IOS_TYPE_NORMAL_IOS);
}
gprintf("Switching Views\n");
bool retval;
switch(m_current_view)
{
case COVERFLOW_CHANNEL:
retval = _loadChannelList();
break;
case COVERFLOW_HOMEBREW:
retval = _loadHomebrewList();
break;
case COVERFLOW_DML:
retval = _loadDmlList();
break;
case COVERFLOW_PLUGIN:
retval = _loadEmuList();
break;
default:
retval = _loadGameList();
break;
}
gprintf("Games found: %i\n", m_gameList.size());
m_cfg.remove(_domainFromView(), "update_cache");
return retval;
}
bool CMenu::_loadGameList(void)
{
currentPartition = m_cfg.getInt("GAMES", "partition", USB1);
if(!DeviceHandle.IsInserted(currentPartition))
return false;
DeviceHandle.OpenWBFS(currentPartition);
string gameDir(fmt(GAMES_DIR, DeviceName[currentPartition]));
string cacheDir(fmt("%s/%s_wii.db", m_listCacheDir.c_str(), DeviceName[currentPartition]));
bool updateCache = m_cfg.getBool(_domainFromView(), "update_cache");
m_gameList.CreateList(m_current_view, currentPartition, gameDir, stringToVector(".wbfs|.iso", '|'), cacheDir, updateCache);
WBFS_Close();
return m_gameList.size() > 0 ? true : false;
}
bool CMenu::_loadHomebrewList()
{
currentPartition = m_cfg.getInt("HOMEBREW", "partition", SD);
if(!DeviceHandle.IsInserted(currentPartition))
return false;
string gameDir(fmt(HOMEBREW_DIR, DeviceName[currentPartition]));
string cacheDir(fmt("%s/%s_homebrew.db", m_listCacheDir.c_str(), DeviceName[currentPartition]));
bool updateCache = m_cfg.getBool(_domainFromView(), "update_cache");
m_gameList.CreateList(m_current_view, currentPartition, gameDir, stringToVector(".dol|.elf", '|'), cacheDir, updateCache);
return m_gameList.size() > 0 ? true : false;
}
bool CMenu::_loadDmlList()
{
currentPartition = m_cfg.getInt("DML", "partition", USB1);
if(!DeviceHandle.IsInserted(currentPartition))
return false;
string gameDir(fmt(currentPartition == SD ? DML_DIR : m_DMLgameDir.c_str(), DeviceName[currentPartition]));
string cacheDir(fmt("%s/%s_gamecube.db", m_listCacheDir.c_str(), DeviceName[currentPartition]));
bool updateCache = m_cfg.getBool(_domainFromView(), "update_cache");
m_gameList.CreateList(m_current_view, currentPartition, gameDir,
stringToVector(".iso|root", '|'),cacheDir, updateCache);
return m_gameList.size() > 0 ? true : false;
}
static vector<string> INI_List;
static void GrabINIFiles(char *FullPath)
{
//Just push back
INI_List.push_back(FullPath);
}
bool CMenu::_loadEmuList()
{
currentPartition = m_cfg.getInt("EMULATOR", "partition", SD);
if(!DeviceHandle.IsInserted(currentPartition))
return false;
bool updateCache = m_cfg.getBool(_domainFromView(), "update_cache");
vector<dir_discHdr> emuList;
Config m_plugin_cfg;
INI_List.clear();
m_gameList.clear();
GetFiles(m_pluginsDir.c_str(), stringToVector(".ini", '|'), GrabINIFiles, false, 1);
for(vector<string>::const_iterator Name = INI_List.begin(); Name != INI_List.end(); ++Name)
{
if(Name->find("scummvm.ini") != string::npos)
continue;
m_plugin_cfg.load(Name->c_str());
if(m_plugin_cfg.loaded())
{
m_plugin.AddPlugin(m_plugin_cfg);
if(m_plugin_cfg.getString(PLUGIN_DOMAIN,"romDir").find("scummvm.ini") == string::npos)
{
string gameDir(fmt("%s:/%s", DeviceName[currentPartition], m_plugin_cfg.getString(PLUGIN_DOMAIN,"romDir").c_str()));
string cacheDir(fmt("%s/%s_%s.db", m_listCacheDir.c_str(), DeviceName[currentPartition], m_plugin_cfg.getString(PLUGIN_DOMAIN,"magic").c_str()));
vector<string> FileTypes = stringToVector(m_plugin_cfg.getString(PLUGIN_DOMAIN,"fileTypes"), '|');
m_gameList.Color = strtoul(m_plugin_cfg.getString(PLUGIN_DOMAIN,"coverColor").c_str(), NULL, 16);
m_gameList.Magic = strtoul(m_plugin_cfg.getString(PLUGIN_DOMAIN,"magic").c_str(), NULL, 16);
m_gameList.CreateList(m_current_view, currentPartition, gameDir, FileTypes, cacheDir, updateCache);
for(vector<dir_discHdr>::iterator tmp_itr = m_gameList.begin(); tmp_itr != m_gameList.end(); tmp_itr++)
emuList.push_back(*tmp_itr);
}
else
{
Config scummvm;
vector<dir_discHdr> scummvmList;
scummvm.load(fmt("%s/%s", m_pluginsDir.c_str(), "scummvm.ini"));
scummvmList = m_plugin.ParseScummvmINI(scummvm, DeviceName[currentPartition]);
for(vector<dir_discHdr>::iterator tmp_itr = scummvmList.begin(); tmp_itr != scummvmList.end(); tmp_itr++)
emuList.push_back(*tmp_itr);
}
}
m_plugin_cfg.unload();
}
m_gameList.clear();
for(vector<dir_discHdr>::iterator tmp_itr = emuList.begin(); tmp_itr != emuList.end(); tmp_itr++)
{
tmp_itr->index = m_gameList.size();
m_gameList.push_back(*tmp_itr);
}
emuList.clear();
//If we return to the coverflow before wiiflow quit we dont need to reload plugins
m_plugin.EndAdd();
return m_gameList.size() > 0 ? true : false;
}
void CMenu::_stopSounds(void)
{
// Fade out sounds
int fade_rate = m_cfg.getInt("GENERAL", "music_fade_rate", 8);
if(!MusicPlayer.IsStopped())
{
while(MusicPlayer.GetVolume() > 0 || m_gameSound.GetVolume() > 0)
{
MusicPlayer.Tick(true);
if(m_gameSound.GetVolume() > 0)
m_gameSound.SetVolume(m_gameSound.GetVolume() < fade_rate ? 0 : m_gameSound.GetVolume() - fade_rate);
VIDEO_WaitVSync();
}
}
m_btnMgr.stopSounds();
m_cf.stopSound();
m_gameSound.Stop();
}
bool CMenu::_loadFile(SmartBuf &buffer, u32 &size, const char *path, const char *file)
{
size = 0;
FILE *fp = fopen(file == NULL ? path : fmt("%s/%s", path, file), "rb");
if (fp == NULL)
return false;
fseek(fp, 0, SEEK_END);
u32 fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
SmartBuf fileBuf = smartMem2Alloc(fileSize);
if (!fileBuf)
{
fclose(fp);
return false;
}
if (fread(fileBuf.get(), 1, fileSize, fp) != fileSize)
{
fclose(fp);
return false;
}
fclose(fp);
if(buffer.get())
buffer.release();
buffer = fileBuf;
size = fileSize;
return true;
}
void CMenu::_load_installed_cioses()
{
gprintf("Loading cIOS map\n");
_installed_cios[0] = 1;
for(u8 slot = 200; slot < 254; slot++)
{
u8 base = 1;
if(IOS_D2X(slot, &base))
{
gprintf("Found d2x base %u in slot %u\n", base, slot);
_installed_cios[slot] = base;
}
else if(CustomIOS(IOS_GetType(slot)))
{
gprintf("Found cIOS in slot %u\n", slot);
_installed_cios[slot] = slot;
}
}
}
void CMenu::_hideWaitMessage()
{
m_vid.hideWaitMessage();
}
void CMenu::_showWaitMessage()
{
TexSet texSet;
m_vid.waitMessage(_textures(texSet, "GENERAL", "waitmessage"), m_theme.getFloat("GENERAL", "waitmessage_delay", 0.f));
}
typedef struct map_entry
{
char filename[8];
u8 sha1[20];
} __attribute((packed)) map_entry_t;
void CMenu::_loadDefaultFont(bool korean)
{
u32 size;
bool retry = false;
// Read content.map from ISFS
u8 *content = ISFS_GetFile((u8 *) "/shared1/content.map", &size, 0);
if(content == NULL)
return;
int items = size / sizeof(map_entry_t);
//gprintf("Open content.map, size %d, items %d\n", size, items);
retry:
bool kor_font = (korean && !retry) || (!korean && retry);
map_entry_t *cm = (map_entry_t *) content;
for (int i = 0; i < items; i++)
{
if (memcmp(cm[i].sha1, kor_font ? WIIFONT_HASH_KOR : WIIFONT_HASH, 20) == 0)
{
// Name found, load it and unpack it
char u8_font_filename[22] = {0};
strcpy(u8_font_filename, "/shared1/XXXXXXXX.app"); // Faster than sprintf
memcpy(u8_font_filename+9, cm[i].filename, 8);
u8 *u8_font_archive = ISFS_GetFile((u8 *) u8_font_filename, &size, 0);
//gprintf("Opened fontfile: %s: %d bytes\n", u8_font_filename, size);
if(u8_font_archive != NULL)
{
const u8 *font_file = u8_get_file_by_index(u8_font_archive, 1, &size); // There is only one file in that app
//gprintf("Extracted font: %d\n", size);
if(m_base_font)
MEM1_lo_free(m_base_font);
m_base_font = (u8*)MEM1_lo_alloc(size);
memcpy(m_base_font, font_file, size);
DCFlushRange(m_base_font, size);
m_base_font_size = size;
free(u8_font_archive);
}
break;
}
else if(memcmp(cm[i].sha1, WFB_HASH, 20) == 0)
{
// Name found, load it and unpack it
char font_filename[32] ATTRIBUTE_ALIGN(32);
strcpy(font_filename, "/shared1/XXXXXXXX.app"); // Faster than sprintf
memcpy(font_filename+9, cm[i].filename, 8);
u8 *u8_font_archive = ISFS_GetFile((u8 *)font_filename, &size, 0);
if(u8_font_archive != NULL)
{
const u8 *font_file1 = u8_get_file(u8_font_archive, "wbf1.brfna", &size);
if(m_wbf1_font)
MEM1_lo_free(m_wbf1_font);
m_wbf1_font = (u8*)MEM1_lo_alloc(size);
memcpy(m_wbf1_font, font_file1, size);
DCFlushRange(m_wbf1_font, size);
const u8 *font_file2 = u8_get_file(u8_font_archive, "wbf2.brfna", &size);
if(m_wbf2_font)
MEM1_lo_free(m_wbf2_font);
m_wbf2_font = (u8*)MEM1_lo_alloc(size);
memcpy(m_wbf2_font, font_file2, size);
DCFlushRange(m_wbf2_font, size);
free(u8_font_archive);
}
}
}
if (!retry)
{
retry = true;
goto retry;
}
free(content);
}
void CMenu::_cleanupDefaultFont()
{
MEM1_lo_free(m_base_font);
m_base_font_size = 0;
MEM1_lo_free(m_wbf1_font);
MEM1_lo_free(m_wbf2_font);
}
string CMenu::_getId()
{
string id;
if(!NoGameID(m_cf.getHdr()->type))
id = m_cf.getId();
else
{
dir_discHdr *hdr = m_cf.getHdr();
string tempname(hdr->path);
if(hdr->type == TYPE_HOMEBREW)
{
tempname.assign(&tempname[tempname.find_last_of('/') + 1]);
id = tempname;
}
else if(hdr->type == TYPE_PLUGIN)
{
if(tempname.find(':') != string::npos)
{
tempname.erase(0, tempname.find_first_of('/')+1);
string dirName = tempname.substr(0, tempname.find_first_of('/')+1);
tempname.assign(&tempname[tempname.find_last_of('/') + 1]);
if(tempname.find_last_of('.') != string::npos)
tempname.erase(tempname.find_last_of('.'), tempname.size() - tempname.find_last_of('.'));
id = dirName+tempname;
}
else
id = tempname;
}
}
return id;
}
const char *CMenu::_domainFromView()
{
switch(m_current_view)
{
case COVERFLOW_CHANNEL:
return "NAND";
case COVERFLOW_HOMEBREW:
return "HOMEBREW";
case COVERFLOW_DML:
return "DML";
case COVERFLOW_PLUGIN:
return "EMULATOR";
default:
return "GAMES";
}
return "NULL";
}
void CMenu::UpdateCache(u32 view)
{
if(view == COVERFLOW_MAX)
{
UpdateCache(COVERFLOW_USB);
UpdateCache(COVERFLOW_HOMEBREW);
UpdateCache(COVERFLOW_DML);
UpdateCache(COVERFLOW_PLUGIN);
UpdateCache(COVERFLOW_CHANNEL);
return;
}
const char *domain;
switch(view)
{
case COVERFLOW_CHANNEL:
domain = "NAND";
break;
case COVERFLOW_HOMEBREW:
domain = "HOMEBREW";
break;
case COVERFLOW_DML:
domain = "DML";
break;
case COVERFLOW_PLUGIN:
domain = "EMULATOR";
break;
default:
domain = "GAMES";
}
m_cfg.setBool(domain, "update_cache", true);
}
int CMenu::MIOSisDML()
{
u32 size = 0;
u8 *appfile = ISFS_GetFile((u8*)"/title/00000001/00000101/content/0000000c.app", &size, 0);
if(appfile)
{
for(u32 i = 0; i < size; ++i)
{
if(*(vu32*)(appfile+i) == 0x44494F53)
{
for(u32 j = 0; j < size; ++j)
{
if(*(vu32*)(appfile+j) == 0x4C697465)
{
gprintf("DIOS-MIOS Lite is installed as MIOS\n");
free(appfile);
return 2;
}
}
gprintf("DIOS-MIOS is installed as MIOS\n");
free(appfile);
return 1;
}
}
free(appfile);
}
gprintf("DIOS-MIOS (Lite) not found\n");
return 0;
}
void CMenu::RemoveCover( char * id )
{
FILE *fp = fopen(fmt("%s/%s.png", m_boxPicDir.c_str(), id), "rb");
if (fp != NULL)
{
fclose(fp);
remove(fmt("%s/%s.png", m_boxPicDir.c_str(), id));
}
fp = fopen(fmt("%s/%s.png", m_picDir.c_str(), id), "rb");
if (fp != NULL)
{
fclose(fp);
remove(fmt("%s/%s.png", m_picDir.c_str(), id));
}
fp = fopen(fmt("%s/%s.wfc", m_cacheDir.c_str(), id), "rb");
if (fp != NULL)
{
fclose(fp);
remove(fmt("%s/%s.wfc", m_cacheDir.c_str(), id));
}
}
void CMenu::_TempLoadIOS(int IOS)
{
/* Only temp reload in IOS58 mode */
if(useMainIOS || neek2o() || Sys_DolphinMode())
return;
if(IOS == IOS_TYPE_NORMAL_IOS)
IOS = 58;
else if(IOS == 0)
IOS = mainIOS;
if(CurrentIOS.Version != IOS)
{
loadIOS(IOS, true);
Open_Inputs();
for(int chan = WPAD_MAX_WIIMOTES-2; chan >= 0; chan--)
WPAD_SetVRes(chan, m_vid.width() + m_cursor[chan].width(), m_vid.height() + m_cursor[chan].height());
}
}