From 2c163e5345c9a8a8d7ee5e6aed6fc93f769e2cf4 Mon Sep 17 00:00:00 2001 From: psxdev Date: Sun, 4 Feb 2024 16:15:42 +0100 Subject: [PATCH] add rcore_dreamcast with input pad from MikeDX --- src/platforms/rcore_dreamcast.c | 658 ++++++++++++++++++++++++++++++++ 1 file changed, 658 insertions(+) create mode 100644 src/platforms/rcore_dreamcast.c diff --git a/src/platforms/rcore_dreamcast.c b/src/platforms/rcore_dreamcast.c new file mode 100644 index 000000000..4b4d41678 --- /dev/null +++ b/src/platforms/rcore_dreamcast.c @@ -0,0 +1,658 @@ +/********************************************************************************************** +* +* rcore_dreamcast - Functions to manage window, graphics device and inputs +* +* PLATFORM: DREAMCAST +* - Sega Dreamcast +* +* LIMITATIONS: +* - Limitation 01 +* - Limitation 02 +* +* POSSIBLE IMPROVEMENTS: +* - Improvement 01 +* - Improvement 02 +* +* ADDITIONAL NOTES: +* - Port done by Antonio Jose Ramos Marquez aka bigboss @psxdev +* +* CONFIGURATION: +* #define RCORE_PLATFORM_CUSTOM_FLAG +* Custom flag for rcore on target platform -not used- +* +* DEPENDENCIES: +* Dreamcast SDK KOS KOS-PORTS - Provides C API to access Dreamcast homebrew functionality +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) and contributors +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ +#include + +#include +#include +#include + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct { + // TODO: Define the platform specific variables required + int version; + // Display data + //EGLDisplay device; // Native display device (physical screen connection) + //EGLSurface surface; // Surface to draw on, framebuffers (connected to context) + //EGLContext context; // Graphic context, mode in which drawing can be done + //EGLConfig config; // Graphic config +} PlatformData; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +extern CoreData CORE; // Global CORE state context + +static PlatformData platform = { 0 }; // Platform specific data + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +int InitPlatform(void); // Initialize platform (graphics, inputs and more) +bool InitGraphicsDevice(void); // Initialize graphics device + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +// NOTE: Functions declaration is provided by raylib.h + +//---------------------------------------------------------------------------------- +// Module Functions Definition: Window and Graphics Device +//---------------------------------------------------------------------------------- + +// Check if application should close +bool WindowShouldClose(void) +{ + if (CORE.Window.ready) return CORE.Window.shouldClose; + else return true; +} + +// Toggle fullscreen mode +void ToggleFullscreen(void) +{ + TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform"); +} + +// Toggle borderless windowed mode +void ToggleBorderlessWindowed(void) +{ + TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform"); +} + +// Set window state: maximized, if resizable +void MaximizeWindow(void) +{ + TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform"); +} + +// Set window state: minimized +void MinimizeWindow(void) +{ + TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform"); +} + +// Set window state: not minimized/maximized +void RestoreWindow(void) +{ + TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform"); +} + +// Set window configuration state using flags +void SetWindowState(unsigned int flags) +{ + TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform"); +} + +// Clear window configuration state flags +void ClearWindowState(unsigned int flags) +{ + TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform"); +} + +// Set icon for window +void SetWindowIcon(Image image) +{ + TRACELOG(LOG_WARNING, "SetWindowIcon() not available on target platform"); +} + +// Set icon for window +void SetWindowIcons(Image *images, int count) +{ + TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform"); +} + +// Set title for window +void SetWindowTitle(const char *title) +{ + CORE.Window.title = title; +} + +// Set window position on screen (windowed mode) +void SetWindowPosition(int x, int y) +{ + TRACELOG(LOG_WARNING, "SetWindowPosition() not available on target platform"); +} + +// Set monitor for the current window +void SetWindowMonitor(int monitor) +{ + TRACELOG(LOG_WARNING, "SetWindowMonitor() not available on target platform"); +} + +// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) +void SetWindowMinSize(int width, int height) +{ + CORE.Window.screenMin.width = width; + CORE.Window.screenMin.height = height; +} + +// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE) +void SetWindowMaxSize(int width, int height) +{ + CORE.Window.screenMax.width = width; + CORE.Window.screenMax.height = height; +} + +// Set window dimensions +void SetWindowSize(int width, int height) +{ + TRACELOG(LOG_WARNING, "SetWindowSize() not available on target platform"); +} + +// Set window opacity, value opacity is between 0.0 and 1.0 +void SetWindowOpacity(float opacity) +{ + TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform"); +} + +// Set window focused +void SetWindowFocused(void) +{ + TRACELOG(LOG_WARNING, "SetWindowFocused() not available on target platform"); +} + +// Get native window handle +void *GetWindowHandle(void) +{ + TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform"); + return NULL; +} + +// Get number of monitors +int GetMonitorCount(void) +{ + TRACELOG(LOG_WARNING, "GetMonitorCount() not implemented on target platform"); + return 1; +} + +// Get number of monitors +int GetCurrentMonitor(void) +{ + TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform"); + return 0; +} + +// Get selected monitor position +Vector2 GetMonitorPosition(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorPosition() not implemented on target platform"); + return (Vector2){ 0, 0 }; +} + +// Get selected monitor width (currently used by monitor) +int GetMonitorWidth(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorWidth() not implemented on target platform"); + return 0; +} + +// Get selected monitor height (currently used by monitor) +int GetMonitorHeight(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorHeight() not implemented on target platform"); + return 0; +} + +// Get selected monitor physical width in millimetres +int GetMonitorPhysicalWidth(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorPhysicalWidth() not implemented on target platform"); + return 0; +} + +// Get selected monitor physical height in millimetres +int GetMonitorPhysicalHeight(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorPhysicalHeight() not implemented on target platform"); + return 0; +} + +// Get selected monitor refresh rate +int GetMonitorRefreshRate(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorRefreshRate() not implemented on target platform"); + return 0; +} + +// Get the human-readable, UTF-8 encoded name of the selected monitor +const char *GetMonitorName(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorName() not implemented on target platform"); + return ""; +} + +// Get window position XY on monitor +Vector2 GetWindowPosition(void) +{ + TRACELOG(LOG_WARNING, "GetWindowPosition() not implemented on target platform"); + return (Vector2){ 0, 0 }; +} + +// Get window scale DPI factor for current monitor +Vector2 GetWindowScaleDPI(void) +{ + TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform"); + return (Vector2){ 1.0f, 1.0f }; +} + +// Set clipboard text content +void SetClipboardText(const char *text) +{ + TRACELOG(LOG_WARNING, "SetClipboardText() not implemented on target platform"); +} + +// Get clipboard text content +// NOTE: returned string is allocated and freed by GLFW +const char *GetClipboardText(void) +{ + TRACELOG(LOG_WARNING, "GetClipboardText() not implemented on target platform"); + return NULL; +} + +// Show mouse cursor +void ShowCursor(void) +{ + CORE.Input.Mouse.cursorHidden = false; +} + +// Hides mouse cursor +void HideCursor(void) +{ + CORE.Input.Mouse.cursorHidden = true; +} + +// Enables cursor (unlock cursor) +void EnableCursor(void) +{ + // Set cursor position in the middle + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); + + CORE.Input.Mouse.cursorHidden = false; +} + +// Disables cursor (lock cursor) +void DisableCursor(void) +{ + // Set cursor position in the middle + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); + + CORE.Input.Mouse.cursorHidden = true; +} + +// Swap back buffer with front buffer (screen drawing) +void SwapScreenBuffer(void) +{ + glKosSwapBuffers(); +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition: Misc +//---------------------------------------------------------------------------------- + +// Get elapsed time measure in seconds since InitTimer() +double GetTime(void) +{ + double time = 0.0; + struct timespec ts = { 0 }; + clock_gettime(CLOCK_MONOTONIC, &ts); + unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; + + time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() + + return time; +} + +// Open URL with default system browser (if available) +// NOTE: This function is only safe to use if you control the URL given. +// A user could craft a malicious string performing another action. +// Only call this function yourself not with user input or make sure to check the string yourself. +// Ref: https://github.com/raysan5/raylib/issues/686 +void OpenURL(const char *url) +{ + // Security check to (partially) avoid malicious code on target platform + if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + else + { + // TODO: + } +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition: Inputs +//---------------------------------------------------------------------------------- + +// Set internal gamepad mappings +int SetGamepadMappings(const char *mappings) +{ + TRACELOG(LOG_WARNING, "SetGamepadMappings() not implemented on target platform"); + return 0; +} + +// Set mouse position XY +void SetMousePosition(int x, int y) +{ + CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; + CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; +} + +// Set mouse cursor +void SetMouseCursor(int cursor) +{ + TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); +} + +// Register all input events +void PollInputEvents(void) +{ +#if defined(SUPPORT_GESTURES_SYSTEM) + // NOTE: Gestures update must be called every frame to reset gestures correctly + // because ProcessGestureEvent() is just called on an event, not every frame + UpdateGestures(); +#endif + + // Reset keys/chars pressed registered + CORE.Input.Keyboard.keyPressedQueueCount = 0; + CORE.Input.Keyboard.charPressedQueueCount = 0; + + // Reset key repeats + for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; + + // Reset last gamepad button/axis registered state + CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN + //CORE.Input.Gamepad.axisCount = 0; + + // Register previous touch states + for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; + + // Get number of gamepads connected + int numGamepads = 0; + maple_device_t *cont; + cont_state_t *pad_state; + + // Check if gamepads are ready + // NOTE: We do it here in case of disconnection + for (int i = 0; i < MAX_GAMEPADS; i++) + { + cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if(cont) { + CORE.Input.Gamepad.ready[i] = true; + numGamepads ++; + } else { + CORE.Input.Gamepad.ready[i] = false; + } + } + + for (int i = 0; (i < numGamepads) && (i < MAX_GAMEPADS); i++) + { + // Register previous gamepad button states + for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) + CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k]; + + cont = maple_enum_type(i, MAPLE_FUNC_CONTROLLER); + + pad_state = (cont_state_t *)maple_dev_status(cont); + + if (pad_state) + { + for (int k = 0; k < 16; k++) { // Dreamcast has 16 face buttons according to + // maple/controller.h + int button = -1; + int dcbutton = -1; + + switch(k) { + case 0: + // #define CONT_C (1<<0) /**< \brief C button Mask. */ + dcbutton = CONT_C; + button = GAMEPAD_BUTTON_UNKNOWN; + break; + case 1: + // #define CONT_B (1<<1) /**< \brief B button Mask. */ + dcbutton = CONT_B; + button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; + break; + case 2: + // #define CONT_A (1<<2) /**< \brief A button Mask. */ + dcbutton = CONT_A; + button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; + break; + case 3: + // #define CONT_START (1<<3) /**< \brief Start button Mask. */ + dcbutton = CONT_START; + button = GAMEPAD_BUTTON_MIDDLE_RIGHT; + break; + case 4: + // #define CONT_DPAD_UP (1<<4) /**< \brief Main Dpad Up button Mask. */ + dcbutton = CONT_DPAD_UP; + button = GAMEPAD_BUTTON_LEFT_FACE_UP; + break; + case 5: + // #define CONT_DPAD_DOWN (1<<5) /**< \brief Main Dpad Down button Mask. */ + dcbutton = CONT_DPAD_DOWN; + button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; + break; + case 6: + // #define CONT_DPAD_LEFT (1<<6) /**< \brief Main Dpad Left button Mask. */ + dcbutton = CONT_DPAD_LEFT; + button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; + break; + case 7: + // #define CONT_DPAD_RIGHT (1<<7) /**< \brief Main Dpad right button Mask. */ + dcbutton = CONT_DPAD_RIGHT; + button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; + break; + case 8: + // #define CONT_Z (1<<8) /**< \brief Z button Mask. */ + dcbutton = CONT_Z; + button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; + break; + case 9: + // #define CONT_Y (1<<9) /**< \brief Y button Mask. */ + dcbutton = CONT_Y; + button = GAMEPAD_BUTTON_RIGHT_FACE_UP; + break; + case 10: + // #define CONT_X (1<<10) /**< \brief X button Mask. */ + dcbutton = CONT_X; + button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; + break; + case 11: + // #define CONT_D (1<<11) /**< \brief D button Mask. */ + dcbutton = CONT_D; + button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; + break; + case 12: + // #define CONT_DPAD2_UP (1<<12) /**< \brief Secondary Dpad Up button Mask. */ + dcbutton = CONT_DPAD2_UP; + button = GAMEPAD_BUTTON_UNKNOWN; + break; + case 13: + // #define CONT_DPAD2_DOWN (1<<13) /**< \brief Secondary Dpad Down button Mask. */ + dcbutton = CONT_DPAD2_UP; + button = GAMEPAD_BUTTON_UNKNOWN; + break; + case 14: + // #define CONT_DPAD2_LEFT (1<<14) /**< \brief Secondary Dpad Left button Mask. */ + dcbutton = CONT_DPAD2_UP; + button = GAMEPAD_BUTTON_UNKNOWN; + break; + case 15: + // #define CONT_DPAD2_RIGHT (1<<15) /**< \brief Secondary Dpad Right button Mask. */ + dcbutton = CONT_DPAD2_UP; + button = GAMEPAD_BUTTON_UNKNOWN; + break; + default: + dcbutton = -1; + button = GAMEPAD_BUTTON_UNKNOWN; + break; + } + + if (button != -1) // Check for valid button + { + if (pad_state->buttons & dcbutton) + { + CORE.Input.Gamepad.currentButtonState[i][button] = 1; + CORE.Input.Gamepad.lastButtonPressed = button; + } + else CORE.Input.Gamepad.currentButtonState[i][button] = 0; + } + + //TRACELOGD("INPUT: Gamepad %d, button %d: Digital: %d, Analog: %g", gamepadState.index, j, gamepadState.digitalButton[j], gamepadState.analogButton[j]); + + // Register axis data for every connected gamepad + CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_X] = (1.0f * pad_state->joyx / 128); + CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_Y] = (1.0f * pad_state->joyy / 128); + CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = (1.0f * pad_state->ltrig)/255 ; + CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = (1.0f * pad_state->rtrig)/255; + CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_X] = pad_state->joy2x; + CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_Y] = pad_state->joy2y; + + CORE.Input.Gamepad.axisCount[i] = 6; + } + + // TODO: Add callbacks for connect / disconnected pads + + // Reset touch positions + // TODO: It resets on target platform the mouse position and not filled again until a move-event, + // so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed! + //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; + + // Register previous keys states + // NOTE: Android supports up to 260 keys + //for (int i = 0; i < 260; i++) + //{ + // CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; + // CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; + //} + + // TODO: Poll input events for current plaform + } + } +} + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- + +// Initialize platform: graphics, inputs and more +int InitPlatform(void) +{ + + TRACELOG(LOG_INFO, "PLATFORM: calling dreamcast gl init"); + glKosInit(); + + + + CORE.Window.fullscreen = true; + CORE.Window.flags |= FLAG_FULLSCREEN_MODE; + + CORE.Window.display.width = CORE.Window.screen.width; // User desired width + CORE.Window.display.height = CORE.Window.screen.height; // User desired height + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + CORE.Window.eventWaiting = false; + CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default + CORE.Window.currentFbo.width = CORE.Window.screen.width; + CORE.Window.currentFbo.height = CORE.Window.screen.height; + CORE.Input.Mouse.currentPosition.x = (float)CORE.Window.screen.width/2.0f; + CORE.Input.Mouse.currentPosition.y = (float)CORE.Window.screen.height/2.0f; + CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f }; + + + + + // At this point we need to manage render size vs screen size + // NOTE: This function use and modify global module variables: + // -> CORE.Window.screen.width/CORE.Window.screen.height + // -> CORE.Window.render.width/CORE.Window.render.height + // -> CORE.Window.screenScale + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); + + //ANativeWindow_setBuffersGeometry(platform.app->window, CORE.Window.render.width, CORE.Window.render.height, displayFormat); + //ANativeWindow_setBuffersGeometry(platform.app->window, 0, 0, displayFormat); // Force use of native display size + + + { + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + CORE.Window.currentFbo.width = CORE.Window.render.width; + CORE.Window.currentFbo.height = CORE.Window.render.height; + + TRACELOG(LOG_INFO, "PLATFORM: Device initialized successfully"); + TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); + TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); + TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); + TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); + } + + // Load OpenGL extensions + // NOTE: GL procedures address loader is required to load extensions + //rlLoadExtensions(eglGetProcAddress); + //const char *gl_exts = (char *) glGetString(GL_EXTENSIONS); + //TRACELOG(LOG_INFO,"PLATFORM: GL_VENDOR: \"%s\"", glGetString(GL_VENDOR)); + //TRACELOG(LOG_INFO,"PLATFORM: GL_VERSION: \"%s\"", glGetString(GL_VERSION)); + //TRACELOG(LOG_INFO,"PLATFORM: GL_RENDERER: \"%s\"", glGetString(GL_RENDERER)); + //TRACELOG(LOG_INFO,"PLATFORM: SL_VERSION: \"%s\"", glGetString(GL_SHADING_LANGUAGE_VERSION)); + CORE.Window.ready = true; + + // Initialize hi-res timer + InitTimer(); + + // Initialize base path for storage + CORE.Storage.basePath = GetWorkingDirectory(); + TRACELOG(LOG_INFO, "PLATFORM: Initialized"); + + return 0; +} + +// Close platform +void ClosePlatform(void) +{ + // TODO: De-initialize graphics, inputs and more +} + +// EOF