summary refs log tree commit diff
path: root/src/Window_Switch.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_Switch.c
initial commit
Diffstat (limited to 'src/Window_Switch.c')
-rw-r--r--src/Window_Switch.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/Window_Switch.c b/src/Window_Switch.c
new file mode 100644
index 0000000..fe892ed
--- /dev/null
+++ b/src/Window_Switch.c
@@ -0,0 +1,309 @@
+#include "Core.h"
+#if defined CC_BUILD_SWITCH
+#include "_WindowBase.h"
+#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 "Input.h"
+#include "Gui.h"
+#include <switch.h>
+
+static cc_bool launcherMode;
+static Framebuffer fb;
+static PadState pad;
+static AppletHookCookie cookie;
+
+struct _DisplayData DisplayInfo;
+struct _WindowData WindowInfo;
+
+static void SetResolution(void) {
+	// check whether the Switch is docked
+	// use 720p for handheld, 1080p for docked
+	AppletOperationMode opMode = appletGetOperationMode();
+	int w = 1280;
+	int h = 720;
+	if (opMode == AppletOperationMode_Console) {
+		w = 1920;
+		h = 1080;
+	}
+
+	DisplayInfo.Width  = w;
+	DisplayInfo.Height = h;
+
+	Window_Main.Width  = w;
+	Window_Main.Height = h;
+}
+
+static void Applet_Event(AppletHookType type, void* param) {
+	if (type == AppletHookType_OnOperationMode) {
+		SetResolution();
+		Event_RaiseVoid(&WindowEvents.Resized);
+	} else if (type == AppletHookType_OnExitRequest) {
+		Window_Main.Exists = false;
+		Window_RequestClose();
+	}
+}
+
+void Window_PreInit(void) {
+	// Configure our supported input layout: a single player with standard controller styles
+	padConfigureInput(1, HidNpadStyleSet_NpadStandard);
+	hidInitializeTouchScreen();
+	// Initialize the default gamepad (which reads handheld mode inputs as well as the first connected controller)
+	padInitializeDefault(&pad);
+	
+	appletHook(&cookie, Applet_Event, NULL);
+}
+
+void Window_Init(void) {
+	DisplayInfo.Depth  = 4; // 32 bit TODO wrong, this is actually 4 bit
+	DisplayInfo.ScaleX = 1;
+	DisplayInfo.ScaleY = 1;
+
+	Window_Main.Focused = true;
+	Window_Main.Exists  = true;
+	Window_Main.Handle = nwindowGetDefault();
+
+	Window_Main.SoftKeyboard = SOFT_KEYBOARD_RESIZE;
+	Input_SetTouchMode(true);
+	Gui_SetTouchUI(true);
+	Input.Sources = INPUT_SOURCE_GAMEPAD;
+
+	nwindowSetDimensions(Window_Main.Handle, 1920, 1080);
+	SetResolution();
+}
+
+void Window_Free(void) {
+	appletUnhook(&cookie);
+}
+
+void Window_Create2D(int width, int height) {
+	launcherMode = true;
+}
+void Window_Create3D(int width, int height) {
+	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(void) {
+	static int prev_touchcount = 0;
+	HidTouchScreenState state = {0};
+	hidGetTouchScreenStates(&state, 1);
+
+	if (state.count) {
+		Input_AddTouch(0,    state.touches[0].x, state.touches[0].y);
+	} else if (prev_touchcount) {
+		Input_RemoveTouch(0, Pointers[0].x,      Pointers[0].y);
+	}
+	prev_touchcount = state.count;
+}
+
+void Window_ProcessEvents(float delta) {
+	// Scan the gamepad. This should be done once for each frame
+	padUpdate(&pad);
+
+	if (!appletMainLoop()) {
+		Window_Main.Exists = false;
+		Window_RequestClose();
+		return;
+	}
+	ProcessTouchInput();
+}
+
+void Cursor_SetPosition(int x, int y) { } // Makes no sense for PSP
+void Window_EnableRawMouse(void)  { Input.RawMode = true;  }
+void Window_DisableRawMouse(void) { Input.RawMode = false; }
+
+void Window_UpdateRawMouse(void)  { }
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Gamepads----------------------------------------------------------*
+*#########################################################################################################################*/
+static void HandleButtons(int port, u64 mods) {
+	Gamepad_SetButton(port, CCPAD_L, mods & HidNpadButton_L);
+	Gamepad_SetButton(port, CCPAD_R, mods & HidNpadButton_R);
+	
+	Gamepad_SetButton(port, CCPAD_A, mods & HidNpadButton_A);
+	Gamepad_SetButton(port, CCPAD_B, mods & HidNpadButton_B);
+	Gamepad_SetButton(port, CCPAD_X, mods & HidNpadButton_X);
+	Gamepad_SetButton(port, CCPAD_Y, mods & HidNpadButton_Y);
+	
+	Gamepad_SetButton(port, CCPAD_START,  mods & HidNpadButton_Plus);
+	Gamepad_SetButton(port, CCPAD_SELECT, mods & HidNpadButton_Minus);
+	
+	Gamepad_SetButton(port, CCPAD_LEFT,   mods & HidNpadButton_Left);
+	Gamepad_SetButton(port, CCPAD_RIGHT,  mods & HidNpadButton_Right);
+	Gamepad_SetButton(port, CCPAD_UP,     mods & HidNpadButton_Up);
+	Gamepad_SetButton(port, CCPAD_DOWN,   mods & HidNpadButton_Down);
+}
+
+#define AXIS_SCALE 512.0f
+static void ProcessJoystickInput(int port, int axis, HidAnalogStickState* pos, float delta) {
+	// May not be exactly 0 on actual hardware
+	if (Math_AbsI(pos->x) <= 16) pos->x = 0;
+	if (Math_AbsI(pos->y) <= 16) pos->y = 0;
+	
+	Gamepad_SetAxis(port, axis, pos->x / AXIS_SCALE, -pos->y / AXIS_SCALE, delta);
+}
+
+void Window_ProcessGamepads(float delta) {
+	u64 keys = padGetButtons(&pad);
+	HandleButtons(0, keys);
+
+	// Read the sticks' position
+	HidAnalogStickState analog_stick_l = padGetStickPos(&pad, 0);
+	HidAnalogStickState analog_stick_r = padGetStickPos(&pad, 1);
+	ProcessJoystickInput(0, PAD_AXIS_LEFT,  &analog_stick_l, delta);
+	ProcessJoystickInput(0, PAD_AXIS_RIGHT, &analog_stick_r, delta);
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Framebuffer--------------------------------------------------------*
+*#########################################################################################################################*/
+void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) {
+	framebufferCreate(&fb, nwindowGetDefault(), DisplayInfo.Width, DisplayInfo.Height, PIXEL_FORMAT_BGRA_8888, 2);
+	framebufferMakeLinear(&fb);
+
+	bmp->scan0  = (BitmapCol*)Mem_Alloc(width * height, 4, "window pixels");
+	bmp->width  = width;
+	bmp->height = height;
+}
+
+void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) {
+	// Retrieve the framebuffer
+	cc_uint32 stride;
+	cc_uint32* framebuf = (cc_uint32*)framebufferBegin(&fb, &stride);
+
+	// flip upside down
+	for (cc_uint32 y = r.y; y < r.y + r.height; y++)
+	{
+		BitmapCol* src = Bitmap_GetRow(bmp, y);
+		cc_uint32* dst = framebuf + y * stride / sizeof(cc_uint32);
+
+		for (cc_uint32 x = r.x; x < r.x + r.width; x++)
+		{
+			dst[x] = src[x];
+		}
+	}
+
+	// We're done rendering, so we end the frame here.
+	framebufferEnd(&fb);
+}
+
+void Window_FreeFramebuffer(struct Bitmap* bmp) {
+	framebufferClose(&fb);
+	Mem_Free(bmp->scan0);
+}
+
+/*########################################################################################################################*
+*-----------------------------------------------------OpenGL context------------------------------------------------------*
+*#########################################################################################################################*/
+static void GLContext_InitSurface(void) {
+	NWindow* window = (NWindow*)Window_Main.Handle;
+	if (!window) return; /* window not created or lost */
+
+	// terrible, but fixes 720p/1080p resolution change on handheld/docked modes
+	int real_w     = window->width;
+	int real_h     = window->height;
+	window->width  = Window_Main.Width;
+	window->height = Window_Main.Height;
+
+	ctx_surface = eglCreateWindowSurface(ctx_display, ctx_config, window, NULL);
+	window->width  = real_w;
+	window->height = real_h;
+	
+	if (!ctx_surface) return;
+	eglMakeCurrent(ctx_display, ctx_surface, ctx_surface, ctx_context);
+}
+
+/*########################################################################################################################*
+*------------------------------------------------------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);
+}
+
+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 };
+	String_EncodeUtf8(input, args->text);
+	
+	int mode = args->type & 0xFF;
+	SwkbdType type = (mode == KEYBOARD_TYPE_NUMBER || mode == KEYBOARD_TYPE_INTEGER) ? SwkbdType_NumPad : SwkbdType_Normal;
+
+	SwkbdConfig kbd;
+	swkbdCreate(&kbd, 0);
+
+	if (mode == KEYBOARD_TYPE_PASSWORD) {
+		swkbdConfigMakePresetPassword(&kbd);
+	} else {
+		swkbdConfigMakePresetDefault(&kbd);
+		swkbdConfigSetType(&kbd, type);
+	}
+
+	swkbdConfigSetInitialText(&kbd, input);
+	swkbdConfigSetGuideText(&kbd, args->placeholder);
+	swkbdConfigSetOkButtonText(&kbd, btnText);
+
+	Result rc = swkbdShow(&kbd, output, sizeof(output));
+	if (R_SUCCEEDED(rc))
+		OnscreenTextChanged(output);
+
+	swkbdClose(&kbd);
+}
+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) {
+static void ShowDialogCore(const char* title, const char* msg) {
+	ErrorApplicationConfig c;
+	errorApplicationCreate(&c, title, msg);
+	errorApplicationShow(&c);
+}
+
+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