summary refs log tree commit diff
path: root/src/Window_3DS.c
diff options
context:
space:
mode:
authorWlodekM <[email protected]>2024-06-16 10:35:45 +0300
committerWlodekM <[email protected]>2024-06-16 10:35:45 +0300
commitabef6da56913f1c55528103e60a50451a39628b1 (patch)
treeb3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/Window_3DS.c
initial commit
Diffstat (limited to 'src/Window_3DS.c')
-rw-r--r--src/Window_3DS.c293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/Window_3DS.c b/src/Window_3DS.c
new file mode 100644
index 0000000..186f035
--- /dev/null
+++ b/src/Window_3DS.c
@@ -0,0 +1,293 @@
+#include "Core.h"
+#if defined CC_BUILD_3DS
+#include "Window.h"
+#include "Platform.h"
+#include "Input.h"
+#include "Event.h"
+#include "Graphics.h"
+#include "String.h"
+#include "Funcs.h"
+#include "Bitmap.h"
+#include "Errors.h"
+#include "ExtMath.h"
+#include "Gui.h"
+#include <3ds.h>
+
+static cc_bool launcherMode;
+static Result irrst_result;
+static u16 top_width, top_height;
+static u16 btm_width, btm_height;
+
+struct _DisplayData DisplayInfo;
+struct _WindowData WindowInfo;
+struct _WindowData Window_Alt;
+cc_bool launcherTop;
+
+void Window_PreInit(void) {
+	gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false);
+}
+
+// Note from https://github.com/devkitPro/libctru/blob/master/libctru/include/3ds/gfx.h
+//  * Please note that the 3DS uses *portrait* screens rotated 90 degrees counterclockwise.
+//  * Width/height refer to the physical dimensions of the screen; that is, the top screen
+//  * is 240 pixels wide and 400 pixels tall; while the bottom screen is 240x320.
+void Window_Init(void) {
+	// deliberately swapped
+	gfxGetFramebuffer(GFX_TOP,    GFX_LEFT, &top_height, &top_width);
+	gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &btm_height, &btm_width);
+	
+	DisplayInfo.Width  = top_width; 
+	DisplayInfo.Height = top_height;
+	DisplayInfo.ScaleX = 0.5f;
+	DisplayInfo.ScaleY = 0.5f;
+	
+	Window_Main.Width   = top_width;
+	Window_Main.Height  = top_height;
+	Window_Main.Focused = true;
+	Window_Main.Exists  = true;
+
+	Window_Main.SoftKeyboard = SOFT_KEYBOARD_RESIZE;
+	Input_SetTouchMode(true);
+	Gui_SetTouchUI(true);
+	Input.Sources = INPUT_SOURCE_GAMEPAD;
+	irrst_result  = irrstInit();
+	
+	Window_Alt.Width  = btm_width;
+	Window_Alt.Height = btm_height;
+}
+
+void Window_Free(void) { irrstExit(); }
+
+void Window_Create2D(int width, int height) {  
+	DisplayInfo.Width = btm_width;
+	Window_Main.Width = btm_width;
+	Window_Alt.Width  = top_width;
+	launcherMode      = true;  
+}
+
+void Window_Create3D(int width, int height) { 
+	DisplayInfo.Width = top_width;
+	Window_Main.Width = top_width;
+	Window_Alt.Width  = btm_width;
+	launcherMode      = false; 
+}
+
+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_RequestClose(void) {
+	Event_RaiseVoid(&WindowEvents.Closing);
+}
+
+/*########################################################################################################################*
+*----------------------------------------------------Input processing-----------------------------------------------------*
+*#########################################################################################################################*/
+static void ProcessTouchInput(int mods) {
+	touchPosition touch;
+	hidTouchRead(&touch);
+
+	if (mods & KEY_TOUCH) {
+		Input_AddTouch(0,    touch.px,      touch.py);
+	} else if (hidKeysUp() & KEY_TOUCH) {
+		Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y);
+	}
+}
+
+void Window_ProcessEvents(float delta) {
+	hidScanInput();
+
+	if (!aptMainLoop()) {
+		Window_Main.Exists = false;
+		Window_RequestClose();
+		return;
+	}
+	
+	u32 mods = hidKeysDown() | hidKeysHeld();
+	ProcessTouchInput(mods);
+}
+
+void Cursor_SetPosition(int x, int y) { } // Makes no sense for 3DS
+
+void Window_EnableRawMouse(void)  { Input.RawMode = true;  }
+void Window_DisableRawMouse(void) { Input.RawMode = false; }
+
+void Window_UpdateRawMouse(void)  { }
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Gamepads----------------------------------------------------------*
+*#########################################################################################################################*/
+static void HandleButtons(u32 mods) {
+	Gamepad_SetButton(0, CCPAD_L, mods & KEY_L);
+	Gamepad_SetButton(0, CCPAD_R, mods & KEY_R);
+	
+	Gamepad_SetButton(0, CCPAD_A, mods & KEY_A);
+	Gamepad_SetButton(0, CCPAD_B, mods & KEY_B);
+	Gamepad_SetButton(0, CCPAD_X, mods & KEY_X);
+	Gamepad_SetButton(0, CCPAD_Y, mods & KEY_Y);
+	
+	Gamepad_SetButton(0, CCPAD_START,  mods & KEY_START);
+	Gamepad_SetButton(0, CCPAD_SELECT, mods & KEY_SELECT);
+	
+	Gamepad_SetButton(0, CCPAD_LEFT,   mods & KEY_DLEFT);
+	Gamepad_SetButton(0, CCPAD_RIGHT,  mods & KEY_DRIGHT);
+	Gamepad_SetButton(0, CCPAD_UP,     mods & KEY_DUP);
+	Gamepad_SetButton(0, CCPAD_DOWN,   mods & KEY_DDOWN);
+	
+	Gamepad_SetButton(0, CCPAD_ZL, mods & KEY_ZL);
+	Gamepad_SetButton(0, CCPAD_ZR, mods & KEY_ZR);
+}
+
+#define AXIS_SCALE 8.0f
+static void ProcessCircleInput(int axis, circlePosition* pos, float delta) {
+	// May not be exactly 0 on actual hardware
+	if (Math_AbsI(pos->dx) <= 24) pos->dx = 0;
+	if (Math_AbsI(pos->dy) <= 24) pos->dy = 0;
+		
+	Gamepad_SetAxis(0, axis, pos->dx / AXIS_SCALE, -pos->dy / AXIS_SCALE, delta);
+}
+
+void Window_ProcessGamepads(float delta) {
+	u32 mods = hidKeysDown() | hidKeysHeld();
+	HandleButtons(mods);
+	
+	circlePosition hid_pos;
+	hidCircleRead(&hid_pos);
+
+	if (irrst_result == 0) {
+		circlePosition stk_pos;
+		irrstScanInput();
+		irrstCstickRead(&stk_pos);
+		
+		ProcessCircleInput(PAD_AXIS_RIGHT, &stk_pos, delta);
+		ProcessCircleInput(PAD_AXIS_LEFT,  &hid_pos, delta);
+	} else {
+		ProcessCircleInput(PAD_AXIS_RIGHT, &hid_pos, delta);
+	}
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Framebuffer--------------------------------------------------------*
+*#########################################################################################################################*/
+void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) {
+	bmp->scan0  = (BitmapCol*)Mem_Alloc(width * height, 4, "window pixels");
+	bmp->width  = width;
+	bmp->height = height;
+}
+
+void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) {
+	u16 width, height;
+	gfxScreen_t screen = launcherTop ? GFX_TOP : GFX_BOTTOM;
+	
+	gfxSetDoubleBuffering(screen, false);
+	u8* fb = gfxGetFramebuffer(screen, GFX_LEFT, &width, &height);
+	// SRC y = 0 to 240
+	// SRC x = 0 to 400
+	// DST X = 0 to 240
+	// DST Y = 0 to 400
+
+	for (int y = r.y; y < r.y + r.height; y++)
+		for (int x = r.x; x < r.x + r.width; x++)
+	{
+		BitmapCol color = Bitmap_GetPixel(bmp, x, y);
+		int addr   = (width - 1 - y + x * width) * 3; // TODO -1 or not
+		fb[addr+0] = BitmapCol_B(color);
+		fb[addr+1] = BitmapCol_G(color);
+		fb[addr+2] = BitmapCol_R(color);
+	}
+	// TODO gspWaitForVBlank();
+	gfxFlushBuffers();
+	//gfxSwapBuffers();
+	// TODO: tearing??
+	/*
+	gfxSetDoubleBuffering(GFX_TOP, false);
+	gfxScreenSwapBuffers(GFX_TOP, true);
+	gfxSetDoubleBuffering(GFX_TOP, true);
+	gfxScreenSwapBuffers(GFX_BOTTOM, true);
+	*/
+}
+
+void Window_FreeFramebuffer(struct Bitmap* bmp) {
+	Mem_Free(bmp->scan0);
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Soft keyboard------------------------------------------------------*
+*#########################################################################################################################*/
+static void OnscreenTextChanged(const char* text) {
+	char tmpBuffer[NATIVE_STR_LEN];
+	cc_string tmp = String_FromArray(tmpBuffer);
+	String_AppendUtf8(&tmp, text, String_Length(text));
+    
+	Event_RaiseString(&InputEvents.TextChanged, &tmp);
+	Input_SetPressed(CCKEY_ENTER);
+	Input_SetReleased(CCKEY_ENTER);
+}
+
+void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) {
+	const char* btnText = args->type & KEYBOARD_FLAG_SEND ? "Send" : "Enter";
+	char input[NATIVE_STR_LEN]  = { 0 };
+	char output[NATIVE_STR_LEN] = { 0 };
+	SwkbdState swkbd;
+	String_EncodeUtf8(input, args->text);
+	
+	int mode = args->type & 0xFF;
+	int type = (mode == KEYBOARD_TYPE_INTEGER || mode == KEYBOARD_TYPE_NUMBER) ? SWKBD_TYPE_NUMPAD : SWKBD_TYPE_WESTERN;
+	
+	swkbdInit(&swkbd, type, 3, -1);
+	swkbdSetInitialText(&swkbd, input);
+	swkbdSetHintText(&swkbd, args->placeholder);
+	//swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false);
+	//swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, btnText, true);
+	swkbdSetButton(&swkbd, SWKBD_BUTTON_CONFIRM, btnText, true);
+	
+	if (mode == KEYBOARD_TYPE_INTEGER) {
+		swkbdSetNumpadKeys(&swkbd, '-', 0);
+	} else if (mode == KEYBOARD_TYPE_NUMBER) {
+		swkbdSetNumpadKeys(&swkbd, '-', '.');
+	}
+	
+	if (mode == KEYBOARD_TYPE_PASSWORD)
+		swkbdSetPasswordMode(&swkbd, SWKBD_PASSWORD_HIDE_DELAY);
+	if (args->multiline)
+		swkbdSetFeatures(&swkbd, SWKBD_MULTILINE);
+		
+	// TODO filter callbacks and OnscreenKeyboard_SetText ??
+	int btn = swkbdInputText(&swkbd, output, sizeof(output));
+	if (btn != SWKBD_BUTTON_CONFIRM) return;
+	OnscreenTextChanged(output);
+}
+void OnscreenKeyboard_SetText(const cc_string* text) { }
+void OnscreenKeyboard_Draw2D(Rect2D* r, struct Bitmap* bmp) { }
+void OnscreenKeyboard_Draw3D(void) { }
+void OnscreenKeyboard_Close(void) { /* TODO implement */ }
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Misc/Other--------------------------------------------------------*
+*#########################################################################################################################*/
+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;
+}
+#endif