Closed michaelfiber closed 1 year ago
Under approach 1
, what would happen to a member that is used, lets say, by PLATFORM_DESKTOP
and PLATFORM_WEB
but not PLATFORM_ANDROID
nor PLATFORM_DRM
.
Would it be under rcore
?
Or not in rcore
but duplicated on rcore_desktop
and on rcore_web
?
I think both approaches have pros and cons.
1
keeps a common unified structure for all platforms with just "some" static additional variables per module (duplicated if required, @ubkp) but makes it more difficult to create multi-windows applications in case it was needed, because of those same custom variables, some pieces of data are spread around. 2
allows more customization per platform and makes the modules more self-contained per platform, but also increases the complexity dealing with multiple duplicated structs, if a change is needed, it should be maybe propagated to all platforms, for example, recently some new variables were added.I think the best option could be 1
, despite the cons. concerns. I think the number of custom variables is not that big and it should be easier to manage if well organized and documented in the code.
In an ideal scenario, the "extra" required variables could be, maybe, removed or integrated in some way into the main CoreData
struct... Actually, that's another possibility, just keep everything in CoreData
independently of the platform, beeing used or not. Probably the overload won't be that dramatic...
EDIT: Copying the info from wishlist for reference:
rcore_desktop.c
- PLATFORM_DESKTOP
(Windows, Linux, macOS)rcore_android.c
- PLATFORM_ANDROID
rcore_native.c
- PLATFORM_DRM
/PLATFORM_RPI
rcore_web.c
- PLATFORM_WEB
rcore_glfw.c
- GLFW library basedrcore_sdl.c
- SDL library basedrcore_native.c
- Native implementationThis 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 submodules
project, some time ago I created a list of functions dependant on GLFW (PLATFORM_DESKTOP
), that's probably the list of functions that should be duplicated between platform:
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.
Actually, that's another possibility, just keep everything in
CoreData
independently of the platform, beeing used or not. Probably the overload won't be that dramatic...
This would be excellent. Would make a lot simpler for anyone that want/need to extend it. I'd vote for this one.
Actually, that's another possibility, just keep everything in
CoreData
independently of the platform, beeing used or not. Probably the overload won't be that dramatic...
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
as the base module, containing all common functions BUT also the inclusion of the required submodules:
// 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 rcore
.
Please, let me know if you could help me with this big redesign!
my idea is to just keep the rcore.c as the base module, containing all common functions BUT also the inclusion of the required submodules
IsWindowMinimized()
(L1154-L1160), would it be under rcore.c
with its #ifdefs
? Or not in rcore.c
but duplicated on rcore_desktop.c
and rcore_web.c
?rcore.c
, then I don't think much would change. rcore.c
would still have a considerable amount of #ifdefs
, thus harder to track. I guess most functions would fall under that case.
if defined(PLATFORM_DESKTOP)
include "rcore_desktop.c"
elif
for example to allow other contributors to hook additional platforms in an easy way;
iOS
. IMHO, I don't think we'd be seeing aditional (e.g.: consoles) platforms even if the conditions were right because of the SDKs and NDAs. Just as a reference, quoting the Godot documentation on a similar subject:The reason other consoles are not officially supported are:
To develop for consoles, one must be licensed as a company. As an open source project, Godot has no legal structure to provide console ports.
Console SDKs are secret and covered by non-disclosure agreements. Even if we could get access to them, we could not publish the platform-specific code under an open source license.
Edit:
I'd also like to accelerate the development of this improvement
@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
as the base module, containing all common functions BUT also the inclusion of the required submodules:// 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.
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 // You shouldn't do this
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 #if defined(PLATFORM_*)
directives in the struct as I split out the rest of the functions. The CoreData structure doesn't get any more difficult to read than it did before but it maintains its very difficult to read directives. Another less disruptive approach may be a simple refactor to move platform specific stuff so there's just one directive per platform in CoreData. CORE->handle
would become CORE->desktop->handle
for instance. It does mean some repeated data structures between platforms but I think the readability would increase dramatically.
TL;DR:
#include "rcore_*.c"
because I would like to not break the build files so thoroughly and I would also like to avoid including a C file if at all possible.@ubkp here the answers for your questions:
In those cases the function would be duplicated for all platforms requiring it.
It's not recommended and probably bad practice from an academic point of view, still, it can be used and it's really handy. Actually raylib uses that approach for all its external libraries, #define XXXX_IMPLEMENTATION
does exactly that.
Yes, most noticeable missing platform is PLATFORM_IOS
, maybe PLATFORM_SOFTWARE
could also be an option... BUT this structure opens the door to the addition of console platforms (by licensed users) in an easier way with minimal raylib modifications. Console homebrew platforms could also follow this same pattern.
Yes, it's a very big change in structure. I don't fully visualize it at the moment but I think it could work.
Completely agree. Still considering if moving the platform-specific parts from CoreData
structure is a better approach, actually CoreData
was created quite recently for organization (as a struct of structs), not long ago it was just a bunch of global variables.
Doing it this way feels wrong but I completely understand not wanting to break builds.
@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.
EDIT: Copying the info from wishlist for reference:
* [ ] **REDESIGN: Module subdivision**. This module has grown a lot with every new supported platform (~7000 loc), at some point it could be divided into separate modules. Two possible approaches: * Divide by platform: * `rcore_desktop.c` - `PLATFORM_DESKTOP` (Windows, Linux, macOS) * `rcore_android.c` - `PLATFORM_ANDROID` * `rcore_native.c` - `PLATFORM_DRM`/`PLATFORM_RPI` * `rcore_web.c` - `PLATFORM_WEB` * Divide by technology * `rcore_glfw.c` - GLFW library based * `rcore_sdl.c` - SDL library based * `rcore_native.c` - Native implementation
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
submodules
project, some time ago I created a list of functions dependant on GLFW (PLATFORM_DESKTOP
), that's probably the list of functions that should be duplicated between platform: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.
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 SetWindowFocused
should be on it too.
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
module for now, at least until we get a functional version and we can validate if it's a good line to follow for raylib (I'm pretty convinced of it!).
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?
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 rcore_platform_split
branch and we can continue from there.
I'm not touching rcore
module for now.
@raysan5 I changed PR #3311 to target rcore_platform_split
and finished moving the listed functions. There were a couple of functions not on the list that I moved because their logic was highly platform dependent. I have a feeling more such functions are there in rcore but I just haven't had the chance to go through every function yet. When a function like that is found it needs to be moved from rcore to all submodules at the same time. So that might create logistical issues as we work on this.
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 PLATFORM_WEB
(it's the one I got more experience with).
@raysan5 @michaelfiber I have cloned the branch and my Windows x64 build using VC/C++ fails with a fatal error in compiling rcore.c
.
rcore_desktop.c(3) fatal error C1083: Cannot open inlude file: 'rcore.h': No such file or directory
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 The previous version had rcore.h
(https://github.com/raysan5/raylib/commit/f27454c57ae252808e03b5a0da074838c305357b) but @raysan5 moved its content to rcore.c
(https://github.com/raysan5/raylib/commit/71a12171f768eb25053ef908732b4ce8fdf802f7). Likely still cleaning up after the change and missed it on rcore_desktop.c
(L3).
@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 rcore.h
's contents to raylib.h
?
@ubkp I prefer to avoid that, it will add too much uneeded content in raylib.h
and probably a lot of confusion that use raylib.h
as their reference cheatsheet. rcore.h
is ok.
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 #define RAYMATH_IMPLEMENTATION
directive. Submitted as pr #3331
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 rcore
master branch (https://github.com/raysan5/raylib/commit/a2b3b1ebe43cdf394b49f901cbaedb2c87959168). I'm afraid it was an issue that could cause a stack overflow in several platforms when using CompressData()
function, it was actually breaking some of my tools in PLATFORM_WEB
because emscripten sets a maximum size for stack of 65KB.
@ubkp did you encounter this as well in your work?
@michaelfiber Not yet. Testing PLATFORM_WEB
is going really smoothly here. After fixing the initial compiling errors I jumped to test the examples and (aside from a few that are actually not working even on current master branch) just found two examples that needed review.
I'm still going through all functions but, so far, everything is working really well. You did an incredible job on the split. :+1:
@raysan5 @michaelfiber Sorry to ask this again, but, just to be absolutely sure, for example, in this case (rcore.c#L2124-L2132):
// Get touch position X for touch point 0 (relative to screen size)
int GetTouchX(void)
{
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
return (int)CORE.Input.Touch.position[0].x;
#else // PLATFORM_DESKTOP, PLATFORM_DRM
return GetMouseX();
#endif
}
Should this be removed from rcore.c
and moved to rcore_android.c
, rcore_web.c
, rcore_desktop.c
and rcore_drm.c
?
If yes, would you like me to do it for rcore_desktop.c
and rcore_android.c
as well while I'm at it? And also for the others functions in similar situation?
@raysan5 @michaelfiber Sorry to ask this again, but, just to be absolutely sure, for example, in this case (rcore.c#L2124-L2132):
// Get touch position X for touch point 0 (relative to screen size) int GetTouchX(void) { #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) return (int)CORE.Input.Touch.position[0].x; #else // PLATFORM_DESKTOP, PLATFORM_DRM return GetMouseX(); #endif }
Should this be removed from
rcore.c
and moved torcore_android.c
,rcore_web.c
,rcore_desktop.c
andrcore_drm.c
?If yes, would you like me to do it for
rcore_desktop.c
andrcore_android.c
as well while I'm at it? And also for the others functions in similar situation?
I think it should be split out. But I guess it depends on the end goal. Is the goal to eliminate all the preprocessor stuff related to platform from rcore.c other than the part where the submodule gets included?
I agree. Otherwise we end up with a 50/50 mix of both, which kind of defeats the purpose of the split.
Should this be removed from rcore.c and moved to rcore_android.c, rcore_web.c, rcore_desktop.c and rcore_drm.c?
Yes.
I think it should be split out. But I guess it depends on the end goal. Is the goal to eliminate all the preprocessor stuff related to platform from rcore.c other than the part where the submodule gets included?
Yes, we want to avoid mixing both.
@michaelfiber @raysan5 I believe I've finished reviewing PLATFORM_WEB
and PLATFORM_DESKTOP
. While going through the functions I also reviewed them for PLATFORM_ANDROID
, but couldn't test it. I've updated the modules and functions tables on #3339 in case it's needed. Also finished the PR #3345 (batch 5), which is ready for merging. :+1:
@ubkp Thank you very much for all your work on this new project! I can continue from this point and double check everything.
@raysan5 Note: the functions I moved on the batches from rcore.c
to the submodules I just left commented instead of deleting them: L1940-L1947, L2109-L2122, L2124-L2132, L2134-L2142, L2144-L2162, L2449-L2721. They can safely be removed after your review.
@ubkp Ok, thanks for letting me know!
That leaves PLATFORM_ANDROID
. In theory I can get that set up and test out building the examples and such. But probably not until the weekend at the earliest. Whichever one of us can get to it first should just make another issue for tracking status and informing the others that testing is underway. Hopefully getting the android dev side of it set up isn't too painful.
@michaelfiber @raysan5
While I went through #3339 I also checked the functions for rcore_android.c
. Unless I missed something, I think everything is there.
Following these wiki instructions and after the #3360 small fix, I was able to successfully compile raylib
for PLATFORM_ANDROID
for ARM
and x86
for both 32bit
and 64bit
.
Unfortunately, I could not compile the examples automatically using make
(I don't think the Makefile
supports that). But I was able to successfully compile a core_basic_window.c
example manually by using the build script from the wiki.
However, the compiled apk
requires Android 6+
, and my device is stuck on 5.1.1
. So I was not able to run it to confirm function. This was as far as I could get. But I'd say there's a pretty good chance it's working.
Edit: @raysan5 Feel free to merge #3360, I don't have other commits to add there.
I have hit a nonstop stream of issues trying to build them for Android. I think because of problem with my distro that is going to require a reinstall. A few other things are broken too. So I won't be able to test the android stuff any time soon. @raysan5 @ubkp not sure what the best way to test will be. @ubkp If you can send me the APK I can test it I just can't seem to get building to work right right now.
@michaelfiber I didn't keep the vm where I compiled it. But I'll rebuild it and try to rollback the Android version to one that matches 5.1.1
so I can test it here. Don't worry about it. :+1:
Update: I managed to setup the environment again and successfully compiled raylib
for PLATFORM_ANDROID
without issues.
However, the apk
file generated was actually malformed. This does not appear to be related to raylib
but to the compiling setup of the program/game (confirmed this case because even a simple int main(void) { return 0; }
is having linking issues).
I'm investigating further.
Edit 1: issue was #3364. Continuing testing now.
Edit 2: managed to generate a well formed apk
and was even able to install it. The game crashes on launch tho, but I'm still using Android-29
, so I'll try to rollback versions now.
@michaelfiber @raysan5
Update: I'm going through all examples and things are looking pretty good. Although Waydroid
is not perfect, it appears to be enough for confirming function. I should have all tested in about one to two days.
@michaelfiber @raysan5
I've finished testing PLATFORM_ANDROID
. The full test logs and results were posted on:
Basically everything is working. The only issues I encountered appear to be related to Waydroid
. In summary:
raylib
on Waydroid
(they appear to be stuck on pressed).Waydroid
.Thus, the mouse presses are the only thing I couldn't really test. So I compiled the examples/textures/textures_mouse_painting.c
for Android 6+
bellow:
PLATFORM_ANDROID
is ready.@ubkp Sorry it took so long! I finally got to test this out.
It works on Android 12. Very nice seeing the Raylib logo appear on the install dialog and it runs fine EXCEPT it cannot save images. The save appears to succeed but the file doesn't end up anywhere. I assume there are a ton of permission things that have to be set up to allow stuff like that so my guess is this is mostly indicative of how annoying it is to develop for Android
But the actual picking of colors and drawing works fine.
@michaelfiber That's excellent, thanks for testing! Yeah, Android is a nightmare.
Well guys, I guess this is it then, everything looks ready. :+1:
@ubkp @michaelfiber do you think it's about time to merge this redesign into master? It's a bit scary for me but there are MANY rcore
issues waiting and probably we shouldn't wait way longer...
I've been using rcore_platform_split
branch for my tools development on desktop and web for a couple of weeks and everything seems to work ok.
@raysan5 I've tested/reviewed everything I could multiple times. The only systems I couldn't test was Windows
and MacOS
because I have neither. But if something slip through, shouldn't be anything major, otherwise we probably would have seen it by now happening on the examples.
I think it's ready for merge.
Fail-safe: Just in case, before merging, could do a point release with current master branch. Or just add tag on the repository in case it needs reverting.
@michaelfiber @ubkp Just reviewed all submodules, mostly formatting and code-gardening. I'm creating a tag, merging the branch and we can continue from there.
@raysan5 I believe you'll have to reapply this commit 7351240218849b1579db962f30e42fb982400c7e change on rcore.c
.
Basically changing LINE 1137 on rcore.c
from:
float aspect = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height;
To (as per 7351240218849b1579db962f30e42fb982400c7e):
double aspect = ((double)width/(double)height);
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