3038 lines
97 KiB
C++
3038 lines
97 KiB
C++
#include "stdafx.h"
|
|
#include "UIController.h"
|
|
#include "UI.h"
|
|
#include "UIScene.h"
|
|
#include "..\..\..\Minecraft.World\StringHelpers.h"
|
|
#include "..\..\LocalPlayer.h"
|
|
#include "..\..\DLCTexturePack.h"
|
|
#include "..\..\TexturePackRepository.h"
|
|
#include "..\..\Minecraft.h"
|
|
#include "..\..\..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h"
|
|
#include "..\..\EnderDragonRenderer.h"
|
|
#include "..\..\MultiPlayerLocalPlayer.h"
|
|
#include "UIFontData.h"
|
|
#ifdef __PSVITA__
|
|
#include <message_dialog.h>
|
|
#endif
|
|
|
|
// 4J Stu - Enable this to override the Iggy Allocator
|
|
//#define ENABLE_IGGY_ALLOCATOR
|
|
//#define EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR
|
|
|
|
//#define ENABLE_IGGY_EXPLORER
|
|
#ifdef ENABLE_IGGY_EXPLORER
|
|
#include "Windows64\Iggy\include\iggyexpruntime.h"
|
|
#endif
|
|
|
|
//#define ENABLE_IGGY_PERFMON
|
|
#ifdef ENABLE_IGGY_PERFMON
|
|
|
|
#define PM_ORIGIN_X 24
|
|
#define PM_ORIGIN_Y 34
|
|
|
|
#ifdef __ORBIS__
|
|
#include "Orbis\Iggy\include\iggyperfmon.h"
|
|
#include "Orbis\Iggy\include\iggyperfmon_orbis.h"
|
|
#elif defined _DURANGO
|
|
#include "Durango\Iggy\include\iggyperfmon.h"
|
|
#elif defined __PS3__
|
|
#include "PS3\Iggy\include\iggyperfmon.h"
|
|
#include "PS3\Iggy\include\iggyperfmon_ps3.h"
|
|
#elif defined __PSVITA__
|
|
#include "PSVita\Iggy\include\iggyperfmon.h"
|
|
#include "PSVita\Iggy\include\iggyperfmon_psp2.h"
|
|
#elif defined __WINDOWS64
|
|
#include "Windows64\Iggy\include\iggyperfmon.h"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
CRITICAL_SECTION UIController::ms_reloadSkinCS;
|
|
bool UIController::ms_bReloadSkinCSInitialised = false;
|
|
|
|
DWORD UIController::m_dwTrialTimerLimitSecs=DYNAMIC_CONFIG_DEFAULT_TRIAL_TIME;
|
|
|
|
static void RADLINK WarningCallback(void *user_callback_data, Iggy *player, IggyResult code, const char *message)
|
|
{
|
|
//enum IggyResult{ IGGY_RESULT_SUCCESS = 0, IGGY_RESULT_Warning_None = 0,
|
|
// IGGY_RESULT_Warning_Misc = 100, IGGY_RESULT_Warning_GDraw = 101,
|
|
// IGGY_RESULT_Warning_ProgramFlow = 102,
|
|
// IGGY_RESULT_Warning_Actionscript = 103,
|
|
// IGGY_RESULT_Warning_Graphics = 104, IGGY_RESULT_Warning_Font = 105,
|
|
// IGGY_RESULT_Warning_Timeline = 106, IGGY_RESULT_Warning_Library = 107,
|
|
// IGGY_RESULT_Warning_CannotSustainFrameRate = 201,
|
|
// IGGY_RESULT_Warning_ThrewException = 202,
|
|
// IGGY_RESULT_Error_Threshhold = 400, IGGY_RESULT_Error_Misc = 400,
|
|
// IGGY_RESULT_Error_GDraw = 401, IGGY_RESULT_Error_ProgramFlow = 402,
|
|
// IGGY_RESULT_Error_Actionscript = 403, IGGY_RESULT_Error_Graphics = 404,
|
|
// IGGY_RESULT_Error_Font = 405, IGGY_RESULT_Error_Create = 406,
|
|
// IGGY_RESULT_Error_Library = 407, IGGY_RESULT_Error_ValuePath = 408,
|
|
// IGGY_RESULT_Error_Audio = 409, IGGY_RESULT_Error_Internal = 499,
|
|
// IGGY_RESULT_Error_InvalidIggy = 501,
|
|
// IGGY_RESULT_Error_InvalidArgument = 502,
|
|
// IGGY_RESULT_Error_InvalidEntity = 503,
|
|
// IGGY_RESULT_Error_UndefinedEntity = 504,
|
|
// IGGY_RESULT_Error_OutOfMemory = 1001,};
|
|
|
|
switch(code)
|
|
{
|
|
case IGGY_RESULT_Warning_CannotSustainFrameRate:
|
|
// Ignore warning
|
|
break;
|
|
default:
|
|
/* Normally, we'd want to issue this warning to some kind of
|
|
logging system or error reporting system, but since this is a
|
|
tutorial app, we just use Win32's default error stream. Since
|
|
ActionScript 3 exceptions are routed through this warning
|
|
callback, it's definitely a good idea to make sure these
|
|
warnings get printed somewhere that's easy for you to read and
|
|
use for debugging, otherwise debugging errors in the
|
|
ActionScript 3 code in your Flash content will be very
|
|
difficult! */
|
|
app.DebugPrintf(app.USER_SR, message);
|
|
app.DebugPrintf(app.USER_SR, "\n");
|
|
break;
|
|
};
|
|
}
|
|
|
|
|
|
/* Flash provides a way for ActionScript 3 code to print debug output
|
|
using a function called "trace". It's very useful for debugging
|
|
Flash programs, so ideally, when using Iggy, we'd like to see any
|
|
trace output alongside our own debugging output. To facilitate
|
|
this, Iggy allows us to install a callback that will be called
|
|
any time ActionScript code calls trace. */
|
|
static void RADLINK TraceCallback(void *user_callback_data, Iggy *player, char const *utf8_string, S32 length_in_bytes)
|
|
{
|
|
app.DebugPrintf(app.USER_UI, (char *)utf8_string);
|
|
}
|
|
|
|
#ifdef ENABLE_IGGY_PERFMON
|
|
static void *RADLINK perf_malloc(void *handle, U32 size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
static void RADLINK perf_free(void *handle, void *ptr)
|
|
{
|
|
return free(ptr);
|
|
}
|
|
#endif
|
|
|
|
#ifdef EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR
|
|
extern "C" void *__real_malloc(size_t t);
|
|
extern "C" void __real_free(void *t);
|
|
#endif
|
|
|
|
__int64 UIController::iggyAllocCount = 0;
|
|
static unordered_map<void *,size_t> allocations;
|
|
static void * RADLINK AllocateFunction ( void * alloc_callback_user_data , size_t size_requested , size_t * size_returned )
|
|
{
|
|
UIController *controller = (UIController *)alloc_callback_user_data;
|
|
EnterCriticalSection(&controller->m_Allocatorlock);
|
|
#ifdef EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR
|
|
void *alloc = __real_malloc(size_requested);
|
|
#else
|
|
void *alloc = malloc(size_requested);
|
|
#endif
|
|
*size_returned = size_requested;
|
|
UIController::iggyAllocCount += size_requested;
|
|
allocations[alloc] = size_requested;
|
|
app.DebugPrintf(app.USER_SR, "Allocating %d, new total: %d\n", size_requested, UIController::iggyAllocCount);
|
|
LeaveCriticalSection(&controller->m_Allocatorlock);
|
|
return alloc;
|
|
}
|
|
|
|
static void RADLINK DeallocateFunction ( void * alloc_callback_user_data , void * ptr )
|
|
{
|
|
UIController *controller = (UIController *)alloc_callback_user_data;
|
|
EnterCriticalSection(&controller->m_Allocatorlock);
|
|
size_t size = allocations[ptr];
|
|
UIController::iggyAllocCount -= size;
|
|
allocations.erase(ptr);
|
|
app.DebugPrintf(app.USER_SR, "Freeing %d, new total %d\n", size, UIController::iggyAllocCount);
|
|
#ifdef EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR
|
|
__real_free(ptr);
|
|
#else
|
|
free(ptr);
|
|
#endif
|
|
LeaveCriticalSection(&controller->m_Allocatorlock);
|
|
}
|
|
|
|
UIController::UIController()
|
|
{
|
|
m_uiDebugConsole = NULL;
|
|
m_reloadSkinThread = NULL;
|
|
m_navigateToHomeOnReload = false;
|
|
m_mcTTFFont= NULL;
|
|
m_moj7 = NULL;
|
|
m_moj11 = NULL;
|
|
|
|
#ifdef ENABLE_IGGY_ALLOCATOR
|
|
InitializeCriticalSection(&m_Allocatorlock);
|
|
#endif
|
|
|
|
// 4J Stu - This is a bit of a hack until we change the Minecraft initialisation to store the proper screen size for other platforms
|
|
#if defined _WINDOWS64 || defined _DURANGO || defined __ORBIS__
|
|
m_fScreenWidth = 1920.0f;
|
|
m_fScreenHeight = 1080.0f;
|
|
m_bScreenWidthSetup = true;
|
|
#else
|
|
m_fScreenWidth = 1280.0f;
|
|
m_fScreenHeight = 720.0f;
|
|
m_bScreenWidthSetup = false;
|
|
#endif
|
|
|
|
for(unsigned int i = 0; i < eLibrary_Count; ++i)
|
|
{
|
|
m_iggyLibraries[i] = IGGY_INVALID_LIBRARY;
|
|
}
|
|
|
|
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
|
|
{
|
|
m_bMenuDisplayed[i] = false;
|
|
m_iCountDown[i]=0;
|
|
m_bMenuToBeClosed[i]=false;
|
|
|
|
for(unsigned int key = 0; key <= ACTION_MAX_MENU; ++key)
|
|
{
|
|
m_actionRepeatTimer[i][key] = 0;
|
|
}
|
|
}
|
|
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
m_bCloseAllScenes[i] = false;
|
|
}
|
|
|
|
m_iPressStartQuadrantsMask = 0;
|
|
|
|
m_currentRenderViewport = C4JRender::VIEWPORT_TYPE_FULLSCREEN;
|
|
m_bCustomRenderPosition = false;
|
|
m_winUserIndex = 0;
|
|
m_accumulatedTicks = 0;
|
|
|
|
InitializeCriticalSection(&m_navigationLock);
|
|
InitializeCriticalSection(&m_registeredCallbackScenesCS);
|
|
//m_bSysUIShowing=false;
|
|
m_bSystemUIShowing=false;
|
|
#ifdef __PSVITA__
|
|
m_bTouchscreenPressed=false;
|
|
#endif
|
|
|
|
if(!ms_bReloadSkinCSInitialised)
|
|
{
|
|
// MGH - added to prevent crash loading Iggy movies while the skins were being reloaded
|
|
InitializeCriticalSection(&ms_reloadSkinCS);
|
|
ms_bReloadSkinCSInitialised = true;
|
|
}
|
|
}
|
|
|
|
void UIController::SetSysUIShowing(bool bVal)
|
|
{
|
|
if(bVal) app.DebugPrintf("System UI showing\n");
|
|
else app.DebugPrintf("System UI stopped showing\n");
|
|
m_bSystemUIShowing=bVal;
|
|
}
|
|
|
|
void UIController::SetSystemUIShowing(LPVOID lpParam,bool bVal)
|
|
{
|
|
UIController *pClass=(UIController *)lpParam;
|
|
pClass->SetSysUIShowing(bVal);
|
|
}
|
|
|
|
// SETUP
|
|
void UIController::preInit(S32 width, S32 height)
|
|
{
|
|
m_fScreenWidth = width;
|
|
m_fScreenHeight = height;
|
|
m_bScreenWidthSetup = true;
|
|
|
|
#ifdef ENABLE_IGGY_ALLOCATOR
|
|
IggyAllocator allocator;
|
|
allocator.user_callback_data = this;
|
|
allocator.mem_alloc = &AllocateFunction;
|
|
allocator.mem_free = &DeallocateFunction;
|
|
IggyInit(&allocator);
|
|
#else
|
|
IggyInit(0);
|
|
#endif
|
|
|
|
IggySetWarningCallback(WarningCallback, 0);
|
|
IggySetTraceCallbackUTF8(TraceCallback, 0);
|
|
|
|
setFontCachingCalculationBuffer(-1);
|
|
}
|
|
|
|
void UIController::postInit()
|
|
{
|
|
// set up a custom rendering callback
|
|
IggySetCustomDrawCallback(&UIController::CustomDrawCallback, this);
|
|
IggySetAS3ExternalFunctionCallbackUTF16 ( &UIController::ExternalFunctionCallback, this );
|
|
IggySetTextureSubstitutionCallbacks ( &UIController::TextureSubstitutionCreateCallback , &UIController::TextureSubstitutionDestroyCallback, this );
|
|
|
|
SetupFont();
|
|
//
|
|
loadSkins();
|
|
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
m_groups[i] = new UIGroup((EUIGroup)i,i-1);
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_IGGY_EXPLORER
|
|
iggy_explorer = IggyExpCreate("127.0.0.1", 9190, malloc(IGGYEXP_MIN_STORAGE), IGGYEXP_MIN_STORAGE);
|
|
if ( iggy_explorer == NULL )
|
|
{
|
|
// not normally an error, just an error for this demo!
|
|
app.DebugPrintf( "Couldn't connect to Iggy Explorer, did you run it first?" );
|
|
}
|
|
else
|
|
{
|
|
IggyUseExplorer( m_groups[1]->getHUD()->getMovie(), iggy_explorer);
|
|
}
|
|
#endif
|
|
|
|
#ifdef ENABLE_IGGY_PERFMON
|
|
m_iggyPerfmonEnabled = false;
|
|
iggy_perfmon = IggyPerfmonCreate(perf_malloc, perf_free, NULL);
|
|
IggyInstallPerfmon(iggy_perfmon);
|
|
#endif
|
|
|
|
NavigateToScene(0, eUIScene_Intro);
|
|
}
|
|
|
|
void UIController::SetupFont()
|
|
{
|
|
bool bBitmapFont=false;
|
|
|
|
if(m_mcTTFFont!=NULL)
|
|
{
|
|
delete m_mcTTFFont;
|
|
}
|
|
|
|
switch(XGetLanguage())
|
|
{
|
|
#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
|
|
case XC_LANGUAGE_JAPANESE:
|
|
m_mcTTFFont = new UITTFFont("Common/Media/font/JPN/DF-DotDotGothic16.ttf", 0x203B); // JPN
|
|
break;
|
|
case XC_LANGUAGE_SCHINESE: //TODO
|
|
case XC_LANGUAGE_TCHINESE:
|
|
m_mcTTFFont = new UITTFFont("Common/Media/font/CHT/DFTT_R5.TTC", 0x203B); // CHT
|
|
break;
|
|
case XC_LANGUAGE_KOREAN:
|
|
m_mcTTFFont = new UITTFFont("Common/Media/font/KOR/candadite2.ttf", 0x203B); // KOR
|
|
break;
|
|
// 4J-JEV, Cyrillic characters have been added to this font now, (4/July/14)
|
|
//case XC_LANGUAGE_RUSSIAN:
|
|
//case XC_LANGUAGE_GREEK:
|
|
#else
|
|
case XC_LANGUAGE_JAPANESE:
|
|
m_mcTTFFont = new UITTFFont("Common/Media/font/JPN/DFGMaruGothic-Md.ttf", 0x2022); // JPN
|
|
break;
|
|
case XC_LANGUAGE_SCHINESE: //TODO
|
|
case XC_LANGUAGE_TCHINESE:
|
|
m_mcTTFFont = new UITTFFont("Common/Media/font/CHT/DFHeiMedium-B5.ttf", 0x2022); // CHT
|
|
break;
|
|
case XC_LANGUAGE_KOREAN:
|
|
m_mcTTFFont = new UITTFFont("Common/Media/font/KOR/BOKMSD.ttf", 0x2022); // KOR
|
|
break;
|
|
#endif
|
|
default:
|
|
bBitmapFont=true;
|
|
// m_mcTTFFont = new UITTFFont("Common/Media/font/Mojangles.ttf", 0x2022); // 4J-JEV: Shouldn't be using this.
|
|
break;
|
|
}
|
|
|
|
if(bBitmapFont)
|
|
{
|
|
// these may have been set up by a previous language being chosen
|
|
if(m_moj7==NULL)
|
|
{
|
|
m_moj7 = new UIBitmapFont(SFontData::Mojangles_7);
|
|
m_moj7->registerFont();
|
|
}
|
|
if(m_moj11==NULL)
|
|
{
|
|
m_moj11 = new UIBitmapFont(SFontData::Mojangles_11);
|
|
m_moj11->registerFont();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
app.DebugPrintf("IggyFontSetIndirectUTF8\n");
|
|
IggyFontSetIndirectUTF8( "Mojangles7", -1, IGGY_FONTFLAG_all, "Mojangles_TTF",-1 ,IGGY_FONTFLAG_none );
|
|
IggyFontSetIndirectUTF8( "Mojangles11", -1, IGGY_FONTFLAG_all, "Mojangles_TTF",-1 ,IGGY_FONTFLAG_none );
|
|
}
|
|
}
|
|
|
|
// TICKING
|
|
void UIController::tick()
|
|
{
|
|
if(m_navigateToHomeOnReload && !ui.IsReloadingSkin())
|
|
{
|
|
ui.CleanUpSkinReload();
|
|
m_navigateToHomeOnReload = false;
|
|
ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MainMenu);
|
|
}
|
|
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
if(m_bCloseAllScenes[i])
|
|
{
|
|
m_groups[i]->closeAllScenes();
|
|
m_groups[i]->getTooltips()->SetTooltips(-1);
|
|
m_bCloseAllScenes[i] = false;
|
|
}
|
|
}
|
|
|
|
if(m_accumulatedTicks == 0) tickInput();
|
|
m_accumulatedTicks = 0;
|
|
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
m_groups[i]->tick();
|
|
|
|
// TODO: May wish to skip ticking other groups here
|
|
}
|
|
|
|
// Fix for HUD ticks so that they all tick before this reference is cleared
|
|
EnderDragonRenderer::bossInstance = nullptr;
|
|
|
|
// Clear out the cached movie file data
|
|
__int64 currentTime = System::currentTimeMillis();
|
|
for(AUTO_VAR(it, m_cachedMovieData.begin()); it != m_cachedMovieData.end();)
|
|
{
|
|
if(it->second.m_expiry < currentTime)
|
|
{
|
|
delete [] it->second.m_ba.data;
|
|
it = m_cachedMovieData.erase(it);
|
|
}
|
|
else
|
|
{
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIController::loadSkins()
|
|
{
|
|
wstring platformSkinPath = L"";
|
|
|
|
#ifdef __PS3__
|
|
platformSkinPath = L"skinPS3.swf";
|
|
#elif defined __PSVITA__
|
|
platformSkinPath = L"skinVita.swf";
|
|
#elif defined _WINDOWS64
|
|
if(m_fScreenHeight>=1080.0f)
|
|
{
|
|
platformSkinPath = L"skinHDWin.swf";
|
|
}
|
|
else
|
|
{
|
|
platformSkinPath = L"skinWin.swf";
|
|
}
|
|
#elif defined _DURANGO
|
|
if(m_fScreenHeight>=1080.0f)
|
|
{
|
|
platformSkinPath = L"skinHDDurango.swf";
|
|
}
|
|
else
|
|
{
|
|
platformSkinPath = L"skinDurango.swf";
|
|
}
|
|
#elif defined __ORBIS__
|
|
if(m_fScreenHeight>=1080.0f)
|
|
{
|
|
platformSkinPath = L"skinHDOrbis.swf";
|
|
}
|
|
else
|
|
{
|
|
platformSkinPath = L"skinOrbis.swf";
|
|
}
|
|
|
|
#endif
|
|
// Every platform has one of these, so nothing shared
|
|
if(m_fScreenHeight>=1080.0f)
|
|
{
|
|
m_iggyLibraries[eLibrary_Platform] = loadSkin(platformSkinPath, L"platformskinHD.swf");
|
|
}
|
|
else
|
|
{
|
|
m_iggyLibraries[eLibrary_Platform] = loadSkin(platformSkinPath, L"platformskin.swf");
|
|
}
|
|
|
|
#if defined(__PS3__) || defined(__PSVITA__)
|
|
m_iggyLibraries[eLibrary_GraphicsDefault] = loadSkin(L"skinGraphics.swf", L"skinGraphics.swf");
|
|
m_iggyLibraries[eLibrary_GraphicsHUD] = loadSkin(L"skinGraphicsHud.swf", L"skinGraphicsHud.swf");
|
|
m_iggyLibraries[eLibrary_GraphicsInGame] = loadSkin(L"skinGraphicsInGame.swf", L"skinGraphicsInGame.swf");
|
|
m_iggyLibraries[eLibrary_GraphicsTooltips] = loadSkin(L"skinGraphicsTooltips.swf", L"skinGraphicsTooltips.swf");
|
|
m_iggyLibraries[eLibrary_GraphicsLabels] = loadSkin(L"skinGraphicsLabels.swf", L"skinGraphicsLabels.swf");
|
|
m_iggyLibraries[eLibrary_Labels] = loadSkin(L"skinLabels.swf", L"skinLabels.swf");
|
|
m_iggyLibraries[eLibrary_InGame] = loadSkin(L"skinInGame.swf", L"skinInGame.swf");
|
|
m_iggyLibraries[eLibrary_HUD] = loadSkin(L"skinHud.swf", L"skinHud.swf");
|
|
m_iggyLibraries[eLibrary_Tooltips] = loadSkin(L"skinTooltips.swf", L"skinTooltips.swf");
|
|
m_iggyLibraries[eLibrary_Default] = loadSkin(L"skin.swf", L"skin.swf");
|
|
#endif
|
|
|
|
#if ( defined(_WINDOWS64) || defined(_DURANGO) || defined(__ORBIS__) )
|
|
|
|
#if defined(_WINDOWS64)
|
|
// 4J Stu - Load the 720/480 skins so that we have something to fallback on during development
|
|
#ifndef _FINAL_BUILD
|
|
m_iggyLibraries[eLibraryFallback_GraphicsDefault] = loadSkin(L"skinGraphics.swf", L"skinGraphics.swf");
|
|
m_iggyLibraries[eLibraryFallback_GraphicsHUD] = loadSkin(L"skinGraphicsHud.swf", L"skinGraphicsHud.swf");
|
|
m_iggyLibraries[eLibraryFallback_GraphicsInGame] = loadSkin(L"skinGraphicsInGame.swf", L"skinGraphicsInGame.swf");
|
|
m_iggyLibraries[eLibraryFallback_GraphicsTooltips] = loadSkin(L"skinGraphicsTooltips.swf", L"skinGraphicsTooltips.swf");
|
|
m_iggyLibraries[eLibraryFallback_GraphicsLabels] = loadSkin(L"skinGraphicsLabels.swf", L"skinGraphicsLabels.swf");
|
|
m_iggyLibraries[eLibraryFallback_Labels] = loadSkin(L"skinLabels.swf", L"skinLabels.swf");
|
|
m_iggyLibraries[eLibraryFallback_InGame] = loadSkin(L"skinInGame.swf", L"skinInGame.swf");
|
|
m_iggyLibraries[eLibraryFallback_HUD] = loadSkin(L"skinHud.swf", L"skinHud.swf");
|
|
m_iggyLibraries[eLibraryFallback_Tooltips] = loadSkin(L"skinTooltips.swf", L"skinTooltips.swf");
|
|
m_iggyLibraries[eLibraryFallback_Default] = loadSkin(L"skin.swf", L"skin.swf");
|
|
#endif
|
|
#endif
|
|
|
|
m_iggyLibraries[eLibrary_GraphicsDefault] = loadSkin(L"skinHDGraphics.swf", L"skinHDGraphics.swf");
|
|
m_iggyLibraries[eLibrary_GraphicsHUD] = loadSkin(L"skinHDGraphicsHud.swf", L"skinHDGraphicsHud.swf");
|
|
m_iggyLibraries[eLibrary_GraphicsInGame] = loadSkin(L"skinHDGraphicsInGame.swf", L"skinHDGraphicsInGame.swf");
|
|
m_iggyLibraries[eLibrary_GraphicsTooltips] = loadSkin(L"skinHDGraphicsTooltips.swf", L"skinHDGraphicsTooltips.swf");
|
|
m_iggyLibraries[eLibrary_GraphicsLabels] = loadSkin(L"skinHDGraphicsLabels.swf", L"skinHDGraphicsLabels.swf");
|
|
m_iggyLibraries[eLibrary_Labels] = loadSkin(L"skinHDLabels.swf", L"skinHDLabels.swf");
|
|
m_iggyLibraries[eLibrary_InGame] = loadSkin(L"skinHDInGame.swf", L"skinHDInGame.swf");
|
|
m_iggyLibraries[eLibrary_HUD] = loadSkin(L"skinHDHud.swf", L"skinHDHud.swf");
|
|
m_iggyLibraries[eLibrary_Tooltips] = loadSkin(L"skinHDTooltips.swf", L"skinHDTooltips.swf");
|
|
m_iggyLibraries[eLibrary_Default] = loadSkin(L"skinHD.swf", L"skinHD.swf");
|
|
#endif // HD platforms
|
|
}
|
|
|
|
IggyLibrary UIController::loadSkin(const wstring &skinPath, const wstring &skinName)
|
|
{
|
|
IggyLibrary lib = IGGY_INVALID_LIBRARY;
|
|
// 4J Stu - We need to load the platformskin before the normal skin, as the normal skin requires some elements from the platform skin
|
|
if(!skinPath.empty() && app.hasArchiveFile(skinPath))
|
|
{
|
|
byteArray baFile = app.getArchiveFile(skinPath);
|
|
lib = IggyLibraryCreateFromMemoryUTF16( (IggyUTF16 *)skinName.c_str() , (void *)baFile.data, baFile.length, NULL );
|
|
|
|
delete[] baFile.data;
|
|
#ifdef _DEBUG
|
|
IggyMemoryUseInfo memoryInfo;
|
|
rrbool res;
|
|
int iteration = 0;
|
|
__int64 totalStatic = 0;
|
|
while(res = IggyDebugGetMemoryUseInfo ( NULL ,
|
|
lib ,
|
|
"" ,
|
|
0 ,
|
|
iteration ,
|
|
&memoryInfo ))
|
|
{
|
|
totalStatic += memoryInfo.static_allocation_bytes;
|
|
app.DebugPrintf(app.USER_SR, "%ls - %.*s, static: %dB, dynamic: %dB\n", skinPath.c_str(), memoryInfo.subcategory_stringlen, memoryInfo.subcategory, memoryInfo.static_allocation_bytes, memoryInfo.dynamic_allocation_bytes);
|
|
++iteration;
|
|
}
|
|
|
|
app.DebugPrintf(app.USER_SR, "%ls - Total static: %dB (%dKB)\n", skinPath.c_str(), totalStatic, totalStatic/1024);
|
|
#endif
|
|
}
|
|
return lib;
|
|
}
|
|
|
|
void UIController::ReloadSkin()
|
|
{
|
|
// Destroy all scene swf
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
//m_bCloseAllScenes[i] = true;
|
|
m_groups[i]->DestroyAll();
|
|
}
|
|
|
|
// Unload the current libraries
|
|
// Some libraries reference others, so we destroy in reverse order
|
|
for(int i = eLibrary_Count - 1; i >= 0; --i)
|
|
{
|
|
if(m_iggyLibraries[i] != IGGY_INVALID_LIBRARY) IggyLibraryDestroy(m_iggyLibraries[i]);
|
|
m_iggyLibraries[i] = IGGY_INVALID_LIBRARY;
|
|
}
|
|
|
|
#ifdef _WINDOWS64
|
|
// 4J Stu - Don't load on a thread on windows. I haven't investigated this in detail, so a quick fix
|
|
reloadSkinThreadProc(this);
|
|
#else
|
|
// Navigate to the timer scene so that we can display something while the loading is happening
|
|
ui.NavigateToScene(0,eUIScene_Timer,(void *)1,eUILayer_Tooltips,eUIGroup_Fullscreen);
|
|
|
|
m_reloadSkinThread = new C4JThread(reloadSkinThreadProc, (void*)this, "Reload skin thread");
|
|
m_reloadSkinThread->SetProcessor(CPU_CORE_UI_SCENE);
|
|
//m_reloadSkinThread->Run();
|
|
|
|
//// Load new skin
|
|
//loadSkins();
|
|
|
|
//// Reload all scene swf
|
|
//for(int i = eUIGroup_Player1; i <= eUIGroup_Player4; ++i)
|
|
//{
|
|
// m_groups[i]->ReloadAll();
|
|
//}
|
|
|
|
//// Always reload the fullscreen group
|
|
//m_groups[eUIGroup_Fullscreen]->ReloadAll();
|
|
#endif
|
|
}
|
|
|
|
void UIController::StartReloadSkinThread()
|
|
{
|
|
if(m_reloadSkinThread) m_reloadSkinThread->Run();
|
|
}
|
|
|
|
int UIController::reloadSkinThreadProc(void* lpParam)
|
|
{
|
|
EnterCriticalSection(&ms_reloadSkinCS); // MGH - added to prevent crash loading Iggy movies while the skins were being reloaded
|
|
UIController *controller = (UIController *)lpParam;
|
|
// Load new skin
|
|
controller->loadSkins();
|
|
|
|
// Reload all scene swf
|
|
for(int i = eUIGroup_Player1; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
controller->m_groups[i]->ReloadAll();
|
|
}
|
|
|
|
// Always reload the fullscreen group
|
|
controller->m_groups[eUIGroup_Fullscreen]->ReloadAll();
|
|
|
|
// 4J Stu - Don't do this on windows, as we never navigated forwards to start with
|
|
#ifndef _WINDOW64
|
|
controller->NavigateBack(0, false, eUIScene_COUNT, eUILayer_Tooltips);
|
|
#endif
|
|
LeaveCriticalSection(&ms_reloadSkinCS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool UIController::IsReloadingSkin()
|
|
{
|
|
return m_reloadSkinThread && (!m_reloadSkinThread->hasStarted() || m_reloadSkinThread->isRunning());
|
|
}
|
|
|
|
bool UIController::IsExpectingOrReloadingSkin()
|
|
{
|
|
return Minecraft::GetInstance()->skins->getSelected()->isLoadingData() || Minecraft::GetInstance()->skins->needsUIUpdate() || IsReloadingSkin();
|
|
}
|
|
|
|
void UIController::CleanUpSkinReload()
|
|
{
|
|
delete m_reloadSkinThread;
|
|
m_reloadSkinThread = NULL;
|
|
|
|
if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin())
|
|
{
|
|
if(!Minecraft::GetInstance()->skins->getSelected()->hasAudio())
|
|
{
|
|
#ifdef _DURANGO
|
|
DWORD result = StorageManager.UnmountInstalledDLC(L"TPACK");
|
|
#else
|
|
DWORD result = StorageManager.UnmountInstalledDLC("TPACK");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
for(AUTO_VAR(it,m_queuedMessageBoxData.begin()); it != m_queuedMessageBoxData.end(); ++it)
|
|
{
|
|
QueuedMessageBoxData *queuedData = *it;
|
|
ui.NavigateToScene(queuedData->iPad, eUIScene_MessageBox, &queuedData->info, queuedData->layer, eUIGroup_Fullscreen);
|
|
delete queuedData->info.uiOptionA;
|
|
delete queuedData;
|
|
}
|
|
m_queuedMessageBoxData.clear();
|
|
}
|
|
|
|
byteArray UIController::getMovieData(const wstring &filename)
|
|
{
|
|
// Cache everything we load in the current tick
|
|
__int64 targetTime = System::currentTimeMillis() + (1000LL * 60);
|
|
AUTO_VAR(it,m_cachedMovieData.find(filename));
|
|
if(it == m_cachedMovieData.end() )
|
|
{
|
|
byteArray baFile = app.getArchiveFile(filename);
|
|
CachedMovieData cmd;
|
|
cmd.m_ba = baFile;
|
|
cmd.m_expiry = targetTime;
|
|
m_cachedMovieData[filename] = cmd;
|
|
return baFile;
|
|
}
|
|
else
|
|
{
|
|
it->second.m_expiry = targetTime;
|
|
return it->second.m_ba;
|
|
}
|
|
}
|
|
|
|
// INPUT
|
|
void UIController::tickInput()
|
|
{
|
|
// If system/commerce UI up, don't handle input
|
|
//if(!m_bSysUIShowing && !m_bSystemUIShowing)
|
|
if(!m_bSystemUIShowing)
|
|
{
|
|
#ifdef ENABLE_IGGY_PERFMON
|
|
if (m_iggyPerfmonEnabled)
|
|
{
|
|
if(InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(), ACTION_MENU_STICK_PRESS)) m_iggyPerfmonEnabled = !m_iggyPerfmonEnabled;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
handleInput();
|
|
++m_accumulatedTicks;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIController::handleInput()
|
|
{
|
|
// For each user, loop over each key type and send messages based on the state
|
|
for(unsigned int iPad = 0; iPad < XUSER_MAX_COUNT; ++iPad)
|
|
{
|
|
#ifdef _DURANGO
|
|
// 4J-JEV: Added exception for primary play who migh've uttered speech commands.
|
|
if(iPad != ProfileManager.GetPrimaryPad()
|
|
&& (!InputManager.IsPadConnected(iPad) || !InputManager.IsPadLocked(iPad)) ) continue;
|
|
#endif
|
|
for(unsigned int key = 0; key <= ACTION_MAX_MENU; ++key)
|
|
{
|
|
handleKeyPress(iPad, key);
|
|
}
|
|
|
|
#ifdef __PSVITA__
|
|
//CD - Vita requires key press 40 - select [MINECRAFT_ACTION_GAME_INFO]
|
|
handleKeyPress(iPad, MINECRAFT_ACTION_GAME_INFO);
|
|
#endif
|
|
}
|
|
|
|
#ifdef _DURANGO
|
|
if(!app.GetGameStarted())
|
|
{
|
|
bool repeat = false;
|
|
int firstUnfocussedUnhandledPad = -1;
|
|
|
|
// For durango, check for unmapped controllers
|
|
for(unsigned int iPad = XUSER_MAX_COUNT; iPad < (XUSER_MAX_COUNT + InputManager.MAX_GAMEPADS); ++iPad)
|
|
{
|
|
if(InputManager.IsPadLocked(iPad) || !InputManager.IsPadConnected(iPad) ) continue;
|
|
|
|
for(unsigned int key = 0; key <= ACTION_MAX_MENU; ++key)
|
|
{
|
|
|
|
bool pressed = InputManager.ButtonPressed(iPad,key); // Toggle
|
|
bool released = InputManager.ButtonReleased(iPad,key); // Toggle
|
|
|
|
if(pressed || released)
|
|
{
|
|
bool handled = false;
|
|
|
|
// Send the key to the fullscreen group first
|
|
m_groups[(int)eUIGroup_Fullscreen]->handleInput(iPad, key, repeat, pressed, released, handled);
|
|
|
|
if(firstUnfocussedUnhandledPad < 0 && !m_groups[(int)eUIGroup_Fullscreen]->HasFocus(iPad))
|
|
{
|
|
firstUnfocussedUnhandledPad = iPad;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ProfileManager.GetLockedProfile() >= 0 && !InputManager.IsPadLocked( ProfileManager.GetLockedProfile() ) && firstUnfocussedUnhandledPad >= 0)
|
|
{
|
|
ProfileManager.RequestSignInUI(false, false, false, false, true, NULL, NULL, firstUnfocussedUnhandledPad );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
|
|
{
|
|
|
|
bool down = false;
|
|
bool pressed = false; // Toggle
|
|
bool released = false; // Toggle
|
|
bool repeat = false;
|
|
|
|
#ifdef __PSVITA__
|
|
if(key==ACTION_MENU_OK)
|
|
{
|
|
bool bTouchScreenInput=false;
|
|
|
|
// check the touchscreen
|
|
|
|
// 4J-PB - use the touchscreen for quickselect
|
|
SceTouchData* pTouchData = InputManager.GetTouchPadData(iPad,false);
|
|
|
|
if((m_bTouchscreenPressed==false) && pTouchData->reportNum==1)
|
|
{
|
|
// no active touch? clear active and highlighted touch UI elements
|
|
m_ActiveUIElement = NULL;
|
|
m_HighlightedUIElement = NULL;
|
|
|
|
// fullscreen first
|
|
UIScene *pScene=m_groups[(int)eUIGroup_Fullscreen]->getCurrentScene();
|
|
// also check tooltip scene if we're not touching anything in the main scene
|
|
UIScene *pToolTips=m_groups[(int)eUIGroup_Fullscreen]->getTooltips();
|
|
if(pScene)
|
|
{
|
|
// scene touch check
|
|
if(TouchBoxHit(pScene,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=pressed=m_bTouchscreenPressed=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
// tooltip touch check
|
|
else if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=pressed=m_bTouchscreenPressed=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pScene=m_groups[(EUIGroup)(iPad+1)]->getCurrentScene();
|
|
pToolTips=m_groups[(int)iPad+1]->getTooltips();
|
|
if(pScene)
|
|
{
|
|
// scene touch check
|
|
if(TouchBoxHit(pScene,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=pressed=m_bTouchscreenPressed=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
// tooltip touch check (if scene exists but not component has been touched)
|
|
else if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=pressed=m_bTouchscreenPressed=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
}
|
|
else if(pToolTips)
|
|
{
|
|
// tooltip touch check (if scene does not exist)
|
|
if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=pressed=m_bTouchscreenPressed=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(m_bTouchscreenPressed && pTouchData->reportNum==1)
|
|
{
|
|
// fullscreen first
|
|
UIScene *pScene=m_groups[(int)eUIGroup_Fullscreen]->getCurrentScene();
|
|
// also check tooltip scene if we're not touching anything in the main scene
|
|
UIScene *pToolTips=m_groups[(int)eUIGroup_Fullscreen]->getTooltips();
|
|
if(pScene)
|
|
{
|
|
// scene touch check
|
|
if(TouchBoxHit(pScene,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
// tooltip touch check (if scene exists but not component has been touched)
|
|
else if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pScene=m_groups[(EUIGroup)(iPad+1)]->getCurrentScene();
|
|
pToolTips=m_groups[(int)iPad+1]->getTooltips();
|
|
if(pScene)
|
|
{
|
|
// scene touch check
|
|
if(TouchBoxHit(pScene,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
// tooltip touch check (if scene exists but not component has been touched)
|
|
else if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
}
|
|
else if(pToolTips)
|
|
{
|
|
// tooltip touch check (if scene does not exist)
|
|
if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
|
|
{
|
|
down=true;
|
|
bTouchScreenInput=true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(m_bTouchscreenPressed && pTouchData->reportNum==0)
|
|
{
|
|
// released
|
|
bTouchScreenInput=true;
|
|
m_bTouchscreenPressed=false;
|
|
released=true;
|
|
}
|
|
|
|
if(pressed)
|
|
{
|
|
// Start repeat timer
|
|
m_actionRepeatTimer[iPad][key] = GetTickCount() + UI_REPEAT_KEY_DELAY_MS;
|
|
}
|
|
else if (released)
|
|
{
|
|
// Stop repeat timer
|
|
m_actionRepeatTimer[iPad][key] = 0;
|
|
}
|
|
else if (down)
|
|
{
|
|
// Check is enough time has elapsed to be a repeat key
|
|
DWORD currentTime = GetTickCount();
|
|
if(m_actionRepeatTimer[iPad][key] > 0 && currentTime > m_actionRepeatTimer[iPad][key])
|
|
{
|
|
repeat = true;
|
|
pressed = true;
|
|
m_actionRepeatTimer[iPad][key] = currentTime + UI_REPEAT_KEY_REPEAT_RATE_MS;
|
|
}
|
|
}
|
|
|
|
// handle touch input
|
|
HandleTouchInput(iPad, key, pressed, repeat, released);
|
|
|
|
// ignore any other presses if the touchscreen has been used
|
|
if(bTouchScreenInput) return;
|
|
}
|
|
#endif
|
|
|
|
down = InputManager.ButtonDown(iPad,key);
|
|
pressed = InputManager.ButtonPressed(iPad,key); // Toggle
|
|
released = InputManager.ButtonReleased(iPad,key); // Toggle
|
|
|
|
#ifdef _WINDOWS64
|
|
// Keyboard menu input for player 0
|
|
if (iPad == 0)
|
|
{
|
|
bool kbDown = false, kbPressed = false, kbReleased = false;
|
|
switch(key)
|
|
{
|
|
case ACTION_MENU_UP: kbDown = KMInput.IsKeyDown(VK_UP); kbPressed = KMInput.IsKeyPressed(VK_UP); kbReleased = KMInput.IsKeyReleased(VK_UP); break;
|
|
case ACTION_MENU_DOWN: kbDown = KMInput.IsKeyDown(VK_DOWN); kbPressed = KMInput.IsKeyPressed(VK_DOWN); kbReleased = KMInput.IsKeyReleased(VK_DOWN); break;
|
|
case ACTION_MENU_LEFT: kbDown = KMInput.IsKeyDown(VK_LEFT); kbPressed = KMInput.IsKeyPressed(VK_LEFT); kbReleased = KMInput.IsKeyReleased(VK_LEFT); break;
|
|
case ACTION_MENU_RIGHT: kbDown = KMInput.IsKeyDown(VK_RIGHT); kbPressed = KMInput.IsKeyPressed(VK_RIGHT); kbReleased = KMInput.IsKeyReleased(VK_RIGHT); break;
|
|
case ACTION_MENU_OK: kbDown = KMInput.IsKeyDown(VK_RETURN); kbPressed = KMInput.IsKeyPressed(VK_RETURN); kbReleased = KMInput.IsKeyReleased(VK_RETURN); break;
|
|
case ACTION_MENU_A: kbDown = KMInput.IsKeyDown(VK_RETURN); kbPressed = KMInput.IsKeyPressed(VK_RETURN); kbReleased = KMInput.IsKeyReleased(VK_RETURN); break;
|
|
case ACTION_MENU_CANCEL: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
|
|
case ACTION_MENU_B: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
|
|
case ACTION_MENU_PAUSEMENU: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
|
|
}
|
|
pressed = pressed || kbPressed;
|
|
released = released || kbReleased;
|
|
down = down || kbDown;
|
|
}
|
|
#endif
|
|
|
|
if(pressed) app.DebugPrintf("Pressed %d\n",key);
|
|
if(released) app.DebugPrintf("Released %d\n",key);
|
|
// Repeat handling
|
|
if(pressed)
|
|
{
|
|
// Start repeat timer
|
|
m_actionRepeatTimer[iPad][key] = GetTickCount() + UI_REPEAT_KEY_DELAY_MS;
|
|
}
|
|
else if (released)
|
|
{
|
|
// Stop repeat timer
|
|
m_actionRepeatTimer[iPad][key] = 0;
|
|
}
|
|
else if (down)
|
|
{
|
|
// Check is enough time has elapsed to be a repeat key
|
|
DWORD currentTime = GetTickCount();
|
|
if(m_actionRepeatTimer[iPad][key] > 0 && currentTime > m_actionRepeatTimer[iPad][key])
|
|
{
|
|
repeat = true;
|
|
pressed = true;
|
|
m_actionRepeatTimer[iPad][key] = currentTime + UI_REPEAT_KEY_REPEAT_RATE_MS;
|
|
}
|
|
}
|
|
|
|
#ifndef _CONTENT_PACKAGE
|
|
|
|
#ifdef ENABLE_IGGY_PERFMON
|
|
if ( pressed && !repeat && key == ACTION_MENU_STICK_PRESS)
|
|
{
|
|
m_iggyPerfmonEnabled = !m_iggyPerfmonEnabled;
|
|
}
|
|
#endif
|
|
|
|
// 4J Stu - Removed this function
|
|
#if 0
|
|
#ifdef __PS3__
|
|
//if ( pressed &&
|
|
// !repeat &&
|
|
// //app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_ToggleFont) &&
|
|
// key == ACTION_MENU_STICK_PRESS)
|
|
//{
|
|
// static bool whichFont = true;
|
|
// if (whichFont)
|
|
// {
|
|
// IggyFontSetIndirectUTF8( "Mojangles_7", -1, IGGY_FONTFLAG_all, "Mojangles_TTF",-1 ,IGGY_FONTFLAG_none );
|
|
// IggyFontSetIndirectUTF8( "Mojangles_11", -1, IGGY_FONTFLAG_all, "Mojangles_TTF",-1 ,IGGY_FONTFLAG_none );
|
|
// whichFont = false;
|
|
// }
|
|
// else
|
|
// {
|
|
// IggyFontSetIndirectUTF8( "Mojangles_7", -1, IGGY_FONTFLAG_all, "Mojangles_7",-1 ,IGGY_FONTFLAG_none );
|
|
// IggyFontSetIndirectUTF8( "Mojangles_11", -1, IGGY_FONTFLAG_all, "Mojangles_11",-1 ,IGGY_FONTFLAG_none );
|
|
// whichFont = true;
|
|
// }
|
|
//}
|
|
//else
|
|
if ( pressed &&
|
|
!repeat &&
|
|
//!(app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_ToggleFont)) &&
|
|
key == ACTION_MENU_STICK_PRESS)
|
|
{
|
|
__int64 totalStatic = 0;
|
|
__int64 totalDynamic = 0;
|
|
app.DebugPrintf(app.USER_SR, "********************************\n");
|
|
app.DebugPrintf(app.USER_SR, "BEGIN TOTAL SWF MEMORY USAGE\n\n");
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
m_groups[i]->PrintTotalMemoryUsage(totalStatic, totalDynamic);
|
|
}
|
|
for(unsigned int i = 0; i < eLibrary_Count; ++i)
|
|
{
|
|
__int64 libraryStatic = 0;
|
|
__int64 libraryDynamic = 0;
|
|
|
|
if(m_iggyLibraries[i] != IGGY_INVALID_LIBRARY)
|
|
{
|
|
|
|
IggyMemoryUseInfo memoryInfo;
|
|
rrbool res;
|
|
int iteration = 0;
|
|
while(res = IggyDebugGetMemoryUseInfo ( NULL ,
|
|
m_iggyLibraries[i] ,
|
|
"" ,
|
|
0 ,
|
|
iteration ,
|
|
&memoryInfo ))
|
|
{
|
|
libraryStatic += memoryInfo.static_allocation_bytes;
|
|
libraryDynamic += memoryInfo.dynamic_allocation_bytes;
|
|
totalStatic += memoryInfo.static_allocation_bytes;
|
|
totalDynamic += memoryInfo.dynamic_allocation_bytes;
|
|
++iteration;
|
|
}
|
|
}
|
|
|
|
app.DebugPrintf(app.USER_SR, "Library static: %dB , Library dynamic: %d, ID: %d\n", libraryStatic, libraryDynamic, i);
|
|
}
|
|
app.DebugPrintf(app.USER_SR, "Total static: %d , Total dynamic: %d\n", totalStatic, totalDynamic);
|
|
app.DebugPrintf(app.USER_SR, "\n\nEND TOTAL SWF MEMORY USAGE\n");
|
|
app.DebugPrintf(app.USER_SR, "********************************\n\n");
|
|
}
|
|
else
|
|
#endif
|
|
#endif
|
|
#endif
|
|
//#endif
|
|
if(repeat || pressed || released)
|
|
{
|
|
bool handled = false;
|
|
|
|
// Send the key to the fullscreen group first
|
|
m_groups[(int)eUIGroup_Fullscreen]->handleInput(iPad, key, repeat, pressed, released, handled);
|
|
if(!handled)
|
|
{
|
|
// If it's not been handled yet, then pass the event onto the players specific group
|
|
m_groups[(iPad+1)]->handleInput(iPad, key, repeat, pressed, released, handled);
|
|
}
|
|
}
|
|
}
|
|
|
|
rrbool RADLINK UIController::ExternalFunctionCallback( void * user_callback_data , Iggy * player , IggyExternalFunctionCallUTF16 * call)
|
|
{
|
|
UIScene *scene = (UIScene *)IggyPlayerGetUserdata(player);
|
|
|
|
if(scene != NULL)
|
|
{
|
|
scene->externalCallback(call);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// RENDERING
|
|
void UIController::renderScenes()
|
|
{
|
|
PIXBeginNamedEvent(0, "Rendering Iggy scenes");
|
|
// Only render player scenes if the game is started
|
|
if(app.GetGameStarted() && !m_groups[eUIGroup_Fullscreen]->hidesLowerScenes())
|
|
{
|
|
for(int i = eUIGroup_Player1; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
PIXBeginNamedEvent(0, "Rendering layer %d scenes", i);
|
|
m_groups[i]->render();
|
|
PIXEndNamedEvent();
|
|
}
|
|
}
|
|
|
|
// Always render the fullscreen group
|
|
PIXBeginNamedEvent(0, "Rendering fullscreen scenes");
|
|
m_groups[eUIGroup_Fullscreen]->render();
|
|
PIXEndNamedEvent();
|
|
|
|
PIXEndNamedEvent();
|
|
|
|
#ifdef ENABLE_IGGY_PERFMON
|
|
if (m_iggyPerfmonEnabled)
|
|
{
|
|
IggyPerfmonPad pm_pad;
|
|
|
|
pm_pad.bits = 0;
|
|
pm_pad.field.dpad_up = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_UP);
|
|
pm_pad.field.dpad_down = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_DOWN);
|
|
pm_pad.field.dpad_left = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_LEFT);
|
|
pm_pad.field.dpad_right = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_RIGHT);
|
|
pm_pad.field.button_up = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_Y);
|
|
pm_pad.field.button_down = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_A);
|
|
pm_pad.field.button_left = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_X);
|
|
pm_pad.field.button_right = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_B);
|
|
pm_pad.field.shoulder_left_hi = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_LEFT_SCROLL);
|
|
pm_pad.field.shoulder_right_hi = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_RIGHT_SCROLL);
|
|
pm_pad.field.trigger_left_low = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_PAGEUP);
|
|
pm_pad.field.trigger_right_low = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_PAGEDOWN);
|
|
//IggyPerfmonPadFromXInputStatePointer(pm_pad, &xi_pad);
|
|
|
|
//gdraw_D3D_SetTileOrigin( fb,
|
|
// zb,
|
|
// PM_ORIGIN_X,
|
|
// PM_ORIGIN_Y );
|
|
IggyPerfmonTickAndDraw(iggy_perfmon, gdraw_funcs, &pm_pad,
|
|
PM_ORIGIN_X, PM_ORIGIN_Y, getScreenWidth(), getScreenHeight()); // perfmon draw area in window coords
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void UIController::getRenderDimensions(C4JRender::eViewportType viewport, S32 &width, S32 &height)
|
|
{
|
|
switch( viewport )
|
|
{
|
|
case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
|
|
width = (S32)(getScreenWidth());
|
|
height = (S32)(getScreenHeight());
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
|
|
width = (S32)(getScreenWidth() / 2);
|
|
height = (S32)(getScreenHeight() / 2);
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
|
|
width = (S32)(getScreenWidth() / 2);
|
|
height = (S32)(getScreenHeight() / 2);
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
|
|
width = (S32)(getScreenWidth() / 2);
|
|
height = (S32)(getScreenHeight() / 2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UIController::setupRenderPosition(C4JRender::eViewportType viewport)
|
|
{
|
|
if(m_bCustomRenderPosition || m_currentRenderViewport != viewport)
|
|
{
|
|
m_currentRenderViewport = viewport;
|
|
m_bCustomRenderPosition = false;
|
|
S32 xPos = 0;
|
|
S32 yPos = 0;
|
|
switch( viewport )
|
|
{
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
|
|
xPos = (S32)(getScreenWidth() / 4);
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
|
|
xPos = (S32)(getScreenWidth() / 4);
|
|
yPos = (S32)(getScreenHeight() / 2);
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
|
|
yPos = (S32)(getScreenHeight() / 4);
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
|
|
xPos = (S32)(getScreenWidth() / 2);
|
|
yPos = (S32)(getScreenHeight() / 4);
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
|
|
xPos = (S32)(getScreenWidth() / 2);
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
|
|
yPos = (S32)(getScreenHeight() / 2);
|
|
break;
|
|
case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
|
|
xPos = (S32)(getScreenWidth() / 2);
|
|
yPos = (S32)(getScreenHeight() / 2);
|
|
break;
|
|
}
|
|
m_tileOriginX = xPos;
|
|
m_tileOriginY = yPos;
|
|
setTileOrigin(xPos, yPos);
|
|
}
|
|
}
|
|
|
|
void UIController::setupRenderPosition(S32 xOrigin, S32 yOrigin)
|
|
{
|
|
m_bCustomRenderPosition = true;
|
|
m_tileOriginX = xOrigin;
|
|
m_tileOriginY = yOrigin;
|
|
setTileOrigin(xOrigin, yOrigin);
|
|
}
|
|
|
|
void UIController::setupCustomDrawGameState()
|
|
{
|
|
// Rest the clear rect
|
|
m_customRenderingClearRect.left = LONG_MAX;
|
|
m_customRenderingClearRect.right = LONG_MIN;
|
|
m_customRenderingClearRect.top = LONG_MAX;
|
|
m_customRenderingClearRect.bottom = LONG_MIN;
|
|
|
|
#if defined _WINDOWS64 || _DURANGO
|
|
PIXBeginNamedEvent(0,"StartFrame");
|
|
RenderManager.StartFrame();
|
|
PIXEndNamedEvent();
|
|
gdraw_D3D11_setViewport_4J();
|
|
#elif defined __PS3__
|
|
RenderManager.StartFrame();
|
|
#elif defined __PSVITA__
|
|
RenderManager.StartFrame();
|
|
#elif defined __ORBIS__
|
|
RenderManager.StartFrame(false);
|
|
// Set up a viewport for the render that matches Iggy's own viewport, apart form using an opengl-style z-range (Iggy uses a DX-style range on PS4), so
|
|
// that the renderer orthographic projection will work
|
|
gdraw_orbis_setViewport_4J();
|
|
#endif
|
|
RenderManager.Set_matrixDirty();
|
|
|
|
// 4J Stu - We don't need to clear this here as iggy hasn't written anything to the depth buffer.
|
|
// We DO however clear after we render which is why we still setup the rectangle here
|
|
//RenderManager.Clear(GL_DEPTH_BUFFER_BIT, &m_customRenderingClearRect);
|
|
//glClear(GL_DEPTH_BUFFER_BIT);
|
|
|
|
PIXBeginNamedEvent(0,"Final setup");
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, m_fScreenWidth, m_fScreenHeight, 0, 1000, 3000);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glAlphaFunc(GL_GREATER, 0.1f);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LEQUAL);
|
|
glDepthMask(true);
|
|
PIXEndNamedEvent();
|
|
}
|
|
|
|
void UIController::setupCustomDrawMatrices(UIScene *scene, CustomDrawData *customDrawRegion)
|
|
{
|
|
Minecraft *pMinecraft=Minecraft::GetInstance();
|
|
|
|
// Clear just the region required for this control.
|
|
float sceneWidth = (float)scene->getRenderWidth();
|
|
float sceneHeight = (float)scene->getRenderHeight();
|
|
|
|
LONG left, right, top, bottom;
|
|
#ifdef __PS3__
|
|
if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen())
|
|
{
|
|
// 4J Stu - Our SD target on PS3 is double width
|
|
left = m_tileOriginX + (sceneWidth + customDrawRegion->mat[(0*4)+3]*sceneWidth);
|
|
right = left + ( (sceneWidth * customDrawRegion->mat[0]) ) * customDrawRegion->x1;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
left = m_tileOriginX + (sceneWidth + customDrawRegion->mat[(0*4)+3]*sceneWidth)/2;
|
|
right = left + ( (sceneWidth * customDrawRegion->mat[0])/2 ) * customDrawRegion->x1;
|
|
}
|
|
|
|
top = m_tileOriginY + (sceneHeight - customDrawRegion->mat[(1*4)+3]*sceneHeight)/2;
|
|
bottom = top + (sceneHeight * -customDrawRegion->mat[(1*4) + 1])/2 * customDrawRegion->y1;
|
|
|
|
m_customRenderingClearRect.left = min(m_customRenderingClearRect.left, left);
|
|
m_customRenderingClearRect.right = max(m_customRenderingClearRect.right, right);;
|
|
m_customRenderingClearRect.top = min(m_customRenderingClearRect.top, top);
|
|
m_customRenderingClearRect.bottom = max(m_customRenderingClearRect.bottom, bottom);
|
|
|
|
if(!m_bScreenWidthSetup)
|
|
{
|
|
Minecraft *pMinecraft=Minecraft::GetInstance();
|
|
if(pMinecraft != NULL)
|
|
{
|
|
m_fScreenWidth=(float)pMinecraft->width_phys;
|
|
m_fScreenHeight=(float)pMinecraft->height_phys;
|
|
m_bScreenWidthSetup = true;
|
|
}
|
|
}
|
|
|
|
glLoadIdentity();
|
|
glTranslatef(0, 0, -2000);
|
|
// Iggy translations are based on a double-size target, with the origin in the centre
|
|
glTranslatef((m_fScreenWidth + customDrawRegion->mat[(0*4)+3]*m_fScreenWidth)/2,(m_fScreenHeight - customDrawRegion->mat[(1*4)+3]*m_fScreenHeight)/2,0);
|
|
// Iggy scales are based on a double-size target
|
|
glScalef( (m_fScreenWidth * customDrawRegion->mat[0])/2,(m_fScreenHeight * -customDrawRegion->mat[(1*4) + 1])/2,1.0f);
|
|
}
|
|
|
|
void UIController::setupCustomDrawGameStateAndMatrices(UIScene *scene, CustomDrawData *customDrawRegion)
|
|
{
|
|
setupCustomDrawGameState();
|
|
setupCustomDrawMatrices(scene, customDrawRegion);
|
|
}
|
|
|
|
void UIController::endCustomDrawGameState()
|
|
{
|
|
#ifdef __ORBIS__
|
|
// TO BE IMPLEMENTED
|
|
RenderManager.Clear(GL_DEPTH_BUFFER_BIT);
|
|
#else
|
|
RenderManager.Clear(GL_DEPTH_BUFFER_BIT, &m_customRenderingClearRect);
|
|
#endif
|
|
//glClear(GL_DEPTH_BUFFER_BIT);
|
|
glDepthMask(false);
|
|
glDisable(GL_ALPHA_TEST);
|
|
}
|
|
|
|
void UIController::endCustomDrawMatrices()
|
|
{
|
|
}
|
|
|
|
void UIController::endCustomDrawGameStateAndMatrices()
|
|
{
|
|
endCustomDrawMatrices();
|
|
endCustomDrawGameState();
|
|
}
|
|
|
|
void RADLINK UIController::CustomDrawCallback(void *user_callback_data, Iggy *player, IggyCustomDrawCallbackRegion *region)
|
|
{
|
|
UIScene *scene = (UIScene *)IggyPlayerGetUserdata(player);
|
|
|
|
if(scene != NULL)
|
|
{
|
|
scene->customDraw(region);
|
|
}
|
|
}
|
|
|
|
//Description
|
|
//Callback to create a user-defined texture to replace SWF-defined textures.
|
|
//Parameters
|
|
//width - Input value: optional number of pixels wide specified from AS3, or -1 if not defined. Output value: the number of pixels wide to pretend to Iggy that the bitmap is. SWF and AS3 scales bitmaps based on their pixel dimensions, so you can use this to substitute a texture that is higher or lower resolution that ActionScript thinks it is.
|
|
//height - Input value: optional number of pixels high specified from AS3, or -1 if not defined. Output value: the number of pixels high to pretend to Iggy that the bitmap is. SWF and AS3 scales bitmaps based on their pixel dimensions, so you can use this to substitute a texture that is higher or lower resolution that ActionScript thinks it is.
|
|
//destroy_callback_data - Optional additional output value you can set; the value will be passed along to the corresponding Iggy_TextureSubstitutionDestroyCallback (e.g. you can store the pointer to your own internal structure here).
|
|
//return - A platform-independent wrapped texture handle provided by GDraw, or NULL (NULL with throw an ActionScript 3 ArgumentError that the Flash developer can catch) Use by calling IggySetTextureSubstitutionCallbacks.
|
|
//
|
|
//Discussion
|
|
//
|
|
//If your texture includes an alpha channel, you must use a premultiplied alpha (where the R,G, and B channels have been multiplied by the alpha value); all Iggy shaders assume premultiplied alpha (and it looks better anyway).
|
|
GDrawTexture * RADLINK UIController::TextureSubstitutionCreateCallback ( void * user_callback_data , IggyUTF16 * texture_name , S32 * width , S32 * height , void * * destroy_callback_data )
|
|
{
|
|
UIController *uiController = (UIController *)user_callback_data;
|
|
AUTO_VAR(it,uiController->m_substitutionTextures.find((wchar_t *)texture_name));
|
|
|
|
if(it != uiController->m_substitutionTextures.end())
|
|
{
|
|
app.DebugPrintf("Found substitution texture %ls, with %d bytes\n", (wchar_t *)texture_name,it->second.length);
|
|
|
|
BufferedImage image(it->second.data, it->second.length);
|
|
if( image.getData() != NULL )
|
|
{
|
|
image.preMultiplyAlpha();
|
|
Textures *t = Minecraft::GetInstance()->textures;
|
|
int id = t->getTexture(&image,C4JRender::TEXTURE_FORMAT_RxGyBzAw,false);
|
|
|
|
// 4J Stu - All our flash controls that allow replacing textures use a special 64x64 symbol
|
|
// Force this size here so that our images don't get scaled wildly
|
|
#if (defined __ORBIS__ || defined _DURANGO )
|
|
*width = 96;
|
|
*height = 96;
|
|
#else
|
|
*width = 64;
|
|
*height = 64;
|
|
|
|
#endif
|
|
*destroy_callback_data = (void *)id;
|
|
|
|
app.DebugPrintf("Found substitution texture %ls (%d) - %dx%d\n", (wchar_t *)texture_name, id, image.getWidth(), image.getHeight());
|
|
return ui.getSubstitutionTexture(id);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
app.DebugPrintf("Could not find substitution texture %ls\n", (wchar_t *)texture_name);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//Description
|
|
//Callback received from Iggy when it stops using a user-defined texture.
|
|
void RADLINK UIController::TextureSubstitutionDestroyCallback ( void * user_callback_data , void * destroy_callback_data , GDrawTexture * handle )
|
|
{
|
|
// Orbis complains about casting a pointer to an int
|
|
LONGLONG llVal=(LONGLONG)destroy_callback_data;
|
|
int id=(int)llVal;
|
|
app.DebugPrintf("Destroying iggy texture %d\n", id);
|
|
|
|
ui.destroySubstitutionTexture(user_callback_data, handle);
|
|
|
|
Textures *t = Minecraft::GetInstance()->textures;
|
|
t->releaseTexture( id );
|
|
}
|
|
|
|
void UIController::registerSubstitutionTexture(const wstring &textureName, PBYTE pbData, DWORD dwLength)
|
|
{
|
|
// Remove it if it already exists
|
|
unregisterSubstitutionTexture(textureName,false);
|
|
|
|
m_substitutionTextures[textureName] = byteArray(pbData, dwLength);
|
|
}
|
|
|
|
void UIController::unregisterSubstitutionTexture(const wstring &textureName, bool deleteData)
|
|
{
|
|
AUTO_VAR(it,m_substitutionTextures.find(textureName));
|
|
|
|
if(it != m_substitutionTextures.end())
|
|
{
|
|
if(deleteData) delete [] it->second.data;
|
|
m_substitutionTextures.erase(it);
|
|
}
|
|
}
|
|
|
|
// NAVIGATION
|
|
bool UIController::NavigateToScene(int iPad, EUIScene scene, void *initData, EUILayer layer, EUIGroup group)
|
|
{
|
|
// if you're trying to navigate to the inventory,the crafting, pause or game info or any of the trigger scenes and there's already a menu up (because you were pressing a few buttons at the same time) then ignore the navigate
|
|
if(GetMenuDisplayed(iPad))
|
|
{
|
|
switch(scene)
|
|
{
|
|
case eUIScene_PauseMenu:
|
|
case eUIScene_Crafting2x2Menu:
|
|
case eUIScene_Crafting3x3Menu:
|
|
case eUIScene_FurnaceMenu:
|
|
case eUIScene_ContainerMenu:
|
|
case eUIScene_LargeContainerMenu:
|
|
case eUIScene_InventoryMenu:
|
|
case eUIScene_CreativeMenu:
|
|
case eUIScene_DispenserMenu:
|
|
case eUIScene_SignEntryMenu:
|
|
case eUIScene_InGameInfoMenu:
|
|
case eUIScene_EnchantingMenu:
|
|
case eUIScene_BrewingStandMenu:
|
|
case eUIScene_AnvilMenu:
|
|
case eUIScene_TradingMenu:
|
|
app.DebugPrintf("IGNORING NAVIGATE - we're trying to navigate to a user selected scene when there's already a scene up: pad:%d, scene:%d\n", iPad, scene);
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch(scene)
|
|
{
|
|
case eUIScene_FullscreenProgress:
|
|
{
|
|
// 4J Stu - The fullscreen progress scene should not interfere with any other scene stack, so should be placed in it's own group/layer
|
|
layer = eUILayer_Fullscreen;
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
break;
|
|
case eUIScene_ConnectingProgress:
|
|
{
|
|
// The connecting progress scene shouldn't interfere with other scenes
|
|
layer = eUILayer_Fullscreen;
|
|
}
|
|
break;
|
|
case eUIScene_EndPoem:
|
|
{
|
|
// The end poem scene shouldn't interfere with other scenes, but will be underneath the autosave progress
|
|
group = eUIGroup_Fullscreen;
|
|
layer = eUILayer_Scene;
|
|
}
|
|
break;
|
|
};
|
|
int menuDisplayedPad = XUSER_INDEX_ANY;
|
|
if(group == eUIGroup_PAD)
|
|
{
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) )
|
|
{
|
|
menuDisplayedPad = iPad;
|
|
group = (EUIGroup)(iPad+1);
|
|
}
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
layer = eUILayer_Fullscreen;
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
}
|
|
|
|
PerformanceTimer timer;
|
|
|
|
EnterCriticalSection(&m_navigationLock);
|
|
SetMenuDisplayed(menuDisplayedPad,true);
|
|
bool success = m_groups[(int)group]->NavigateToScene(iPad, scene, initData, layer);
|
|
if(success && group == eUIGroup_Fullscreen) setFullscreenMenuDisplayed(true);
|
|
LeaveCriticalSection(&m_navigationLock);
|
|
|
|
timer.PrintElapsedTime(L"Navigate to scene");
|
|
|
|
return success;
|
|
//return true;
|
|
}
|
|
|
|
bool UIController::NavigateBack(int iPad, bool forceUsePad, EUIScene eScene, EUILayer eLayer)
|
|
{
|
|
bool navComplete = false;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
bool navComplete = m_groups[(int)eUIGroup_Fullscreen]->NavigateBack(iPad, eScene, eLayer);
|
|
|
|
if(!navComplete && ( iPad != 255 ) && ( iPad >= 0 ) )
|
|
{
|
|
EUIGroup group = (EUIGroup)(iPad+1);
|
|
navComplete = m_groups[(int)group]->NavigateBack(iPad, eScene, eLayer);
|
|
if(!m_groups[(int)group]->GetMenuDisplayed())SetMenuDisplayed(iPad,false);
|
|
}
|
|
// 4J-PB - autosave in fullscreen doesn't clear the menuDisplayed flag
|
|
else
|
|
{
|
|
if(!m_groups[(int)eUIGroup_Fullscreen]->GetMenuDisplayed())
|
|
{
|
|
setFullscreenMenuDisplayed(false);
|
|
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
|
|
{
|
|
SetMenuDisplayed(i,m_groups[i+1]->GetMenuDisplayed());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
navComplete = m_groups[(int)eUIGroup_Fullscreen]->NavigateBack(iPad, eScene, eLayer);
|
|
if(!m_groups[(int)eUIGroup_Fullscreen]->GetMenuDisplayed()) SetMenuDisplayed(XUSER_INDEX_ANY,false);
|
|
}
|
|
return navComplete;
|
|
}
|
|
|
|
void UIController::NavigateToHomeMenu()
|
|
{
|
|
ui.CloseAllPlayersScenes();
|
|
|
|
// Alert the app the we no longer want to be informed of ethernet connections
|
|
app.SetLiveLinkRequired( false );
|
|
|
|
Minecraft *pMinecraft = Minecraft::GetInstance();
|
|
|
|
// 4J-PB - just about to switched to the default texture pack , so clean up anything texture pack related here
|
|
|
|
// unload any texture pack audio
|
|
// if there is audio in use, clear out the audio, and unmount the pack
|
|
TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected();
|
|
|
|
|
|
DLCTexturePack *pDLCTexPack=NULL;
|
|
if(pTexPack->hasAudio())
|
|
{
|
|
// get the dlc texture pack, and store it
|
|
pDLCTexPack=(DLCTexturePack *)pTexPack;
|
|
}
|
|
|
|
// change to the default texture pack
|
|
pMinecraft->skins->selectTexturePackById(TexturePackRepository::DEFAULT_TEXTURE_PACK_ID);
|
|
|
|
|
|
if(pTexPack->hasAudio())
|
|
{
|
|
// need to stop the streaming audio - by playing streaming audio from the default texture pack now
|
|
// reset the streaming sounds back to the normal ones
|
|
pMinecraft->soundEngine->SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3,
|
|
eStream_Nether1,eStream_Nether4,
|
|
eStream_end_dragon,eStream_end_end,
|
|
eStream_CD_1);
|
|
pMinecraft->soundEngine->playStreaming(L"", 0, 0, 0, 1, 1);
|
|
|
|
// if(pDLCTexPack->m_pStreamedWaveBank!=NULL)
|
|
// {
|
|
// pDLCTexPack->m_pStreamedWaveBank->Destroy();
|
|
// }
|
|
// if(pDLCTexPack->m_pSoundBank!=NULL)
|
|
// {
|
|
// pDLCTexPack->m_pSoundBank->Destroy();
|
|
// }
|
|
#ifdef _XBOX_ONE
|
|
DWORD result = StorageManager.UnmountInstalledDLC(L"TPACK");
|
|
#else
|
|
DWORD result = StorageManager.UnmountInstalledDLC("TPACK");
|
|
#endif
|
|
|
|
app.DebugPrintf("Unmount result is %d\n",result);
|
|
}
|
|
|
|
g_NetworkManager.ForceFriendsSessionRefresh();
|
|
|
|
if(pMinecraft->skins->needsUIUpdate())
|
|
{
|
|
m_navigateToHomeOnReload = true;
|
|
}
|
|
else
|
|
{
|
|
ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MainMenu);
|
|
}
|
|
}
|
|
|
|
UIScene *UIController::GetTopScene(int iPad, EUILayer layer, EUIGroup group)
|
|
{
|
|
if(group == eUIGroup_PAD)
|
|
{
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) )
|
|
{
|
|
group = (EUIGroup)(iPad+1);
|
|
}
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
layer = eUILayer_Fullscreen;
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
}
|
|
return m_groups[(int)group]->GetTopScene(layer);
|
|
}
|
|
|
|
size_t UIController::RegisterForCallbackId(UIScene *scene)
|
|
{
|
|
EnterCriticalSection(&m_registeredCallbackScenesCS);
|
|
size_t newId = GetTickCount();
|
|
newId &= 0xFFFFFF; // Chop off the top byte, we don't need any more accuracy than that
|
|
newId |= (scene->getSceneType() << 24); // Add in the scene's type to help keep this unique
|
|
m_registeredCallbackScenes[newId] = scene;
|
|
LeaveCriticalSection(&m_registeredCallbackScenesCS);
|
|
return newId;
|
|
}
|
|
|
|
void UIController::UnregisterCallbackId(size_t id)
|
|
{
|
|
EnterCriticalSection(&m_registeredCallbackScenesCS);
|
|
AUTO_VAR(it, m_registeredCallbackScenes.find(id) );
|
|
if(it != m_registeredCallbackScenes.end() )
|
|
{
|
|
m_registeredCallbackScenes.erase(it);
|
|
}
|
|
LeaveCriticalSection(&m_registeredCallbackScenesCS);
|
|
}
|
|
|
|
UIScene *UIController::GetSceneFromCallbackId(size_t id)
|
|
{
|
|
UIScene *scene = NULL;
|
|
AUTO_VAR(it, m_registeredCallbackScenes.find(id) );
|
|
if(it != m_registeredCallbackScenes.end() )
|
|
{
|
|
scene = it->second;
|
|
}
|
|
return scene;
|
|
}
|
|
|
|
void UIController::EnterCallbackIdCriticalSection()
|
|
{
|
|
EnterCriticalSection(&m_registeredCallbackScenesCS);
|
|
}
|
|
|
|
void UIController::LeaveCallbackIdCriticalSection()
|
|
{
|
|
LeaveCriticalSection(&m_registeredCallbackScenesCS);
|
|
}
|
|
|
|
void UIController::CloseAllPlayersScenes()
|
|
{
|
|
m_groups[(int)eUIGroup_Fullscreen]->getTooltips()->SetTooltips(-1);
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
//m_bCloseAllScenes[i] = true;
|
|
m_groups[i]->closeAllScenes();
|
|
m_groups[i]->getTooltips()->SetTooltips(-1);
|
|
}
|
|
|
|
if (!m_groups[eUIGroup_Fullscreen]->GetMenuDisplayed()) {
|
|
for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
|
|
{
|
|
SetMenuDisplayed(i,false);
|
|
}
|
|
}
|
|
setFullscreenMenuDisplayed(false);
|
|
}
|
|
|
|
void UIController::CloseUIScenes(int iPad, bool forceIPad)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() || forceIPad )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
|
|
m_groups[(int)group]->closeAllScenes();
|
|
m_groups[(int)group]->getTooltips()->SetTooltips(-1);
|
|
|
|
// This should cause the popup to dissappear
|
|
TutorialPopupInfo popupInfo;
|
|
if(m_groups[(int)group]->getTutorialPopup()) m_groups[(int)group]->getTutorialPopup()->SetTutorialDescription(&popupInfo);
|
|
|
|
if(group==eUIGroup_Fullscreen) setFullscreenMenuDisplayed(false);
|
|
|
|
SetMenuDisplayed((group == eUIGroup_Fullscreen ? XUSER_INDEX_ANY : iPad), m_groups[(int)group]->GetMenuDisplayed());
|
|
}
|
|
|
|
void UIController::setFullscreenMenuDisplayed(bool displayed)
|
|
{
|
|
// Show/hide the tooltips for the fullscreen group
|
|
m_groups[(int)eUIGroup_Fullscreen]->showComponent(ProfileManager.GetPrimaryPad(),eUIComponent_Tooltips,eUILayer_Tooltips,displayed);
|
|
|
|
// Show/hide tooltips for the other layers
|
|
for(unsigned int i = (eUIGroup_Fullscreen+1); i < eUIGroup_COUNT; ++i)
|
|
{
|
|
m_groups[i]->showComponent(i,eUIComponent_Tooltips,eUILayer_Tooltips,!displayed);
|
|
}
|
|
}
|
|
|
|
bool UIController::IsPauseMenuDisplayed(int iPad)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
return m_groups[(int)group]->IsPauseMenuDisplayed();
|
|
}
|
|
|
|
bool UIController::IsContainerMenuDisplayed(int iPad)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
return m_groups[(int)group]->IsContainerMenuDisplayed();
|
|
}
|
|
|
|
bool UIController::IsIgnorePlayerJoinMenuDisplayed(int iPad)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
return m_groups[(int)group]->IsIgnorePlayerJoinMenuDisplayed();
|
|
}
|
|
|
|
bool UIController::IsIgnoreAutosaveMenuDisplayed(int iPad)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
return m_groups[(int)eUIGroup_Fullscreen]->IsIgnoreAutosaveMenuDisplayed() || (group != eUIGroup_Fullscreen && m_groups[(int)group]->IsIgnoreAutosaveMenuDisplayed());
|
|
}
|
|
|
|
void UIController::SetIgnoreAutosaveMenuDisplayed(int iPad, bool displayed)
|
|
{
|
|
app.DebugPrintf(app.USER_SR, "UIController::SetIgnoreAutosaveMenuDisplayed is not implemented\n");
|
|
}
|
|
|
|
bool UIController::IsSceneInStack(int iPad, EUIScene eScene)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
return m_groups[(int)group]->IsSceneInStack(eScene);
|
|
}
|
|
|
|
bool UIController::GetMenuDisplayed(int iPad)
|
|
{
|
|
return m_bMenuDisplayed[iPad];
|
|
}
|
|
|
|
void UIController::SetMenuDisplayed(int iPad,bool bVal)
|
|
{
|
|
if(bVal)
|
|
{
|
|
if(iPad==XUSER_INDEX_ANY)
|
|
{
|
|
for(int i=0;i<XUSER_MAX_COUNT;i++)
|
|
{
|
|
InputManager.SetMenuDisplayed(i,true);
|
|
m_bMenuDisplayed[i]=true;
|
|
// 4J Stu - Fix for #11018 - Functional: When the controller is unplugged during active gameplay and plugged back in at the resulting pause menu, it will demonstrate dual-functionality.
|
|
m_bMenuToBeClosed[i]=false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
InputManager.SetMenuDisplayed(iPad,true);
|
|
m_bMenuDisplayed[iPad]=true;
|
|
// 4J Stu - Fix for #11018 - Functional: When the controller is unplugged during active gameplay and plugged back in at the resulting pause menu, it will demonstrate dual-functionality.
|
|
m_bMenuToBeClosed[iPad]=false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(iPad==XUSER_INDEX_ANY)
|
|
{
|
|
for(int i=0;i<XUSER_MAX_COUNT;i++)
|
|
{
|
|
m_bMenuToBeClosed[i]=true;
|
|
m_iCountDown[i]=10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bMenuToBeClosed[iPad]=true;
|
|
m_iCountDown[iPad]=10;
|
|
|
|
#ifdef _DURANGO
|
|
// 4J-JEV: When in-game, allow player to toggle the 'Pause' and 'IngameInfo' menus via Kinnect.
|
|
if (Minecraft::GetInstance()->running)
|
|
InputManager.SetEnabledGtcButtons(_360_GTC_MENU | _360_GTC_PAUSE | _360_GTC_VIEW);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIController::CheckMenuDisplayed()
|
|
{
|
|
for(int iPad=0;iPad<XUSER_MAX_COUNT;iPad++)
|
|
{
|
|
if(m_bMenuToBeClosed[iPad])
|
|
{
|
|
if(m_iCountDown[iPad]!=0)
|
|
{
|
|
m_iCountDown[iPad]--;
|
|
}
|
|
else
|
|
{
|
|
m_bMenuToBeClosed[iPad]=false;
|
|
m_bMenuDisplayed[iPad]=false;
|
|
InputManager.SetMenuDisplayed(iPad,false);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIController::SetTooltipText( unsigned int iPad, unsigned int tooltip, int iTextID )
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->SetTooltipText(tooltip, iTextID);
|
|
}
|
|
|
|
void UIController::SetEnableTooltips( unsigned int iPad, BOOL bVal )
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->SetEnableTooltips(bVal);
|
|
}
|
|
|
|
void UIController::ShowTooltip( unsigned int iPad, unsigned int tooltip, bool show )
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->ShowTooltip(tooltip,show);
|
|
}
|
|
|
|
void UIController::SetTooltips( unsigned int iPad, int iA, int iB, int iX, int iY, int iLT, int iRT, int iLB, int iRB, int iLS, bool forceUpdate)
|
|
{
|
|
EUIGroup group;
|
|
|
|
// 4J-PB - strip out any that are not applicable on the platform
|
|
#ifndef _XBOX
|
|
if(iX==IDS_TOOLTIPS_SELECTDEVICE) iX=-1;
|
|
if(iX==IDS_TOOLTIPS_CHANGEDEVICE) iX=-1;
|
|
|
|
#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
|
|
if(iY==IDS_TOOLTIPS_VIEW_GAMERCARD) iY=-1;
|
|
if(iY==IDS_TOOLTIPS_VIEW_GAMERPROFILE) iY=-1;
|
|
|
|
#endif
|
|
#endif
|
|
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->SetTooltips(iA, iB, iX, iY, iLT, iRT, iLB, iRB, iLS, forceUpdate);
|
|
}
|
|
|
|
void UIController::EnableTooltip( unsigned int iPad, unsigned int tooltip, bool enable )
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->EnableTooltip(tooltip,enable);
|
|
}
|
|
|
|
void UIController::RefreshTooltips(unsigned int iPad)
|
|
{
|
|
app.DebugPrintf(app.USER_SR, "UIController::RefreshTooltips is not implemented\n");
|
|
}
|
|
|
|
void UIController::AnimateKeyPress(int iPad, int iAction, bool bRepeat, bool bPressed, bool bReleased)
|
|
{
|
|
EUIGroup group;
|
|
if(bPressed==false)
|
|
{
|
|
// only animating button press
|
|
return;
|
|
}
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
bool handled = false;
|
|
if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->handleInput(iPad, iAction, bRepeat, bPressed, bReleased, handled);
|
|
}
|
|
|
|
void UIController::OverrideSFX(int iPad, int iAction,bool bVal)
|
|
{
|
|
EUIGroup group;
|
|
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
bool handled = false;
|
|
if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->overrideSFX(iPad, iAction,bVal);
|
|
}
|
|
|
|
void UIController::PlayUISFX(ESoundEffect eSound)
|
|
{
|
|
Minecraft::GetInstance()->soundEngine->playUI(eSound,1.0f,1.0f);
|
|
}
|
|
|
|
void UIController::DisplayGamertag(unsigned int iPad, bool show)
|
|
{
|
|
// The host decides whether these are on or off
|
|
if( app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_DisplaySplitscreenGamertags) == 0)
|
|
{
|
|
show = false;
|
|
}
|
|
EUIGroup group = (EUIGroup)(iPad+1);
|
|
if(m_groups[(int)group]->getHUD()) m_groups[(int)group]->getHUD()->ShowDisplayName(show);
|
|
|
|
// Update TutorialPopup in Splitscreen if no container is displayed (to make sure the Popup does not overlap with the Gamertag!)
|
|
if(app.GetLocalPlayerCount() > 1 && m_groups[(int)group]->getTutorialPopup() && !m_groups[(int)group]->IsContainerMenuDisplayed())
|
|
{
|
|
m_groups[(int)group]->getTutorialPopup()->UpdateTutorialPopup();
|
|
}
|
|
}
|
|
|
|
void UIController::SetSelectedItem(unsigned int iPad, const wstring &name)
|
|
{
|
|
EUIGroup group;
|
|
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
bool handled = false;
|
|
if(m_groups[(int)group]->getHUD()) m_groups[(int)group]->getHUD()->SetSelectedLabel(name);
|
|
}
|
|
|
|
void UIController::UpdateSelectedItemPos(unsigned int iPad)
|
|
{
|
|
app.DebugPrintf(app.USER_SR, "UIController::UpdateSelectedItemPos not implemented\n");
|
|
}
|
|
|
|
void UIController::HandleDLCMountingComplete()
|
|
{
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
app.DebugPrintf("UIController::HandleDLCMountingComplete - m_groups[%d]\n",i);
|
|
m_groups[i]->HandleDLCMountingComplete();
|
|
}
|
|
}
|
|
|
|
void UIController::HandleDLCInstalled(int iPad)
|
|
{
|
|
//app.DebugPrintf(app.USER_SR, "UIController::HandleDLCInstalled not implemented\n");
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
m_groups[i]->HandleDLCInstalled();
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef _XBOX_ONE
|
|
void UIController::HandleDLCLicenseChange()
|
|
{
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
app.DebugPrintf("UIController::HandleDLCLicenseChange - m_groups[%d]\n",i);
|
|
m_groups[i]->HandleDLCLicenseChange();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void UIController::HandleTMSDLCFileRetrieved(int iPad)
|
|
{
|
|
app.DebugPrintf(app.USER_SR, "UIController::HandleTMSDLCFileRetrieved not implemented\n");
|
|
}
|
|
|
|
void UIController::HandleTMSBanFileRetrieved(int iPad)
|
|
{
|
|
app.DebugPrintf(app.USER_SR, "UIController::HandleTMSBanFileRetrieved not implemented\n");
|
|
}
|
|
|
|
void UIController::HandleInventoryUpdated(int iPad)
|
|
{
|
|
app.DebugPrintf(app.USER_SR, "UIController::HandleInventoryUpdated not implemented\n");
|
|
}
|
|
|
|
void UIController::HandleGameTick()
|
|
{
|
|
tickInput();
|
|
|
|
for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
|
|
{
|
|
if(m_groups[i]->getHUD()) m_groups[i]->getHUD()->handleGameTick();
|
|
}
|
|
}
|
|
|
|
void UIController::SetTutorial(int iPad, Tutorial *tutorial)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
if(m_groups[(int)group]->getTutorialPopup()) m_groups[(int)group]->getTutorialPopup()->SetTutorial(tutorial);
|
|
}
|
|
|
|
void UIController::SetTutorialDescription(int iPad, TutorialPopupInfo *info)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
|
|
if(m_groups[(int)group]->getTutorialPopup())
|
|
{
|
|
// tutorial popup needs to know if a container menu is being displayed
|
|
m_groups[(int)group]->getTutorialPopup()->SetContainerMenuVisible(m_groups[(int)group]->IsContainerMenuDisplayed());
|
|
m_groups[(int)group]->getTutorialPopup()->SetTutorialDescription(info);
|
|
}
|
|
}
|
|
|
|
#ifndef _XBOX
|
|
void UIController::RemoveInteractSceneReference(int iPad, UIScene *scene)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
if(m_groups[(int)group]->getTutorialPopup()) m_groups[(int)group]->getTutorialPopup()->RemoveInteractSceneReference(scene);
|
|
}
|
|
#endif
|
|
|
|
void UIController::SetTutorialVisible(int iPad, bool visible)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
if(m_groups[(int)group]->getTutorialPopup()) m_groups[(int)group]->getTutorialPopup()->SetVisible(visible);
|
|
}
|
|
|
|
bool UIController::IsTutorialVisible(int iPad)
|
|
{
|
|
EUIGroup group;
|
|
if( app.GetGameStarted() )
|
|
{
|
|
// If the game isn't running treat as user 0, otherwise map index directly from pad
|
|
if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
|
|
else group = eUIGroup_Fullscreen;
|
|
}
|
|
else
|
|
{
|
|
group = eUIGroup_Fullscreen;
|
|
}
|
|
bool visible = false;
|
|
if(m_groups[(int)group]->getTutorialPopup()) visible = m_groups[(int)group]->getTutorialPopup()->IsVisible();
|
|
return visible;
|
|
}
|
|
|
|
void UIController::UpdatePlayerBasePositions()
|
|
{
|
|
Minecraft *pMinecraft = Minecraft::GetInstance();
|
|
|
|
for( BYTE idx = 0; idx < XUSER_MAX_COUNT; ++idx)
|
|
{
|
|
if(pMinecraft->localplayers[idx] != NULL)
|
|
{
|
|
if(pMinecraft->localplayers[idx]->m_iScreenSection==C4JRender::VIEWPORT_TYPE_FULLSCREEN)
|
|
{
|
|
DisplayGamertag(idx,false);
|
|
}
|
|
else
|
|
{
|
|
DisplayGamertag(idx,true);
|
|
}
|
|
m_groups[idx+1]->SetViewportType((C4JRender::eViewportType)pMinecraft->localplayers[idx]->m_iScreenSection);
|
|
}
|
|
else
|
|
{
|
|
// 4J Stu - This is a legacy thing from our XUI implementation that we don't need
|
|
// Changing the viewport to fullscreen for users that no longer exist is SLOW
|
|
// This should probably be on all platforms, but I don't have time to test them all just now!
|
|
#ifndef __ORBIS__
|
|
m_groups[idx+1]->SetViewportType(C4JRender::VIEWPORT_TYPE_FULLSCREEN);
|
|
#endif
|
|
DisplayGamertag(idx,false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIController::SetEmptyQuadrantLogo(int iSection)
|
|
{
|
|
// 4J Stu - We shouldn't need to implement this
|
|
}
|
|
|
|
void UIController::HideAllGameUIElements()
|
|
{
|
|
// 4J Stu - We might not need to implement this
|
|
app.DebugPrintf(app.USER_SR, "UIController::HideAllGameUIElements not implemented\n");
|
|
}
|
|
|
|
void UIController::ShowOtherPlayersBaseScene(unsigned int iPad, bool show)
|
|
{
|
|
// 4J Stu - We shouldn't need to implement this
|
|
}
|
|
|
|
void UIController::ShowTrialTimer(bool show)
|
|
{
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showTrialTimer(show);
|
|
}
|
|
|
|
void UIController::SetTrialTimerLimitSecs(unsigned int uiSeconds)
|
|
{
|
|
UIController::m_dwTrialTimerLimitSecs = uiSeconds;
|
|
}
|
|
|
|
void UIController::UpdateTrialTimer(unsigned int iPad)
|
|
{
|
|
WCHAR wcTime[20];
|
|
|
|
DWORD dwTimeTicks=(DWORD)app.getTrialTimer();
|
|
|
|
if(dwTimeTicks>m_dwTrialTimerLimitSecs)
|
|
{
|
|
dwTimeTicks=m_dwTrialTimerLimitSecs;
|
|
}
|
|
|
|
dwTimeTicks=m_dwTrialTimerLimitSecs-dwTimeTicks;
|
|
|
|
#ifndef _CONTENT_PACKAGE
|
|
if(true)
|
|
#else
|
|
// display the time - only if there's less than 3 minutes
|
|
if(dwTimeTicks<180)
|
|
#endif
|
|
{
|
|
int iMins=dwTimeTicks/60;
|
|
int iSeconds=dwTimeTicks%60;
|
|
swprintf( wcTime, 20, L"%d:%02d",iMins,iSeconds);
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->setTrialTimer(wcTime);
|
|
}
|
|
else
|
|
{
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->setTrialTimer(L"");
|
|
}
|
|
|
|
// are we out of time?
|
|
if((dwTimeTicks==0))
|
|
{
|
|
// Trial over
|
|
// bring up the pause menu to stop the trial over message box being called again?
|
|
if(!ui.GetMenuDisplayed( iPad ) )
|
|
{
|
|
ui.NavigateToScene(iPad, eUIScene_PauseMenu, NULL, eUILayer_Scene);
|
|
|
|
app.SetAction(iPad,eAppAction_TrialOver);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIController::ReduceTrialTimerValue()
|
|
{
|
|
DWORD dwTimeTicks=(int)app.getTrialTimer();
|
|
|
|
if(dwTimeTicks>m_dwTrialTimerLimitSecs)
|
|
{
|
|
dwTimeTicks=m_dwTrialTimerLimitSecs;
|
|
}
|
|
|
|
m_dwTrialTimerLimitSecs-=dwTimeTicks;
|
|
}
|
|
|
|
void UIController::ShowAutosaveCountdownTimer(bool show)
|
|
{
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showTrialTimer(show);
|
|
}
|
|
|
|
void UIController::UpdateAutosaveCountdownTimer(unsigned int uiSeconds)
|
|
{
|
|
#if !(defined(_XBOX_ONE) || defined(__ORBIS__))
|
|
WCHAR wcAutosaveCountdown[100];
|
|
swprintf( wcAutosaveCountdown, 100, app.GetString(IDS_AUTOSAVE_COUNTDOWN),uiSeconds);
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->setTrialTimer(wcAutosaveCountdown);
|
|
#endif
|
|
}
|
|
|
|
void UIController::ShowSavingMessage(unsigned int iPad, C4JStorage::ESavingMessage eVal)
|
|
{
|
|
bool show = false;
|
|
switch(eVal)
|
|
{
|
|
case C4JStorage::ESavingMessage_None:
|
|
show = false;
|
|
break;
|
|
case C4JStorage::ESavingMessage_Short:
|
|
case C4JStorage::ESavingMessage_Long:
|
|
show = true;
|
|
break;
|
|
}
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showSaveIcon(show);
|
|
}
|
|
|
|
void UIController::ShowPlayerDisplayname(bool show)
|
|
{
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showPlayerDisplayName(show);
|
|
}
|
|
|
|
void UIController::SetWinUserIndex(unsigned int iPad)
|
|
{
|
|
m_winUserIndex = iPad;
|
|
}
|
|
|
|
unsigned int UIController::GetWinUserIndex()
|
|
{
|
|
return m_winUserIndex;
|
|
}
|
|
|
|
void UIController::ShowUIDebugConsole(bool show)
|
|
{
|
|
#ifndef _CONTENT_PACKAGE
|
|
|
|
if(show)
|
|
{
|
|
m_uiDebugConsole = (UIComponent_DebugUIConsole *)m_groups[eUIGroup_Fullscreen]->addComponent(0, eUIComponent_DebugUIConsole, eUILayer_Debug);
|
|
}
|
|
else
|
|
{
|
|
m_groups[eUIGroup_Fullscreen]->removeComponent(eUIComponent_DebugUIConsole, eUILayer_Debug);
|
|
m_uiDebugConsole = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void UIController::ShowUIDebugMarketingGuide(bool show)
|
|
{
|
|
#ifndef _CONTENT_PACKAGE
|
|
|
|
if(show)
|
|
{
|
|
m_uiDebugMarketingGuide = (UIComponent_DebugUIMarketingGuide *)m_groups[eUIGroup_Fullscreen]->addComponent(0, eUIComponent_DebugUIMarketingGuide, eUILayer_Debug);
|
|
}
|
|
else
|
|
{
|
|
m_groups[eUIGroup_Fullscreen]->removeComponent(eUIComponent_DebugUIMarketingGuide, eUILayer_Debug);
|
|
m_uiDebugMarketingGuide = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void UIController::logDebugString(const string &text)
|
|
{
|
|
if(m_uiDebugConsole) m_uiDebugConsole->addText(text);
|
|
}
|
|
|
|
bool UIController::PressStartPlaying(unsigned int iPad)
|
|
{
|
|
return m_iPressStartQuadrantsMask&(1<<iPad)?true:false;
|
|
}
|
|
|
|
void UIController::ShowPressStart(unsigned int iPad)
|
|
{
|
|
m_iPressStartQuadrantsMask|=1<<iPad;
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showPressStart(iPad, true);
|
|
}
|
|
|
|
void UIController::HidePressStart()
|
|
{
|
|
ClearPressStart();
|
|
if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showPressStart(0, false);
|
|
}
|
|
|
|
void UIController::ClearPressStart()
|
|
{
|
|
m_iPressStartQuadrantsMask = 0;
|
|
}
|
|
|
|
// 4J Stu - For the different StringTable classes. Should really fix the libraries.
|
|
#ifndef __PS3__
|
|
C4JStorage::EMessageResult UIController::RequestMessageBox(UINT uiTitle, UINT uiText, UINT *uiOptionA,UINT uiOptionC, DWORD dwPad,
|
|
int( *Func)(LPVOID,int,const C4JStorage::EMessageResult),LPVOID lpParam, C4JStringTable *pStringTable, WCHAR *pwchFormatString,DWORD dwFocusButton, bool bIsError)
|
|
#else
|
|
C4JStorage::EMessageResult UIController::RequestMessageBox(UINT uiTitle, UINT uiText, UINT *uiOptionA,UINT uiOptionC, DWORD dwPad,
|
|
int( *Func)(LPVOID,int,const C4JStorage::EMessageResult),LPVOID lpParam, StringTable *pStringTable, WCHAR *pwchFormatString,DWORD dwFocusButton, bool bIsError)
|
|
#endif
|
|
{
|
|
MessageBoxInfo param;
|
|
param.uiTitle = uiTitle;
|
|
param.uiText = uiText;
|
|
param.uiOptionA = uiOptionA;
|
|
param.uiOptionC = uiOptionC;
|
|
param.dwPad = dwPad;
|
|
param.Func = Func;\
|
|
param.lpParam = lpParam;
|
|
param.pwchFormatString = pwchFormatString;
|
|
param.dwFocusButton = dwFocusButton;
|
|
|
|
EUILayer layer = bIsError?eUILayer_Error:eUILayer_Alert;
|
|
|
|
bool completed = false;
|
|
if(ui.IsReloadingSkin())
|
|
{
|
|
// Queue this message box
|
|
QueuedMessageBoxData *queuedData = new QueuedMessageBoxData();
|
|
queuedData->info = param;
|
|
queuedData->info.uiOptionA = new UINT[param.uiOptionC];
|
|
memcpy(queuedData->info.uiOptionA, param.uiOptionA, param.uiOptionC * sizeof(UINT));
|
|
queuedData->iPad = dwPad;
|
|
queuedData->layer = eUILayer_Error; // Ensures that these don't get wiped out by a CloseAllScenes call
|
|
m_queuedMessageBoxData.push_back(queuedData);
|
|
}
|
|
else
|
|
{
|
|
completed = ui.NavigateToScene(dwPad, eUIScene_MessageBox, ¶m, layer, eUIGroup_Fullscreen);
|
|
}
|
|
|
|
if( completed )
|
|
{
|
|
// This may happen if we had to queue the message box, or there was already a message box displaying and so the NavigateToScene returned false;
|
|
return C4JStorage::EMessage_Pending;
|
|
}
|
|
else
|
|
{
|
|
return C4JStorage::EMessage_Busy;
|
|
}
|
|
}
|
|
|
|
C4JStorage::EMessageResult UIController::RequestUGCMessageBox(UINT title/* = -1 */, UINT message/* = -1 */, int iPad/* = -1*/, int( *Func)(LPVOID,int,const C4JStorage::EMessageResult)/* = NULL*/, LPVOID lpParam/* = NULL*/)
|
|
{
|
|
// Default title / messages
|
|
if (title == -1)
|
|
{
|
|
title = IDS_FAILED_TO_CREATE_GAME_TITLE;
|
|
}
|
|
|
|
if (message == -1)
|
|
{
|
|
message = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE;
|
|
}
|
|
|
|
// Default pad to primary player
|
|
if (iPad == -1) iPad = ProfileManager.GetPrimaryPad();
|
|
|
|
#ifdef __ORBIS__
|
|
// Show the vague UGC system message in addition to our message
|
|
ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_UGC_RESTRICTION, iPad );
|
|
return C4JStorage::EMessage_ResultAccept;
|
|
#elif defined(__PSVITA__)
|
|
ProfileManager.ShowSystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, iPad );
|
|
UINT uiIDA[1];
|
|
uiIDA[0]=IDS_CONFIRM_OK;
|
|
return ui.RequestMessageBox( title, IDS_CHAT_RESTRICTION_UGC, uiIDA, 1, iPad, Func, lpParam, app.GetStringTable(), NULL, 0, false);
|
|
#else
|
|
UINT uiIDA[1];
|
|
uiIDA[0]=IDS_CONFIRM_OK;
|
|
return ui.RequestMessageBox( title, message, uiIDA, 1, iPad, Func, lpParam, app.GetStringTable(), NULL, 0, false);
|
|
#endif
|
|
}
|
|
|
|
C4JStorage::EMessageResult UIController::RequestContentRestrictedMessageBox(UINT title/* = -1 */, UINT message/* = -1 */, int iPad/* = -1*/, int( *Func)(LPVOID,int,const C4JStorage::EMessageResult)/* = NULL*/, LPVOID lpParam/* = NULL*/)
|
|
{
|
|
// Default title / messages
|
|
if (title == -1)
|
|
{
|
|
title = IDS_FAILED_TO_CREATE_GAME_TITLE;
|
|
}
|
|
|
|
if (message == -1)
|
|
{
|
|
#if defined(_XBOX_ONE) || defined(_WINDOWS64)
|
|
// IDS_CONTENT_RESTRICTION doesn't exist on XB1
|
|
message = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE;
|
|
#else
|
|
message = IDS_CONTENT_RESTRICTION;
|
|
#endif
|
|
}
|
|
|
|
// Default pad to primary player
|
|
if (iPad == -1) iPad = ProfileManager.GetPrimaryPad();
|
|
|
|
#ifdef __ORBIS__
|
|
// Show the vague UGC system message in addition to our message
|
|
ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_UGC_RESTRICTION, iPad );
|
|
return C4JStorage::EMessage_ResultAccept;
|
|
#elif defined(__PSVITA__)
|
|
ProfileManager.ShowSystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_AGE_RESTRICTION, iPad );
|
|
return C4JStorage::EMessage_ResultAccept;
|
|
#else
|
|
UINT uiIDA[1];
|
|
uiIDA[0]=IDS_CONFIRM_OK;
|
|
return ui.RequestMessageBox( title, message, uiIDA, 1, iPad, Func, lpParam, app.GetStringTable(), NULL, 0, false);
|
|
#endif
|
|
}
|
|
|
|
void UIController::setFontCachingCalculationBuffer(int length)
|
|
{
|
|
/* 4J-JEV: As described in an email from Sean.
|
|
If your `optional_temp_buffer` is NULL, Iggy will allocate the temp
|
|
buffer on the stack during Iggy draw calls. The size of the buffer it
|
|
will allocate is 16 bytes times `max_chars` in 32-bit, and 24 bytes
|
|
times `max_chars` in 64-bit. If the stack of the thread making the
|
|
draw call is not large enough, Iggy will crash or otherwise behave
|
|
incorrectly.
|
|
*/
|
|
#if defined __ORBIS__ || defined _DURANGO || defined _WIN64
|
|
static const int CHAR_SIZE = 24;
|
|
#else
|
|
static const int CHAR_SIZE = 16;
|
|
#endif
|
|
|
|
if (m_tempBuffer != NULL) delete [] m_tempBuffer;
|
|
if (length<0)
|
|
{
|
|
if (m_defaultBuffer == NULL) m_defaultBuffer = new char[CHAR_SIZE*5000];
|
|
IggySetFontCachingCalculationBuffer(5000, m_defaultBuffer, CHAR_SIZE*5000);
|
|
}
|
|
else
|
|
{
|
|
m_tempBuffer = new char[CHAR_SIZE*length];
|
|
IggySetFontCachingCalculationBuffer(length, m_tempBuffer, CHAR_SIZE*length);
|
|
}
|
|
}
|
|
|
|
// Returns the first scene of given type if it exists, NULL otherwise
|
|
UIScene *UIController::FindScene(EUIScene sceneType)
|
|
{
|
|
UIScene *pScene = NULL;
|
|
|
|
for (int i = 0; i < eUIGroup_COUNT; i++)
|
|
{
|
|
pScene = m_groups[i]->FindScene(sceneType);
|
|
#ifdef __PS3__
|
|
if (pScene != NULL) return pScene;
|
|
#else
|
|
if (pScene != nullptr) return pScene;
|
|
#endif
|
|
}
|
|
|
|
return pScene;
|
|
}
|
|
|
|
#ifdef __PSVITA__
|
|
|
|
void UIController::TouchBoxAdd(UIControl *pControl,UIScene *pUIScene)
|
|
{
|
|
EUIGroup eUIGroup=pUIScene->GetParentLayerGroup();
|
|
EUILayer eUILayer=pUIScene->GetParentLayer()->m_iLayer;
|
|
EUIScene eUIscene=pUIScene->getSceneType();
|
|
|
|
TouchBoxAdd(pControl,eUIGroup,eUILayer,eUIscene, pUIScene->GetMainPanel());
|
|
}
|
|
|
|
void UIController::TouchBoxAdd(UIControl *pControl,EUIGroup eUIGroup,EUILayer eUILayer,EUIScene eUIscene, UIControl *pMainPanelControl)
|
|
{
|
|
UIELEMENT *puiElement = new UIELEMENT;
|
|
puiElement->pControl = pControl;
|
|
|
|
S32 iControlWidth = pControl->getWidth();
|
|
S32 iControlHeight = pControl->getHeight();
|
|
S32 iMainPanelOffsetX = 0;
|
|
S32 iMainPanelOffsetY= 0;
|
|
|
|
// 4J-TomK add main panel offset if controls do not live in the root scene
|
|
if(pMainPanelControl)
|
|
{
|
|
iMainPanelOffsetX = pMainPanelControl->getXPos();
|
|
iMainPanelOffsetY = pMainPanelControl->getYPos();
|
|
}
|
|
|
|
// 4J-TomK override control width / height where needed
|
|
if(puiElement->pControl->getControlType() == UIControl::eSlider)
|
|
{
|
|
// Sliders are never scaled but masked, so we have to get the real width from AS
|
|
UIControl_Slider *pSlider = (UIControl_Slider *)puiElement->pControl;
|
|
iControlWidth = pSlider->GetRealWidth();
|
|
}
|
|
else if(puiElement->pControl->getControlType() == UIControl::eTexturePackList)
|
|
{
|
|
// The origin of the TexturePackList is NOT in the top left corner but where the slot area starts. therefore we need the height of the slot area itself.
|
|
UIControl_TexturePackList *pTexturePackList = (UIControl_TexturePackList *)puiElement->pControl;
|
|
iControlHeight = pTexturePackList->GetRealHeight();
|
|
}
|
|
else if(puiElement->pControl->getControlType() == UIControl::eDynamicLabel)
|
|
{
|
|
// The height and width of this control changes per how to play page
|
|
UIControl_DynamicLabel *pDynamicLabel = (UIControl_DynamicLabel *)puiElement->pControl;
|
|
iControlWidth = pDynamicLabel->GetRealWidth();
|
|
iControlHeight = pDynamicLabel->GetRealHeight();
|
|
}
|
|
else if(puiElement->pControl->getControlType() == UIControl::eHTMLLabel)
|
|
{
|
|
// The height and width of this control changes per how to play page
|
|
UIControl_HTMLLabel *pHtmlLabel = (UIControl_HTMLLabel *)puiElement->pControl;
|
|
iControlWidth = pHtmlLabel->GetRealWidth();
|
|
iControlHeight = pHtmlLabel->GetRealHeight();
|
|
}
|
|
|
|
puiElement->x1=(S32)((float)pControl->getXPos() + (float)iMainPanelOffsetX);
|
|
puiElement->y1=(S32)((float)pControl->getYPos() + (float)iMainPanelOffsetY);
|
|
puiElement->x2=(S32)(((float)pControl->getXPos() + (float)iControlWidth + (float)iMainPanelOffsetX));
|
|
puiElement->y2=(S32)(((float)pControl->getYPos() + (float)iControlHeight + (float)iMainPanelOffsetY));
|
|
|
|
if(puiElement->pControl->getControlType() == UIControl::eNoControl)
|
|
{
|
|
app.DebugPrintf("NO CONTROL!");
|
|
}
|
|
|
|
if(puiElement->x1 == puiElement->x2 || puiElement->y1 == puiElement->y2)
|
|
{
|
|
app.DebugPrintf("NOT adding touchbox %d,%d,%d,%d\n",puiElement->x1,puiElement->y1,puiElement->x2,puiElement->y2);
|
|
}
|
|
else
|
|
{
|
|
app.DebugPrintf("Adding touchbox %d,%d,%d,%d\n",puiElement->x1,puiElement->y1,puiElement->x2,puiElement->y2);
|
|
m_TouchBoxes[eUIGroup][eUILayer][eUIscene].push_back(puiElement);
|
|
}
|
|
}
|
|
|
|
void UIController::TouchBoxRebuild(UIScene *pUIScene)
|
|
{
|
|
EUIGroup eUIGroup=pUIScene->GetParentLayerGroup();
|
|
EUILayer eUILayer=pUIScene->GetParentLayer()->m_iLayer;
|
|
EUIScene eUIscene=pUIScene->getSceneType();
|
|
|
|
// if we delete an element, it's possible that the scene has re-arranged all the elements, so we need to rebuild the boxes
|
|
ui.TouchBoxesClear(pUIScene);
|
|
|
|
// rebuild boxes
|
|
AUTO_VAR(itEnd, pUIScene->GetControls()->end());
|
|
for (AUTO_VAR(it, pUIScene->GetControls()->begin()); it != itEnd; it++)
|
|
{
|
|
UIControl *control=(UIControl *)*it;
|
|
|
|
if(control->getControlType() == UIControl::eButton ||
|
|
control->getControlType() == UIControl::eSlider ||
|
|
control->getControlType() == UIControl::eCheckBox ||
|
|
control->getControlType() == UIControl::eTexturePackList ||
|
|
control->getControlType() == UIControl::eButtonList ||
|
|
control->getControlType() == UIControl::eTextInput ||
|
|
control->getControlType() == UIControl::eDynamicLabel ||
|
|
control->getControlType() == UIControl::eHTMLLabel ||
|
|
control->getControlType() == UIControl::eLeaderboardList ||
|
|
control->getControlType() == UIControl::eTouchControl)
|
|
{
|
|
// 4J-TomK update the control (it might have been moved by flash / AS)
|
|
control->UpdateControl();
|
|
|
|
ui.TouchBoxAdd(control,eUIGroup,eUILayer,eUIscene, pUIScene->GetMainPanel());
|
|
}
|
|
}
|
|
}
|
|
|
|
void UIController::TouchBoxesClear(UIScene *pUIScene)
|
|
{
|
|
EUIGroup eUIGroup=pUIScene->GetParentLayerGroup();
|
|
EUILayer eUILayer=pUIScene->GetParentLayer()->m_iLayer;
|
|
EUIScene eUIscene=pUIScene->getSceneType();
|
|
|
|
AUTO_VAR(itEnd, m_TouchBoxes[eUIGroup][eUILayer][eUIscene].end());
|
|
for (AUTO_VAR(it, m_TouchBoxes[eUIGroup][eUILayer][eUIscene].begin()); it != itEnd; it++)
|
|
{
|
|
UIELEMENT *element=(UIELEMENT *)*it;
|
|
delete element;
|
|
}
|
|
m_TouchBoxes[eUIGroup][eUILayer][eUIscene].clear();
|
|
}
|
|
|
|
bool UIController::TouchBoxHit(UIScene *pUIScene,S32 x, S32 y)
|
|
{
|
|
EUIGroup eUIGroup=pUIScene->GetParentLayerGroup();
|
|
EUILayer eUILayer=pUIScene->GetParentLayer()->m_iLayer;
|
|
EUIScene eUIscene=pUIScene->getSceneType();
|
|
|
|
// 4J-TomK let's do the transformation from touch resolution to screen resolution here, so our touchbox values always are in screen resolution!
|
|
x *= (m_fScreenWidth/1920.0f);
|
|
y *= (m_fScreenHeight/1080.0f);
|
|
|
|
if(m_TouchBoxes[eUIGroup][eUILayer][eUIscene].size()>0)
|
|
{
|
|
AUTO_VAR(itEnd, m_TouchBoxes[eUIGroup][eUILayer][eUIscene].end());
|
|
for (AUTO_VAR(it, m_TouchBoxes[eUIGroup][eUILayer][eUIscene].begin()); it != itEnd; it++)
|
|
{
|
|
UIELEMENT *element=(UIELEMENT *)*it;
|
|
if(element->pControl->getHidden() == false && element->pControl->getVisible()) // ignore removed controls
|
|
{
|
|
if((x>=element->x1) &&(x<=element->x2) && (y>=element->y1) && (y<=element->y2))
|
|
{
|
|
if(!m_bTouchscreenPressed)
|
|
{
|
|
app.DebugPrintf("SET m_ActiveUIElement (Layer: %i) at x = %i y = %i\n", (int)eUILayer, (int)x, (int)y);
|
|
m_ActiveUIElement = element;
|
|
}
|
|
// remember the currently highlighted element
|
|
m_HighlightedUIElement = element;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//app.DebugPrintf("MISS at x = %i y = %i\n", (int)x, (int)y);
|
|
m_HighlightedUIElement = NULL;
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Handle Touch Input
|
|
//
|
|
void UIController::HandleTouchInput(unsigned int iPad, unsigned int key, bool bPressed, bool bRepeat, bool bReleased)
|
|
{
|
|
// no input? no handling!
|
|
if(!bPressed && !bRepeat && !bReleased)
|
|
{
|
|
// override for instand repeat without delay!
|
|
if(m_bTouchscreenPressed && m_ActiveUIElement && (
|
|
m_ActiveUIElement->pControl->getControlType() == UIControl::eSlider ||
|
|
m_ActiveUIElement->pControl->getControlType() == UIControl::eButtonList ||
|
|
m_ActiveUIElement->pControl->getControlType() == UIControl::eTexturePackList ||
|
|
m_ActiveUIElement->pControl->getControlType() == UIControl::eDynamicLabel ||
|
|
m_ActiveUIElement->pControl->getControlType() == UIControl::eHTMLLabel ||
|
|
m_ActiveUIElement->pControl->getControlType() == UIControl::eLeaderboardList ||
|
|
m_ActiveUIElement->pControl->getControlType() == UIControl::eTouchControl))
|
|
bRepeat = true; // the above controls need to be controllable without having the finger over them
|
|
else
|
|
return;
|
|
}
|
|
|
|
SceTouchData* pTouchData = InputManager.GetTouchPadData(iPad,false);
|
|
S32 x = pTouchData->report[0].x * (m_fScreenWidth/1920.0f);
|
|
S32 y = pTouchData->report[0].y * (m_fScreenHeight/1080.0f);
|
|
|
|
if(bPressed && !bRepeat && !bReleased) // PRESSED HANDLING
|
|
{
|
|
app.DebugPrintf("touch input pressed\n");
|
|
switch(m_ActiveUIElement->pControl->getControlType())
|
|
{
|
|
case UIControl::eButton:
|
|
// set focus
|
|
UIControl_Button *pButton=(UIControl_Button *)m_ActiveUIElement->pControl;
|
|
pButton->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
|
|
// override bPressed to false. we only want the button to trigger on touch release!
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eSlider:
|
|
// set focus
|
|
UIControl_Slider *pSlider=(UIControl_Slider *)m_ActiveUIElement->pControl;
|
|
pSlider->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
|
|
break;
|
|
case UIControl::eCheckBox:
|
|
// set focus
|
|
UIControl_CheckBox *pCheckbox=(UIControl_CheckBox *)m_ActiveUIElement->pControl;
|
|
pCheckbox->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
|
|
// override bPressed. we only want the checkbox to trigger on touch release!
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eButtonList:
|
|
// set focus to list
|
|
UIControl_ButtonList *pButtonList=(UIControl_ButtonList *)m_ActiveUIElement->pControl;
|
|
//pButtonList->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
|
|
// tell list where we tapped it so it can set focus to the correct button
|
|
pButtonList->SetTouchFocus((float)x, (float)y, false);
|
|
// override bPressed. we only want the ButtonList to trigger on touch release!
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eTexturePackList:
|
|
// set focus to list
|
|
UIControl_TexturePackList *pTexturePackList=(UIControl_TexturePackList *)m_ActiveUIElement->pControl;
|
|
pTexturePackList->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
|
|
// tell list where we tapped it so it can set focus to the correct texture pack
|
|
pTexturePackList->SetTouchFocus((float)x - (float)m_ActiveUIElement->x1, (float)y - (float)m_ActiveUIElement->y1, false);
|
|
// override bPressed. we only want the TexturePack List to trigger on touch release!
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eTextInput:
|
|
// set focus
|
|
UIControl_TextInput *pTextInput=(UIControl_TextInput *)m_ActiveUIElement->pControl;
|
|
pTextInput->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
|
|
// override bPressed to false. we only want the textinput to trigger on touch release!
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eDynamicLabel:
|
|
// handle dynamic label scrolling
|
|
UIControl_DynamicLabel *pDynamicLabel=(UIControl_DynamicLabel *)m_ActiveUIElement->pControl;
|
|
pDynamicLabel->TouchScroll(y, true);
|
|
// override bPressed to false
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eHTMLLabel:
|
|
// handle dynamic label scrolling
|
|
UIControl_HTMLLabel *pHtmlLabel=(UIControl_HTMLLabel *)m_ActiveUIElement->pControl;
|
|
pHtmlLabel->TouchScroll(y, true);
|
|
// override bPressed to false
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eLeaderboardList:
|
|
// set focus to list
|
|
UIControl_LeaderboardList *pLeaderboardList=(UIControl_LeaderboardList *)m_ActiveUIElement->pControl;
|
|
// tell list where we tapped it so it can set focus to the correct button
|
|
pLeaderboardList->SetTouchFocus((float)x, (float)y, false);
|
|
// override bPressed. we only want the ButtonList to trigger on touch release!
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eTouchControl:
|
|
// pass on touch input to relevant parent scene so we can handle it there!
|
|
m_ActiveUIElement->pControl->getParentScene()->handleTouchInput(iPad, x, y, m_ActiveUIElement->pControl->getId(), bPressed, bRepeat, bReleased);
|
|
// override bPressed to false
|
|
bPressed = false;
|
|
break;
|
|
default:
|
|
app.DebugPrintf("PRESSED - UNHANDLED UI ELEMENT\n");
|
|
break;
|
|
}
|
|
}
|
|
else if(bRepeat) // REPEAT HANDLING
|
|
{
|
|
switch(m_ActiveUIElement->pControl->getControlType())
|
|
{
|
|
case UIControl::eButton:
|
|
/* no action */
|
|
break;
|
|
case UIControl::eSlider:
|
|
// handle slider movement
|
|
UIControl_Slider *pSlider=(UIControl_Slider *)m_ActiveUIElement->pControl;
|
|
float fNewSliderPos = ((float)x - (float)m_ActiveUIElement->x1) / (float)pSlider->GetRealWidth();
|
|
pSlider->SetSliderTouchPos(fNewSliderPos);
|
|
break;
|
|
case UIControl::eCheckBox:
|
|
/* no action */
|
|
bRepeat = false;
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eButtonList:
|
|
// handle button list scrolling
|
|
UIControl_ButtonList *pButtonList=(UIControl_ButtonList *)m_ActiveUIElement->pControl;
|
|
pButtonList->SetTouchFocus((float)x, (float)y, true);
|
|
break;
|
|
case UIControl::eTexturePackList:
|
|
// handle texturepack list scrolling
|
|
UIControl_TexturePackList *pTexturePackList=(UIControl_TexturePackList *)m_ActiveUIElement->pControl;
|
|
pTexturePackList->SetTouchFocus((float)x - (float)m_ActiveUIElement->x1, (float)y - (float)m_ActiveUIElement->y1, true);
|
|
break;
|
|
case UIControl::eTextInput:
|
|
/* no action */
|
|
bRepeat = false;
|
|
bPressed = false;
|
|
break;
|
|
case UIControl::eDynamicLabel:
|
|
// handle dynamic label scrolling
|
|
UIControl_DynamicLabel *pDynamicLabel=(UIControl_DynamicLabel *)m_ActiveUIElement->pControl;
|
|
pDynamicLabel->TouchScroll(y, true);
|
|
// override bPressed & bRepeat to false
|
|
bPressed = false;
|
|
bRepeat = false;
|
|
break;
|
|
case UIControl::eHTMLLabel:
|
|
// handle dynamic label scrolling
|
|
UIControl_HTMLLabel *pHtmlLabel=(UIControl_HTMLLabel *)m_ActiveUIElement->pControl;
|
|
pHtmlLabel->TouchScroll(y, true);
|
|
// override bPressed & bRepeat to false
|
|
bPressed = false;
|
|
bRepeat = false;
|
|
break;
|
|
case UIControl::eLeaderboardList:
|
|
// handle button list scrolling
|
|
UIControl_LeaderboardList *pLeaderboardList=(UIControl_LeaderboardList *)m_ActiveUIElement->pControl;
|
|
pLeaderboardList->SetTouchFocus((float)x, (float)y, true);
|
|
break;
|
|
case UIControl::eTouchControl:
|
|
// override bPressed to false
|
|
bPressed = false;
|
|
// pass on touch input to relevant parent scene so we can handle it there!
|
|
m_ActiveUIElement->pControl->getParentScene()->handleTouchInput(iPad, x, y, m_ActiveUIElement->pControl->getId(), bPressed, bRepeat, bReleased);
|
|
// override bRepeat to false
|
|
bRepeat = false;
|
|
break;
|
|
default:
|
|
app.DebugPrintf("REPEAT - UNHANDLED UI ELEMENT\n");
|
|
break;
|
|
}
|
|
}
|
|
if(bReleased) // RELEASED HANDLING
|
|
{
|
|
app.DebugPrintf("touch input released\n");
|
|
switch(m_ActiveUIElement->pControl->getControlType())
|
|
{
|
|
case UIControl::eButton:
|
|
// trigger button on release (ONLY if the finger is still on it!)
|
|
if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
|
|
bPressed = true;
|
|
break;
|
|
case UIControl::eSlider:
|
|
/* no action */
|
|
break;
|
|
case UIControl::eCheckBox:
|
|
// trigger checkbox on release (ONLY if the finger is still on it!)
|
|
if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
|
|
{
|
|
UIControl_CheckBox *pCheckbox=(UIControl_CheckBox *)m_ActiveUIElement->pControl;
|
|
pCheckbox->TouchSetCheckbox(!pCheckbox->IsChecked());
|
|
}
|
|
bReleased = false;
|
|
break;
|
|
case UIControl::eButtonList:
|
|
// trigger buttonlist on release (ONLY if the finger is still on it!)
|
|
if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
|
|
{
|
|
UIControl_ButtonList *pButtonList=(UIControl_ButtonList *)m_ActiveUIElement->pControl;
|
|
if(pButtonList->CanTouchTrigger(x,y))
|
|
bPressed = true;
|
|
}
|
|
break;
|
|
case UIControl::eTexturePackList:
|
|
// trigger texturepack list on release (ONLY if the finger is still on it!)
|
|
if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
|
|
{
|
|
UIControl_TexturePackList *pTexturePackList=(UIControl_TexturePackList *)m_ActiveUIElement->pControl;
|
|
if(pTexturePackList->CanTouchTrigger((float)x - (float)m_ActiveUIElement->x1, (float)y - (float)m_ActiveUIElement->y1))
|
|
bPressed = true;
|
|
}
|
|
break;
|
|
case UIControl::eTextInput:
|
|
// trigger TextInput on release (ONLY if the finger is still on it!)
|
|
if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
|
|
bPressed = true;
|
|
break;
|
|
case UIControl::eDynamicLabel:
|
|
// handle dynamic label scrolling
|
|
UIControl_DynamicLabel *pDynamicLabel=(UIControl_DynamicLabel *)m_ActiveUIElement->pControl;
|
|
pDynamicLabel->TouchScroll(y, false);
|
|
break;
|
|
case UIControl::eHTMLLabel:
|
|
// handle dynamic label scrolling
|
|
UIControl_HTMLLabel *pHtmlLabel=(UIControl_HTMLLabel *)m_ActiveUIElement->pControl;
|
|
pHtmlLabel->TouchScroll(y, false);
|
|
break;
|
|
case UIControl::eLeaderboardList:
|
|
/* no action */
|
|
break;
|
|
case UIControl::eTouchControl:
|
|
// trigger only if touch is released over the same component!
|
|
if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
|
|
{
|
|
// pass on touch input to relevant parent scene so we can handle it there!
|
|
m_ActiveUIElement->pControl->getParentScene()->handleTouchInput(iPad, x, y, m_ActiveUIElement->pControl->getId(), bPressed, bRepeat, bReleased);
|
|
}
|
|
// override bReleased to false
|
|
bReleased = false;
|
|
break;
|
|
default:
|
|
app.DebugPrintf("RELEASED - UNHANDLED UI ELEMENT\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
// only proceed if there's input to be handled
|
|
if(bPressed || bRepeat || bReleased)
|
|
{
|
|
SendTouchInput(iPad, key, bPressed, bRepeat, bReleased);
|
|
}
|
|
}
|
|
|
|
void UIController::SendTouchInput(unsigned int iPad, unsigned int key, bool bPressed, bool bRepeat, bool bReleased)
|
|
{
|
|
bool handled = false;
|
|
|
|
// Send the key to the fullscreen group first
|
|
m_groups[(int)eUIGroup_Fullscreen]->handleInput(iPad, key, bRepeat, bPressed, bReleased, handled);
|
|
if(!handled)
|
|
{
|
|
// If it's not been handled yet, then pass the event onto the players specific group
|
|
m_groups[(iPad+1)]->handleInput(iPad, key, bRepeat, bPressed, bReleased, handled);
|
|
}
|
|
}
|
|
|
|
|
|
#endif |