the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "UIController.h"
3#include "UI.h"
4#include "UIScene.h"
5#include "..\..\..\Minecraft.World\StringHelpers.h"
6#include "..\..\LocalPlayer.h"
7#include "..\..\DLCTexturePack.h"
8#include "..\..\TexturePackRepository.h"
9#include "..\..\Minecraft.h"
10#include "..\..\..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h"
11#include "..\..\EnderDragonRenderer.h"
12#include "..\..\MultiPlayerLocalPlayer.h"
13#include "UIFontData.h"
14#ifdef __PSVITA__
15#include <message_dialog.h>
16#endif
17
18// 4J Stu - Enable this to override the Iggy Allocator
19//#define ENABLE_IGGY_ALLOCATOR
20//#define EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR
21
22//#define ENABLE_IGGY_EXPLORER
23#ifdef ENABLE_IGGY_EXPLORER
24#include "Windows64\Iggy\include\iggyexpruntime.h"
25#endif
26
27//#define ENABLE_IGGY_PERFMON
28#ifdef ENABLE_IGGY_PERFMON
29
30#define PM_ORIGIN_X 24
31#define PM_ORIGIN_Y 34
32
33#ifdef __ORBIS__
34#include "Orbis\Iggy\include\iggyperfmon.h"
35#include "Orbis\Iggy\include\iggyperfmon_orbis.h"
36#elif defined _DURANGO
37#include "Durango\Iggy\include\iggyperfmon.h"
38#elif defined __PS3__
39#include "PS3\Iggy\include\iggyperfmon.h"
40#include "PS3\Iggy\include\iggyperfmon_ps3.h"
41#elif defined __PSVITA__
42#include "PSVita\Iggy\include\iggyperfmon.h"
43#include "PSVita\Iggy\include\iggyperfmon_psp2.h"
44#elif defined __WINDOWS64
45#include "Windows64\Iggy\include\iggyperfmon.h"
46#endif
47
48#endif
49
50CRITICAL_SECTION UIController::ms_reloadSkinCS;
51bool UIController::ms_bReloadSkinCSInitialised = false;
52
53DWORD UIController::m_dwTrialTimerLimitSecs=DYNAMIC_CONFIG_DEFAULT_TRIAL_TIME;
54
55static void RADLINK WarningCallback(void *user_callback_data, Iggy *player, IggyResult code, const char *message)
56{
57 //enum IggyResult{ IGGY_RESULT_SUCCESS = 0, IGGY_RESULT_Warning_None = 0,
58 // IGGY_RESULT_Warning_Misc = 100, IGGY_RESULT_Warning_GDraw = 101,
59 // IGGY_RESULT_Warning_ProgramFlow = 102,
60 // IGGY_RESULT_Warning_Actionscript = 103,
61 // IGGY_RESULT_Warning_Graphics = 104, IGGY_RESULT_Warning_Font = 105,
62 // IGGY_RESULT_Warning_Timeline = 106, IGGY_RESULT_Warning_Library = 107,
63 // IGGY_RESULT_Warning_CannotSustainFrameRate = 201,
64 // IGGY_RESULT_Warning_ThrewException = 202,
65 // IGGY_RESULT_Error_Threshhold = 400, IGGY_RESULT_Error_Misc = 400,
66 // IGGY_RESULT_Error_GDraw = 401, IGGY_RESULT_Error_ProgramFlow = 402,
67 // IGGY_RESULT_Error_Actionscript = 403, IGGY_RESULT_Error_Graphics = 404,
68 // IGGY_RESULT_Error_Font = 405, IGGY_RESULT_Error_Create = 406,
69 // IGGY_RESULT_Error_Library = 407, IGGY_RESULT_Error_ValuePath = 408,
70 // IGGY_RESULT_Error_Audio = 409, IGGY_RESULT_Error_Internal = 499,
71 // IGGY_RESULT_Error_InvalidIggy = 501,
72 // IGGY_RESULT_Error_InvalidArgument = 502,
73 // IGGY_RESULT_Error_InvalidEntity = 503,
74 // IGGY_RESULT_Error_UndefinedEntity = 504,
75 // IGGY_RESULT_Error_OutOfMemory = 1001,};
76
77 switch(code)
78 {
79 case IGGY_RESULT_Warning_CannotSustainFrameRate:
80 // Ignore warning
81 break;
82 default:
83 /* Normally, we'd want to issue this warning to some kind of
84 logging system or error reporting system, but since this is a
85 tutorial app, we just use Win32's default error stream. Since
86 ActionScript 3 exceptions are routed through this warning
87 callback, it's definitely a good idea to make sure these
88 warnings get printed somewhere that's easy for you to read and
89 use for debugging, otherwise debugging errors in the
90 ActionScript 3 code in your Flash content will be very
91 difficult! */
92 app.DebugPrintf(app.USER_SR, message);
93 app.DebugPrintf(app.USER_SR, "\n");
94 break;
95 };
96}
97
98
99/* Flash provides a way for ActionScript 3 code to print debug output
100using a function called "trace". It's very useful for debugging
101Flash programs, so ideally, when using Iggy, we'd like to see any
102trace output alongside our own debugging output. To facilitate
103this, Iggy allows us to install a callback that will be called
104any time ActionScript code calls trace. */
105static void RADLINK TraceCallback(void *user_callback_data, Iggy *player, char const *utf8_string, S32 length_in_bytes)
106{
107 app.DebugPrintf(app.USER_UI, (char *)utf8_string);
108}
109
110#ifdef ENABLE_IGGY_PERFMON
111static void *RADLINK perf_malloc(void *handle, U32 size)
112{
113 return malloc(size);
114}
115
116static void RADLINK perf_free(void *handle, void *ptr)
117{
118 return free(ptr);
119}
120#endif
121
122#ifdef EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR
123extern "C" void *__real_malloc(size_t t);
124extern "C" void __real_free(void *t);
125#endif
126
127__int64 UIController::iggyAllocCount = 0;
128static unordered_map<void *,size_t> allocations;
129static void * RADLINK AllocateFunction ( void * alloc_callback_user_data , size_t size_requested , size_t * size_returned )
130{
131 UIController *controller = (UIController *)alloc_callback_user_data;
132 EnterCriticalSection(&controller->m_Allocatorlock);
133#ifdef EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR
134 void *alloc = __real_malloc(size_requested);
135#else
136 void *alloc = malloc(size_requested);
137#endif
138 *size_returned = size_requested;
139 UIController::iggyAllocCount += size_requested;
140 allocations[alloc] = size_requested;
141 app.DebugPrintf(app.USER_SR, "Allocating %d, new total: %d\n", size_requested, UIController::iggyAllocCount);
142 LeaveCriticalSection(&controller->m_Allocatorlock);
143 return alloc;
144}
145
146static void RADLINK DeallocateFunction ( void * alloc_callback_user_data , void * ptr )
147{
148 UIController *controller = (UIController *)alloc_callback_user_data;
149 EnterCriticalSection(&controller->m_Allocatorlock);
150 size_t size = allocations[ptr];
151 UIController::iggyAllocCount -= size;
152 allocations.erase(ptr);
153 app.DebugPrintf(app.USER_SR, "Freeing %d, new total %d\n", size, UIController::iggyAllocCount);
154#ifdef EXCLUDE_IGGY_ALLOCATIONS_FROM_HEAP_INSPECTOR
155 __real_free(ptr);
156#else
157 free(ptr);
158#endif
159 LeaveCriticalSection(&controller->m_Allocatorlock);
160}
161
162UIController::UIController()
163{
164 m_uiDebugConsole = NULL;
165 m_reloadSkinThread = NULL;
166
167 m_navigateToHomeOnReload = false;
168
169 m_bCleanupOnReload = false;
170 m_mcTTFFont = NULL;
171 m_moj7 = NULL;
172 m_moj11 = NULL;
173
174 // 4J-JEV: It's important that these remain the same, unless updateCurrentLanguage is going to be called.
175 m_eCurrentFont = m_eTargetFont = eFont_NotLoaded;
176
177#ifdef ENABLE_IGGY_ALLOCATOR
178 InitializeCriticalSection(&m_Allocatorlock);
179#endif
180
181 // 4J Stu - This is a bit of a hack until we change the Minecraft initialisation to store the proper screen size for other platforms
182#if defined _WINDOWS64 || defined _DURANGO || defined __ORBIS__
183 m_fScreenWidth = 1920.0f;
184 m_fScreenHeight = 1080.0f;
185 m_bScreenWidthSetup = false;
186#else
187 m_fScreenWidth = 1280.0f;
188 m_fScreenHeight = 720.0f;
189 m_bScreenWidthSetup = false;
190#endif
191
192 for(unsigned int i = 0; i < eLibrary_Count; ++i)
193 {
194 m_iggyLibraries[i] = IGGY_INVALID_LIBRARY;
195 }
196
197 for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
198 {
199 m_bMenuDisplayed[i] = false;
200 m_iCountDown[i]=0;
201 m_bMenuToBeClosed[i]=false;
202
203 for(unsigned int key = 0; key <= ACTION_MAX_MENU; ++key)
204 {
205 m_actionRepeatTimer[i][key] = 0;
206 }
207 }
208
209 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
210 {
211 m_bCloseAllScenes[i] = false;
212 }
213
214 m_iPressStartQuadrantsMask = 0;
215
216 m_currentRenderViewport = C4JRender::VIEWPORT_TYPE_FULLSCREEN;
217 m_bCustomRenderPosition = false;
218 m_winUserIndex = 0;
219 m_accumulatedTicks = 0;
220 m_lastUiSfx = 0;
221
222 InitializeCriticalSection(&m_navigationLock);
223 InitializeCriticalSection(&m_registeredCallbackScenesCS);
224 //m_bSysUIShowing=false;
225 m_bSystemUIShowing=false;
226#ifdef __PSVITA__
227 m_bTouchscreenPressed=false;
228#endif
229
230 if(!ms_bReloadSkinCSInitialised)
231 {
232 // MGH - added to prevent crash loading Iggy movies while the skins were being reloaded
233 InitializeCriticalSection(&ms_reloadSkinCS);
234 ms_bReloadSkinCSInitialised = true;
235 }
236}
237
238void UIController::SetSysUIShowing(bool bVal)
239{
240 if(bVal) app.DebugPrintf("System UI showing\n");
241 else app.DebugPrintf("System UI stopped showing\n");
242 m_bSystemUIShowing=bVal;
243}
244
245void UIController::SetSystemUIShowing(LPVOID lpParam,bool bVal)
246{
247 UIController *pClass=(UIController *)lpParam;
248 pClass->SetSysUIShowing(bVal);
249}
250
251// SETUP
252void UIController::preInit(S32 width, S32 height)
253{
254 m_fScreenWidth = width;
255 m_fScreenHeight = height;
256 m_bScreenWidthSetup = true;
257
258#ifdef ENABLE_IGGY_ALLOCATOR
259 IggyAllocator allocator;
260 allocator.user_callback_data = this;
261 allocator.mem_alloc = &AllocateFunction;
262 allocator.mem_free = &DeallocateFunction;
263 IggyInit(&allocator);
264#else
265 IggyInit(0);
266#endif
267
268 IggySetWarningCallback(WarningCallback, 0);
269 IggySetTraceCallbackUTF8(TraceCallback, 0);
270
271 setFontCachingCalculationBuffer(-1);
272}
273
274void UIController::postInit()
275{
276 // set up a custom rendering callback
277 IggySetCustomDrawCallback(&UIController::CustomDrawCallback, this);
278 IggySetAS3ExternalFunctionCallbackUTF16 ( &UIController::ExternalFunctionCallback, this );
279 IggySetTextureSubstitutionCallbacks ( &UIController::TextureSubstitutionCreateCallback , &UIController::TextureSubstitutionDestroyCallback, this );
280
281 SetupFont();
282 //
283 loadSkins();
284
285 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
286 {
287 m_groups[i] = new UIGroup((EUIGroup)i,i-1);
288 }
289
290
291#ifdef ENABLE_IGGY_EXPLORER
292 iggy_explorer = IggyExpCreate("127.0.0.1", 9190, malloc(IGGYEXP_MIN_STORAGE), IGGYEXP_MIN_STORAGE);
293 if ( iggy_explorer == NULL )
294 {
295 // not normally an error, just an error for this demo!
296 app.DebugPrintf( "Couldn't connect to Iggy Explorer, did you run it first?" );
297 }
298 else
299 {
300 IggyUseExplorer( m_groups[1]->getHUD()->getMovie(), iggy_explorer);
301 }
302#endif
303
304#ifdef ENABLE_IGGY_PERFMON
305 m_iggyPerfmonEnabled = false;
306 iggy_perfmon = IggyPerfmonCreate(perf_malloc, perf_free, NULL);
307 IggyInstallPerfmon(iggy_perfmon);
308#endif
309
310 NavigateToScene(0, eUIScene_Intro);
311}
312
313
314UIController::EFont UIController::getFontForLanguage(int language)
315 {
316 switch(language)
317 {
318 case XC_LANGUAGE_JAPANESE: return eFont_Japanese;
319#ifdef _DURANGO
320 case XC_LANGUAGE_SCHINESE: return eFont_SimpChinese;
321#endif
322 case XC_LANGUAGE_TCHINESE: return eFont_TradChinese;
323 case XC_LANGUAGE_KOREAN: return eFont_Korean;
324 default: return eFont_Bitmap;
325 }
326}
327
328UITTFFont *UIController::createFont(EFont fontLanguage)
329 {
330 switch(fontLanguage)
331 {
332#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
333 case eFont_Japanese: return new UITTFFont("Mojangles_TTF_jaJP", "Common/Media/font/JPN/DF-DotDotGothic16.ttf", 0x203B); // JPN
334 // case eFont_SimpChinese: Simplified Chinese is unsupported.
335 case eFont_TradChinese: return new UITTFFont("Mojangles_TTF_cnTD", "Common/Media/font/CHT/DFTT_R5.TTC", 0x203B); // CHT
336 case eFont_Korean: return new UITTFFont("Mojangles_TTF_koKR", "Common/Media/font/KOR/candadite2.ttf", 0x203B); // KOR
337#else
338 case eFont_Japanese: return new UITTFFont("Mojangles_TTF_jaJP", "Common/Media/font/JPN/DFGMaruGothic-Md.ttf", 0x2022); // JPN
339#ifdef _DURANGO
340 case eFont_SimpChinese: return new UITTFFont("Mojangled_TTF_cnCN", "Common/Media/font/CHS/MSYH.ttf", 0x2022); // CHS
341#endif
342 case eFont_TradChinese: return new UITTFFont("Mojangles_TTF_cnTD", "Common/Media/font/CHT/DFHeiMedium-B5.ttf", 0x2022); // CHT
343 case eFont_Korean: return new UITTFFont("Mojangles_TTF_koKR", "Common/Media/font/KOR/BOKMSD.ttf", 0x2022); // KOR
344#endif
345 // 4J-JEV, Cyrillic characters have been added to this font now, (4/July/14)
346 // XC_LANGUAGE_RUSSIAN and XC_LANGUAGE_GREEK:
347 default: return NULL;
348 }
349}
350
351void UIController::SetupFont()
352{
353 // 4J-JEV: Language hasn't changed or is already changing.
354 if ( (m_eCurrentFont != m_eTargetFont) || !UIString::setCurrentLanguage() ) return;
355
356 DWORD nextLanguage = UIString::getCurrentLanguage();
357 m_eTargetFont = getFontForLanguage(nextLanguage);
358
359 // flag a language change to reload the string tables in the DLC
360 app.m_dlcManager.LanguageChanged();
361
362 app.loadStringTable(); // Switch to use new string table,
363
364 if (m_eTargetFont == m_eCurrentFont)
365 {
366 // 4J-JEV: If we're ingame, reload the font to update all the text.
367 if (app.GetGameStarted()) app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_ReloadFont);
368 return;
369 }
370
371 if (m_eCurrentFont != eFont_NotLoaded) app.DebugPrintf("[UIController] Font switch required for language transition to %i.\n", nextLanguage);
372 else app.DebugPrintf("[UIController] Initialising font for language %i.\n", nextLanguage);
373
374 if (m_mcTTFFont != NULL)
375 {
376 delete m_mcTTFFont;
377 m_mcTTFFont = NULL;
378 }
379
380 if(m_eTargetFont == eFont_Bitmap)
381 {
382 // these may have been set up by a previous language being chosen
383 if (m_moj7 == NULL) m_moj7 = new UIBitmapFont(SFontData::Mojangles_7);
384 if (m_moj11 == NULL) m_moj11 = new UIBitmapFont(SFontData::Mojangles_11);
385
386 // 4J-JEV: Ensure we redirect to them correctly, even if the objects were previously initialised.
387 m_moj7->registerFont();
388 m_moj11->registerFont();
389 }
390 else if (m_eTargetFont != eFont_NotLoaded)
391 {
392 m_mcTTFFont = createFont(m_eTargetFont);
393
394 app.DebugPrintf("[Iggy] Set font indirect to '%hs'.\n", m_mcTTFFont->getFontName().c_str());
395 IggyFontSetIndirectUTF8( "Mojangles7", -1, IGGY_FONTFLAG_all, m_mcTTFFont->getFontName().c_str(), -1, IGGY_FONTFLAG_none );
396 IggyFontSetIndirectUTF8( "Mojangles11", -1, IGGY_FONTFLAG_all, m_mcTTFFont->getFontName().c_str(), -1, IGGY_FONTFLAG_none );
397 }
398 else
399 {
400 assert(false);
401 }
402
403 // Reload ui to set new font.
404 if (m_eCurrentFont != eFont_NotLoaded)
405 {
406 app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_ReloadFont);
407 }
408 else
409 {
410 updateCurrentFont();
411 }
412}
413
414bool UIController::PendingFontChange()
415{
416 return getFontForLanguage( XGetLanguage() ) != m_eCurrentFont;
417}
418
419void UIController::setCleanupOnReload()
420{
421 m_bCleanupOnReload = true;
422}
423
424void UIController::updateCurrentFont()
425{
426 m_eCurrentFont = m_eTargetFont;
427}
428
429bool UIController::UsingBitmapFont()
430{
431 return m_eCurrentFont == eFont_Bitmap;
432}
433
434// TICKING
435void UIController::tick()
436{
437 SetupFont(); // If necessary, change font.
438
439 if ( (m_navigateToHomeOnReload || m_bCleanupOnReload) && !ui.IsReloadingSkin() )
440 {
441 ui.CleanUpSkinReload();
442
443 if (m_navigateToHomeOnReload || !g_NetworkManager.IsInSession())
444 {
445 ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MainMenu);
446 }
447 else
448 {
449 ui.CloseAllPlayersScenes();
450 }
451
452 updateCurrentFont();
453
454 m_navigateToHomeOnReload = false;
455 m_bCleanupOnReload = false;
456 }
457
458 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
459 {
460 if(m_bCloseAllScenes[i])
461 {
462 m_groups[i]->closeAllScenes();
463 m_groups[i]->getTooltips()->SetTooltips(-1);
464 m_bCloseAllScenes[i] = false;
465 }
466 }
467
468 if(m_accumulatedTicks == 0) tickInput();
469 m_accumulatedTicks = 0;
470
471 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
472 {
473 m_groups[i]->tick();
474
475 // TODO: May wish to skip ticking other groups here
476 }
477
478 // Clear out the cached movie file data
479 __int64 currentTime = System::currentTimeMillis();
480 for(AUTO_VAR(it, m_cachedMovieData.begin()); it != m_cachedMovieData.end();)
481 {
482 if(it->second.m_expiry < currentTime)
483 {
484 delete [] it->second.m_ba.data;
485 it = m_cachedMovieData.erase(it);
486 }
487 else
488 {
489 ++it;
490 }
491 }
492}
493
494void UIController::loadSkins()
495{
496 wstring platformSkinPath = L"";
497
498#ifdef __PS3__
499 platformSkinPath = L"skinPS3.swf";
500#elif defined __PSVITA__
501 platformSkinPath = L"skinVita.swf";
502#elif defined _WINDOWS64
503 if(m_fScreenHeight>720.0f)
504 {
505 platformSkinPath = L"skinHDWin.swf";
506 }
507 else
508 {
509 platformSkinPath = L"skinWin.swf";
510 }
511#elif defined _DURANGO
512 if(m_fScreenHeight>720.0f)
513 {
514 platformSkinPath = L"skinHDDurango.swf";
515 }
516 else
517 {
518 platformSkinPath = L"skinDurango.swf";
519 }
520#elif defined __ORBIS__
521 if(m_fScreenHeight>720.0f)
522 {
523 platformSkinPath = L"skinHDOrbis.swf";
524 }
525 else
526 {
527 platformSkinPath = L"skinOrbis.swf";
528 }
529
530#endif
531 // Every platform has one of these, so nothing shared
532 if(m_fScreenHeight>720.0f)
533 {
534 m_iggyLibraries[eLibrary_Platform] = loadSkin(platformSkinPath, L"platformskinHD.swf");
535 }
536 else
537 {
538 m_iggyLibraries[eLibrary_Platform] = loadSkin(platformSkinPath, L"platformskin.swf");
539 }
540
541#if defined(__PS3__) || defined(__PSVITA__)
542 m_iggyLibraries[eLibrary_GraphicsDefault] = loadSkin(L"skinGraphics.swf", L"skinGraphics.swf");
543 m_iggyLibraries[eLibrary_GraphicsHUD] = loadSkin(L"skinGraphicsHud.swf", L"skinGraphicsHud.swf");
544 m_iggyLibraries[eLibrary_GraphicsInGame] = loadSkin(L"skinGraphicsInGame.swf", L"skinGraphicsInGame.swf");
545 m_iggyLibraries[eLibrary_GraphicsTooltips] = loadSkin(L"skinGraphicsTooltips.swf", L"skinGraphicsTooltips.swf");
546 m_iggyLibraries[eLibrary_GraphicsLabels] = loadSkin(L"skinGraphicsLabels.swf", L"skinGraphicsLabels.swf");
547 m_iggyLibraries[eLibrary_Labels] = loadSkin(L"skinLabels.swf", L"skinLabels.swf");
548 m_iggyLibraries[eLibrary_InGame] = loadSkin(L"skinInGame.swf", L"skinInGame.swf");
549 m_iggyLibraries[eLibrary_HUD] = loadSkin(L"skinHud.swf", L"skinHud.swf");
550 m_iggyLibraries[eLibrary_Tooltips] = loadSkin(L"skinTooltips.swf", L"skinTooltips.swf");
551 m_iggyLibraries[eLibrary_Default] = loadSkin(L"skin.swf", L"skin.swf");
552#endif
553
554#if ( defined(_WINDOWS64) || defined(_DURANGO) || defined(__ORBIS__) )
555
556#if defined(_WINDOWS64)
557 // 4J Stu - Load the 720/480 skins so that we have something to fallback on during development
558#ifndef _FINAL_BUILD
559 m_iggyLibraries[eLibraryFallback_GraphicsDefault] = loadSkin(L"skinGraphics.swf", L"skinGraphics.swf");
560 m_iggyLibraries[eLibraryFallback_GraphicsHUD] = loadSkin(L"skinGraphicsHud.swf", L"skinGraphicsHud.swf");
561 m_iggyLibraries[eLibraryFallback_GraphicsInGame] = loadSkin(L"skinGraphicsInGame.swf", L"skinGraphicsInGame.swf");
562 m_iggyLibraries[eLibraryFallback_GraphicsTooltips] = loadSkin(L"skinGraphicsTooltips.swf", L"skinGraphicsTooltips.swf");
563 m_iggyLibraries[eLibraryFallback_GraphicsLabels] = loadSkin(L"skinGraphicsLabels.swf", L"skinGraphicsLabels.swf");
564 m_iggyLibraries[eLibraryFallback_Labels] = loadSkin(L"skinLabels.swf", L"skinLabels.swf");
565 m_iggyLibraries[eLibraryFallback_InGame] = loadSkin(L"skinInGame.swf", L"skinInGame.swf");
566 m_iggyLibraries[eLibraryFallback_HUD] = loadSkin(L"skinHud.swf", L"skinHud.swf");
567 m_iggyLibraries[eLibraryFallback_Tooltips] = loadSkin(L"skinTooltips.swf", L"skinTooltips.swf");
568 m_iggyLibraries[eLibraryFallback_Default] = loadSkin(L"skin.swf", L"skin.swf");
569#endif
570#endif
571
572 m_iggyLibraries[eLibrary_GraphicsDefault] = loadSkin(L"skinHDGraphics.swf", L"skinHDGraphics.swf");
573 m_iggyLibraries[eLibrary_GraphicsHUD] = loadSkin(L"skinHDGraphicsHud.swf", L"skinHDGraphicsHud.swf");
574 m_iggyLibraries[eLibrary_GraphicsInGame] = loadSkin(L"skinHDGraphicsInGame.swf", L"skinHDGraphicsInGame.swf");
575 m_iggyLibraries[eLibrary_GraphicsTooltips] = loadSkin(L"skinHDGraphicsTooltips.swf", L"skinHDGraphicsTooltips.swf");
576 m_iggyLibraries[eLibrary_GraphicsLabels] = loadSkin(L"skinHDGraphicsLabels.swf", L"skinHDGraphicsLabels.swf");
577 m_iggyLibraries[eLibrary_Labels] = loadSkin(L"skinHDLabels.swf", L"skinHDLabels.swf");
578 m_iggyLibraries[eLibrary_InGame] = loadSkin(L"skinHDInGame.swf", L"skinHDInGame.swf");
579 m_iggyLibraries[eLibrary_HUD] = loadSkin(L"skinHDHud.swf", L"skinHDHud.swf");
580 m_iggyLibraries[eLibrary_Tooltips] = loadSkin(L"skinHDTooltips.swf", L"skinHDTooltips.swf");
581 m_iggyLibraries[eLibrary_Default] = loadSkin(L"skinHD.swf", L"skinHD.swf");
582#endif // HD platforms
583}
584
585IggyLibrary UIController::loadSkin(const wstring &skinPath, const wstring &skinName)
586{
587 IggyLibrary lib = IGGY_INVALID_LIBRARY;
588 // 4J Stu - We need to load the platformskin before the normal skin, as the normal skin requires some elements from the platform skin
589 if(!skinPath.empty() && app.hasArchiveFile(skinPath))
590 {
591 byteArray baFile = app.getArchiveFile(skinPath);
592 lib = IggyLibraryCreateFromMemoryUTF16( (IggyUTF16 *)skinName.c_str() , (void *)baFile.data, baFile.length, NULL );
593
594 delete[] baFile.data;
595#ifdef _DEBUG
596 IggyMemoryUseInfo memoryInfo;
597 rrbool res;
598 int iteration = 0;
599 __int64 totalStatic = 0;
600 while(res = IggyDebugGetMemoryUseInfo ( NULL ,
601 lib ,
602 "" ,
603 0 ,
604 iteration ,
605 &memoryInfo ))
606 {
607 totalStatic += memoryInfo.static_allocation_bytes;
608 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);
609 ++iteration;
610 }
611
612 app.DebugPrintf(app.USER_SR, "%ls - Total static: %dB (%dKB)\n", skinPath.c_str(), totalStatic, totalStatic/1024);
613#endif
614 }
615 return lib;
616}
617
618void UIController::ReloadSkin()
619{
620 // Destroy all scene swf
621 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
622 {
623 //m_bCloseAllScenes[i] = true;
624 m_groups[i]->DestroyAll();
625 }
626
627 // Unload the current libraries
628 // Some libraries reference others, so we destroy in reverse order
629 for(int i = eLibrary_Count - 1; i >= 0; --i)
630 {
631 if(m_iggyLibraries[i] != IGGY_INVALID_LIBRARY) IggyLibraryDestroy(m_iggyLibraries[i]);
632 m_iggyLibraries[i] = IGGY_INVALID_LIBRARY;
633 }
634
635#ifdef _WINDOWS64
636 // 4J Stu - Don't load on a thread on windows. I haven't investigated this in detail, so a quick fix
637 reloadSkinThreadProc(this);
638#else
639
640 m_reloadSkinThread = new C4JThread(reloadSkinThreadProc, (void*)this, "Reload skin thread");
641 m_reloadSkinThread->SetProcessor(CPU_CORE_UI_SCENE);
642
643 // Navigate to the timer scene so that we can display something while the loading is happening
644 ui.NavigateToScene(0,eUIScene_Timer,(void *)1,eUILayer_Tooltips,eUIGroup_Fullscreen);
645 //m_reloadSkinThread->Run();
646
647 //// Load new skin
648 //loadSkins();
649
650 //// Reload all scene swf
651 //for(int i = eUIGroup_Player1; i <= eUIGroup_Player4; ++i)
652 //{
653 // m_groups[i]->ReloadAll();
654 //}
655
656 //// Always reload the fullscreen group
657 //m_groups[eUIGroup_Fullscreen]->ReloadAll();
658#endif
659}
660
661void UIController::StartReloadSkinThread()
662{
663 if(m_reloadSkinThread) m_reloadSkinThread->Run();
664}
665
666int UIController::reloadSkinThreadProc(void* lpParam)
667{
668 EnterCriticalSection(&ms_reloadSkinCS); // MGH - added to prevent crash loading Iggy movies while the skins were being reloaded
669 UIController *controller = (UIController *)lpParam;
670 // Load new skin
671 controller->loadSkins();
672
673 // Reload all scene swf
674 for(int i = eUIGroup_Player1; i < eUIGroup_COUNT; ++i)
675 {
676 controller->m_groups[i]->ReloadAll();
677 }
678
679 // Always reload the fullscreen group
680 controller->m_groups[eUIGroup_Fullscreen]->ReloadAll();
681
682 // 4J Stu - Don't do this on windows, as we never navigated forwards to start with
683#ifndef _WINDOW64
684 controller->NavigateBack(0, false, eUIScene_COUNT, eUILayer_Tooltips);
685#endif
686 LeaveCriticalSection(&ms_reloadSkinCS);
687
688 return 0;
689}
690
691bool UIController::IsReloadingSkin()
692{
693 return m_reloadSkinThread && (!m_reloadSkinThread->hasStarted() || m_reloadSkinThread->isRunning());
694}
695
696bool UIController::IsExpectingOrReloadingSkin()
697{
698 return Minecraft::GetInstance()->skins->getSelected()->isLoadingData() || Minecraft::GetInstance()->skins->needsUIUpdate() || IsReloadingSkin() || PendingFontChange();
699}
700
701void UIController::CleanUpSkinReload()
702{
703 delete m_reloadSkinThread;
704 m_reloadSkinThread = NULL;
705
706 if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin())
707 {
708 if(!Minecraft::GetInstance()->skins->getSelected()->hasAudio())
709 {
710#ifdef _DURANGO
711 DWORD result = StorageManager.UnmountInstalledDLC(L"TPACK");
712#else
713 DWORD result = StorageManager.UnmountInstalledDLC("TPACK");
714#endif
715 }
716 }
717
718 for(AUTO_VAR(it,m_queuedMessageBoxData.begin()); it != m_queuedMessageBoxData.end(); ++it)
719 {
720 QueuedMessageBoxData *queuedData = *it;
721 ui.NavigateToScene(queuedData->iPad, eUIScene_MessageBox, &queuedData->info, queuedData->layer, eUIGroup_Fullscreen);
722 delete queuedData->info.uiOptionA;
723 delete queuedData;
724 }
725 m_queuedMessageBoxData.clear();
726}
727
728byteArray UIController::getMovieData(const wstring &filename)
729{
730 // Cache everything we load in the current tick
731 __int64 targetTime = System::currentTimeMillis() + (1000LL * 60);
732 AUTO_VAR(it,m_cachedMovieData.find(filename));
733 if(it == m_cachedMovieData.end() )
734 {
735 byteArray baFile = app.getArchiveFile(filename);
736 CachedMovieData cmd;
737 cmd.m_ba = baFile;
738 cmd.m_expiry = targetTime;
739 m_cachedMovieData[filename] = cmd;
740 return baFile;
741 }
742 else
743 {
744 it->second.m_expiry = targetTime;
745 return it->second.m_ba;
746 }
747}
748
749// INPUT
750void UIController::tickInput()
751{
752 // If system/commerce UI up, don't handle input
753 //if(!m_bSysUIShowing && !m_bSystemUIShowing)
754 if(!m_bSystemUIShowing)
755 {
756#ifdef ENABLE_IGGY_PERFMON
757 if (m_iggyPerfmonEnabled)
758 {
759 if(InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(), ACTION_MENU_STICK_PRESS)) m_iggyPerfmonEnabled = !m_iggyPerfmonEnabled;
760 }
761 else
762#endif
763 {
764 handleInput();
765 ++m_accumulatedTicks;
766 }
767 }
768}
769
770void UIController::handleInput()
771{
772 // For each user, loop over each key type and send messages based on the state
773 for(unsigned int iPad = 0; iPad < XUSER_MAX_COUNT; ++iPad)
774 {
775#ifdef _DURANGO
776 // 4J-JEV: Added exception for primary play who migh've uttered speech commands.
777 if(iPad != ProfileManager.GetPrimaryPad()
778 && (!InputManager.IsPadConnected(iPad) || !InputManager.IsPadLocked(iPad)) ) continue;
779#endif
780 for(unsigned int key = 0; key <= ACTION_MAX_MENU; ++key)
781 {
782 handleKeyPress(iPad, key);
783 }
784
785#ifdef __PSVITA__
786 //CD - Vita requires key press 40 - select [MINECRAFT_ACTION_GAME_INFO]
787 handleKeyPress(iPad, MINECRAFT_ACTION_GAME_INFO);
788#endif
789 }
790
791#ifdef _DURANGO
792 if(!app.GetGameStarted())
793 {
794 bool repeat = false;
795 int firstUnfocussedUnhandledPad = -1;
796
797 // For durango, check for unmapped controllers
798 for(unsigned int iPad = XUSER_MAX_COUNT; iPad < (XUSER_MAX_COUNT + InputManager.MAX_GAMEPADS); ++iPad)
799 {
800 if(InputManager.IsPadLocked(iPad) || !InputManager.IsPadConnected(iPad) ) continue;
801
802 for(unsigned int key = 0; key <= ACTION_MAX_MENU; ++key)
803 {
804
805 bool pressed = InputManager.ButtonPressed(iPad,key); // Toggle
806 bool released = InputManager.ButtonReleased(iPad,key); // Toggle
807
808 if(pressed || released)
809 {
810 bool handled = false;
811
812 // Send the key to the fullscreen group first
813 m_groups[(int)eUIGroup_Fullscreen]->handleInput(iPad, key, repeat, pressed, released, handled);
814
815 if(firstUnfocussedUnhandledPad < 0 && !m_groups[(int)eUIGroup_Fullscreen]->HasFocus(iPad))
816 {
817 firstUnfocussedUnhandledPad = iPad;
818 }
819 }
820 }
821 }
822
823 if(ProfileManager.GetLockedProfile() >= 0 && !InputManager.IsPadLocked( ProfileManager.GetLockedProfile() ) && firstUnfocussedUnhandledPad >= 0)
824 {
825 ProfileManager.RequestSignInUI(false, false, false, false, true, NULL, NULL, firstUnfocussedUnhandledPad );
826 }
827 }
828#endif
829}
830
831void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
832{
833
834 bool down = false;
835 bool pressed = false; // Toggle
836 bool released = false; // Toggle
837 bool repeat = false;
838
839#ifdef __PSVITA__
840 if(key==ACTION_MENU_OK)
841 {
842 bool bTouchScreenInput=false;
843
844 // check the touchscreen
845
846 // 4J-PB - use the touchscreen for quickselect
847 SceTouchData* pTouchData = InputManager.GetTouchPadData(iPad,false);
848
849 if((m_bTouchscreenPressed==false) && pTouchData->reportNum==1)
850 {
851 // no active touch? clear active and highlighted touch UI elements
852 m_ActiveUIElement = NULL;
853 m_HighlightedUIElement = NULL;
854
855 // fullscreen first
856 UIScene *pScene=m_groups[(int)eUIGroup_Fullscreen]->getCurrentScene();
857 // also check tooltip scene if we're not touching anything in the main scene
858 UIScene *pToolTips=m_groups[(int)eUIGroup_Fullscreen]->getTooltips();
859 if(pScene)
860 {
861 // scene touch check
862 if(TouchBoxHit(pScene,pTouchData->report[0].x,pTouchData->report[0].y))
863 {
864 down=pressed=m_bTouchscreenPressed=true;
865 bTouchScreenInput=true;
866 }
867 // tooltip touch check
868 else if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
869 {
870 down=pressed=m_bTouchscreenPressed=true;
871 bTouchScreenInput=true;
872 }
873 }
874 else
875 {
876 pScene=m_groups[(EUIGroup)(iPad+1)]->getCurrentScene();
877 pToolTips=m_groups[(int)iPad+1]->getTooltips();
878 if(pScene)
879 {
880 // scene touch check
881 if(TouchBoxHit(pScene,pTouchData->report[0].x,pTouchData->report[0].y))
882 {
883 down=pressed=m_bTouchscreenPressed=true;
884 bTouchScreenInput=true;
885 }
886 // tooltip touch check (if scene exists but not component has been touched)
887 else if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
888 {
889 down=pressed=m_bTouchscreenPressed=true;
890 bTouchScreenInput=true;
891 }
892 }
893 else if(pToolTips)
894 {
895 // tooltip touch check (if scene does not exist)
896 if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
897 {
898 down=pressed=m_bTouchscreenPressed=true;
899 bTouchScreenInput=true;
900 }
901 }
902 }
903 }
904 else if(m_bTouchscreenPressed && pTouchData->reportNum==1)
905 {
906 // fullscreen first
907 UIScene *pScene=m_groups[(int)eUIGroup_Fullscreen]->getCurrentScene();
908 // also check tooltip scene if we're not touching anything in the main scene
909 UIScene *pToolTips=m_groups[(int)eUIGroup_Fullscreen]->getTooltips();
910 if(pScene)
911 {
912 // scene touch check
913 if(TouchBoxHit(pScene,pTouchData->report[0].x,pTouchData->report[0].y))
914 {
915 down=true;
916 bTouchScreenInput=true;
917 }
918 // tooltip touch check (if scene exists but not component has been touched)
919 else if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
920 {
921 down=true;
922 bTouchScreenInput=true;
923 }
924 }
925 else
926 {
927 pScene=m_groups[(EUIGroup)(iPad+1)]->getCurrentScene();
928 pToolTips=m_groups[(int)iPad+1]->getTooltips();
929 if(pScene)
930 {
931 // scene touch check
932 if(TouchBoxHit(pScene,pTouchData->report[0].x,pTouchData->report[0].y))
933 {
934 down=true;
935 bTouchScreenInput=true;
936 }
937 // tooltip touch check (if scene exists but not component has been touched)
938 else if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
939 {
940 down=true;
941 bTouchScreenInput=true;
942 }
943 }
944 else if(pToolTips)
945 {
946 // tooltip touch check (if scene does not exist)
947 if(TouchBoxHit(pToolTips,pTouchData->report[0].x,pTouchData->report[0].y))
948 {
949 down=true;
950 bTouchScreenInput=true;
951 }
952 }
953 }
954 }
955 else if(m_bTouchscreenPressed && pTouchData->reportNum==0)
956 {
957 // released
958 bTouchScreenInput=true;
959 m_bTouchscreenPressed=false;
960 released=true;
961 }
962
963 if(pressed)
964 {
965 // Start repeat timer
966 m_actionRepeatTimer[iPad][key] = GetTickCount() + UI_REPEAT_KEY_DELAY_MS;
967 }
968 else if (released)
969 {
970 // Stop repeat timer
971 m_actionRepeatTimer[iPad][key] = 0;
972 }
973 else if (down)
974 {
975 // Check is enough time has elapsed to be a repeat key
976 DWORD currentTime = GetTickCount();
977 if(m_actionRepeatTimer[iPad][key] > 0 && currentTime > m_actionRepeatTimer[iPad][key])
978 {
979 repeat = true;
980 pressed = true;
981 m_actionRepeatTimer[iPad][key] = currentTime + UI_REPEAT_KEY_REPEAT_RATE_MS;
982 }
983 }
984
985 // handle touch input
986 HandleTouchInput(iPad, key, pressed, repeat, released);
987
988 // ignore any other presses if the touchscreen has been used
989 if(bTouchScreenInput) return;
990 }
991#endif
992
993 down = InputManager.ButtonDown(iPad,key);
994 pressed = InputManager.ButtonPressed(iPad,key); // Toggle
995 released = InputManager.ButtonReleased(iPad,key); // Toggle
996
997#ifdef _WINDOWS64
998 // Keyboard menu input for player 0
999 if (iPad == 0)
1000 {
1001 bool kbDown = false, kbPressed = false, kbReleased = false;
1002 switch(key)
1003 {
1004 case ACTION_MENU_UP: kbDown = KMInput.IsKeyDown(VK_UP); kbPressed = KMInput.IsKeyPressed(VK_UP); kbReleased = KMInput.IsKeyReleased(VK_UP); break;
1005 case ACTION_MENU_DOWN: kbDown = KMInput.IsKeyDown(VK_DOWN); kbPressed = KMInput.IsKeyPressed(VK_DOWN); kbReleased = KMInput.IsKeyReleased(VK_DOWN); break;
1006 case ACTION_MENU_LEFT: kbDown = KMInput.IsKeyDown(VK_LEFT); kbPressed = KMInput.IsKeyPressed(VK_LEFT); kbReleased = KMInput.IsKeyReleased(VK_LEFT); break;
1007 case ACTION_MENU_RIGHT: kbDown = KMInput.IsKeyDown(VK_RIGHT); kbPressed = KMInput.IsKeyPressed(VK_RIGHT); kbReleased = KMInput.IsKeyReleased(VK_RIGHT); break;
1008 case ACTION_MENU_OK: kbDown = KMInput.IsKeyDown(VK_RETURN); kbPressed = KMInput.IsKeyPressed(VK_RETURN); kbReleased = KMInput.IsKeyReleased(VK_RETURN); break;
1009 case ACTION_MENU_A: kbDown = KMInput.IsKeyDown(VK_RETURN); kbPressed = KMInput.IsKeyPressed(VK_RETURN); kbReleased = KMInput.IsKeyReleased(VK_RETURN); break;
1010 case ACTION_MENU_CANCEL: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
1011 case ACTION_MENU_B: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
1012 case ACTION_MENU_PAUSEMENU: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
1013 case ACTION_MENU_LEFT_SCROLL: kbDown = KMInput.IsKeyDown('Q'); kbPressed = KMInput.IsKeyPressed('Q'); kbReleased = KMInput.IsKeyReleased('Q'); break;
1014 case ACTION_MENU_RIGHT_SCROLL: kbDown = KMInput.IsKeyDown('E'); kbPressed = KMInput.IsKeyPressed('E'); kbReleased = KMInput.IsKeyReleased('E'); break;
1015 }
1016 pressed = pressed || kbPressed;
1017 released = released || kbReleased;
1018 down = down || kbDown;
1019 }
1020#endif
1021
1022 if(pressed) app.DebugPrintf("Pressed %d\n",key);
1023 if(released) app.DebugPrintf("Released %d\n",key);
1024 // Repeat handling
1025 if(pressed)
1026 {
1027 // Start repeat timer
1028 m_actionRepeatTimer[iPad][key] = GetTickCount() + UI_REPEAT_KEY_DELAY_MS;
1029 }
1030 else if (released)
1031 {
1032 // Stop repeat timer
1033 m_actionRepeatTimer[iPad][key] = 0;
1034 }
1035 else if (down)
1036 {
1037 // Check is enough time has elapsed to be a repeat key
1038 DWORD currentTime = GetTickCount();
1039 if(m_actionRepeatTimer[iPad][key] > 0 && currentTime > m_actionRepeatTimer[iPad][key])
1040 {
1041 repeat = true;
1042 pressed = true;
1043 m_actionRepeatTimer[iPad][key] = currentTime + UI_REPEAT_KEY_REPEAT_RATE_MS;
1044 }
1045 }
1046
1047#ifndef _CONTENT_PACKAGE
1048
1049#ifdef ENABLE_IGGY_PERFMON
1050 if ( pressed && !repeat && key == ACTION_MENU_STICK_PRESS)
1051 {
1052 m_iggyPerfmonEnabled = !m_iggyPerfmonEnabled;
1053 }
1054#endif
1055
1056 // 4J Stu - Removed this function
1057#if 0
1058#ifdef __PS3__
1059 //if ( pressed &&
1060 // !repeat &&
1061 // //app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_ToggleFont) &&
1062 // key == ACTION_MENU_STICK_PRESS)
1063 //{
1064 // static bool whichFont = true;
1065 // if (whichFont)
1066 // {
1067 // IggyFontSetIndirectUTF8( "Mojangles_7", -1, IGGY_FONTFLAG_all, "Mojangles_TTF",-1 ,IGGY_FONTFLAG_none );
1068 // IggyFontSetIndirectUTF8( "Mojangles_11", -1, IGGY_FONTFLAG_all, "Mojangles_TTF",-1 ,IGGY_FONTFLAG_none );
1069 // whichFont = false;
1070 // }
1071 // else
1072 // {
1073 // IggyFontSetIndirectUTF8( "Mojangles_7", -1, IGGY_FONTFLAG_all, "Mojangles_7",-1 ,IGGY_FONTFLAG_none );
1074 // IggyFontSetIndirectUTF8( "Mojangles_11", -1, IGGY_FONTFLAG_all, "Mojangles_11",-1 ,IGGY_FONTFLAG_none );
1075 // whichFont = true;
1076 // }
1077 //}
1078 //else
1079 if ( pressed &&
1080 !repeat &&
1081 //!(app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<<eDebugSetting_ToggleFont)) &&
1082 key == ACTION_MENU_STICK_PRESS)
1083 {
1084 __int64 totalStatic = 0;
1085 __int64 totalDynamic = 0;
1086 app.DebugPrintf(app.USER_SR, "********************************\n");
1087 app.DebugPrintf(app.USER_SR, "BEGIN TOTAL SWF MEMORY USAGE\n\n");
1088 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
1089 {
1090 m_groups[i]->PrintTotalMemoryUsage(totalStatic, totalDynamic);
1091 }
1092 for(unsigned int i = 0; i < eLibrary_Count; ++i)
1093 {
1094 __int64 libraryStatic = 0;
1095 __int64 libraryDynamic = 0;
1096
1097 if(m_iggyLibraries[i] != IGGY_INVALID_LIBRARY)
1098 {
1099
1100 IggyMemoryUseInfo memoryInfo;
1101 rrbool res;
1102 int iteration = 0;
1103 while(res = IggyDebugGetMemoryUseInfo ( NULL ,
1104 m_iggyLibraries[i] ,
1105 "" ,
1106 0 ,
1107 iteration ,
1108 &memoryInfo ))
1109 {
1110 libraryStatic += memoryInfo.static_allocation_bytes;
1111 libraryDynamic += memoryInfo.dynamic_allocation_bytes;
1112 totalStatic += memoryInfo.static_allocation_bytes;
1113 totalDynamic += memoryInfo.dynamic_allocation_bytes;
1114 ++iteration;
1115 }
1116 }
1117
1118 app.DebugPrintf(app.USER_SR, "Library static: %dB , Library dynamic: %d, ID: %d\n", libraryStatic, libraryDynamic, i);
1119 }
1120 app.DebugPrintf(app.USER_SR, "Total static: %d , Total dynamic: %d\n", totalStatic, totalDynamic);
1121 app.DebugPrintf(app.USER_SR, "\n\nEND TOTAL SWF MEMORY USAGE\n");
1122 app.DebugPrintf(app.USER_SR, "********************************\n\n");
1123 }
1124 else
1125#endif
1126#endif
1127#endif
1128 //#endif
1129 if(repeat || pressed || released)
1130 {
1131 bool handled = false;
1132
1133 // Send the key to the fullscreen group first
1134 m_groups[(int)eUIGroup_Fullscreen]->handleInput(iPad, key, repeat, pressed, released, handled);
1135 if(!handled)
1136 {
1137 // If it's not been handled yet, then pass the event onto the players specific group
1138 m_groups[(iPad+1)]->handleInput(iPad, key, repeat, pressed, released, handled);
1139 }
1140 }
1141}
1142
1143rrbool RADLINK UIController::ExternalFunctionCallback( void * user_callback_data , Iggy * player , IggyExternalFunctionCallUTF16 * call)
1144{
1145 UIScene *scene = (UIScene *)IggyPlayerGetUserdata(player);
1146
1147 if(scene != NULL)
1148 {
1149 scene->externalCallback(call);
1150 }
1151
1152 return true;
1153}
1154
1155// RENDERING
1156void UIController::renderScenes()
1157{
1158 PIXBeginNamedEvent(0, "Rendering Iggy scenes");
1159 // Only render player scenes if the game is started
1160 if(app.GetGameStarted() && !m_groups[eUIGroup_Fullscreen]->hidesLowerScenes())
1161 {
1162 for(int i = eUIGroup_Player1; i < eUIGroup_COUNT; ++i)
1163 {
1164 PIXBeginNamedEvent(0, "Rendering layer %d scenes", i);
1165 m_groups[i]->render();
1166 PIXEndNamedEvent();
1167 }
1168 }
1169
1170 // Always render the fullscreen group
1171 PIXBeginNamedEvent(0, "Rendering fullscreen scenes");
1172 m_groups[eUIGroup_Fullscreen]->render();
1173 PIXEndNamedEvent();
1174
1175 PIXEndNamedEvent();
1176
1177#ifdef ENABLE_IGGY_PERFMON
1178 if (m_iggyPerfmonEnabled)
1179 {
1180 IggyPerfmonPad pm_pad;
1181
1182 pm_pad.bits = 0;
1183 pm_pad.field.dpad_up = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_UP);
1184 pm_pad.field.dpad_down = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_DOWN);
1185 pm_pad.field.dpad_left = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_LEFT);
1186 pm_pad.field.dpad_right = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_RIGHT);
1187 pm_pad.field.button_up = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_Y);
1188 pm_pad.field.button_down = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_A);
1189 pm_pad.field.button_left = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_X);
1190 pm_pad.field.button_right = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_B);
1191 pm_pad.field.shoulder_left_hi = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_LEFT_SCROLL);
1192 pm_pad.field.shoulder_right_hi = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_RIGHT_SCROLL);
1193 pm_pad.field.trigger_left_low = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_PAGEUP);
1194 pm_pad.field.trigger_right_low = InputManager.ButtonPressed(ProfileManager.GetPrimaryPad(),ACTION_MENU_PAGEDOWN);
1195 //IggyPerfmonPadFromXInputStatePointer(pm_pad, &xi_pad);
1196
1197 //gdraw_D3D_SetTileOrigin( fb,
1198 // zb,
1199 // PM_ORIGIN_X,
1200 // PM_ORIGIN_Y );
1201 IggyPerfmonTickAndDraw(iggy_perfmon, gdraw_funcs, &pm_pad,
1202 PM_ORIGIN_X, PM_ORIGIN_Y, getScreenWidth(), getScreenHeight()); // perfmon draw area in window coords
1203 }
1204#endif
1205}
1206
1207void UIController::getRenderDimensions(C4JRender::eViewportType viewport, S32 &width, S32 &height)
1208{
1209 switch( viewport )
1210 {
1211 case C4JRender::VIEWPORT_TYPE_FULLSCREEN:
1212 width = (S32)(getScreenWidth());
1213 height = (S32)(getScreenHeight());
1214 break;
1215 case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
1216 case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
1217 width = (S32)(getScreenWidth() / 2);
1218 height = (S32)(getScreenHeight() / 2);
1219 break;
1220 case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
1221 case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
1222 width = (S32)(getScreenWidth() / 2);
1223 height = (S32)(getScreenHeight() / 2);
1224 break;
1225 case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
1226 case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
1227 case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
1228 case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
1229 width = (S32)(getScreenWidth() / 2);
1230 height = (S32)(getScreenHeight() / 2);
1231 break;
1232 }
1233}
1234
1235void UIController::setupRenderPosition(C4JRender::eViewportType viewport)
1236{
1237 if(m_bCustomRenderPosition || m_currentRenderViewport != viewport)
1238 {
1239 m_currentRenderViewport = viewport;
1240 m_bCustomRenderPosition = false;
1241 S32 xPos = 0;
1242 S32 yPos = 0;
1243 switch( viewport )
1244 {
1245 case C4JRender::VIEWPORT_TYPE_SPLIT_TOP:
1246 xPos = (S32)(getScreenWidth() / 4);
1247 break;
1248 case C4JRender::VIEWPORT_TYPE_SPLIT_BOTTOM:
1249 xPos = (S32)(getScreenWidth() / 4);
1250 yPos = (S32)(getScreenHeight() / 2);
1251 break;
1252 case C4JRender::VIEWPORT_TYPE_SPLIT_LEFT:
1253 yPos = (S32)(getScreenHeight() / 4);
1254 break;
1255 case C4JRender::VIEWPORT_TYPE_SPLIT_RIGHT:
1256 xPos = (S32)(getScreenWidth() / 2);
1257 yPos = (S32)(getScreenHeight() / 4);
1258 break;
1259 case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT:
1260 break;
1261 case C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_RIGHT:
1262 xPos = (S32)(getScreenWidth() / 2);
1263 break;
1264 case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT:
1265 yPos = (S32)(getScreenHeight() / 2);
1266 break;
1267 case C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT:
1268 xPos = (S32)(getScreenWidth() / 2);
1269 yPos = (S32)(getScreenHeight() / 2);
1270 break;
1271 }
1272 m_tileOriginX = xPos;
1273 m_tileOriginY = yPos;
1274 setTileOrigin(xPos, yPos);
1275 }
1276}
1277
1278void UIController::setupRenderPosition(S32 xOrigin, S32 yOrigin)
1279{
1280 m_bCustomRenderPosition = true;
1281 m_tileOriginX = xOrigin;
1282 m_tileOriginY = yOrigin;
1283 setTileOrigin(xOrigin, yOrigin);
1284}
1285
1286void UIController::setupCustomDrawGameState()
1287{
1288 // Rest the clear rect
1289 m_customRenderingClearRect.left = LONG_MAX;
1290 m_customRenderingClearRect.right = LONG_MIN;
1291 m_customRenderingClearRect.top = LONG_MAX;
1292 m_customRenderingClearRect.bottom = LONG_MIN;
1293
1294#if defined _WINDOWS64 || _DURANGO
1295 PIXBeginNamedEvent(0,"StartFrame");
1296 RenderManager.StartFrame();
1297 PIXEndNamedEvent();
1298 gdraw_D3D11_setViewport_4J();
1299#elif defined __PS3__
1300 RenderManager.StartFrame();
1301#elif defined __PSVITA__
1302 RenderManager.StartFrame();
1303#elif defined __ORBIS__
1304 RenderManager.StartFrame(false);
1305 // 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
1306 // that the renderer orthographic projection will work
1307 gdraw_orbis_setViewport_4J();
1308#endif
1309 RenderManager.Set_matrixDirty();
1310
1311 // 4J Stu - We don't need to clear this here as iggy hasn't written anything to the depth buffer.
1312 // We DO however clear after we render which is why we still setup the rectangle here
1313 //RenderManager.Clear(GL_DEPTH_BUFFER_BIT, &m_customRenderingClearRect);
1314 //glClear(GL_DEPTH_BUFFER_BIT);
1315
1316 PIXBeginNamedEvent(0,"Final setup");
1317 glMatrixMode(GL_PROJECTION);
1318 glLoadIdentity();
1319 glOrtho(0, m_fScreenWidth, m_fScreenHeight, 0, 1000, 3000);
1320 glMatrixMode(GL_MODELVIEW);
1321 glEnable(GL_ALPHA_TEST);
1322 glAlphaFunc(GL_GREATER, 0.1f);
1323 glEnable(GL_DEPTH_TEST);
1324 glDepthFunc(GL_LEQUAL);
1325 glDepthMask(true);
1326 PIXEndNamedEvent();
1327}
1328
1329void UIController::setupCustomDrawMatrices(UIScene *scene, CustomDrawData *customDrawRegion)
1330{
1331 Minecraft *pMinecraft=Minecraft::GetInstance();
1332
1333 // Clear just the region required for this control.
1334 float sceneWidth = (float)scene->getRenderWidth();
1335 float sceneHeight = (float)scene->getRenderHeight();
1336
1337 LONG left, right, top, bottom;
1338#ifdef __PS3__
1339 if(!RenderManager.IsHiDef() && !RenderManager.IsWidescreen())
1340 {
1341 // 4J Stu - Our SD target on PS3 is double width
1342 left = m_tileOriginX + (sceneWidth + customDrawRegion->mat[(0*4)+3]*sceneWidth);
1343 right = left + ( (sceneWidth * customDrawRegion->mat[0]) ) * customDrawRegion->x1;
1344 }
1345 else
1346#endif
1347 {
1348 left = m_tileOriginX + (sceneWidth + customDrawRegion->mat[(0*4)+3]*sceneWidth)/2;
1349 right = left + ( (sceneWidth * customDrawRegion->mat[0])/2 ) * customDrawRegion->x1;
1350 }
1351
1352 top = m_tileOriginY + (sceneHeight - customDrawRegion->mat[(1*4)+3]*sceneHeight)/2;
1353 bottom = top + (sceneHeight * -customDrawRegion->mat[(1*4) + 1])/2 * customDrawRegion->y1;
1354
1355 m_customRenderingClearRect.left = min(m_customRenderingClearRect.left, left);
1356 m_customRenderingClearRect.right = max(m_customRenderingClearRect.right, right);;
1357 m_customRenderingClearRect.top = min(m_customRenderingClearRect.top, top);
1358 m_customRenderingClearRect.bottom = max(m_customRenderingClearRect.bottom, bottom);
1359
1360 if(!m_bScreenWidthSetup)
1361 {
1362 Minecraft *pMinecraft=Minecraft::GetInstance();
1363 if(pMinecraft != NULL)
1364 {
1365 m_fScreenWidth=(float)pMinecraft->width_phys;
1366 m_fScreenHeight=(float)pMinecraft->height_phys;
1367 m_bScreenWidthSetup = true;
1368 }
1369 }
1370
1371 glLoadIdentity();
1372 glTranslatef(0, 0, -2000);
1373 // Iggy translations are based on a double-size target, with the origin in the centre
1374 glTranslatef((m_fScreenWidth + customDrawRegion->mat[(0*4)+3]*m_fScreenWidth)/2,(m_fScreenHeight - customDrawRegion->mat[(1*4)+3]*m_fScreenHeight)/2,0);
1375 // Iggy scales are based on a double-size target
1376 glScalef( (m_fScreenWidth * customDrawRegion->mat[0])/2,(m_fScreenHeight * -customDrawRegion->mat[(1*4) + 1])/2,1.0f);
1377}
1378
1379void UIController::setupCustomDrawGameStateAndMatrices(UIScene *scene, CustomDrawData *customDrawRegion)
1380{
1381 setupCustomDrawGameState();
1382 setupCustomDrawMatrices(scene, customDrawRegion);
1383}
1384
1385void UIController::endCustomDrawGameState()
1386{
1387#ifdef __ORBIS__
1388 // TO BE IMPLEMENTED
1389 RenderManager.Clear(GL_DEPTH_BUFFER_BIT);
1390#else
1391 RenderManager.Clear(GL_DEPTH_BUFFER_BIT, &m_customRenderingClearRect);
1392#endif
1393 //glClear(GL_DEPTH_BUFFER_BIT);
1394 glDepthMask(false);
1395 glDisable(GL_ALPHA_TEST);
1396}
1397
1398void UIController::endCustomDrawMatrices()
1399{
1400}
1401
1402void UIController::endCustomDrawGameStateAndMatrices()
1403{
1404 endCustomDrawMatrices();
1405 endCustomDrawGameState();
1406}
1407
1408void RADLINK UIController::CustomDrawCallback(void *user_callback_data, Iggy *player, IggyCustomDrawCallbackRegion *region)
1409{
1410 UIScene *scene = (UIScene *)IggyPlayerGetUserdata(player);
1411
1412 if(scene != NULL)
1413 {
1414 scene->customDraw(region);
1415 }
1416}
1417
1418//Description
1419//Callback to create a user-defined texture to replace SWF-defined textures.
1420//Parameters
1421//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.
1422//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.
1423//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).
1424//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.
1425//
1426//Discussion
1427//
1428//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).
1429GDrawTexture * RADLINK UIController::TextureSubstitutionCreateCallback ( void * user_callback_data , IggyUTF16 * texture_name , S32 * width , S32 * height , void * * destroy_callback_data )
1430{
1431 UIController *uiController = (UIController *)user_callback_data;
1432 AUTO_VAR(it,uiController->m_substitutionTextures.find((wchar_t *)texture_name));
1433
1434 if(it != uiController->m_substitutionTextures.end())
1435 {
1436 app.DebugPrintf("Found substitution texture %ls, with %d bytes\n", (wchar_t *)texture_name,it->second.length);
1437
1438 BufferedImage image(it->second.data, it->second.length);
1439 if( image.getData() != NULL )
1440 {
1441 image.preMultiplyAlpha();
1442 Textures *t = Minecraft::GetInstance()->textures;
1443 int id = t->getTexture(&image,C4JRender::TEXTURE_FORMAT_RxGyBzAw,false);
1444
1445 // 4J Stu - All our flash controls that allow replacing textures use a special 64x64 symbol
1446 // Force this size here so that our images don't get scaled wildly
1447 #if (defined __ORBIS__ || defined _DURANGO )
1448 *width = 96;
1449 *height = 96;
1450 #else
1451 *width = 64;
1452 *height = 64;
1453
1454 #endif
1455 *destroy_callback_data = (void *)id;
1456
1457 app.DebugPrintf("Found substitution texture %ls (%d) - %dx%d\n", (wchar_t *)texture_name, id, image.getWidth(), image.getHeight());
1458 return ui.getSubstitutionTexture(id);
1459 }
1460 else
1461 {
1462 return NULL;
1463 }
1464 }
1465 else
1466 {
1467 app.DebugPrintf("Could not find substitution texture %ls\n", (wchar_t *)texture_name);
1468 return NULL;
1469 }
1470}
1471
1472//Description
1473//Callback received from Iggy when it stops using a user-defined texture.
1474void RADLINK UIController::TextureSubstitutionDestroyCallback ( void * user_callback_data , void * destroy_callback_data , GDrawTexture * handle )
1475{
1476 // Orbis complains about casting a pointer to an int
1477 LONGLONG llVal=(LONGLONG)destroy_callback_data;
1478 int id=(int)llVal;
1479 app.DebugPrintf("Destroying iggy texture %d\n", id);
1480
1481 ui.destroySubstitutionTexture(user_callback_data, handle);
1482
1483 Textures *t = Minecraft::GetInstance()->textures;
1484 t->releaseTexture( id );
1485}
1486
1487void UIController::registerSubstitutionTexture(const wstring &textureName, PBYTE pbData, DWORD dwLength)
1488{
1489 // Remove it if it already exists
1490 unregisterSubstitutionTexture(textureName,false);
1491
1492 m_substitutionTextures[textureName] = byteArray(pbData, dwLength);
1493}
1494
1495void UIController::unregisterSubstitutionTexture(const wstring &textureName, bool deleteData)
1496{
1497 AUTO_VAR(it,m_substitutionTextures.find(textureName));
1498
1499 if(it != m_substitutionTextures.end())
1500 {
1501 if(deleteData) delete [] it->second.data;
1502 m_substitutionTextures.erase(it);
1503 }
1504}
1505
1506// NAVIGATION
1507bool UIController::NavigateToScene(int iPad, EUIScene scene, void *initData, EUILayer layer, EUIGroup group)
1508{
1509 static bool bSeenUpdateTextThisSession = false;
1510 // If you're navigating to the multigamejoinload, and the player hasn't seen the updates message yet, display it now
1511 // display this message the first 3 times
1512 if((scene==eUIScene_LoadOrJoinMenu) && (bSeenUpdateTextThisSession==false) && ( app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_DisplayUpdateMessage)!=0))
1513 {
1514 scene=eUIScene_NewUpdateMessage;
1515 bSeenUpdateTextThisSession=true;
1516 }
1517
1518 // 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
1519 if(GetMenuDisplayed(iPad))
1520 {
1521 switch(scene)
1522 {
1523 case eUIScene_PauseMenu:
1524 case eUIScene_Crafting2x2Menu:
1525 case eUIScene_Crafting3x3Menu:
1526 case eUIScene_FurnaceMenu:
1527 case eUIScene_ContainerMenu:
1528 case eUIScene_LargeContainerMenu:
1529 case eUIScene_InventoryMenu:
1530 case eUIScene_CreativeMenu:
1531 case eUIScene_DispenserMenu:
1532 case eUIScene_SignEntryMenu:
1533 case eUIScene_InGameInfoMenu:
1534 case eUIScene_EnchantingMenu:
1535 case eUIScene_BrewingStandMenu:
1536 case eUIScene_AnvilMenu:
1537 case eUIScene_TradingMenu:
1538 case eUIScene_BeaconMenu:
1539 case eUIScene_HorseMenu:
1540 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);
1541 return false;
1542 break;
1543 }
1544 }
1545
1546 switch(scene)
1547 {
1548 case eUIScene_FullscreenProgress:
1549 {
1550 // 4J Stu - The fullscreen progress scene should not interfere with any other scene stack, so should be placed in it's own group/layer
1551 layer = eUILayer_Fullscreen;
1552 group = eUIGroup_Fullscreen;
1553 }
1554 break;
1555 case eUIScene_ConnectingProgress:
1556 {
1557 // The connecting progress scene shouldn't interfere with other scenes
1558 layer = eUILayer_Fullscreen;
1559 }
1560 break;
1561 case eUIScene_EndPoem:
1562 {
1563 // The end poem scene shouldn't interfere with other scenes, but will be underneath the autosave progress
1564 group = eUIGroup_Fullscreen;
1565 layer = eUILayer_Scene;
1566 }
1567 break;
1568 };
1569 int menuDisplayedPad = XUSER_INDEX_ANY;
1570 if(group == eUIGroup_PAD)
1571 {
1572 if( app.GetGameStarted() )
1573 {
1574 // If the game isn't running treat as user 0, otherwise map index directly from pad
1575 if( ( iPad != 255 ) && ( iPad >= 0 ) )
1576 {
1577 menuDisplayedPad = iPad;
1578 group = (EUIGroup)(iPad+1);
1579 }
1580 else group = eUIGroup_Fullscreen;
1581 }
1582 else
1583 {
1584 layer = eUILayer_Fullscreen;
1585 group = eUIGroup_Fullscreen;
1586 }
1587 }
1588
1589 PerformanceTimer timer;
1590
1591 EnterCriticalSection(&m_navigationLock);
1592 SetMenuDisplayed(menuDisplayedPad,true);
1593 bool success = m_groups[(int)group]->NavigateToScene(iPad, scene, initData, layer);
1594 if(success && group == eUIGroup_Fullscreen) setFullscreenMenuDisplayed(true);
1595 LeaveCriticalSection(&m_navigationLock);
1596
1597 timer.PrintElapsedTime(L"Navigate to scene");
1598
1599 return success;
1600 //return true;
1601}
1602
1603bool UIController::NavigateBack(int iPad, bool forceUsePad, EUIScene eScene, EUILayer eLayer)
1604{
1605 bool navComplete = false;
1606 if( app.GetGameStarted() )
1607 {
1608 bool navComplete = m_groups[(int)eUIGroup_Fullscreen]->NavigateBack(iPad, eScene, eLayer);
1609
1610 if(!navComplete && ( iPad != 255 ) && ( iPad >= 0 ) )
1611 {
1612 EUIGroup group = (EUIGroup)(iPad+1);
1613 navComplete = m_groups[(int)group]->NavigateBack(iPad, eScene, eLayer);
1614 if(!m_groups[(int)group]->GetMenuDisplayed())SetMenuDisplayed(iPad,false);
1615 }
1616 // 4J-PB - autosave in fullscreen doesn't clear the menuDisplayed flag
1617 else
1618 {
1619 if(!m_groups[(int)eUIGroup_Fullscreen]->GetMenuDisplayed())
1620 {
1621 setFullscreenMenuDisplayed(false);
1622 for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
1623 {
1624 SetMenuDisplayed(i,m_groups[i+1]->GetMenuDisplayed());
1625 }
1626 }
1627 }
1628 }
1629 else
1630 {
1631 navComplete = m_groups[(int)eUIGroup_Fullscreen]->NavigateBack(iPad, eScene, eLayer);
1632 if(!m_groups[(int)eUIGroup_Fullscreen]->GetMenuDisplayed()) SetMenuDisplayed(XUSER_INDEX_ANY,false);
1633 }
1634 return navComplete;
1635}
1636
1637void UIController::NavigateToHomeMenu()
1638{
1639 ui.CloseAllPlayersScenes();
1640
1641 // Alert the app the we no longer want to be informed of ethernet connections
1642 app.SetLiveLinkRequired( false );
1643
1644 Minecraft *pMinecraft = Minecraft::GetInstance();
1645
1646 // 4J-PB - just about to switched to the default texture pack , so clean up anything texture pack related here
1647
1648 // unload any texture pack audio
1649 // if there is audio in use, clear out the audio, and unmount the pack
1650 TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected();
1651
1652
1653 DLCTexturePack *pDLCTexPack=NULL;
1654 if(pTexPack->hasAudio())
1655 {
1656 // get the dlc texture pack, and store it
1657 pDLCTexPack=(DLCTexturePack *)pTexPack;
1658 }
1659
1660 // change to the default texture pack
1661 pMinecraft->skins->selectTexturePackById(TexturePackRepository::DEFAULT_TEXTURE_PACK_ID);
1662
1663
1664 if(pTexPack->hasAudio())
1665 {
1666 // need to stop the streaming audio - by playing streaming audio from the default texture pack now
1667 // reset the streaming sounds back to the normal ones
1668 pMinecraft->soundEngine->SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3,
1669 eStream_Nether1,eStream_Nether4,
1670 eStream_end_dragon,eStream_end_end,
1671 eStream_CD_1);
1672 pMinecraft->soundEngine->playStreaming(L"", 0, 0, 0, 1, 1);
1673
1674 // if(pDLCTexPack->m_pStreamedWaveBank!=NULL)
1675 // {
1676 // pDLCTexPack->m_pStreamedWaveBank->Destroy();
1677 // }
1678 // if(pDLCTexPack->m_pSoundBank!=NULL)
1679 // {
1680 // pDLCTexPack->m_pSoundBank->Destroy();
1681 // }
1682#ifdef _XBOX_ONE
1683 DWORD result = StorageManager.UnmountInstalledDLC(L"TPACK");
1684#else
1685 DWORD result = StorageManager.UnmountInstalledDLC("TPACK");
1686#endif
1687
1688 app.DebugPrintf("Unmount result is %d\n",result);
1689 }
1690
1691 g_NetworkManager.ForceFriendsSessionRefresh();
1692
1693 if(pMinecraft->skins->needsUIUpdate())
1694 {
1695 m_navigateToHomeOnReload = true;
1696 }
1697 else
1698 {
1699 ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MainMenu);
1700 }
1701}
1702
1703UIScene *UIController::GetTopScene(int iPad, EUILayer layer, EUIGroup group)
1704{
1705 if(group == eUIGroup_PAD)
1706 {
1707 if( app.GetGameStarted() )
1708 {
1709 // If the game isn't running treat as user 0, otherwise map index directly from pad
1710 if( ( iPad != 255 ) && ( iPad >= 0 ) )
1711 {
1712 group = (EUIGroup)(iPad+1);
1713 }
1714 else group = eUIGroup_Fullscreen;
1715 }
1716 else
1717 {
1718 layer = eUILayer_Fullscreen;
1719 group = eUIGroup_Fullscreen;
1720 }
1721 }
1722 return m_groups[(int)group]->GetTopScene(layer);
1723}
1724
1725size_t UIController::RegisterForCallbackId(UIScene *scene)
1726{
1727 EnterCriticalSection(&m_registeredCallbackScenesCS);
1728 size_t newId = GetTickCount();
1729 newId &= 0xFFFFFF; // Chop off the top byte, we don't need any more accuracy than that
1730 newId |= (scene->getSceneType() << 24); // Add in the scene's type to help keep this unique
1731 m_registeredCallbackScenes[newId] = scene;
1732 LeaveCriticalSection(&m_registeredCallbackScenesCS);
1733 return newId;
1734}
1735
1736void UIController::UnregisterCallbackId(size_t id)
1737{
1738 EnterCriticalSection(&m_registeredCallbackScenesCS);
1739 AUTO_VAR(it, m_registeredCallbackScenes.find(id) );
1740 if(it != m_registeredCallbackScenes.end() )
1741 {
1742 m_registeredCallbackScenes.erase(it);
1743 }
1744 LeaveCriticalSection(&m_registeredCallbackScenesCS);
1745}
1746
1747UIScene *UIController::GetSceneFromCallbackId(size_t id)
1748{
1749 UIScene *scene = NULL;
1750 AUTO_VAR(it, m_registeredCallbackScenes.find(id) );
1751 if(it != m_registeredCallbackScenes.end() )
1752 {
1753 scene = it->second;
1754 }
1755 return scene;
1756}
1757
1758void UIController::EnterCallbackIdCriticalSection()
1759{
1760 EnterCriticalSection(&m_registeredCallbackScenesCS);
1761}
1762
1763void UIController::LeaveCallbackIdCriticalSection()
1764{
1765 LeaveCriticalSection(&m_registeredCallbackScenesCS);
1766}
1767
1768void UIController::CloseAllPlayersScenes()
1769{
1770 m_groups[(int)eUIGroup_Fullscreen]->getTooltips()->SetTooltips(-1);
1771 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
1772 {
1773 //m_bCloseAllScenes[i] = true;
1774 m_groups[i]->closeAllScenes();
1775 m_groups[i]->getTooltips()->SetTooltips(-1);
1776 }
1777
1778 if (!m_groups[eUIGroup_Fullscreen]->GetMenuDisplayed()) {
1779 for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
1780 {
1781 SetMenuDisplayed(i,false);
1782 }
1783 }
1784 setFullscreenMenuDisplayed(false);
1785}
1786
1787void UIController::CloseUIScenes(int iPad, bool forceIPad)
1788{
1789 EUIGroup group;
1790 if( app.GetGameStarted() || forceIPad )
1791 {
1792 // If the game isn't running treat as user 0, otherwise map index directly from pad
1793 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
1794 else group = eUIGroup_Fullscreen;
1795 }
1796 else
1797 {
1798 group = eUIGroup_Fullscreen;
1799 }
1800
1801 m_groups[(int)group]->closeAllScenes();
1802 m_groups[(int)group]->getTooltips()->SetTooltips(-1);
1803
1804 // This should cause the popup to dissappear
1805 TutorialPopupInfo popupInfo;
1806 if(m_groups[(int)group]->getTutorialPopup()) m_groups[(int)group]->getTutorialPopup()->SetTutorialDescription(&popupInfo);
1807
1808 if(group==eUIGroup_Fullscreen) setFullscreenMenuDisplayed(false);
1809
1810 SetMenuDisplayed((group == eUIGroup_Fullscreen ? XUSER_INDEX_ANY : iPad), m_groups[(int)group]->GetMenuDisplayed());
1811}
1812
1813void UIController::setFullscreenMenuDisplayed(bool displayed)
1814{
1815 // Show/hide the tooltips for the fullscreen group
1816 m_groups[(int)eUIGroup_Fullscreen]->showComponent(ProfileManager.GetPrimaryPad(),eUIComponent_Tooltips,eUILayer_Tooltips,displayed);
1817
1818 // Show/hide tooltips for the other layers
1819 for(unsigned int i = (eUIGroup_Fullscreen+1); i < eUIGroup_COUNT; ++i)
1820 {
1821 m_groups[i]->showComponent(i,eUIComponent_Tooltips,eUILayer_Tooltips,!displayed);
1822 }
1823}
1824
1825bool UIController::IsPauseMenuDisplayed(int iPad)
1826{
1827 EUIGroup group;
1828 if( app.GetGameStarted() )
1829 {
1830 // If the game isn't running treat as user 0, otherwise map index directly from pad
1831 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
1832 else group = eUIGroup_Fullscreen;
1833 }
1834 else
1835 {
1836 group = eUIGroup_Fullscreen;
1837 }
1838 return m_groups[(int)group]->IsPauseMenuDisplayed();
1839}
1840
1841bool UIController::IsContainerMenuDisplayed(int iPad)
1842{
1843 EUIGroup group;
1844 if( app.GetGameStarted() )
1845 {
1846 // If the game isn't running treat as user 0, otherwise map index directly from pad
1847 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
1848 else group = eUIGroup_Fullscreen;
1849 }
1850 else
1851 {
1852 group = eUIGroup_Fullscreen;
1853 }
1854 return m_groups[(int)group]->IsContainerMenuDisplayed();
1855}
1856
1857bool UIController::IsIgnorePlayerJoinMenuDisplayed(int iPad)
1858{
1859 EUIGroup group;
1860 if( app.GetGameStarted() )
1861 {
1862 // If the game isn't running treat as user 0, otherwise map index directly from pad
1863 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
1864 else group = eUIGroup_Fullscreen;
1865 }
1866 else
1867 {
1868 group = eUIGroup_Fullscreen;
1869 }
1870 return m_groups[(int)group]->IsIgnorePlayerJoinMenuDisplayed();
1871}
1872
1873bool UIController::IsIgnoreAutosaveMenuDisplayed(int iPad)
1874{
1875 EUIGroup group;
1876 if( app.GetGameStarted() )
1877 {
1878 // If the game isn't running treat as user 0, otherwise map index directly from pad
1879 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
1880 else group = eUIGroup_Fullscreen;
1881 }
1882 else
1883 {
1884 group = eUIGroup_Fullscreen;
1885 }
1886 return m_groups[(int)eUIGroup_Fullscreen]->IsIgnoreAutosaveMenuDisplayed() || (group != eUIGroup_Fullscreen && m_groups[(int)group]->IsIgnoreAutosaveMenuDisplayed());
1887}
1888
1889void UIController::SetIgnoreAutosaveMenuDisplayed(int iPad, bool displayed)
1890{
1891 app.DebugPrintf(app.USER_SR, "UIController::SetIgnoreAutosaveMenuDisplayed is not implemented\n");
1892}
1893
1894bool UIController::IsSceneInStack(int iPad, EUIScene eScene)
1895{
1896 EUIGroup group;
1897 if( app.GetGameStarted() )
1898 {
1899 // If the game isn't running treat as user 0, otherwise map index directly from pad
1900 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
1901 else group = eUIGroup_Fullscreen;
1902 }
1903 else
1904 {
1905 group = eUIGroup_Fullscreen;
1906 }
1907 return m_groups[(int)group]->IsSceneInStack(eScene);
1908}
1909
1910bool UIController::GetMenuDisplayed(int iPad)
1911{
1912 return m_bMenuDisplayed[iPad];
1913}
1914
1915void UIController::SetMenuDisplayed(int iPad,bool bVal)
1916{
1917 if(bVal)
1918 {
1919 if(iPad==XUSER_INDEX_ANY)
1920 {
1921 for(int i=0;i<XUSER_MAX_COUNT;i++)
1922 {
1923 InputManager.SetMenuDisplayed(i,true);
1924 m_bMenuDisplayed[i]=true;
1925 // 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.
1926 m_bMenuToBeClosed[i]=false;
1927 }
1928 }
1929 else
1930 {
1931 InputManager.SetMenuDisplayed(iPad,true);
1932 m_bMenuDisplayed[iPad]=true;
1933 // 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.
1934 m_bMenuToBeClosed[iPad]=false;
1935 }
1936 }
1937 else
1938 {
1939 if(iPad==XUSER_INDEX_ANY)
1940 {
1941 for(int i=0;i<XUSER_MAX_COUNT;i++)
1942 {
1943 m_bMenuToBeClosed[i]=true;
1944 m_iCountDown[i]=10;
1945 }
1946 }
1947 else
1948 {
1949 m_bMenuToBeClosed[iPad]=true;
1950 m_iCountDown[iPad]=10;
1951
1952#ifdef _DURANGO
1953 // 4J-JEV: When in-game, allow player to toggle the 'Pause' and 'IngameInfo' menus via Kinnect.
1954 if (Minecraft::GetInstance()->running)
1955 InputManager.SetEnabledGtcButtons(_360_GTC_MENU | _360_GTC_PAUSE | _360_GTC_VIEW);
1956#endif
1957 }
1958 }
1959}
1960
1961void UIController::CheckMenuDisplayed()
1962{
1963 for(int iPad=0;iPad<XUSER_MAX_COUNT;iPad++)
1964 {
1965 if(m_bMenuToBeClosed[iPad])
1966 {
1967 if(m_iCountDown[iPad]!=0)
1968 {
1969 m_iCountDown[iPad]--;
1970 }
1971 else
1972 {
1973 m_bMenuToBeClosed[iPad]=false;
1974 m_bMenuDisplayed[iPad]=false;
1975 InputManager.SetMenuDisplayed(iPad,false);
1976 }
1977
1978 }
1979 }
1980}
1981
1982void UIController::SetTooltipText( unsigned int iPad, unsigned int tooltip, int iTextID )
1983{
1984 EUIGroup group;
1985 if( app.GetGameStarted() )
1986 {
1987 // If the game isn't running treat as user 0, otherwise map index directly from pad
1988 if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
1989 else group = eUIGroup_Fullscreen;
1990 }
1991 else
1992 {
1993 group = eUIGroup_Fullscreen;
1994 }
1995 if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->SetTooltipText(tooltip, iTextID);
1996}
1997
1998void UIController::SetEnableTooltips( unsigned int iPad, BOOL bVal )
1999{
2000 EUIGroup group;
2001 if( app.GetGameStarted() )
2002 {
2003 // If the game isn't running treat as user 0, otherwise map index directly from pad
2004 if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
2005 else group = eUIGroup_Fullscreen;
2006 }
2007 else
2008 {
2009 group = eUIGroup_Fullscreen;
2010 }
2011 if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->SetEnableTooltips(bVal);
2012}
2013
2014void UIController::ShowTooltip( unsigned int iPad, unsigned int tooltip, bool show )
2015{
2016 EUIGroup group;
2017 if( app.GetGameStarted() )
2018 {
2019 // If the game isn't running treat as user 0, otherwise map index directly from pad
2020 if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
2021 else group = eUIGroup_Fullscreen;
2022 }
2023 else
2024 {
2025 group = eUIGroup_Fullscreen;
2026 }
2027 if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->ShowTooltip(tooltip,show);
2028}
2029
2030void UIController::SetTooltips( unsigned int iPad, int iA, int iB, int iX, int iY, int iLT, int iRT, int iLB, int iRB, int iLS, int iRS, int iBack, bool forceUpdate)
2031{
2032 EUIGroup group;
2033
2034 // 4J-PB - strip out any that are not applicable on the platform
2035#ifndef _XBOX
2036 if(iX==IDS_TOOLTIPS_SELECTDEVICE) iX=-1;
2037 if(iX==IDS_TOOLTIPS_CHANGEDEVICE) iX=-1;
2038
2039#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__)
2040 if(iY==IDS_TOOLTIPS_VIEW_GAMERCARD) iY=-1;
2041 if(iY==IDS_TOOLTIPS_VIEW_GAMERPROFILE) iY=-1;
2042
2043#endif
2044#endif
2045
2046 if( app.GetGameStarted() )
2047 {
2048 // If the game isn't running treat as user 0, otherwise map index directly from pad
2049 if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
2050 else group = eUIGroup_Fullscreen;
2051 }
2052 else
2053 {
2054 group = eUIGroup_Fullscreen;
2055 }
2056 if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->SetTooltips(iA, iB, iX, iY, iLT, iRT, iLB, iRB, iLS, iRS, iBack, forceUpdate);
2057}
2058
2059void UIController::EnableTooltip( unsigned int iPad, unsigned int tooltip, bool enable )
2060{
2061 EUIGroup group;
2062 if( app.GetGameStarted() )
2063 {
2064 // If the game isn't running treat as user 0, otherwise map index directly from pad
2065 if( ( iPad != 255 ) ) group = (EUIGroup)(iPad+1);
2066 else group = eUIGroup_Fullscreen;
2067 }
2068 else
2069 {
2070 group = eUIGroup_Fullscreen;
2071 }
2072 if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->EnableTooltip(tooltip,enable);
2073}
2074
2075void UIController::RefreshTooltips(unsigned int iPad)
2076{
2077 app.DebugPrintf(app.USER_SR, "UIController::RefreshTooltips is not implemented\n");
2078}
2079
2080void UIController::AnimateKeyPress(int iPad, int iAction, bool bRepeat, bool bPressed, bool bReleased)
2081{
2082 EUIGroup group;
2083 if(bPressed==false)
2084 {
2085 // only animating button press
2086 return;
2087 }
2088 if( app.GetGameStarted() )
2089 {
2090 // If the game isn't running treat as user 0, otherwise map index directly from pad
2091 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
2092 else group = eUIGroup_Fullscreen;
2093 }
2094 else
2095 {
2096 group = eUIGroup_Fullscreen;
2097 }
2098 bool handled = false;
2099 if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->handleInput(iPad, iAction, bRepeat, bPressed, bReleased, handled);
2100}
2101
2102void UIController::OverrideSFX(int iPad, int iAction,bool bVal)
2103{
2104 EUIGroup group;
2105
2106 if( app.GetGameStarted() )
2107 {
2108 // If the game isn't running treat as user 0, otherwise map index directly from pad
2109 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
2110 else group = eUIGroup_Fullscreen;
2111 }
2112 else
2113 {
2114 group = eUIGroup_Fullscreen;
2115 }
2116 bool handled = false;
2117 if(m_groups[(int)group]->getTooltips()) m_groups[(int)group]->getTooltips()->overrideSFX(iPad, iAction,bVal);
2118}
2119
2120void UIController::PlayUISFX(ESoundEffect eSound)
2121{
2122 __uint64 time = System::currentTimeMillis();
2123
2124 // Don't play multiple SFX on the same tick
2125 // (prevents horrible sounds when programmatically setting multiple checkboxes)
2126 if (time - m_lastUiSfx < 10) { return; }
2127 m_lastUiSfx = time;
2128
2129 Minecraft::GetInstance()->soundEngine->playUI(eSound,1.0f,1.0f);
2130}
2131
2132void UIController::DisplayGamertag(unsigned int iPad, bool show)
2133{
2134 // The host decides whether these are on or off
2135 if( app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_DisplaySplitscreenGamertags) == 0)
2136 {
2137 show = false;
2138 }
2139 EUIGroup group = (EUIGroup)(iPad+1);
2140 if(m_groups[(int)group]->getHUD()) m_groups[(int)group]->getHUD()->ShowDisplayName(show);
2141
2142 // Update TutorialPopup in Splitscreen if no container is displayed (to make sure the Popup does not overlap with the Gamertag!)
2143 if(app.GetLocalPlayerCount() > 1 && m_groups[(int)group]->getTutorialPopup() && !m_groups[(int)group]->IsContainerMenuDisplayed())
2144 {
2145 m_groups[(int)group]->getTutorialPopup()->UpdateTutorialPopup();
2146 }
2147}
2148
2149void UIController::SetSelectedItem(unsigned int iPad, const wstring &name)
2150{
2151 EUIGroup group;
2152
2153 if( app.GetGameStarted() )
2154 {
2155 // If the game isn't running treat as user 0, otherwise map index directly from pad
2156 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
2157 else group = eUIGroup_Fullscreen;
2158 }
2159 else
2160 {
2161 group = eUIGroup_Fullscreen;
2162 }
2163 bool handled = false;
2164 if(m_groups[(int)group]->getHUD()) m_groups[(int)group]->getHUD()->SetSelectedLabel(name);
2165}
2166
2167void UIController::UpdateSelectedItemPos(unsigned int iPad)
2168{
2169 app.DebugPrintf(app.USER_SR, "UIController::UpdateSelectedItemPos not implemented\n");
2170}
2171
2172void UIController::HandleDLCMountingComplete()
2173{
2174 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
2175 {
2176 app.DebugPrintf("UIController::HandleDLCMountingComplete - m_groups[%d]\n",i);
2177 m_groups[i]->HandleDLCMountingComplete();
2178 }
2179}
2180
2181void UIController::HandleDLCInstalled(int iPad)
2182{
2183 //app.DebugPrintf(app.USER_SR, "UIController::HandleDLCInstalled not implemented\n");
2184 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
2185 {
2186 m_groups[i]->HandleDLCInstalled();
2187 }
2188}
2189
2190
2191#ifdef _XBOX_ONE
2192void UIController::HandleDLCLicenseChange()
2193{
2194 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
2195 {
2196 app.DebugPrintf("UIController::HandleDLCLicenseChange - m_groups[%d]\n",i);
2197 m_groups[i]->HandleDLCLicenseChange();
2198 }
2199}
2200#endif
2201
2202void UIController::HandleTMSDLCFileRetrieved(int iPad)
2203{
2204 app.DebugPrintf(app.USER_SR, "UIController::HandleTMSDLCFileRetrieved not implemented\n");
2205}
2206
2207void UIController::HandleTMSBanFileRetrieved(int iPad)
2208{
2209 app.DebugPrintf(app.USER_SR, "UIController::HandleTMSBanFileRetrieved not implemented\n");
2210}
2211
2212void UIController::HandleInventoryUpdated(int iPad)
2213{
2214 EUIGroup group = eUIGroup_Fullscreen;
2215 if( app.GetGameStarted() && ( iPad != 255 ) && ( iPad >= 0 ) )
2216 {
2217 group = (EUIGroup)(iPad+1);
2218 }
2219
2220 m_groups[group]->HandleMessage(eUIMessage_InventoryUpdated, NULL);
2221}
2222
2223void UIController::HandleGameTick()
2224{
2225 tickInput();
2226
2227 for(unsigned int i = 0; i < eUIGroup_COUNT; ++i)
2228 {
2229 if(m_groups[i]->getHUD()) m_groups[i]->getHUD()->handleGameTick();
2230 }
2231}
2232
2233void UIController::SetTutorial(int iPad, Tutorial *tutorial)
2234{
2235 EUIGroup group;
2236 if( app.GetGameStarted() )
2237 {
2238 // If the game isn't running treat as user 0, otherwise map index directly from pad
2239 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
2240 else group = eUIGroup_Fullscreen;
2241 }
2242 else
2243 {
2244 group = eUIGroup_Fullscreen;
2245 }
2246 if(m_groups[(int)group]->getTutorialPopup()) m_groups[(int)group]->getTutorialPopup()->SetTutorial(tutorial);
2247}
2248
2249void UIController::SetTutorialDescription(int iPad, TutorialPopupInfo *info)
2250{
2251 EUIGroup group;
2252 if( app.GetGameStarted() )
2253 {
2254 // If the game isn't running treat as user 0, otherwise map index directly from pad
2255 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
2256 else group = eUIGroup_Fullscreen;
2257 }
2258 else
2259 {
2260 group = eUIGroup_Fullscreen;
2261 }
2262
2263 if(m_groups[(int)group]->getTutorialPopup())
2264 {
2265 // tutorial popup needs to know if a container menu is being displayed
2266 m_groups[(int)group]->getTutorialPopup()->SetContainerMenuVisible(m_groups[(int)group]->IsContainerMenuDisplayed());
2267 m_groups[(int)group]->getTutorialPopup()->SetTutorialDescription(info);
2268 }
2269}
2270
2271#ifndef _XBOX
2272void UIController::RemoveInteractSceneReference(int iPad, UIScene *scene)
2273{
2274 EUIGroup group;
2275 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
2276 else group = eUIGroup_Fullscreen;
2277 if(m_groups[(int)group]->getTutorialPopup()) m_groups[(int)group]->getTutorialPopup()->RemoveInteractSceneReference(scene);
2278}
2279#endif
2280
2281void UIController::SetTutorialVisible(int iPad, bool visible)
2282{
2283 EUIGroup group;
2284 if( app.GetGameStarted() )
2285 {
2286 // If the game isn't running treat as user 0, otherwise map index directly from pad
2287 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
2288 else group = eUIGroup_Fullscreen;
2289 }
2290 else
2291 {
2292 group = eUIGroup_Fullscreen;
2293 }
2294 if(m_groups[(int)group]->getTutorialPopup()) m_groups[(int)group]->getTutorialPopup()->SetVisible(visible);
2295}
2296
2297bool UIController::IsTutorialVisible(int iPad)
2298{
2299 EUIGroup group;
2300 if( app.GetGameStarted() )
2301 {
2302 // If the game isn't running treat as user 0, otherwise map index directly from pad
2303 if( ( iPad != 255 ) && ( iPad >= 0 ) ) group = (EUIGroup)(iPad+1);
2304 else group = eUIGroup_Fullscreen;
2305 }
2306 else
2307 {
2308 group = eUIGroup_Fullscreen;
2309 }
2310 bool visible = false;
2311 if(m_groups[(int)group]->getTutorialPopup()) visible = m_groups[(int)group]->getTutorialPopup()->IsVisible();
2312 return visible;
2313}
2314
2315void UIController::UpdatePlayerBasePositions()
2316{
2317 Minecraft *pMinecraft = Minecraft::GetInstance();
2318
2319 for( BYTE idx = 0; idx < XUSER_MAX_COUNT; ++idx)
2320 {
2321 if(pMinecraft->localplayers[idx] != NULL)
2322 {
2323 if(pMinecraft->localplayers[idx]->m_iScreenSection==C4JRender::VIEWPORT_TYPE_FULLSCREEN)
2324 {
2325 DisplayGamertag(idx,false);
2326 }
2327 else
2328 {
2329 DisplayGamertag(idx,true);
2330 }
2331 m_groups[idx+1]->SetViewportType((C4JRender::eViewportType)pMinecraft->localplayers[idx]->m_iScreenSection);
2332 }
2333 else
2334 {
2335 // 4J Stu - This is a legacy thing from our XUI implementation that we don't need
2336 // Changing the viewport to fullscreen for users that no longer exist is SLOW
2337 // This should probably be on all platforms, but I don't have time to test them all just now!
2338#ifndef __ORBIS__
2339 m_groups[idx+1]->SetViewportType(C4JRender::VIEWPORT_TYPE_FULLSCREEN);
2340#endif
2341 DisplayGamertag(idx,false);
2342 }
2343 }
2344}
2345
2346void UIController::SetEmptyQuadrantLogo(int iSection)
2347{
2348 // 4J Stu - We shouldn't need to implement this
2349}
2350
2351void UIController::HideAllGameUIElements()
2352{
2353 // 4J Stu - We might not need to implement this
2354 app.DebugPrintf(app.USER_SR, "UIController::HideAllGameUIElements not implemented\n");
2355}
2356
2357void UIController::ShowOtherPlayersBaseScene(unsigned int iPad, bool show)
2358{
2359 // 4J Stu - We shouldn't need to implement this
2360}
2361
2362void UIController::ShowTrialTimer(bool show)
2363{
2364 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showTrialTimer(show);
2365}
2366
2367void UIController::SetTrialTimerLimitSecs(unsigned int uiSeconds)
2368{
2369 UIController::m_dwTrialTimerLimitSecs = uiSeconds;
2370}
2371
2372void UIController::UpdateTrialTimer(unsigned int iPad)
2373{
2374 WCHAR wcTime[20];
2375
2376 DWORD dwTimeTicks=(DWORD)app.getTrialTimer();
2377
2378 if(dwTimeTicks>m_dwTrialTimerLimitSecs)
2379 {
2380 dwTimeTicks=m_dwTrialTimerLimitSecs;
2381 }
2382
2383 dwTimeTicks=m_dwTrialTimerLimitSecs-dwTimeTicks;
2384
2385#ifndef _CONTENT_PACKAGE
2386 if(true)
2387#else
2388 // display the time - only if there's less than 3 minutes
2389 if(dwTimeTicks<180)
2390#endif
2391 {
2392 int iMins=dwTimeTicks/60;
2393 int iSeconds=dwTimeTicks%60;
2394 swprintf( wcTime, 20, L"%d:%02d",iMins,iSeconds);
2395 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->setTrialTimer(wcTime);
2396 }
2397 else
2398 {
2399 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->setTrialTimer(L"");
2400 }
2401
2402 // are we out of time?
2403 if((dwTimeTicks==0))
2404 {
2405 // Trial over
2406 // bring up the pause menu to stop the trial over message box being called again?
2407 if(!ui.GetMenuDisplayed( iPad ) )
2408 {
2409 ui.NavigateToScene(iPad, eUIScene_PauseMenu, NULL, eUILayer_Scene);
2410
2411 app.SetAction(iPad,eAppAction_TrialOver);
2412 }
2413 }
2414}
2415
2416void UIController::ReduceTrialTimerValue()
2417{
2418 DWORD dwTimeTicks=(int)app.getTrialTimer();
2419
2420 if(dwTimeTicks>m_dwTrialTimerLimitSecs)
2421 {
2422 dwTimeTicks=m_dwTrialTimerLimitSecs;
2423 }
2424
2425 m_dwTrialTimerLimitSecs-=dwTimeTicks;
2426}
2427
2428void UIController::ShowAutosaveCountdownTimer(bool show)
2429{
2430 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showTrialTimer(show);
2431}
2432
2433void UIController::UpdateAutosaveCountdownTimer(unsigned int uiSeconds)
2434{
2435#if !(defined(_XBOX_ONE) || defined(__ORBIS__))
2436 WCHAR wcAutosaveCountdown[100];
2437 swprintf( wcAutosaveCountdown, 100, app.GetString(IDS_AUTOSAVE_COUNTDOWN),uiSeconds);
2438 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->setTrialTimer(wcAutosaveCountdown);
2439#endif
2440}
2441
2442void UIController::ShowSavingMessage(unsigned int iPad, C4JStorage::ESavingMessage eVal)
2443{
2444 bool show = false;
2445 switch(eVal)
2446 {
2447 case C4JStorage::ESavingMessage_None:
2448 show = false;
2449 break;
2450 case C4JStorage::ESavingMessage_Short:
2451 case C4JStorage::ESavingMessage_Long:
2452 show = true;
2453 break;
2454 }
2455 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showSaveIcon(show);
2456}
2457
2458void UIController::ShowPlayerDisplayname(bool show)
2459{
2460 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showPlayerDisplayName(show);
2461}
2462
2463void UIController::SetWinUserIndex(unsigned int iPad)
2464{
2465 m_winUserIndex = iPad;
2466}
2467
2468unsigned int UIController::GetWinUserIndex()
2469{
2470 return m_winUserIndex;
2471}
2472
2473void UIController::ShowUIDebugConsole(bool show)
2474{
2475#ifndef _CONTENT_PACKAGE
2476
2477 if(show)
2478 {
2479 m_uiDebugConsole = (UIComponent_DebugUIConsole *)m_groups[eUIGroup_Fullscreen]->addComponent(0, eUIComponent_DebugUIConsole, eUILayer_Debug);
2480 }
2481 else
2482 {
2483 m_groups[eUIGroup_Fullscreen]->removeComponent(eUIComponent_DebugUIConsole, eUILayer_Debug);
2484 m_uiDebugConsole = NULL;
2485 }
2486#endif
2487}
2488
2489void UIController::ShowUIDebugMarketingGuide(bool show)
2490{
2491#ifndef _CONTENT_PACKAGE
2492
2493 if(show)
2494 {
2495 m_uiDebugMarketingGuide = (UIComponent_DebugUIMarketingGuide *)m_groups[eUIGroup_Fullscreen]->addComponent(0, eUIComponent_DebugUIMarketingGuide, eUILayer_Debug);
2496 }
2497 else
2498 {
2499 m_groups[eUIGroup_Fullscreen]->removeComponent(eUIComponent_DebugUIMarketingGuide, eUILayer_Debug);
2500 m_uiDebugMarketingGuide = NULL;
2501 }
2502#endif
2503}
2504
2505void UIController::logDebugString(const string &text)
2506{
2507 if(m_uiDebugConsole) m_uiDebugConsole->addText(text);
2508}
2509
2510bool UIController::PressStartPlaying(unsigned int iPad)
2511{
2512 return m_iPressStartQuadrantsMask&(1<<iPad)?true:false;
2513}
2514
2515void UIController::ShowPressStart(unsigned int iPad)
2516{
2517 m_iPressStartQuadrantsMask|=1<<iPad;
2518 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showPressStart(iPad, true);
2519}
2520
2521void UIController::HidePressStart()
2522{
2523 ClearPressStart();
2524 if(m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()) m_groups[(int)eUIGroup_Fullscreen]->getPressStartToPlay()->showPressStart(0, false);
2525}
2526
2527void UIController::ClearPressStart()
2528{
2529 m_iPressStartQuadrantsMask = 0;
2530}
2531
2532C4JStorage::EMessageResult UIController::RequestAlertMessage(UINT uiTitle, UINT uiText, UINT *uiOptionA,UINT uiOptionC, DWORD dwPad, int( *Func)(LPVOID,int,const C4JStorage::EMessageResult),LPVOID lpParam, WCHAR *pwchFormatString)
2533{
2534 return RequestMessageBox(uiTitle, uiText, uiOptionA, uiOptionC, dwPad, Func, lpParam, pwchFormatString, 0, false);
2535}
2536
2537C4JStorage::EMessageResult UIController::RequestErrorMessage(UINT uiTitle, UINT uiText, UINT *uiOptionA,UINT uiOptionC, DWORD dwPad, int( *Func)(LPVOID,int,const C4JStorage::EMessageResult),LPVOID lpParam, WCHAR *pwchFormatString)
2538{
2539 return RequestMessageBox(uiTitle, uiText, uiOptionA, uiOptionC, dwPad, Func, lpParam, pwchFormatString, 0, true);
2540}
2541
2542C4JStorage::EMessageResult UIController::RequestMessageBox(UINT uiTitle, UINT uiText, UINT *uiOptionA,UINT uiOptionC, DWORD dwPad,
2543 int( *Func)(LPVOID,int,const C4JStorage::EMessageResult),LPVOID lpParam, WCHAR *pwchFormatString,DWORD dwFocusButton, bool bIsError)
2544
2545{
2546 MessageBoxInfo param;
2547 param.uiTitle = uiTitle;
2548 param.uiText = uiText;
2549 param.uiOptionA = uiOptionA;
2550 param.uiOptionC = uiOptionC;
2551 param.dwPad = dwPad;
2552 param.Func = Func;
2553 param.lpParam = lpParam;
2554 param.pwchFormatString = pwchFormatString;
2555 param.dwFocusButton = dwFocusButton;
2556
2557 EUILayer layer = bIsError?eUILayer_Error:eUILayer_Alert;
2558
2559 bool completed = false;
2560 if(ui.IsReloadingSkin())
2561 {
2562 // Queue this message box
2563 QueuedMessageBoxData *queuedData = new QueuedMessageBoxData();
2564 queuedData->info = param;
2565 queuedData->info.uiOptionA = new UINT[param.uiOptionC];
2566 memcpy(queuedData->info.uiOptionA, param.uiOptionA, param.uiOptionC * sizeof(UINT));
2567 queuedData->iPad = dwPad;
2568 queuedData->layer = eUILayer_Error; // Ensures that these don't get wiped out by a CloseAllScenes call
2569 m_queuedMessageBoxData.push_back(queuedData);
2570 }
2571 else
2572 {
2573 completed = ui.NavigateToScene(dwPad, eUIScene_MessageBox, ¶m, layer, eUIGroup_Fullscreen);
2574 }
2575
2576 if( completed )
2577 {
2578 // 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;
2579 return C4JStorage::EMessage_Pending;
2580 }
2581 else
2582 {
2583 return C4JStorage::EMessage_Busy;
2584 }
2585}
2586
2587C4JStorage::EMessageResult UIController::RequestUGCMessageBox(UINT title/* = -1 */, UINT message/* = -1 */, int iPad/* = -1*/, int( *Func)(LPVOID,int,const C4JStorage::EMessageResult)/* = NULL*/, LPVOID lpParam/* = NULL*/)
2588{
2589 // Default title / messages
2590 if (title == -1)
2591 {
2592 title = IDS_FAILED_TO_CREATE_GAME_TITLE;
2593 }
2594
2595 if (message == -1)
2596 {
2597 message = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE;
2598 }
2599
2600 // Default pad to primary player
2601 if (iPad == -1) iPad = ProfileManager.GetPrimaryPad();
2602
2603#ifdef __ORBIS__
2604 // Show the vague UGC system message in addition to our message
2605 ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_UGC_RESTRICTION, iPad );
2606 return C4JStorage::EMessage_ResultAccept;
2607#elif defined(__PSVITA__)
2608 ProfileManager.ShowSystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, iPad );
2609 UINT uiIDA[1];
2610 uiIDA[0]=IDS_CONFIRM_OK;
2611 return ui.RequestAlertMessage( title, IDS_CHAT_RESTRICTION_UGC, uiIDA, 1, iPad, Func, lpParam);
2612#else
2613 UINT uiIDA[1];
2614 uiIDA[0]=IDS_CONFIRM_OK;
2615 return ui.RequestAlertMessage( title, message, uiIDA, 1, iPad, Func, lpParam);
2616#endif
2617}
2618
2619C4JStorage::EMessageResult UIController::RequestContentRestrictedMessageBox(UINT title/* = -1 */, UINT message/* = -1 */, int iPad/* = -1*/, int( *Func)(LPVOID,int,const C4JStorage::EMessageResult)/* = NULL*/, LPVOID lpParam/* = NULL*/)
2620{
2621 // Default title / messages
2622 if (title == -1)
2623 {
2624 title = IDS_FAILED_TO_CREATE_GAME_TITLE;
2625 }
2626
2627 if (message == -1)
2628 {
2629#if defined(_XBOX_ONE) || defined(_WINDOWS64)
2630 // IDS_CONTENT_RESTRICTION doesn't exist on XB1
2631 message = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_CREATE;
2632#else
2633 message = IDS_CONTENT_RESTRICTION;
2634#endif
2635 }
2636
2637 // Default pad to primary player
2638 if (iPad == -1) iPad = ProfileManager.GetPrimaryPad();
2639
2640#ifdef __ORBIS__
2641 // Show the vague UGC system message in addition to our message
2642 ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_UGC_RESTRICTION, iPad );
2643 return C4JStorage::EMessage_ResultAccept;
2644#elif defined(__PSVITA__)
2645 ProfileManager.ShowSystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_AGE_RESTRICTION, iPad );
2646 return C4JStorage::EMessage_ResultAccept;
2647#else
2648 UINT uiIDA[1];
2649 uiIDA[0]=IDS_CONFIRM_OK;
2650 return ui.RequestAlertMessage( title, message, uiIDA, 1, iPad, Func, lpParam);
2651#endif
2652}
2653
2654void UIController::setFontCachingCalculationBuffer(int length)
2655{
2656 /* 4J-JEV: As described in an email from Sean.
2657 If your `optional_temp_buffer` is NULL, Iggy will allocate the temp
2658 buffer on the stack during Iggy draw calls. The size of the buffer it
2659 will allocate is 16 bytes times `max_chars` in 32-bit, and 24 bytes
2660 times `max_chars` in 64-bit. If the stack of the thread making the
2661 draw call is not large enough, Iggy will crash or otherwise behave
2662 incorrectly.
2663 */
2664#if defined __ORBIS__ || defined _DURANGO || defined _WIN64
2665 static const int CHAR_SIZE = 24;
2666#else
2667 static const int CHAR_SIZE = 16;
2668#endif
2669
2670 if (m_tempBuffer != NULL) delete [] m_tempBuffer;
2671 if (length<0)
2672 {
2673 if (m_defaultBuffer == NULL) m_defaultBuffer = new char[CHAR_SIZE*5000];
2674 IggySetFontCachingCalculationBuffer(5000, m_defaultBuffer, CHAR_SIZE*5000);
2675 }
2676 else
2677 {
2678 m_tempBuffer = new char[CHAR_SIZE*length];
2679 IggySetFontCachingCalculationBuffer(length, m_tempBuffer, CHAR_SIZE*length);
2680 }
2681}
2682
2683// Returns the first scene of given type if it exists, NULL otherwise
2684UIScene *UIController::FindScene(EUIScene sceneType)
2685{
2686 UIScene *pScene = NULL;
2687
2688 for (int i = 0; i < eUIGroup_COUNT; i++)
2689 {
2690 pScene = m_groups[i]->FindScene(sceneType);
2691#ifdef __PS3__
2692 if (pScene != NULL) return pScene;
2693#else
2694 if (pScene != nullptr) return pScene;
2695#endif
2696 }
2697
2698 return pScene;
2699}
2700
2701#ifdef __PSVITA__
2702
2703void UIController::TouchBoxAdd(UIControl *pControl,UIScene *pUIScene)
2704{
2705 EUIGroup eUIGroup=pUIScene->GetParentLayerGroup();
2706 EUILayer eUILayer=pUIScene->GetParentLayer()->m_iLayer;
2707 EUIScene eUIscene=pUIScene->getSceneType();
2708
2709 TouchBoxAdd(pControl,eUIGroup,eUILayer,eUIscene, pUIScene->GetMainPanel());
2710}
2711
2712void UIController::TouchBoxAdd(UIControl *pControl,EUIGroup eUIGroup,EUILayer eUILayer,EUIScene eUIscene, UIControl *pMainPanelControl)
2713{
2714 UIELEMENT *puiElement = new UIELEMENT;
2715 puiElement->pControl = pControl;
2716
2717 S32 iControlWidth = pControl->getWidth();
2718 S32 iControlHeight = pControl->getHeight();
2719 S32 iMainPanelOffsetX = 0;
2720 S32 iMainPanelOffsetY= 0;
2721
2722 // 4J-TomK add main panel offset if controls do not live in the root scene
2723 if(pMainPanelControl)
2724 {
2725 iMainPanelOffsetX = pMainPanelControl->getXPos();
2726 iMainPanelOffsetY = pMainPanelControl->getYPos();
2727 }
2728
2729 // 4J-TomK override control width / height where needed
2730 if(puiElement->pControl->getControlType() == UIControl::eSlider)
2731 {
2732 // Sliders are never scaled but masked, so we have to get the real width from AS
2733 UIControl_Slider *pSlider = (UIControl_Slider *)puiElement->pControl;
2734 iControlWidth = pSlider->GetRealWidth();
2735 }
2736 else if(puiElement->pControl->getControlType() == UIControl::eTexturePackList)
2737 {
2738 // 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.
2739 UIControl_TexturePackList *pTexturePackList = (UIControl_TexturePackList *)puiElement->pControl;
2740 iControlHeight = pTexturePackList->GetRealHeight();
2741 }
2742 else if(puiElement->pControl->getControlType() == UIControl::eDynamicLabel)
2743 {
2744 // The height and width of this control changes per how to play page
2745 UIControl_DynamicLabel *pDynamicLabel = (UIControl_DynamicLabel *)puiElement->pControl;
2746 iControlWidth = pDynamicLabel->GetRealWidth();
2747 iControlHeight = pDynamicLabel->GetRealHeight();
2748 }
2749 else if(puiElement->pControl->getControlType() == UIControl::eHTMLLabel)
2750 {
2751 // The height and width of this control changes per how to play page
2752 UIControl_HTMLLabel *pHtmlLabel = (UIControl_HTMLLabel *)puiElement->pControl;
2753 iControlWidth = pHtmlLabel->GetRealWidth();
2754 iControlHeight = pHtmlLabel->GetRealHeight();
2755 }
2756
2757 puiElement->x1=(S32)((float)pControl->getXPos() + (float)iMainPanelOffsetX);
2758 puiElement->y1=(S32)((float)pControl->getYPos() + (float)iMainPanelOffsetY);
2759 puiElement->x2=(S32)(((float)pControl->getXPos() + (float)iControlWidth + (float)iMainPanelOffsetX));
2760 puiElement->y2=(S32)(((float)pControl->getYPos() + (float)iControlHeight + (float)iMainPanelOffsetY));
2761
2762 if(puiElement->pControl->getControlType() == UIControl::eNoControl)
2763 {
2764 app.DebugPrintf("NO CONTROL!");
2765 }
2766
2767 if(puiElement->x1 == puiElement->x2 || puiElement->y1 == puiElement->y2)
2768 {
2769 app.DebugPrintf("NOT adding touchbox %d,%d,%d,%d\n",puiElement->x1,puiElement->y1,puiElement->x2,puiElement->y2);
2770 }
2771 else
2772 {
2773 app.DebugPrintf("Adding touchbox %d,%d,%d,%d\n",puiElement->x1,puiElement->y1,puiElement->x2,puiElement->y2);
2774 m_TouchBoxes[eUIGroup][eUILayer][eUIscene].push_back(puiElement);
2775 }
2776}
2777
2778void UIController::TouchBoxRebuild(UIScene *pUIScene)
2779{
2780 EUIGroup eUIGroup=pUIScene->GetParentLayerGroup();
2781 EUILayer eUILayer=pUIScene->GetParentLayer()->m_iLayer;
2782 EUIScene eUIscene=pUIScene->getSceneType();
2783
2784 // if we delete an element, it's possible that the scene has re-arranged all the elements, so we need to rebuild the boxes
2785 ui.TouchBoxesClear(pUIScene);
2786
2787 // rebuild boxes
2788 AUTO_VAR(itEnd, pUIScene->GetControls()->end());
2789 for (AUTO_VAR(it, pUIScene->GetControls()->begin()); it != itEnd; it++)
2790 {
2791 UIControl *control=(UIControl *)*it;
2792
2793 if(control->getControlType() == UIControl::eButton ||
2794 control->getControlType() == UIControl::eSlider ||
2795 control->getControlType() == UIControl::eCheckBox ||
2796 control->getControlType() == UIControl::eTexturePackList ||
2797 control->getControlType() == UIControl::eButtonList ||
2798 control->getControlType() == UIControl::eTextInput ||
2799 control->getControlType() == UIControl::eDynamicLabel ||
2800 control->getControlType() == UIControl::eHTMLLabel ||
2801 control->getControlType() == UIControl::eLeaderboardList ||
2802 control->getControlType() == UIControl::eTouchControl)
2803 {
2804 if(control->getVisible())
2805 {
2806 // 4J-TomK update the control (it might have been moved by flash / AS)
2807 control->UpdateControl();
2808
2809 ui.TouchBoxAdd(control,eUIGroup,eUILayer,eUIscene, pUIScene->GetMainPanel());
2810 }
2811 }
2812 }
2813}
2814
2815void UIController::TouchBoxesClear(UIScene *pUIScene)
2816{
2817 EUIGroup eUIGroup=pUIScene->GetParentLayerGroup();
2818 EUILayer eUILayer=pUIScene->GetParentLayer()->m_iLayer;
2819 EUIScene eUIscene=pUIScene->getSceneType();
2820
2821 AUTO_VAR(itEnd, m_TouchBoxes[eUIGroup][eUILayer][eUIscene].end());
2822 for (AUTO_VAR(it, m_TouchBoxes[eUIGroup][eUILayer][eUIscene].begin()); it != itEnd; it++)
2823 {
2824 UIELEMENT *element=(UIELEMENT *)*it;
2825 delete element;
2826 }
2827 m_TouchBoxes[eUIGroup][eUILayer][eUIscene].clear();
2828}
2829
2830bool UIController::TouchBoxHit(UIScene *pUIScene,S32 x, S32 y)
2831{
2832 EUIGroup eUIGroup=pUIScene->GetParentLayerGroup();
2833 EUILayer eUILayer=pUIScene->GetParentLayer()->m_iLayer;
2834 EUIScene eUIscene=pUIScene->getSceneType();
2835
2836 // 4J-TomK let's do the transformation from touch resolution to screen resolution here, so our touchbox values always are in screen resolution!
2837 x *= (m_fScreenWidth/1920.0f);
2838 y *= (m_fScreenHeight/1080.0f);
2839
2840 if(m_TouchBoxes[eUIGroup][eUILayer][eUIscene].size()>0)
2841 {
2842 AUTO_VAR(itEnd, m_TouchBoxes[eUIGroup][eUILayer][eUIscene].end());
2843 for (AUTO_VAR(it, m_TouchBoxes[eUIGroup][eUILayer][eUIscene].begin()); it != itEnd; it++)
2844 {
2845 UIELEMENT *element=(UIELEMENT *)*it;
2846 if(element->pControl->getHidden() == false && element->pControl->getVisible()) // ignore removed controls
2847 {
2848 if((x>=element->x1) &&(x<=element->x2) && (y>=element->y1) && (y<=element->y2))
2849 {
2850 if(!m_bTouchscreenPressed)
2851 {
2852 app.DebugPrintf("SET m_ActiveUIElement (Layer: %i) at x = %i y = %i\n", (int)eUILayer, (int)x, (int)y);
2853 m_ActiveUIElement = element;
2854 }
2855 // remember the currently highlighted element
2856 m_HighlightedUIElement = element;
2857
2858 return true;
2859 }
2860 }
2861 }
2862 }
2863
2864 //app.DebugPrintf("MISS at x = %i y = %i\n", (int)x, (int)y);
2865 m_HighlightedUIElement = NULL;
2866 return false;
2867}
2868
2869//
2870// Handle Touch Input
2871//
2872void UIController::HandleTouchInput(unsigned int iPad, unsigned int key, bool bPressed, bool bRepeat, bool bReleased)
2873{
2874 // no input? no handling!
2875 if(!bPressed && !bRepeat && !bReleased)
2876 {
2877 // override for instand repeat without delay!
2878 if(m_bTouchscreenPressed && m_ActiveUIElement && (
2879 m_ActiveUIElement->pControl->getControlType() == UIControl::eSlider ||
2880 m_ActiveUIElement->pControl->getControlType() == UIControl::eButtonList ||
2881 m_ActiveUIElement->pControl->getControlType() == UIControl::eTexturePackList ||
2882 m_ActiveUIElement->pControl->getControlType() == UIControl::eDynamicLabel ||
2883 m_ActiveUIElement->pControl->getControlType() == UIControl::eHTMLLabel ||
2884 m_ActiveUIElement->pControl->getControlType() == UIControl::eLeaderboardList ||
2885 m_ActiveUIElement->pControl->getControlType() == UIControl::eTouchControl))
2886 bRepeat = true; // the above controls need to be controllable without having the finger over them
2887 else
2888 return;
2889 }
2890
2891 SceTouchData* pTouchData = InputManager.GetTouchPadData(iPad,false);
2892 S32 x = pTouchData->report[0].x * (m_fScreenWidth/1920.0f);
2893 S32 y = pTouchData->report[0].y * (m_fScreenHeight/1080.0f);
2894
2895 if(bPressed && !bRepeat && !bReleased) // PRESSED HANDLING
2896 {
2897 app.DebugPrintf("touch input pressed\n");
2898 switch(m_ActiveUIElement->pControl->getControlType())
2899 {
2900 case UIControl::eButton:
2901 // set focus
2902 UIControl_Button *pButton=(UIControl_Button *)m_ActiveUIElement->pControl;
2903 pButton->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
2904 // override bPressed to false. we only want the button to trigger on touch release!
2905 bPressed = false;
2906 break;
2907 case UIControl::eSlider:
2908 // set focus
2909 UIControl_Slider *pSlider=(UIControl_Slider *)m_ActiveUIElement->pControl;
2910 pSlider->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
2911 break;
2912 case UIControl::eCheckBox:
2913 // set focus
2914 UIControl_CheckBox *pCheckbox=(UIControl_CheckBox *)m_ActiveUIElement->pControl;
2915 pCheckbox->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
2916 // override bPressed. we only want the checkbox to trigger on touch release!
2917 bPressed = false;
2918 break;
2919 case UIControl::eButtonList:
2920 // set focus to list
2921 UIControl_ButtonList *pButtonList=(UIControl_ButtonList *)m_ActiveUIElement->pControl;
2922 //pButtonList->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
2923 // tell list where we tapped it so it can set focus to the correct button
2924 pButtonList->SetTouchFocus((float)x, (float)y, false);
2925 // override bPressed. we only want the ButtonList to trigger on touch release!
2926 bPressed = false;
2927 break;
2928 case UIControl::eTexturePackList:
2929 // set focus to list
2930 UIControl_TexturePackList *pTexturePackList=(UIControl_TexturePackList *)m_ActiveUIElement->pControl;
2931 pTexturePackList->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
2932 // tell list where we tapped it so it can set focus to the correct texture pack
2933 pTexturePackList->SetTouchFocus((float)x - (float)m_ActiveUIElement->x1, (float)y - (float)m_ActiveUIElement->y1, false);
2934 // override bPressed. we only want the TexturePack List to trigger on touch release!
2935 bPressed = false;
2936 break;
2937 case UIControl::eTextInput:
2938 // set focus
2939 UIControl_TextInput *pTextInput=(UIControl_TextInput *)m_ActiveUIElement->pControl;
2940 pTextInput->getParentScene()->SetFocusToElement(m_ActiveUIElement->pControl->getId());
2941 // override bPressed to false. we only want the textinput to trigger on touch release!
2942 bPressed = false;
2943 break;
2944 case UIControl::eDynamicLabel:
2945 // handle dynamic label scrolling
2946 UIControl_DynamicLabel *pDynamicLabel=(UIControl_DynamicLabel *)m_ActiveUIElement->pControl;
2947 pDynamicLabel->TouchScroll(y, true);
2948 // override bPressed to false
2949 bPressed = false;
2950 break;
2951 case UIControl::eHTMLLabel:
2952 // handle dynamic label scrolling
2953 UIControl_HTMLLabel *pHtmlLabel=(UIControl_HTMLLabel *)m_ActiveUIElement->pControl;
2954 pHtmlLabel->TouchScroll(y, true);
2955 // override bPressed to false
2956 bPressed = false;
2957 break;
2958 case UIControl::eLeaderboardList:
2959 // set focus to list
2960 UIControl_LeaderboardList *pLeaderboardList=(UIControl_LeaderboardList *)m_ActiveUIElement->pControl;
2961 // tell list where we tapped it so it can set focus to the correct button
2962 pLeaderboardList->SetTouchFocus((float)x, (float)y, false);
2963 // override bPressed. we only want the ButtonList to trigger on touch release!
2964 bPressed = false;
2965 break;
2966 case UIControl::eTouchControl:
2967 // pass on touch input to relevant parent scene so we can handle it there!
2968 m_ActiveUIElement->pControl->getParentScene()->handleTouchInput(iPad, x, y, m_ActiveUIElement->pControl->getId(), bPressed, bRepeat, bReleased);
2969 // override bPressed to false
2970 bPressed = false;
2971 break;
2972 default:
2973 app.DebugPrintf("PRESSED - UNHANDLED UI ELEMENT\n");
2974 break;
2975 }
2976 }
2977 else if(bRepeat) // REPEAT HANDLING
2978 {
2979 switch(m_ActiveUIElement->pControl->getControlType())
2980 {
2981 case UIControl::eButton:
2982 /* no action */
2983 break;
2984 case UIControl::eSlider:
2985 // handle slider movement
2986 UIControl_Slider *pSlider=(UIControl_Slider *)m_ActiveUIElement->pControl;
2987 float fNewSliderPos = ((float)x - (float)m_ActiveUIElement->x1) / (float)pSlider->GetRealWidth();
2988 pSlider->SetSliderTouchPos(fNewSliderPos);
2989 break;
2990 case UIControl::eCheckBox:
2991 /* no action */
2992 bRepeat = false;
2993 bPressed = false;
2994 break;
2995 case UIControl::eButtonList:
2996 // handle button list scrolling
2997 UIControl_ButtonList *pButtonList=(UIControl_ButtonList *)m_ActiveUIElement->pControl;
2998 pButtonList->SetTouchFocus((float)x, (float)y, true);
2999 break;
3000 case UIControl::eTexturePackList:
3001 // handle texturepack list scrolling
3002 UIControl_TexturePackList *pTexturePackList=(UIControl_TexturePackList *)m_ActiveUIElement->pControl;
3003 pTexturePackList->SetTouchFocus((float)x - (float)m_ActiveUIElement->x1, (float)y - (float)m_ActiveUIElement->y1, true);
3004 break;
3005 case UIControl::eTextInput:
3006 /* no action */
3007 bRepeat = false;
3008 bPressed = false;
3009 break;
3010 case UIControl::eDynamicLabel:
3011 // handle dynamic label scrolling
3012 UIControl_DynamicLabel *pDynamicLabel=(UIControl_DynamicLabel *)m_ActiveUIElement->pControl;
3013 pDynamicLabel->TouchScroll(y, true);
3014 // override bPressed & bRepeat to false
3015 bPressed = false;
3016 bRepeat = false;
3017 break;
3018 case UIControl::eHTMLLabel:
3019 // handle dynamic label scrolling
3020 UIControl_HTMLLabel *pHtmlLabel=(UIControl_HTMLLabel *)m_ActiveUIElement->pControl;
3021 pHtmlLabel->TouchScroll(y, true);
3022 // override bPressed & bRepeat to false
3023 bPressed = false;
3024 bRepeat = false;
3025 break;
3026 case UIControl::eLeaderboardList:
3027 // handle button list scrolling
3028 UIControl_LeaderboardList *pLeaderboardList=(UIControl_LeaderboardList *)m_ActiveUIElement->pControl;
3029 pLeaderboardList->SetTouchFocus((float)x, (float)y, true);
3030 break;
3031 case UIControl::eTouchControl:
3032 // override bPressed to false
3033 bPressed = false;
3034 // pass on touch input to relevant parent scene so we can handle it there!
3035 m_ActiveUIElement->pControl->getParentScene()->handleTouchInput(iPad, x, y, m_ActiveUIElement->pControl->getId(), bPressed, bRepeat, bReleased);
3036 // override bRepeat to false
3037 bRepeat = false;
3038 break;
3039 default:
3040 app.DebugPrintf("REPEAT - UNHANDLED UI ELEMENT\n");
3041 break;
3042 }
3043 }
3044 if(bReleased) // RELEASED HANDLING
3045 {
3046 app.DebugPrintf("touch input released\n");
3047 switch(m_ActiveUIElement->pControl->getControlType())
3048 {
3049 case UIControl::eButton:
3050 // trigger button on release (ONLY if the finger is still on it!)
3051 if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
3052 bPressed = true;
3053 break;
3054 case UIControl::eSlider:
3055 /* no action */
3056 break;
3057 case UIControl::eCheckBox:
3058 // trigger checkbox on release (ONLY if the finger is still on it!)
3059 if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
3060 {
3061 UIControl_CheckBox *pCheckbox=(UIControl_CheckBox *)m_ActiveUIElement->pControl;
3062 if(pCheckbox->IsEnabled()) // only proceed if checkbox is enabled!
3063 pCheckbox->TouchSetCheckbox(!pCheckbox->IsChecked());
3064 }
3065 bReleased = false;
3066 break;
3067 case UIControl::eButtonList:
3068 // trigger buttonlist on release (ONLY if the finger is still on it!)
3069 if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
3070 {
3071 UIControl_ButtonList *pButtonList=(UIControl_ButtonList *)m_ActiveUIElement->pControl;
3072 if(pButtonList->CanTouchTrigger(x,y))
3073 bPressed = true;
3074 }
3075 break;
3076 case UIControl::eTexturePackList:
3077 // trigger texturepack list on release (ONLY if the finger is still on it!)
3078 if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
3079 {
3080 UIControl_TexturePackList *pTexturePackList=(UIControl_TexturePackList *)m_ActiveUIElement->pControl;
3081 if(pTexturePackList->CanTouchTrigger((float)x - (float)m_ActiveUIElement->x1, (float)y - (float)m_ActiveUIElement->y1))
3082 bPressed = true;
3083 }
3084 break;
3085 case UIControl::eTextInput:
3086 // trigger TextInput on release (ONLY if the finger is still on it!)
3087 if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
3088 bPressed = true;
3089 break;
3090 case UIControl::eDynamicLabel:
3091 // handle dynamic label scrolling
3092 UIControl_DynamicLabel *pDynamicLabel=(UIControl_DynamicLabel *)m_ActiveUIElement->pControl;
3093 pDynamicLabel->TouchScroll(y, false);
3094 break;
3095 case UIControl::eHTMLLabel:
3096 // handle dynamic label scrolling
3097 UIControl_HTMLLabel *pHtmlLabel=(UIControl_HTMLLabel *)m_ActiveUIElement->pControl;
3098 pHtmlLabel->TouchScroll(y, false);
3099 break;
3100 case UIControl::eLeaderboardList:
3101 /* no action */
3102 break;
3103 case UIControl::eTouchControl:
3104 // trigger only if touch is released over the same component!
3105 if(m_HighlightedUIElement && m_ActiveUIElement->pControl == m_HighlightedUIElement->pControl)
3106 {
3107 // pass on touch input to relevant parent scene so we can handle it there!
3108 m_ActiveUIElement->pControl->getParentScene()->handleTouchInput(iPad, x, y, m_ActiveUIElement->pControl->getId(), bPressed, bRepeat, bReleased);
3109 }
3110 // override bReleased to false
3111 bReleased = false;
3112 break;
3113 default:
3114 app.DebugPrintf("RELEASED - UNHANDLED UI ELEMENT\n");
3115 break;
3116 }
3117 }
3118
3119 // only proceed if there's input to be handled
3120 if(bPressed || bRepeat || bReleased)
3121 {
3122 SendTouchInput(iPad, key, bPressed, bRepeat, bReleased);
3123 }
3124}
3125
3126void UIController::SendTouchInput(unsigned int iPad, unsigned int key, bool bPressed, bool bRepeat, bool bReleased)
3127{
3128 bool handled = false;
3129
3130 // Send the key to the fullscreen group first
3131 m_groups[(int)eUIGroup_Fullscreen]->handleInput(iPad, key, bRepeat, bPressed, bReleased, handled);
3132 if(!handled)
3133 {
3134 // If it's not been handled yet, then pass the event onto the players specific group
3135 m_groups[(iPad+1)]->handleInput(iPad, key, bRepeat, bPressed, bReleased, handled);
3136 }
3137}
3138
3139
3140#endif