summary refs log tree commit diff
path: root/src/Window_Dreamcast.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_Dreamcast.c
initial commit
Diffstat (limited to 'src/Window_Dreamcast.c')
-rw-r--r--src/Window_Dreamcast.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/src/Window_Dreamcast.c b/src/Window_Dreamcast.c
new file mode 100644
index 0000000..7502130
--- /dev/null
+++ b/src/Window_Dreamcast.c
@@ -0,0 +1,353 @@
+#include "Core.h"
+#if defined CC_BUILD_DREAMCAST
+#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 "VirtualKeyboard.h"
+#include <kos.h>
+static cc_bool launcherMode;
+cc_bool window_inited;
+
+struct _DisplayData DisplayInfo;
+struct _WindowData WindowInfo;
+
+void Window_PreInit(void) {
+	vid_set_mode(DEFAULT_VID_MODE, DEFAULT_PIXEL_MODE);
+	vid_flip(0);
+
+	int cable = vid_check_cable();
+	if (cable == CT_VGA) return;
+
+	if (flashrom_get_region() == FLASHROM_REGION_EUROPE) {
+		Platform_LogConst("Forcing 50hz for PAL region");
+		vid_set_mode(DM_640x480_PAL_IL, DEFAULT_PIXEL_MODE);
+	}
+}
+
+void Window_Init(void) {
+	DisplayInfo.Width  = vid_mode->width;
+	DisplayInfo.Height = vid_mode->height;
+	DisplayInfo.ScaleX = 1;
+	DisplayInfo.ScaleY = 1;
+	
+	Window_Main.Width   = vid_mode->width;
+	Window_Main.Height  = vid_mode->height;
+	Window_Main.Focused = true;
+	Window_Main.Exists  = true;
+
+	Input.Sources = INPUT_SOURCE_GAMEPAD;
+	DisplayInfo.ContentOffsetX = 10;
+	DisplayInfo.ContentOffsetY = 20;
+	Window_Main.SoftKeyboard   = SOFT_KEYBOARD_VIRTUAL;
+
+	window_inited = true;
+}
+
+void Window_Free(void) { }
+
+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-----------------------------------------------------*
+*#########################################################################################################################*/
+// TODO: More intelligent diffing that uses less space
+static cc_bool has_prevState;
+static kbd_state_t prevState;
+
+static int MapKey(int k) {
+	if (k >= KBD_KEY_A  && k <= KBD_KEY_Z)   return 'A'      + (k - KBD_KEY_A);
+	if (k >= KBD_KEY_0  && k <= KBD_KEY_9)   return '0'      + (k - KBD_KEY_0);
+	if (k >= KBD_KEY_F1 && k <= KBD_KEY_F12) return CCKEY_F1 + (k - KBD_KEY_F1);
+	// KBD_KEY_PAD_0 isn't before KBD_KEY_PAD_1
+	if (k >= KBD_KEY_PAD_1 && k <= KBD_KEY_PAD_9) return CCKEY_KP1 + (k - KBD_KEY_PAD_1);
+	
+	switch (k) {
+	case KBD_KEY_ENTER:     return CCKEY_ENTER;
+	case KBD_KEY_ESCAPE:    return CCKEY_ESCAPE;
+	case KBD_KEY_BACKSPACE: return CCKEY_BACKSPACE;
+	case KBD_KEY_TAB:       return CCKEY_TAB;
+	case KBD_KEY_SPACE:     return CCKEY_SPACE;
+	case KBD_KEY_MINUS:     return CCKEY_MINUS;
+	case KBD_KEY_PLUS:      return CCKEY_EQUALS;
+	case KBD_KEY_LBRACKET:  return CCKEY_LBRACKET;
+	case KBD_KEY_RBRACKET:  return CCKEY_RBRACKET;
+	case KBD_KEY_BACKSLASH: return CCKEY_BACKSLASH;
+	case KBD_KEY_SEMICOLON: return CCKEY_SEMICOLON;
+	case KBD_KEY_QUOTE:     return CCKEY_QUOTE;
+	case KBD_KEY_TILDE:     return CCKEY_TILDE;
+	case KBD_KEY_COMMA:     return CCKEY_COMMA;
+	case KBD_KEY_PERIOD:    return CCKEY_PERIOD;
+	case KBD_KEY_SLASH:     return CCKEY_SLASH;
+	case KBD_KEY_CAPSLOCK:  return CCKEY_CAPSLOCK;
+	case KBD_KEY_PRINT:     return CCKEY_PRINTSCREEN;
+	case KBD_KEY_SCRLOCK:   return CCKEY_SCROLLLOCK;
+	case KBD_KEY_PAUSE:     return CCKEY_PAUSE;
+	case KBD_KEY_INSERT:    return CCKEY_INSERT;
+	case KBD_KEY_HOME:      return CCKEY_HOME;
+	case KBD_KEY_PGUP:      return CCKEY_PAGEUP;
+	case KBD_KEY_DEL:       return CCKEY_DELETE;
+	case KBD_KEY_END:       return CCKEY_END;
+	case KBD_KEY_PGDOWN:    return CCKEY_PAGEDOWN;
+	case KBD_KEY_RIGHT:     return CCKEY_RIGHT;
+	case KBD_KEY_LEFT:      return CCKEY_LEFT;
+	case KBD_KEY_DOWN:      return CCKEY_DOWN;
+	case KBD_KEY_UP:        return CCKEY_UP;
+	
+	case KBD_KEY_PAD_NUMLOCK:  return CCKEY_NUMLOCK;
+	case KBD_KEY_PAD_DIVIDE:   return CCKEY_KP_DIVIDE;
+	case KBD_KEY_PAD_MULTIPLY: return CCKEY_KP_MULTIPLY;
+	case KBD_KEY_PAD_MINUS:    return CCKEY_KP_MINUS;
+	case KBD_KEY_PAD_PLUS:     return CCKEY_KP_PLUS;
+	case KBD_KEY_PAD_ENTER:    return CCKEY_KP_ENTER;
+	case KBD_KEY_PAD_0:        return CCKEY_KP0;
+	case KBD_KEY_PAD_PERIOD:   return CCKEY_KP_DECIMAL;
+	}
+	return INPUT_NONE;
+}
+#define ToggleKey(diff, cur, mask, btn) if (diff & mask) Input_Set(btn, cur & mask)
+static void UpdateKeyboardState(kbd_state_t* state) {
+	int cur_keys  = state->shift_keys;
+	int diff_keys = prevState.shift_keys ^ state->shift_keys;
+	
+	if (diff_keys) {
+		ToggleKey(diff_keys, cur_keys, KBD_MOD_LALT,   CCKEY_LALT);
+		ToggleKey(diff_keys, cur_keys, KBD_MOD_RALT,   CCKEY_RALT);
+		ToggleKey(diff_keys, cur_keys, KBD_MOD_LCTRL,  CCKEY_LCTRL);
+		ToggleKey(diff_keys, cur_keys, KBD_MOD_RCTRL,  CCKEY_RCTRL);
+		ToggleKey(diff_keys, cur_keys, KBD_MOD_LSHIFT, CCKEY_LSHIFT);
+		ToggleKey(diff_keys, cur_keys, KBD_MOD_RSHIFT, CCKEY_RSHIFT);
+	}
+	
+	// see keyboard.h, KEY_S3 seems to be highest used key
+	for (int i = KBD_KEY_A; i < KBD_KEY_S3; i++)
+	{
+		if (state->matrix[i] == prevState.matrix[i]) continue;
+		int btn = MapKey(i);
+		if (btn) Input_Set(btn, state->matrix[i]);
+	}
+}
+
+static void ProcessKeyboardInput(void) {
+	maple_device_t* kb_dev;
+	kbd_state_t* state;
+
+	kb_dev = maple_enum_type(0, MAPLE_FUNC_KEYBOARD);
+	if (!kb_dev) return;
+	state  = (kbd_state_t*)maple_dev_status(kb_dev);
+	if (!state)  return;
+	
+	if (has_prevState) UpdateKeyboardState(state);
+	has_prevState = true;
+	prevState     = *state;
+	
+	Input.Sources |= INPUT_SOURCE_NORMAL;
+	int ret = kbd_queue_pop(kb_dev, 1);
+	if (ret < 0) return;
+        
+	// Ascii printable characters
+	//  NOTE: Escape, Enter etc map to ASCII control characters
+	if (ret >= ' ' && ret <= 0x7F)
+		Event_RaiseInt(&InputEvents.Press, ret);
+}
+
+
+/*########################################################################################################################*
+*----------------------------------------------------Input processing-----------------------------------------------------*
+*#########################################################################################################################*/
+static void ProcessMouseInput(float delta) {
+	maple_device_t* mouse;
+	mouse_state_t*  state;
+
+	mouse = maple_enum_type(0, MAPLE_FUNC_MOUSE);
+	if (!mouse) return;
+	state = (mouse_state_t*)maple_dev_status(mouse);
+	if (!state) return;
+	
+	int mods = state->buttons;
+	Input_SetNonRepeatable(CCMOUSE_L, mods & MOUSE_LEFTBUTTON);
+	Input_SetNonRepeatable(CCMOUSE_R, mods & MOUSE_RIGHTBUTTON);
+	Input_SetNonRepeatable(CCMOUSE_M, mods & MOUSE_SIDEBUTTON);
+	
+	if (!Input.RawMode) return;	
+	float scale = (delta * 60.0) / 2.0f;
+	Event_RaiseRawMove(&PointerEvents.RawMoved, 
+				state->dx * scale, state->dy * scale);
+}
+
+void Window_ProcessEvents(float delta) {
+	ProcessKeyboardInput();
+	ProcessMouseInput(delta);
+}
+
+void Cursor_SetPosition(int x, int y) { } /* TODO: Dreamcast mouse support */
+
+void Window_EnableRawMouse(void)  { Input.RawMode = true;  }
+void Window_DisableRawMouse(void) { Input.RawMode = false; }
+void Window_UpdateRawMouse(void)  { }
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------Gamepads----------------------------------------------------------*
+*#########################################################################################################################*/
+static void HandleButtons(int port, int mods) {
+	Gamepad_SetButton(port, CCPAD_A, mods & CONT_A);
+	Gamepad_SetButton(port, CCPAD_B, mods & CONT_B);
+	Gamepad_SetButton(port, CCPAD_X, mods & CONT_X);
+	Gamepad_SetButton(port, CCPAD_Y, mods & CONT_Y);
+      
+	Gamepad_SetButton(port, CCPAD_START,  mods & CONT_START);
+	Gamepad_SetButton(port, CCPAD_SELECT, mods & CONT_D);
+
+	Gamepad_SetButton(port, CCPAD_LEFT,   mods & CONT_DPAD_LEFT);
+	Gamepad_SetButton(port, CCPAD_RIGHT,  mods & CONT_DPAD_RIGHT);
+	Gamepad_SetButton(port, CCPAD_UP,     mods & CONT_DPAD_UP);
+	Gamepad_SetButton(port, CCPAD_DOWN,   mods & CONT_DPAD_DOWN);
+	
+	// Buttons not on standard controller
+	Gamepad_SetButton(port, CCPAD_C,       mods & CONT_C);
+	Gamepad_SetButton(port, CCPAD_D,       mods & CONT_D);
+	Gamepad_SetButton(port, CCPAD_Z,       mods & CONT_Z);
+	Gamepad_SetButton(port, CCPAD_CLEFT,   mods & CONT_DPAD2_LEFT);
+	Gamepad_SetButton(port, CCPAD_CRIGHT,  mods & CONT_DPAD2_RIGHT);
+	Gamepad_SetButton(port, CCPAD_CUP,     mods & CONT_DPAD2_UP);
+	Gamepad_SetButton(port, CCPAD_CDOWN,   mods & CONT_DPAD2_DOWN);
+}
+
+#define AXIS_SCALE 8.0f
+static void HandleJoystick(int port, int axis, int x, int y, float delta) {
+	if (Math_AbsI(x) <= 8) x = 0;
+	if (Math_AbsI(y) <= 8) y = 0;	
+	
+	Gamepad_SetAxis(port, axis, x / AXIS_SCALE, y / AXIS_SCALE, delta);
+}
+
+static void HandleController(int port, cont_state_t* state, float delta) {
+	Gamepad_SetButton(port, CCPAD_L, state->ltrig > 10);
+	Gamepad_SetButton(port, CCPAD_R, state->rtrig > 10);
+	// TODO second joystick
+	// TODO: verify values are right     
+	HandleJoystick(port, PAD_AXIS_RIGHT, state->joyx, state->joyy, delta);
+}
+
+void Window_ProcessGamepads(float delta) {
+	maple_device_t* cont;
+	cont_state_t*  state;
+
+	for (int port = 0; port < INPUT_MAX_GAMEPADS; port++)
+	{
+		cont  = maple_enum_type(port, MAPLE_FUNC_CONTROLLER);
+		if (!cont)  return;
+		state = (cont_state_t*)maple_dev_status(cont);
+		if (!state) return;
+		
+		HandleButtons(port, state->buttons);
+		HandleController(port, state, 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) {
+	// TODO: double buffering ??
+	//	https://dcemulation.org/phpBB/viewtopic.php?t=99999
+	//	https://dcemulation.org/phpBB/viewtopic.php?t=43214
+	vid_waitvbl();
+	
+	for (int y = r.y; y < r.y + r.height; y++)
+	{
+		BitmapCol* src = Bitmap_GetRow(bmp, y);
+		uint16_t*  dst = vram_s + vid_mode->width * y;
+		
+		for (int x = r.x; x < r.x + r.width; x++)
+		{
+			BitmapCol color = src[x];
+			// 888 to 565 (discard least significant bits)
+			dst[x] = ((BitmapCol_R(color) & 0xF8) << 8) | ((BitmapCol_G(color) & 0xFC) << 3) | (BitmapCol_B(color) >> 3);
+		}
+	}
+}
+
+void Window_FreeFramebuffer(struct Bitmap* bmp) {
+	Mem_Free(bmp->scan0);
+}
+
+
+/*########################################################################################################################*
+*------------------------------------------------------Soft keyboard------------------------------------------------------*
+*#########################################################################################################################*/
+void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { 
+	if (Input.Sources & INPUT_SOURCE_NORMAL) return;
+	VirtualKeyboard_Open(args, launcherMode);
+}
+
+void OnscreenKeyboard_SetText(const cc_string* text) {
+	VirtualKeyboard_SetText(text);
+}
+
+void OnscreenKeyboard_Draw2D(Rect2D* r, struct Bitmap* bmp) {
+	VirtualKeyboard_Display2D(r, bmp);
+}
+
+void OnscreenKeyboard_Draw3D(void) {
+	VirtualKeyboard_Display3D();
+}
+
+void OnscreenKeyboard_Close(void) {
+	VirtualKeyboard_Close();
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------------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