#include "Core.h" #if defined CC_BUILD_WIIU extern "C" { #include "Window.h" #include "Platform.h" #include "Input.h" #include "Event.h" #include "String.h" #include "Funcs.h" #include "Bitmap.h" #include "Errors.h" #include "ExtMath.h" #include "Graphics.h" #include "Launcher.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include } #include static cc_bool launcherMode; static cc_bool keyboardOpen; struct _DisplayData DisplayInfo; struct _WindowData WindowInfo; struct _WindowData Window_Alt; cc_bool launcherTop; static void OnscreenKeyboard_Update(void); static void OnscreenKeyboard_DrawTV(void); static void OnscreenKeyboard_DrawDRC(void); static void LoadTVDimensions(void) { switch(GX2GetSystemTVScanMode()) { case GX2_TV_SCAN_MODE_480I: case GX2_TV_SCAN_MODE_480P: DisplayInfo.Width = 854; DisplayInfo.Height = 480; break; case GX2_TV_SCAN_MODE_1080I: case GX2_TV_SCAN_MODE_1080P: DisplayInfo.Width = 1920; DisplayInfo.Height = 1080; break; case GX2_TV_SCAN_MODE_720P: default: DisplayInfo.Width = 1280; DisplayInfo.Height = 720; break; } } static uint32_t OnAcquired(void* context) { Window_Main.Inactive = false; Event_RaiseVoid(&WindowEvents.InactiveChanged); return 0; } static uint32_t OnReleased(void* context) { Window_Main.Inactive = true; Event_RaiseVoid(&WindowEvents.InactiveChanged); return 0; } void Window_PreInit(void) { KPADInit(); VPADInit(); ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, OnAcquired, NULL, 100); ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, OnReleased, NULL, 100); } void Window_Init(void) { LoadTVDimensions(); DisplayInfo.ScaleX = 1; DisplayInfo.ScaleY = 1; Window_Main.Width = DisplayInfo.Width; Window_Main.Height = DisplayInfo.Height; Window_Main.Focused = true; Window_Main.Exists = true; Input.Sources = INPUT_SOURCE_GAMEPAD; DisplayInfo.ContentOffsetX = 10; DisplayInfo.ContentOffsetY = 10; Window_Main.SoftKeyboard = SOFT_KEYBOARD_RESIZE; Input_SetTouchMode(true); Window_Alt.Width = 854; Window_Alt.Height = 480; WHBGfxInit(); } void Window_Free(void) { } // OSScreen is always this buffer size, regardless of the current TV resolution #define OSSCREEN_TV_WIDTH 1280 #define OSSCREEN_TV_HEIGHT 720 #define OSSCREEN_DRC_WIDTH 854 #define OSSCREEN_DRC_HEIGHT 480 static void LauncherInactiveChanged(void* obj); static void Init2DResources(void); void Window_Create2D(int width, int height) { Window_Main.Width = OSSCREEN_DRC_WIDTH; Window_Main.Height = OSSCREEN_DRC_HEIGHT; launcherMode = true; Event_Register_(&WindowEvents.InactiveChanged, NULL, LauncherInactiveChanged); Init2DResources(); } void Window_Create3D(int width, int height) { Window_Main.Width = DisplayInfo.Width; Window_Main.Height = DisplayInfo.Height; launcherMode = false; Event_Unregister_(&WindowEvents.InactiveChanged, NULL, LauncherInactiveChanged); } void Window_RequestClose(void) { Event_RaiseVoid(&WindowEvents.Closing); } /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ extern Rect2D dirty_rect; void Window_ProcessEvents(float delta) { if (!dirty_rect.width) dirty_rect.width = 1; if (!WHBProcIsRunning()) { Window_Main.Exists = false; Window_RequestClose(); } } void Window_UpdateRawMouse(void) { } void Cursor_SetPosition(int x, int y) { } void Window_EnableRawMouse(void) { Input.RawMode = true; } void Window_DisableRawMouse(void) { Input.RawMode = false; } /*########################################################################################################################* *-------------------------------------------------------Gamepads----------------------------------------------------------* *#########################################################################################################################*/ static VPADStatus vpadStatus; static bool kpad_valid[4]; static KPADStatus kpads[4]; static void ProcessKPadButtons(int port, int mods) { Gamepad_SetButton(port, CCPAD_L, mods & WPAD_BUTTON_1); Gamepad_SetButton(port, CCPAD_R, mods & WPAD_BUTTON_2); Gamepad_SetButton(port, CCPAD_A, mods & WPAD_BUTTON_A); Gamepad_SetButton(port, CCPAD_B, mods & WPAD_BUTTON_B); Gamepad_SetButton(port, CCPAD_X, mods & WPAD_BUTTON_PLUS); Gamepad_SetButton(port, CCPAD_START, mods & WPAD_BUTTON_HOME); Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_BUTTON_MINUS); Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_BUTTON_LEFT); Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_BUTTON_RIGHT); Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_BUTTON_UP); Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_BUTTON_DOWN); } static void ProcessNunchuckButtons(int port, int mods) { Gamepad_SetButton(port, CCPAD_L, mods & WPAD_NUNCHUK_BUTTON_Z); Gamepad_SetButton(port, CCPAD_R, mods & WPAD_NUNCHUK_BUTTON_C); } static void ProcessClassicButtons(int port, int mods) { Gamepad_SetButton(port, CCPAD_L, mods & WPAD_CLASSIC_BUTTON_L); Gamepad_SetButton(port, CCPAD_R, mods & WPAD_CLASSIC_BUTTON_R); Gamepad_SetButton(port, CCPAD_ZL, mods & WPAD_CLASSIC_BUTTON_ZL); Gamepad_SetButton(port, CCPAD_ZR, mods & WPAD_CLASSIC_BUTTON_ZR); Gamepad_SetButton(port, CCPAD_A, mods & WPAD_CLASSIC_BUTTON_A); Gamepad_SetButton(port, CCPAD_B, mods & WPAD_CLASSIC_BUTTON_B); Gamepad_SetButton(port, CCPAD_X, mods & WPAD_CLASSIC_BUTTON_X); Gamepad_SetButton(port, CCPAD_Y, mods & WPAD_CLASSIC_BUTTON_Y); Gamepad_SetButton(port, CCPAD_START, mods & WPAD_CLASSIC_BUTTON_HOME); Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_CLASSIC_BUTTON_MINUS); Gamepad_SetButton(port, CCPAD_Z, mods & WPAD_CLASSIC_BUTTON_PLUS); Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_CLASSIC_BUTTON_LEFT); Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_CLASSIC_BUTTON_RIGHT); Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_CLASSIC_BUTTON_UP); Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_CLASSIC_BUTTON_DOWN); } static void ProcessProButtons(int port, int mods) { Gamepad_SetButton(port, CCPAD_L, mods & WPAD_PRO_TRIGGER_L); Gamepad_SetButton(port, CCPAD_R, mods & WPAD_PRO_TRIGGER_R); Gamepad_SetButton(port, CCPAD_ZL, mods & WPAD_PRO_TRIGGER_ZL); Gamepad_SetButton(port, CCPAD_ZR, mods & WPAD_PRO_TRIGGER_ZR); Gamepad_SetButton(port, CCPAD_A, mods & WPAD_PRO_BUTTON_A); Gamepad_SetButton(port, CCPAD_B, mods & WPAD_PRO_BUTTON_B); Gamepad_SetButton(port, CCPAD_X, mods & WPAD_PRO_BUTTON_X); Gamepad_SetButton(port, CCPAD_Y, mods & WPAD_PRO_BUTTON_Y); Gamepad_SetButton(port, CCPAD_START, mods & WPAD_PRO_BUTTON_HOME); Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_PRO_BUTTON_MINUS); Gamepad_SetButton(port, CCPAD_Z, mods & WPAD_PRO_BUTTON_PLUS); Gamepad_SetButton(port, CCPAD_LSTICK, mods & WPAD_PRO_BUTTON_STICK_L); Gamepad_SetButton(port, CCPAD_RSTICK, mods & WPAD_PRO_BUTTON_STICK_R); Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_PRO_BUTTON_LEFT); Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_PRO_BUTTON_RIGHT); Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_PRO_BUTTON_UP); Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_PRO_BUTTON_DOWN); } static void ProcessKPAD(float delta, int i) { kpad_valid[i] = false; int res = KPADRead((WPADChan)(WPAD_CHAN_0 + i), &kpads[i], 1); if (res != KPAD_ERROR_OK) return; kpad_valid[i] = true; switch (kpads[i].extensionType) { case WPAD_EXT_CLASSIC: ProcessClassicButtons(i, kpads[i].classic.hold | kpads[i].classic.trigger); break; case WPAD_EXT_PRO_CONTROLLER: ProcessProButtons( i, kpads[i].pro.hold | kpads[i].pro.trigger); break; case WPAD_EXT_NUNCHUK: ProcessKPadButtons(i, kpads[i].hold | kpads[i].trigger); ProcessNunchuckButtons(i, kpads[i].nunchuck.hold | kpads[i].nunchuck.trigger); break; default: ProcessKPadButtons(i, kpads[i].hold | kpads[i].trigger); break; } } #define AXIS_SCALE 4.0f static void ProcessVpadStick(int port, int axis, float x, float y, float delta) { // May not be exactly 0 on actual hardware if (Math_AbsF(x) <= 0.1f) x = 0; if (Math_AbsF(y) <= 0.1f) y = 0; Gamepad_SetAxis(port, axis, x * AXIS_SCALE, -y * AXIS_SCALE, delta); } static void ProcessVpadButtons(int port, int mods) { Gamepad_SetButton(port, CCPAD_L, mods & VPAD_BUTTON_L); Gamepad_SetButton(port, CCPAD_R, mods & VPAD_BUTTON_R); Gamepad_SetButton(port, CCPAD_ZL, mods & VPAD_BUTTON_ZL); Gamepad_SetButton(port, CCPAD_ZR, mods & VPAD_BUTTON_ZR); Gamepad_SetButton(port, CCPAD_A, mods & VPAD_BUTTON_A); Gamepad_SetButton(port, CCPAD_B, mods & VPAD_BUTTON_B); Gamepad_SetButton(port, CCPAD_X, mods & VPAD_BUTTON_X); Gamepad_SetButton(port, CCPAD_Y, mods & VPAD_BUTTON_Y); Gamepad_SetButton(port, CCPAD_START, mods & VPAD_BUTTON_PLUS); Gamepad_SetButton(port, CCPAD_SELECT, mods & VPAD_BUTTON_MINUS); Gamepad_SetButton(port, CCPAD_LEFT, mods & VPAD_BUTTON_LEFT); Gamepad_SetButton(port, CCPAD_RIGHT, mods & VPAD_BUTTON_RIGHT); Gamepad_SetButton(port, CCPAD_UP, mods & VPAD_BUTTON_UP); Gamepad_SetButton(port, CCPAD_DOWN, mods & VPAD_BUTTON_DOWN); } static void ProcessVpadTouch(VPADTouchData* data) { static int was_touched; // TODO rescale to main screen size if (data->touched) { int x = data->x; int y = data->y; Platform_Log2("TOUCH: %i, %i", &x, &y); x = x * Window_Main.Width / 1280; y = y * Window_Main.Height / 720; Input_AddTouch(0, x, y); } else if (was_touched) { Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y); } was_touched = data->touched; } static void ProcessVPAD(float delta) { VPADReadError error = VPAD_READ_SUCCESS; VPADRead(VPAD_CHAN_0, &vpadStatus, 1, &error); if (error != VPAD_READ_SUCCESS) return; VPADGetTPCalibratedPoint(VPAD_CHAN_0, &vpadStatus.tpNormal, &vpadStatus.tpNormal); ProcessVpadButtons(0, vpadStatus.hold); ProcessVpadTouch(&vpadStatus.tpNormal); ProcessVpadStick(0, PAD_AXIS_LEFT, vpadStatus.leftStick.x, vpadStatus.leftStick.y, delta); ProcessVpadStick(0, PAD_AXIS_RIGHT, vpadStatus.rightStick.x, vpadStatus.rightStick.y, delta); } void Window_ProcessGamepads(float delta) { ProcessVPAD(delta); for (int i = 0; i < 4; i++) ProcessKPAD(delta, i); if (keyboardOpen) OnscreenKeyboard_Update(); } /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* *#########################################################################################################################*/ static GfxResourceID framebuffer_vb; static void LauncherInactiveChanged(void* obj) { // TODO } static void Init2DResources(void) { Gfx_Create(); if (framebuffer_vb) return; struct VertexTextured* data = (struct VertexTextured*)Gfx_RecreateAndLockVb(&framebuffer_vb, VERTEX_FORMAT_TEXTURED, 4); data[0].x = -1.0f; data[0].y = -1.0f; data[0].z = 0.0f; data[0].Col = PACKEDCOL_WHITE; data[0].U = 0.0f; data[0].V = 1.0f; data[1].x = 1.0f; data[1].y = -1.0f; data[1].z = 0.0f; data[1].Col = PACKEDCOL_WHITE; data[1].U = 1.0f; data[1].V = 1.0f; data[2].x = 1.0f; data[2].y = 1.0f; data[2].z = 0.0f; data[2].Col = PACKEDCOL_WHITE; data[2].U = 1.0f; data[2].V = 0.0f; data[3].x = -1.0f; data[3].y = 1.0f; data[3].z = 0.0f; data[3].Col = PACKEDCOL_WHITE; data[3].U = 0.0f; data[2].V = 0.0f; Gfx_UnlockVb(framebuffer_vb); } static GX2Texture fb; void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) { fb.surface.width = width; fb.surface.height = height; fb.surface.depth = 1; fb.surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; fb.surface.format = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; fb.surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED; fb.viewNumSlices = 1; fb.compMap = 0x00010203; GX2CalcSurfaceSizeAndAlignment(&fb.surface); GX2InitTextureRegs(&fb); fb.surface.image = MEMAllocFromDefaultHeapEx(fb.surface.imageSize, fb.surface.alignment); bmp->scan0 = (BitmapCol*)Mem_Alloc(width * height, 4, "window pixels"); bmp->width = width; bmp->height = height; } static void DrawLauncher(void) { Gfx_LoadIdentityMatrix(MATRIX_VIEW); Gfx_LoadIdentityMatrix(MATRIX_PROJECTION); Gfx_SetDepthTest(false); Gfx_SetVertexFormat(VERTEX_FORMAT_COLOURED); Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); Gfx_BindTexture(&fb); Gfx_BindVb(framebuffer_vb); Gfx_DrawVb_IndexedTris(4); } static void DrawTV(void) { WHBGfxBeginRenderTV(); WHBGfxClearColor(0.7f, 0.7f, 0.7f, 1.0f); DrawLauncher(); if (keyboardOpen) OnscreenKeyboard_DrawTV(); WHBGfxFinishRenderTV(); } static void DrawDRC(void) { WHBGfxBeginRenderDRC(); WHBGfxClearColor(0.7f, 0.7f, 0.7f, 1.0f); DrawLauncher(); if (keyboardOpen) OnscreenKeyboard_DrawDRC(); WHBGfxFinishRenderDRC(); } void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { if (launcherTop || Window_Main.Inactive) return; struct Bitmap part; part.scan0 = Bitmap_GetRow(bmp, r.y) + r.x; part.width = r.width; part.height = r.height; Gfx_UpdateTexture(&fb, r.x, r.y, &part, bmp->width, false); WHBGfxBeginRender(); DrawDRC(); DrawTV(); WHBGfxFinishRender(); } void Window_FreeFramebuffer(struct Bitmap* bmp) { MEMFreeToDefaultHeap(fb.surface.image); Mem_Free(bmp->scan0); } /*########################################################################################################################* *-------------------------------------------------------Misc/Other--------------------------------------------------------* *#########################################################################################################################*/ void Window_SetTitle(const cc_string* title) { } void Clipboard_GetText(cc_string* value) { } void Clipboard_SetText(const cc_string* value) { } int Window_GetWindowState(void) { return WINDOW_STATE_FULLSCREEN; } cc_result Window_EnterFullscreen(void) { return 0; } cc_result Window_ExitFullscreen(void) { return 0; } int Window_IsObscured(void) { return 0; } void Window_Show(void) { } void Window_SetSize(int width, int height) { } void Window_ShowDialog(const char* title, const char* msg) { /* TODO implement */ Platform_LogConst(title); Platform_LogConst(msg); } cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { return ERR_NOT_SUPPORTED; } cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { return ERR_NOT_SUPPORTED; } /*########################################################################################################################* *----------------------------------------------------Onscreen keyboard----------------------------------------------------* *#########################################################################################################################*/ static FSClient* fs_client; static nn::swkbd::CreateArg create_arg; static nn::swkbd::AppearArg appear_arg; static char kb_buffer[512]; static cc_string kb_str = String_FromArray(kb_buffer); #define UNI_STR_LENGTH 64 static int UniString_Length(const char16_t* raw) { int length = 0; while (length < UInt16_MaxValue && *raw) { raw++; length++; } return length; } static void UniString_WriteConst(const char* src, char16_t* dst) { while (*src) { *dst++ = *src++; } *dst = '\0'; } static void UniString_WriteString(const cc_string* src, char16_t* dst) { int len = min(src->length, UNI_STR_LENGTH); for (int i = 0; i < len; i++) { *dst++ = Convert_CP437ToUnicode(src->buffer[i]); } *dst = '\0'; } void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { if (keyboardOpen) OnscreenKeyboard_Close(); char16_t hint[UNI_STR_LENGTH + 1] = { 0 }; char16_t initial[UNI_STR_LENGTH + 1] = { 0 }; int mode = args->type & 0xFF; kb_str.length = 0; keyboardOpen = true; Window_Main.SoftKeyboardFocus = true; fs_client = (FSClient *)MEMAllocFromDefaultHeap(sizeof(FSClient)); FSAddClient(fs_client, FS_ERROR_FLAG_NONE); Mem_Set(&create_arg, 0, sizeof(create_arg)); create_arg.regionType = nn::swkbd::RegionType::Europe; create_arg.workMemory = MEMAllocFromDefaultHeap(nn::swkbd::GetWorkMemorySize(0)); create_arg.fsClient = fs_client; if (!nn::swkbd::Create(create_arg)) { Platform_LogConst("nn::swkbd::Create failed"); return; } nn::swkbd::MuteAllSound(false); Mem_Set(&appear_arg, 0, sizeof(appear_arg)); nn::swkbd::ConfigArg* cfg = &appear_arg.keyboardArg.configArg; cfg->languageType = nn::swkbd::LanguageType::English; cfg->okString = args->type & KEYBOARD_FLAG_SEND ? u"Send" : u"OK"; if (mode == KEYBOARD_TYPE_INTEGER) { cfg->keyboardMode = nn::swkbd::KeyboardMode::Numpad; cfg->numpadCharLeft = '-'; cfg->numpadCharRight = 0; } else if (mode == KEYBOARD_TYPE_NUMBER) { cfg->keyboardMode = nn::swkbd::KeyboardMode::Numpad; cfg->numpadCharLeft = '-'; cfg->numpadCharRight = '.'; } nn::swkbd::InputFormArg* ipt = &appear_arg.inputFormArg; UniString_WriteConst(args->placeholder, hint); UniString_WriteString(args->text, initial); ipt->hintText = hint; ipt->initialText = initial; if (mode == KEYBOARD_TYPE_PASSWORD) ipt->passwordMode = nn::swkbd::PasswordMode::Hide; if (!nn::swkbd::AppearInputForm(appear_arg)) { Platform_LogConst("nn::swkbd::AppearInputForm failed"); return; } } static void ProcessKeyboardInput(void) { char tmpBuffer[NATIVE_STR_LEN]; cc_string tmp = String_FromArray(tmpBuffer); const char16_t* str = nn::swkbd::GetInputFormString(); if (!str) return; String_AppendUtf16(&tmp, str, UniString_Length(str)); if (String_Equals(&tmp, &kb_str)) return; String_Copy(&kb_str, &tmp); Event_RaiseString(&InputEvents.TextChanged, &tmp); } static void OnscreenKeyboard_Update(void) { nn::swkbd::ControllerInfo controllerInfo; controllerInfo.vpad = &vpadStatus; controllerInfo.kpad[0] = kpad_valid[0] ? &kpads[0] : nullptr; controllerInfo.kpad[1] = kpad_valid[1] ? &kpads[1] : nullptr; controllerInfo.kpad[2] = kpad_valid[2] ? &kpads[2] : nullptr; controllerInfo.kpad[3] = kpad_valid[3] ? &kpads[3] : nullptr; nn::swkbd::Calc(controllerInfo); if (nn::swkbd::IsNeedCalcSubThreadFont()) { nn::swkbd::CalcSubThreadFont(); } if (nn::swkbd::IsNeedCalcSubThreadPredict()) { nn::swkbd::CalcSubThreadPredict(); } ProcessKeyboardInput(); if (nn::swkbd::IsDecideOkButton(nullptr)) { Input_SetPressed(CCKEY_ENTER); Input_SetReleased(CCKEY_ENTER); OnscreenKeyboard_Close(); return; } if (nn::swkbd::IsDecideCancelButton(nullptr)) { OnscreenKeyboard_Close(); return; } } static void OnscreenKeyboard_DrawTV(void) { nn::swkbd::DrawTV(); } static void OnscreenKeyboard_DrawDRC(void) { nn::swkbd::DrawDRC(); } void OnscreenKeyboard_SetText(const cc_string* text) { } void OnscreenKeyboard_Draw2D(Rect2D* r, struct Bitmap* bmp) { } void OnscreenKeyboard_Draw3D(void) { } void OnscreenKeyboard_Close(void) { if (!keyboardOpen) return; keyboardOpen = false; Window_Main.SoftKeyboardFocus = false; nn::swkbd::DisappearInputForm(); nn::swkbd::Destroy(); MEMFreeToDefaultHeap(create_arg.workMemory); FSDelClient(fs_client, FS_ERROR_FLAG_NONE); MEMFreeToDefaultHeap(fs_client); } #endif