-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[core] Splitting rcore
by platform into submodules
#3313
Comments
Under approach Would it be under Or not in |
I think both approaches have pros and cons.
I think the best option could be In an ideal scenario, the "extra" required variables could be, maybe, removed or integrated in some way into the main |
EDIT: Copying the info from wishlist for reference:
This is not an easy task, still deciding the proper approach for it. There are 45 functions depending on ~100 GLFW functions, those 45 functions should be reproduced separately for the different platforms/technologies and exposed through the same common API. Also related to this void CloseWindow(void)
glfwDestroyWindow();
glfwTerminate();
bool WindowShouldClose(void)
glfwWaitEvents();
glfwWindowShouldClose();
void ToggleFullscreen(void)
glfwGetWindowPos()
glfwGetMonitors();
glfwSetWindowMonitor()
glfwSwapInterval();
void MaximizeWindow(void)
glfwGetWindowAttrib()
glfwMaximizeWindow()
void MinimizeWindow(void)
glfwIconifyWindow()
void RestoreWindow(void)
glfwRestoreWindow()
void SetWindowState(unsigned int flags)
glfwSwapInterval();
glfwSetWindowAttrib()
glfwHideWindow()
glfwShowWindow()
void SetWindowIcon(Image image)
glfwSetWindowIcon()
void SetWindowIcons(Image *images, int count)
glfwSetWindowIcon()
void SetWindowTitle(const char *title)
glfwSetWindowTitle()
void SetWindowPosition(int x, int y)
glfwSetWindowPos()
void SetWindowMonitor(int monitor)
glfwGetMonitors()
glfwGetMonitorName()
glfwGetVideoMode()
glfwSetWindowMonitor()
void SetWindowMinSize(int width, int height)
glfwGetVideoMode()
glfwSetWindowSizeLimits()
void SetWindowSize(int width, int height)
glfwSetWindowSize()
void SetWindowOpacity(float opacity)
glfwSetWindowOpacity()
void *GetWindowHandle(void)
glfwGetWin32Window()
glfwGetX11Window()
glfwGetCocoaWindow()
int GetMonitorCount(void)
glfwGetMonitors();
int GetCurrentMonitor(void)
glfwGetMonitors();
glfwGetWindowMonitor()
glfwGetWindowPos()
glfwGetMonitorWorkarea()
Vector2 GetMonitorPosition(int monitor)
glfwGetMonitors()
glfwGetMonitorPos()
int GetMonitorWidth(int monitor)
glfwGetMonitors()
glfwGetVideoMode()
int GetMonitorHeight(int monitor)
glfwGetMonitors()
glfwGetVideoMode()
int GetMonitorPhysicalWidth(int monitor)
glfwGetMonitors()
glfwGetMonitorPhysicalSize()
int GetMonitorPhysicalHeight(int monitor)
glfwGetMonitors()
glfwGetMonitorPhysicalSize()
int GetMonitorRefreshRate(int monitor)
glfwGetMonitors()
glfwGetVideoMode()
Vector2 GetWindowPosition(void)
glfwGetWindowPos()
Vector2 GetWindowScaleDPI(void)
glfwGetMonitors()
glfwGetMonitorContentScale()
glfwGetMonitorWorkarea()
const char *GetMonitorName(int monitor)
glfwGetMonitors()
glfwGetMonitorName()
void SetClipboardText(const char *text)
glfwSetClipboardString()
const char *GetClipboardText(void)
glfwGetClipboardString()
void ShowCursor(void)
glfwSetInputMode()
void HideCursor(void)
glfwSetInputMode()
void EnableCursor(void)
glfwSetInputMode()
void DisableCursor(void)
glfwSetInputMode()
double GetTime(void)
glfwGetTime()
const char *GetGamepadName(int gamepad)
glfwGetJoystickName();
void SetMousePosition(int x, int y)
glfwSetCursorPos()
void SetMouseCursor(int cursor)
glfwSetCursor()
glfwCreateStandardCursor()
static bool InitGraphicsDevice(int width, int height)
glfwSetErrorCallback();
glfwInitHint()
glfwInit()
glfwDefaultWindowHints();
glfwWindowHint()
glfwSetJoystickCallback();
glfwGetPrimaryMonitor();
glfwGetVideoMode(monitor);
glfwGetVideoModes()
glfwCreateWindow()
glfwSetWindowMonitor()
glfwTerminate();
glfwSetWindowSizeCallback()
glfwSetWindowMaximizeCallback()
glfwSetWindowIconifyCallback()
glfwSetWindowFocusCallback()
glfwSetDropCallback()
glfwSetKeyCallback()
glfwSetCharCallback()
glfwSetMouseButtonCallback()
glfwSetCursorPosCallback()
glfwSetScrollCallback()
glfwSetCursorEnterCallback()
glfwMakeContextCurrent();
glfwSetInputMode()
glfwSwapInterval()
glfwGetFramebufferSize()
glfwGetProcAddress()
static void SetupViewport(int width, int height)
glfwGetWindowContentScale()
void SwapScreenBuffer(void)
glfwSwapBuffers();
void PollInputEvents(void)
glfwJoystickPresent()
glfwGetGamepadState()
glfwWaitEvents()
glfwPollEvents()
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
glfwSetWindowShouldClose() Here the functions list clean: void CloseWindow(void)
bool WindowShouldClose(void)
void ToggleFullscreen(void)
void MaximizeWindow(void
void MinimizeWindow(void)
void RestoreWindow(void)
void SetWindowState(unsigned int flags)
void SetWindowIcon(Image image)
void SetWindowIcons(Image *images, int count)
void SetWindowTitle(const char *title)
void SetWindowPosition(int x, int y)
void SetWindowMonitor(int monitor)
void SetWindowMinSize(int width, int height)
void SetWindowSize(int width, int height)
void SetWindowOpacity(float opacity)
void *GetWindowHandle(void)
int GetMonitorCount(void)
int GetCurrentMonitor(void)
Vector2 GetMonitorPosition(int monitor)
int GetMonitorWidth(int monitor)
int GetMonitorHeight(int monitor)
int GetMonitorPhysicalWidth(int monitor)
int GetMonitorPhysicalHeight(int monitor)
int GetMonitorRefreshRate(int monitor)
Vector2 GetWindowPosition(void)
Vector2 GetWindowScaleDPI(void)
const char *GetMonitorName(int monitor)
void SetClipboardText(const char *text)
const char *GetClipboardText(void)
void ShowCursor(void)
void HideCursor(void)
void EnableCursor(void)
void DisableCursor(void)
double GetTime(void)
const char *GetGamepadName(int gamepad)
void SetMousePosition(int x, int y)
void SetMouseCursor(int cursor)
static bool InitGraphicsDevice(int width, int height)
static void SetupViewport(int width, int height)
void SwapScreenBuffer(void)
void PollInputEvents(void) Most of those functions could be not required on target platform and just fallback to some default value. |
This would be excellent. Would make a lot simpler for anyone that want/need to extend it. I'd vote for this one. |
I like that. It would be super clear. And a shared data structure would probably guide platform specific development to re-use rather than reinvent since every platform would have access to all the data structure anyway. I hadn't considered multiple windows when I was thinking through it so the approach I was leaning towards before would probably need a lot of work to handle that sanely. And it would lose a lot of clarity. |
@michaelfiber @ubkp I've been thinking about the best approach for code organization and I got to the conclusion that avoiding breaking all raylib current build systems (and potentially many bindings or user codebases) is the best option, my idea is to just keep the // rcore.c
// Required data types and variables
#if defined(PLATFORM_DESKTOP)
#include "rcore_desktop.c"
#elif defined(PLATFORM_WEB)
#include "rcore_web.c"
#elif defined(PLATFOM_DRM)
#include "rcore_drm.c"
#elif defined(PLATFOM_ANDROID)
#include "rcore_android.c"
#else
// Software rendering backend, user needs to provide buffer ;)
#endif
// Common functions to all platforms From an academic point of view it could be ugly but in practice it works very well. |
@michaelfiber @ubkp I'd also like to accelerate the development of this improvement, considering the latest events on the gamedev industry I think it could be beneficial for raylib in multiple ways, for example to allow other contributors to hook additional platforms in an easy way; at this moment I know is quite scary to look at Please, let me know if you could help me with this big redesign! |
Edit:
|
Doing it this way feels wrong but I completely understand not wanting to break builds. Updating the Makefile was easy but I don't know about updating the others. Right now for testing I'm going to leave the Makefile change and then as I progress through this maybe I'll spot another way that doesn't feel so wrong? With the position of raylib as a great tool for education I'd hate to include something that would have a comment like Also for the CoreData I realized that if all the data is always there without preprocessor directives then it either needs all dependencies included no matter that target platform OR a lot of void pointers that will have to be cast each time in the platform specific rcore files. Right now I am leaving the TL;DR:
|
@ubkp here the answers for your questions:
@michaelfiber I know, it feels wrong... but it actually works like a charm for this kind of situations. |
@raysan5 Ok, I can try that out. |
I'll probably just go function by function through rcore and move the functions that have platform_specific logic. That will probably align with the list of functions that reference glfw but I'm not sure. Also If you are keeping a list then |
Immediately as I make this transition I see the opportunity to add some simple javascript functions to the default HTML templates for emscripten that would help with things like reading the clipboard and disabling the cursor without having the ID of the canvas element hard coded into raylib. That makes me think this submodule approach might be a good one. It's much easier to check at a glance how complete each implementation is. |
@michaelfiber If you need help with anything, please let me know. |
@michaelfiber thank you very much for this big effort! Undoubtely it opens the door to many per-platform improvements. This is a lot of work, please, let me and @ubkp help with it. I created a separate branch to start merging the changes: https://github.com/raysan5/raylib/tree/rcore_platform_split We can divide the functions to port in chunks between us. Also, I'm locking any change in |
rcore
by platform into submodules
I'm doing a basic split on the platform specific preprocessor directives so it's actually very easy. But once its done the real work of making sure each submodule is correct and builds will be more time consuming I think and that'll be very easy to divvy up. I should be done splitting rcore today and maybe after that we can share going through the submodules? |
Perfect, it sounds like a plan. Feel free to send the redesign to I'm not touching |
@raysan5 I changed PR #3311 to target I did all my work on Linux and it shows as the linux builds are the only ones working at this time. The windows build has been succeeding every time I push even though it was definitely actually failing so that needs more than just the github action to verify if it is working at all. I think this is a good place to start divvying up the work since different people can work on different submodules simuiltaneously and the only real friction will be when changes need to be made to rcore.c or rcore.h. I'm going to be away from my computer for a few days now but when I get back I can continue to hack away at some of this. I would probably start working specifically on PLATFORM_DRM since I have some experience with it and a variety of devices already running raylib projects to test with. |
@michaelfiber Thank you very much for the big amount work put into this improvement! I'm merging it right now and reviewing Windows build in the following days! Thanks! |
@raysan5 @michaelfiber I can review |
@raysan5 @michaelfiber I have cloned the branch and my Windows x64 build using VC/C++ fails with a fatal error in compiling
Seems to be the case. 2023-09-21T00:02Z @ubkp @raysan5 @michaelfiber That problem is now fixed and a simple conformation test of raylib component compiles works fine. |
@orcmid @ubkp Sorry, I broke it just trying some things, reviewed it now, it should work but still some issues... I'm afraid this redesign could be more complex than I anticipated... let's see how evolves... |
@raysan5 Would it be a bad idea to move |
@ubkp I prefer to avoid that, it will add too much uneeded content in |
Yeah I think its more likely rcore.h will go away than be integrated with raylib.h. With the #includes being there there isn't a ton of need for it except that I think the IDE experience might break down a bit without it. I could be wrong though. |
@raysan5 I moved raymath.h out of rcore.h because it was clobbering the That fixed my build issues across platform related to not being able to find raymath functions. EDIT: I closed that down because I was still committing to the branch. I am trying to rush things a bit too much. I also moved the block of code that includes the submodules to the end of rcore.c because I realized I put it ahead of function definitions originally and that was creating issues compiling examples. @ubkp did you encounter this as well in your work? |
Please note that I pushed a commit to |
@michaelfiber Not yet. Testing I'm still going through all functions but, so far, everything is working really well. You did an incredible job on the split. 👍 |
@Bigfoot71 Awesome! Thank you very much! My apologies again for deleting the message. I was trying to do two things at once and messed up. |
Or we think that the problem comes from our way of obtaining the mouse delta. We could make sure that Edit: This way the delta would always be correct and the mouse would not be stuck in the center of the screen when hidden. Edit 2: But it would be necessary to create a new variable to store the delta. When trying Alternatively, we could see how |
@Bigfoot71 Yeah, you're right. Also good idea using the
This sounds like a good solution. By the way, I was messing around testing zeroing the Edit: @Bigfoot71 Yeah, I'm trying to figure out why |
@Bigfoot71 Managed to fix it. I'll clean this up and send you a diff. The solution was zeroing indeed. |
@Bigfoot71 Could you please test this: diff --git a/rcore_desktop_sdl.c b/rcore_desktop_sdl_FIXED.c
index cddee74..8657094 100644
--- a/rcore_desktop_sdl.c
+++ b/rcore_desktop_sdl_FIXED.c
@@ -63,6 +63,7 @@ typedef struct {
SDL_Joystick *gamepad;
SDL_Cursor *cursor;
+ bool cursorRelative;
} PlatformData;
//----------------------------------------------------------------------------------
@@ -529,7 +530,7 @@ void EnableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_FALSE);
SDL_ShowCursor(SDL_ENABLE);
-
+ platform.cursorRelative = false;
CORE.Input.Mouse.cursorHidden = false;
}
@@ -537,7 +538,7 @@ void EnableCursor(void)
void DisableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_TRUE);
-
+ platform.cursorRelative = true;
CORE.Input.Mouse.cursorHidden = true;
}
@@ -612,7 +613,8 @@ void PollInputEvents(void)
CORE.Input.Mouse.currentWheelMove.y = 0;
// Register previous mouse position
- CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+ if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
+ else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
// Reset last gamepad button/axis registered state
CORE.Input.Gamepad.lastButtonPressed = GAMEPAD_BUTTON_UNKNOWN;
@@ -710,8 +712,17 @@ void PollInputEvents(void)
} break;
case SDL_MOUSEMOTION:
{
- CORE.Input.Mouse.currentPosition.x = (float)event.motion.x;
- CORE.Input.Mouse.currentPosition.y = (float)event.motion.y;
+ if (platform.cursorRelative)
+ {
+ CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel;
+ CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel;
+ CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
+ }
+ else
+ {
+ CORE.Input.Mouse.currentPosition.x = (float)event.motion.x;
+ CORE.Input.Mouse.currentPosition.y = (float)event.motion.y;
+ }
} break;
// Check gamepad events What do you think? If you agree, feel free to add it to #3439. |
@ubkp I try this right after! Otherwise, do you think it is necessary to check |
@Bigfoot71 IMHO, I don't think it's necessary right now. |
@ubkp Your solution for the delta works! I'm adding it to the PR! The only issue left is with simplescreenrecorder-2023-10-18_20.31.03.mp4 |
@Bigfoot71 Oh yeah, forgot about that. Let me take a look at it. |
@Bigfoot71 I think I found the problem. Looks like we are polling by I guess the solution could be checking What do you think? Edit: code correction. Edit 2, 3: |
@ubkp, look no further, I've found it, and it was quite simple. I had realized that it wasn't working for all the keys, and I immediately guessed that it was the loop for defining the previous keys. Currently, we are doing this: for (int i = 0; i < 260; i++)
{
CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
} However, with for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
{
CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
} |
@Bigfoot71 Great catch! Tested here and that's indeed the fix. Great job! |
@ubkp It was the sneaky error; now we need to see what's missing. I think we've covered almost everything, haven't we? (Except for |
@Bigfoot71 Yup, I think this was indeed mostly it. It was a great sprint! Really fantastic job! 👍 There are a few minor things like @raysan5 After reviewing and merging #3439, if you want to move everything to a |
@ubkp I just see that only For DPI, it doesn't seem to work the same way as with GLFW. Here is the SDL function (doc): int SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi); It returns a diagonal, horizontal, and vertical value, but I'm not sure if you need to divide the value or use it as is. (to see) I will now see for Edit: I have a feeling that SDL won't support |
@Bigfoot71 That's true. I actually thought
For And as I type this I just realized I probably used the wrong Edit 2: Tested with all 3 (ddpi, hdpi, vdpi), their values are almost he same:
I think the ddpi is the correct one. If anyone knows if we should be using the others instead, please send a PR correcting it. Edit 3: Changed at #3442. |
@Bigfoot71 @ubkp thank you very much for all the latests reviews and improvements! Excuse for the late response, for the last two days I've been working on Switch platform and thanks to the platform split, it worked very nicely! Unfortunately, that platform can not be open sourced... |
@michaelfiber @ubkp @Bigfoot71 Hi! Just moved the Also marked |
Tested current master branch (081fffd) successfully:
Edit 2: Environment: Linux (Ubuntu 22.04 64-bit); Web (Firefox 115.3.1esr 64-bit and Chromium 117.0.5938.149 64-bit); DRM (Raspberry Pi 3 Model B 1.2 with Raspberry Pi OS 11 Bullseye 32-bit armhf). Edit 1, 4, 5: corrections. |
No problems reported with the Makefile for |
I think this issue can already by closed. @ubkp @michaelfiber @Bigfoot71 thank you very much for making it possible! I think is about time to prepare |
@raysan5 Just one last issue. While using ScreenshotCode example
If you can, could you please take a look at this issue. I really wasn't able to figure out why. It's probably something that should be fixed before the Edit: updated code example. |
@raysan5 I think the issue above is because we're missing something like We probably need to poll the Edit: editing. |
Maybe an event watch could help us avoid putting the resizing detection in the input-related function. (doc) I could take a look at it tomorrow if I have some time, if you'd like. Edit: Sorry for the link problem, phone... |
@Bigfoot71 Very good find! By the way, while inspecting the So, as a temporary/stopgap fix, changed it to this (which fixes the issue):
@Bigfoot71 Since I have this ready, I'll add it to #3450. But feel free to revert it and properly fix it with |
@ubkp @Bigfoot71 Yeah, I prefer to avoid the callback system and just do the polling manually, I just left the |
Issue description
As part of my experimenting in pr #3311 to divide rcore into submodules, one of the things I found was that the CoreData structure adds a lot of complexity to that endeavor and MAY benefit from being split up as well. I believe it may benefit because the current CoreData structure can be fairly difficult to understand with the large number of preprocessor directives within the struct itself. This is largely done to accommodate the many different target platforms. But if rcore is divided into different submodules based on platforms there is an opportunity to increase clarity.
Here are a couple of initial ideas for approaches:
Maintain a single instance of CoreData but have CoreData only contain data that all submodules use so that it is a simpler struct with no preprocessor directives. A single CORE instance would be defined extern in rcore.h, defined in rcore.c, and accessed from rcore.c and all the submodules. In addition to this each submodule would have a small CoreData like struct of its own, i.e. DesktopData, WebData, etc. The data that is currently in CoreData that is specific to an submodule would be moved to the data struct in that submodule. Each struct definition would become much more legible because it wouldn't be full of preprocessor directives but there would be more structs overall and they'd be more spread out instead of centralized in rcore.
Another option could be to have the CoreData struct defined entirely within a submodule specific header file so that each submodule has a complete CoreData struct and rcore.c can include a specific one based on the PLATFORM variable. There'd be more duplication but fewer structs and data would not be divided across multiple structs. Any changes to the data in CoreData that is used by all submodules would require applying the change to each submodule.
Personally I'm leaning towards the first option but am interested in what others think.
Environment
Experiments are being coded in Ubuntu 23.04 and leverage github actions to attempt to run build steps for all platforms.
Code Example
#3311
The text was updated successfully, but these errors were encountered: