#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 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