summary refs log tree commit diff
path: root/src/Window_NDS.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_NDS.c
initial commit
Diffstat (limited to 'src/Window_NDS.c')
-rw-r--r--src/Window_NDS.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/src/Window_NDS.c b/src/Window_NDS.c
new file mode 100644
index 0000000..3db1721
--- /dev/null
+++ b/src/Window_NDS.c
@@ -0,0 +1,350 @@
+#include "Core.h"
+#if defined CC_BUILD_NDS
+#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 "Camera.h"
+#include <nds/arm9/background.h>
+#include <nds/arm9/input.h>
+#include <nds/arm9/keyboard.h>
+#include <nds/interrupts.h>
+#include <nds/system.h>
+#include <fat.h>
+
+
+/*########################################################################################################################*
+*----------------------------------------------------Onscreen console-----------------------------------------------------*
+*#########################################################################################################################*/
+// A majorly cutdown version of the Console included in libnds
+#define CON_WIDTH  32
+#define CON_HEIGHT 24
+
+extern u8 default_fontTiles[];
+#define FONT_NUM_CHARACTERS 96
+
+#define FONT_ASCII_OFFSET 32
+static u16* conFontBgMap;
+static int  conFontCurPal;
+static int  conCursorX, conCurrentRow;
+
+static void consoleClear(void) {
+    for (int i = 0; i < CON_WIDTH * CON_HEIGHT; i++)
+    {
+        conFontBgMap[i] = ' ' - FONT_ASCII_OFFSET;
+    }
+
+    conCursorX    = 0;
+    conCurrentRow = 0;
+}
+
+static void consoleNewLine(void) {
+    conCursorX = 0;
+    conCurrentRow++;
+    if (conCurrentRow < CON_HEIGHT) return;
+
+    // Shift entire screen upwards by one row
+    conCurrentRow--;
+
+    for (int y = 0; y < CON_HEIGHT - 1; y++)
+    {
+        for (int x = 0; x < CON_WIDTH; x++)
+        {
+            int src = x + (y + 1) * CON_WIDTH;
+            int dst = x + (y    ) * CON_WIDTH;
+            conFontBgMap[dst] = conFontBgMap[src];
+        }
+    }
+
+    for (int x = 0; x < CON_WIDTH; x++)
+    {
+        int index = x + (CON_HEIGHT - 1) * CON_WIDTH;
+        conFontBgMap[index] = ' ' - FONT_ASCII_OFFSET;
+    }
+}
+
+static void consolePrintChar(char c) {
+	if (c < ' ') return; // only ASCII supported
+
+    if (conCursorX >= CON_WIDTH) 
+        consoleNewLine();
+
+    u16 value = conFontCurPal | (c - FONT_ASCII_OFFSET);
+    conFontBgMap[conCursorX + conCurrentRow * CON_WIDTH] = value;
+    conCursorX++;
+}
+
+void consolePrintString(const char* ptr, int len) {
+	if (!conFontBgMap) return;
+
+    for (int i = 0; i < len; i++)
+    {
+        consolePrintChar(ptr[i]);
+    }
+    consoleNewLine();
+}
+
+static void consoleLoadFont(u16* fontBgGfx) {
+    u16* palette  = BG_PALETTE_SUB;
+    conFontCurPal = 15 << 12;
+
+    for (int i = 0; i < FONT_NUM_CHARACTERS * 8; i++)
+    {
+        u8 row  = default_fontTiles[i];
+        u32 gfx = 0;
+        if (row & 0x01) gfx |= 0x0000000F;
+        if (row & 0x02) gfx |= 0x000000F0;
+        if (row & 0x04) gfx |= 0x00000F00;
+        if (row & 0x08) gfx |= 0x0000F000;
+        if (row & 0x10) gfx |= 0x000F0000;
+        if (row & 0x20) gfx |= 0x00F00000;
+        if (row & 0x40) gfx |= 0x0F000000;
+        if (row & 0x80) gfx |= 0xF0000000;
+        ((u32 *)fontBgGfx)[i] = gfx;
+    }
+
+    palette[16 * 16 - 1] = RGB15(31, 31, 31);
+    palette[0]           = RGB15( 0,  0,  0);
+}
+
+static void consoleInit(void) {
+    int bgId = bgInitSub(0, BgType_Text4bpp, BgSize_T_256x256, 22, 2);
+    conFontBgMap = (u16*)bgGetMapPtr(bgId);
+
+    consoleLoadFont((u16*)bgGetGfxPtr(bgId));
+    consoleClear();
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------General data-------------------------------------------------------*
+*#########################################################################################################################*/
+static cc_bool launcherMode;
+cc_bool keyboardOpen;
+static int bg_id;
+static u16* bg_ptr;
+
+struct _DisplayData DisplayInfo;
+struct _WindowData WindowInfo;
+
+void Window_PreInit(void) {
+	videoSetModeSub(MODE_0_2D);
+    vramSetBankH(VRAM_H_SUB_BG);
+	vramSetBankI(VRAM_I_SUB_BG_0x06208000);
+    setBrightness(2, 0);
+	consoleInit();
+}
+
+void Window_Init(void) {  
+	DisplayInfo.Width  = SCREEN_WIDTH;
+	DisplayInfo.Height = SCREEN_HEIGHT;
+	DisplayInfo.ScaleX = 0.5f;
+	DisplayInfo.ScaleY = 0.5f;
+	
+	Window_Main.Width   = DisplayInfo.Width;
+	Window_Main.Height  = DisplayInfo.Height;
+	Window_Main.Focused = true;
+	Window_Main.Exists  = true;
+
+	Window_Main.SoftKeyboard = SOFT_KEYBOARD_RESIZE;
+	Input_SetTouchMode(true);
+	Input.Sources = INPUT_SOURCE_GAMEPAD;
+}
+
+void Window_Free(void) { }
+
+void Window_Create2D(int width, int height) { 
+    launcherMode = true;
+	videoSetMode(MODE_5_2D);
+	vramSetBankA(VRAM_A_MAIN_BG);
+	
+	bg_id  = bgInit(2, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
+	bg_ptr = bgGetGfxPtr(bg_id);
+}
+
+void Window_Create3D(int width, int height) { 
+    launcherMode = false;
+	videoSetMode(MODE_0_3D);
+}
+
+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;
+	touchRead(&touch);
+	Camera.Sensitivity = 100; // TODO not hardcode this
+	
+	if (mods & KEY_TOUCH) {
+		Input_AddTouch(0,    touch.px,      touch.py);
+	} else if (keysUp() & KEY_TOUCH) {
+		Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y);
+	}
+}
+
+void Window_ProcessEvents(float delta) {
+	scanKeys();	
+	
+	if (keyboardOpen) {
+		keyboardUpdate();
+	} else {
+		ProcessTouchInput(keysDown() | keysHeld());
+	}
+}
+
+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----------------------------------------------------------*
+*#########################################################################################################################*/
+void Window_ProcessGamepads(float delta) {
+	int mods = keysDown() | keysHeld();
+	
+	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_LEFT);
+	Gamepad_SetButton(0, CCPAD_RIGHT,  mods & KEY_RIGHT);
+	Gamepad_SetButton(0, CCPAD_UP,     mods & KEY_UP);
+	Gamepad_SetButton(0, CCPAD_DOWN,   mods & KEY_DOWN);
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------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) {
+	swiWaitForVBlank();
+	 
+	for (int y = r.y; y < r.y + r.height; y++)
+	{
+		BitmapCol* src = Bitmap_GetRow(bmp, y);
+		uint16_t*  dst = bg_ptr + 256 * y;
+		
+		for (int x = r.x; x < r.x + r.width; x++)
+		{
+			BitmapCol color = src[x];
+			// 888 to 565 (discard least significant bits)
+			// quoting libDNS: < Bitmap background with 16 bit color values of the form aBBBBBGGGGGRRRRR (if 'a' is not set, the pixel will be transparent)
+			dst[x] = 0x8000 | ((BitmapCol_B(color) & 0xF8) << 7) | ((BitmapCol_G(color) & 0xF8) << 2) | (BitmapCol_R(color) >> 3);
+		}
+	}
+	
+	bgShow(bg_id);
+    bgUpdate();
+}
+
+void Window_FreeFramebuffer(struct Bitmap* bmp) {
+	Mem_Free(bmp->scan0);
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Soft keyboard------------------------------------------------------*
+*#########################################################################################################################*/
+static char kbBuffer[NATIVE_STR_LEN + 1];
+static cc_string kbText;
+
+static void OnKeyPressed(int key) {
+    if (key == 0) {
+        OnscreenKeyboard_Close();
+    } else if (key == DVK_ENTER) {
+        OnscreenKeyboard_Close();
+        Input_SetPressed(CCKEY_ENTER);
+        Input_SetReleased(CCKEY_ENTER);
+    } else if (key == DVK_BACKSPACE) {
+        if (kbText.length) kbText.length--;
+        Event_RaiseString(&InputEvents.TextChanged, &kbText);
+    } else if (key > 0) {
+        String_Append(&kbText, key);
+        Event_RaiseString(&InputEvents.TextChanged, &kbText);
+    }
+}
+
+void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { 
+    Keyboard* kbd = keyboardGetDefault();
+    videoBgDisableSub(0); // hide console
+
+    keyboardInit(kbd, 3, BgType_Text4bpp, BgSize_T_256x512,
+                       14, 0, false, true);
+    keyboardShow();
+
+    kbd->OnKeyPressed = OnKeyPressed;
+    String_InitArray(kbText, kbBuffer);
+	String_AppendString(&kbText, args->text);
+    keyboardOpen = true;
+}
+
+void OnscreenKeyboard_SetText(const cc_string* text) { }
+
+void OnscreenKeyboard_Draw2D(Rect2D* r, struct Bitmap* bmp) { }
+void OnscreenKeyboard_Draw3D(void) { }
+
+void OnscreenKeyboard_Close(void) {
+    keyboardHide();
+	if (!keyboardOpen) return;
+    keyboardOpen = false;
+
+    videoBgEnableSub(0); // show console
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------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