diff --git a/src/rcore.c b/src/rcore.c index a5bd8839a..386af2024 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -828,7 +828,7 @@ VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device) // Unload VR stereo config properties void UnloadVrStereoConfig(VrStereoConfig config) { - //... + TRACELOG(LOG_INFO, "UnloadVrStereoConfig not implemented in rcore.c"); } // Load shader from files and bind default locations @@ -1937,14 +1937,14 @@ int GetCharPressed(void) return value; } -// Set a custom key to exit program -// NOTE: default exitKey is ESCAPE -void SetExitKey(int key) -{ -#if !defined(PLATFORM_ANDROID) - CORE.Input.Keyboard.exitKey = key; -#endif -} +//// Set a custom key to exit program +//// NOTE: default exitKey is ESCAPE +//void SetExitKey(int key) +//{ +//#if !defined(PLATFORM_ANDROID) +// CORE.Input.Keyboard.exitKey = key; +//#endif +//} // NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) @@ -2446,279 +2446,279 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); } -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - -// GLFW3 WindowSize Callback, runs when window is resizedLastFrame -// NOTE: Window resizing not allowed by default -static void WindowSizeCallback(GLFWwindow *window, int width, int height) -{ - // Reset viewport and projection matrix for new size - SetupViewport(width, height); - - CORE.Window.currentFbo.width = width; - CORE.Window.currentFbo.height = height; - CORE.Window.resizedLastFrame = true; - - if (IsWindowFullscreen()) return; - - // Set current screen size -#if defined(__APPLE__) - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; -#else - if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) - { - Vector2 windowScaleDPI = GetWindowScaleDPI(); - - CORE.Window.screen.width = (unsigned int)(width/windowScaleDPI.x); - CORE.Window.screen.height = (unsigned int)(height/windowScaleDPI.y); - } - else - { - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; - } -#endif - - // NOTE: Postprocessing texture is not scaled to new size -} - -// GLFW3 WindowIconify Callback, runs when window is minimized/restored -static void WindowIconifyCallback(GLFWwindow *window, int iconified) -{ - if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified - else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored -} - -// GLFW3 WindowFocus Callback, runs when window get/lose focus -static void WindowFocusCallback(GLFWwindow *window, int focused) -{ - if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused - else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus -} - -// GLFW3 Keyboard Callback, runs on key pressed -static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) -{ - if (key < 0) return; // Security check, macOS fn key generates -1 - - // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 - // to work properly with our implementation (IsKeyDown/IsKeyUp checks) - if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; - else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1; - else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; - -#if !defined(PLATFORM_WEB) - // WARNING: Check if CAPS/NUM key modifiers are enabled and force down state for those keys - if (((key == KEY_CAPS_LOCK) && ((mods & GLFW_MOD_CAPS_LOCK) > 0)) || - ((key == KEY_NUM_LOCK) && ((mods & GLFW_MOD_NUM_LOCK) > 0))) CORE.Input.Keyboard.currentKeyState[key] = 1; -#endif - - // Check if there is space available in the key queue - if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS)) - { - // Add character to the queue - CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; - CORE.Input.Keyboard.keyPressedQueueCount++; - } - - // Check the exit key to set close window - if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(CORE.Window.handle, GLFW_TRUE); - -#if defined(SUPPORT_SCREEN_CAPTURE) - if ((key == GLFW_KEY_F12) && (action == GLFW_PRESS)) - { -#if defined(SUPPORT_GIF_RECORDING) - if (mods & GLFW_MOD_CONTROL) - { - if (gifRecording) - { - gifRecording = false; - - MsfGifResult result = msf_gif_end(&gifState); - - SaveFileData(TextFormat("%s/screenrec%03i.gif", CORE.Storage.basePath, screenshotCounter), result.data, (unsigned int)result.dataSize); - msf_gif_free(result); - - #if defined(PLATFORM_WEB) - // Download file from MEMFS (emscripten memory filesystem) - // saveFileFromMEMFSToDisk() function is defined in raylib/templates/web_shel/shell.html - emscripten_run_script(TextFormat("saveFileFromMEMFSToDisk('%s','%s')", TextFormat("screenrec%03i.gif", screenshotCounter - 1), TextFormat("screenrec%03i.gif", screenshotCounter - 1))); - #endif - - TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording"); - } - else - { - gifRecording = true; - gifFrameCounter = 0; - - Vector2 scale = GetWindowScaleDPI(); - msf_gif_begin(&gifState, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); - screenshotCounter++; - - TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter)); - } - } - else -#endif // SUPPORT_GIF_RECORDING - { - TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); - screenshotCounter++; - } - } -#endif // SUPPORT_SCREEN_CAPTURE - -#if defined(SUPPORT_EVENTS_AUTOMATION) - if ((key == GLFW_KEY_F11) && (action == GLFW_PRESS)) - { - eventsRecording = !eventsRecording; - - // On finish recording, we export events into a file - if (!eventsRecording) ExportAutomationEvents("eventsrec.rep"); - } - else if ((key == GLFW_KEY_F9) && (action == GLFW_PRESS)) - { - LoadAutomationEvents("eventsrec.rep"); - eventsPlaying = true; - - TRACELOG(LOG_WARNING, "eventsPlaying enabled!"); - } -#endif -} - -// GLFW3 Char Key Callback, runs on key down (gets equivalent unicode char value) -static void CharCallback(GLFWwindow *window, unsigned int key) -{ - //TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key); - - // NOTE: Registers any key down considering OS keyboard layout but - // does not detect action events, those should be managed by user... - // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 - // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char - - // Check if there is space available in the queue - if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) - { - // Add character to the queue - CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = key; - CORE.Input.Keyboard.charPressedQueueCount++; - } -} - -// GLFW3 Mouse Button Callback, runs on mouse button pressed -static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) -{ - // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, - // but future releases may add more actions (i.e. GLFW_REPEAT) - CORE.Input.Mouse.currentButtonState[button] = action; - -#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP - // Process mouse events as touches to be able to use mouse-gestures - GestureEvent gestureEvent = { 0 }; - - // Register touch actions - if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN; - else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP; - - // NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback() - - // Assign a pointer ID - gestureEvent.pointId[0] = 0; - - // Register touch points count - gestureEvent.pointCount = 1; - - // Register touch points position, only one point registered - gestureEvent.position[0] = GetMousePosition(); - - // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures-system for processing -#if defined(PLATFORM_WEB) - // Prevent calling ProcessGestureEvent() when Emscripten is present and there's a touch gesture, so EmscriptenTouchCallback() can handle it itself - if (GetMouseX() != 0 || GetMouseY() != 0) ProcessGestureEvent(gestureEvent); -#else - ProcessGestureEvent(gestureEvent); -#endif - -#endif -} - -// GLFW3 Cursor Position Callback, runs on mouse move -static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) -{ - CORE.Input.Mouse.currentPosition.x = (float)x; - CORE.Input.Mouse.currentPosition.y = (float)y; - CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; - -#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP - // Process mouse events as touches to be able to use mouse-gestures - GestureEvent gestureEvent = { 0 }; - - gestureEvent.touchAction = TOUCH_ACTION_MOVE; - - // Assign a pointer ID - gestureEvent.pointId[0] = 0; - - // Register touch points count - gestureEvent.pointCount = 1; - - // Register touch points position, only one point registered - gestureEvent.position[0] = CORE.Input.Touch.position[0]; - - // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height - gestureEvent.position[0].x /= (float)GetScreenWidth(); - gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures-system for processing - ProcessGestureEvent(gestureEvent); -#endif -} - -// GLFW3 Scrolling Callback, runs on mouse wheel -static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) -{ - CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset }; -} - -// GLFW3 CursorEnter Callback, when cursor enters the window -static void CursorEnterCallback(GLFWwindow *window, int enter) -{ - if (enter == true) CORE.Input.Mouse.cursorOnScreen = true; - else CORE.Input.Mouse.cursorOnScreen = false; -} - -// GLFW3 Window Drop Callback, runs when drop files into window -static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) -{ - if (count > 0) - { - // In case previous dropped filepaths have not been freed, we free them - if (CORE.Window.dropFileCount > 0) - { - for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); - - RL_FREE(CORE.Window.dropFilepaths); - - CORE.Window.dropFileCount = 0; - CORE.Window.dropFilepaths = NULL; - } - - // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy - CORE.Window.dropFileCount = count; - CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); - - for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) - { - CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strcpy(CORE.Window.dropFilepaths[i], paths[i]); - } - } -} -#endif +//#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) +// +//// GLFW3 WindowSize Callback, runs when window is resizedLastFrame +//// NOTE: Window resizing not allowed by default +//static void WindowSizeCallback(GLFWwindow *window, int width, int height) +//{ +// // Reset viewport and projection matrix for new size +// SetupViewport(width, height); +// +// CORE.Window.currentFbo.width = width; +// CORE.Window.currentFbo.height = height; +// CORE.Window.resizedLastFrame = true; +// +// if (IsWindowFullscreen()) return; +// +// // Set current screen size +//#if defined(__APPLE__) +// CORE.Window.screen.width = width; +// CORE.Window.screen.height = height; +//#else +// if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) +// { +// Vector2 windowScaleDPI = GetWindowScaleDPI(); +// +// CORE.Window.screen.width = (unsigned int)(width/windowScaleDPI.x); +// CORE.Window.screen.height = (unsigned int)(height/windowScaleDPI.y); +// } +// else +// { +// CORE.Window.screen.width = width; +// CORE.Window.screen.height = height; +// } +//#endif +// +// // NOTE: Postprocessing texture is not scaled to new size +//} +// +//// GLFW3 WindowIconify Callback, runs when window is minimized/restored +//static void WindowIconifyCallback(GLFWwindow *window, int iconified) +//{ +// if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified +// else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored +//} +// +//// GLFW3 WindowFocus Callback, runs when window get/lose focus +//static void WindowFocusCallback(GLFWwindow *window, int focused) +//{ +// if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused +// else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus +//} +// +//// GLFW3 Keyboard Callback, runs on key pressed +//static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) +//{ +// if (key < 0) return; // Security check, macOS fn key generates -1 +// +// // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 +// // to work properly with our implementation (IsKeyDown/IsKeyUp checks) +// if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; +// else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1; +// else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; +// +//#if !defined(PLATFORM_WEB) +// // WARNING: Check if CAPS/NUM key modifiers are enabled and force down state for those keys +// if (((key == KEY_CAPS_LOCK) && ((mods & GLFW_MOD_CAPS_LOCK) > 0)) || +// ((key == KEY_NUM_LOCK) && ((mods & GLFW_MOD_NUM_LOCK) > 0))) CORE.Input.Keyboard.currentKeyState[key] = 1; +//#endif +// +// // Check if there is space available in the key queue +// if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS)) +// { +// // Add character to the queue +// CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; +// CORE.Input.Keyboard.keyPressedQueueCount++; +// } +// +// // Check the exit key to set close window +// if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(CORE.Window.handle, GLFW_TRUE); +// +//#if defined(SUPPORT_SCREEN_CAPTURE) +// if ((key == GLFW_KEY_F12) && (action == GLFW_PRESS)) +// { +//#if defined(SUPPORT_GIF_RECORDING) +// if (mods & GLFW_MOD_CONTROL) +// { +// if (gifRecording) +// { +// gifRecording = false; +// +// MsfGifResult result = msf_gif_end(&gifState); +// +// SaveFileData(TextFormat("%s/screenrec%03i.gif", CORE.Storage.basePath, screenshotCounter), result.data, (unsigned int)result.dataSize); +// msf_gif_free(result); +// +// #if defined(PLATFORM_WEB) +// // Download file from MEMFS (emscripten memory filesystem) +// // saveFileFromMEMFSToDisk() function is defined in raylib/templates/web_shel/shell.html +// emscripten_run_script(TextFormat("saveFileFromMEMFSToDisk('%s','%s')", TextFormat("screenrec%03i.gif", screenshotCounter - 1), TextFormat("screenrec%03i.gif", screenshotCounter - 1))); +// #endif +// +// TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording"); +// } +// else +// { +// gifRecording = true; +// gifFrameCounter = 0; +// +// Vector2 scale = GetWindowScaleDPI(); +// msf_gif_begin(&gifState, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); +// screenshotCounter++; +// +// TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter)); +// } +// } +// else +//#endif // SUPPORT_GIF_RECORDING +// { +// TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); +// screenshotCounter++; +// } +// } +//#endif // SUPPORT_SCREEN_CAPTURE +// +//#if defined(SUPPORT_EVENTS_AUTOMATION) +// if ((key == GLFW_KEY_F11) && (action == GLFW_PRESS)) +// { +// eventsRecording = !eventsRecording; +// +// // On finish recording, we export events into a file +// if (!eventsRecording) ExportAutomationEvents("eventsrec.rep"); +// } +// else if ((key == GLFW_KEY_F9) && (action == GLFW_PRESS)) +// { +// LoadAutomationEvents("eventsrec.rep"); +// eventsPlaying = true; +// +// TRACELOG(LOG_WARNING, "eventsPlaying enabled!"); +// } +//#endif +//} +// +//// GLFW3 Char Key Callback, runs on key down (gets equivalent unicode char value) +//static void CharCallback(GLFWwindow *window, unsigned int key) +//{ +// //TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key); +// +// // NOTE: Registers any key down considering OS keyboard layout but +// // does not detect action events, those should be managed by user... +// // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 +// // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char +// +// // Check if there is space available in the queue +// if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) +// { +// // Add character to the queue +// CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = key; +// CORE.Input.Keyboard.charPressedQueueCount++; +// } +//} +// +//// GLFW3 Mouse Button Callback, runs on mouse button pressed +//static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) +//{ +// // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, +// // but future releases may add more actions (i.e. GLFW_REPEAT) +// CORE.Input.Mouse.currentButtonState[button] = action; +// +//#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP +// // Process mouse events as touches to be able to use mouse-gestures +// GestureEvent gestureEvent = { 0 }; +// +// // Register touch actions +// if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN; +// else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP; +// +// // NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback() +// +// // Assign a pointer ID +// gestureEvent.pointId[0] = 0; +// +// // Register touch points count +// gestureEvent.pointCount = 1; +// +// // Register touch points position, only one point registered +// gestureEvent.position[0] = GetMousePosition(); +// +// // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height +// gestureEvent.position[0].x /= (float)GetScreenWidth(); +// gestureEvent.position[0].y /= (float)GetScreenHeight(); +// +// // Gesture data is sent to gestures-system for processing +//#if defined(PLATFORM_WEB) +// // Prevent calling ProcessGestureEvent() when Emscripten is present and there's a touch gesture, so EmscriptenTouchCallback() can handle it itself +// if (GetMouseX() != 0 || GetMouseY() != 0) ProcessGestureEvent(gestureEvent); +//#else +// ProcessGestureEvent(gestureEvent); +//#endif +// +//#endif +//} +// +//// GLFW3 Cursor Position Callback, runs on mouse move +//static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) +//{ +// CORE.Input.Mouse.currentPosition.x = (float)x; +// CORE.Input.Mouse.currentPosition.y = (float)y; +// CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; +// +//#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP +// // Process mouse events as touches to be able to use mouse-gestures +// GestureEvent gestureEvent = { 0 }; +// +// gestureEvent.touchAction = TOUCH_ACTION_MOVE; +// +// // Assign a pointer ID +// gestureEvent.pointId[0] = 0; +// +// // Register touch points count +// gestureEvent.pointCount = 1; +// +// // Register touch points position, only one point registered +// gestureEvent.position[0] = CORE.Input.Touch.position[0]; +// +// // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height +// gestureEvent.position[0].x /= (float)GetScreenWidth(); +// gestureEvent.position[0].y /= (float)GetScreenHeight(); +// +// // Gesture data is sent to gestures-system for processing +// ProcessGestureEvent(gestureEvent); +//#endif +//} +// +//// GLFW3 Scrolling Callback, runs on mouse wheel +//static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) +//{ +// CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset }; +//} +// +//// GLFW3 CursorEnter Callback, when cursor enters the window +//static void CursorEnterCallback(GLFWwindow *window, int enter) +//{ +// if (enter == true) CORE.Input.Mouse.cursorOnScreen = true; +// else CORE.Input.Mouse.cursorOnScreen = false; +//} +// +//// GLFW3 Window Drop Callback, runs when drop files into window +//static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) +//{ +// if (count > 0) +// { +// // In case previous dropped filepaths have not been freed, we free them +// if (CORE.Window.dropFileCount > 0) +// { +// for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); +// +// RL_FREE(CORE.Window.dropFilepaths); +// +// CORE.Window.dropFileCount = 0; +// CORE.Window.dropFilepaths = NULL; +// } +// +// // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy +// CORE.Window.dropFileCount = count; +// CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); +// +// for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) +// { +// CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); +// strcpy(CORE.Window.dropFilepaths[i], paths[i]); +// } +// } +//} +//#endif #if defined(PLATFORM_DRM) // Initialize Keyboard system (using standard input) diff --git a/src/rcore_android.c b/src/rcore_android.c index cb9472ffa..8553b4076 100644 --- a/src/rcore_android.c +++ b/src/rcore_android.c @@ -136,511 +136,18 @@ static bool InitGraphicsDevice(int width, int height) CORE.Window.screen.height = height; // User desired height CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default - // Set the window minimum and maximum default values to 0 - CORE.Window.windowMin.width = 0; - CORE.Window.windowMin.height = 0; - CORE.Window.windowMax.width = 0; - CORE.Window.windowMax.height = 0; + // Set the screen minimum and maximum default values to 0 + CORE.Window.screenMin.width = 0; + CORE.Window.screenMin.height = 0; + CORE.Window.screenMax.width = 0; + CORE.Window.screenMax.height = 0; // NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars... // ...in top-down or left-right to match display aspect ratio (no weird scaling) -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - glfwSetErrorCallback(ErrorCallback); -/* - // TODO: Setup GLFW custom allocators to match raylib ones - const GLFWallocator allocator = { - .allocate = MemAlloc, - .deallocate = MemFree, - .reallocate = MemRealloc, - .user = NULL - }; - - glfwInitAllocator(&allocator); -*/ -#if defined(__APPLE__) - glfwInitHint(GLFW_COCOA_CHDIR_RESOURCES, GLFW_FALSE); -#endif - - if (!glfwInit()) - { - TRACELOG(LOG_WARNING, "GLFW: Failed to initialize GLFW"); - return false; - } - - glfwDefaultWindowHints(); // Set default windows hints - //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits - //glfwWindowHint(GLFW_GREEN_BITS, 8); // Framebuffer green color component bits - //glfwWindowHint(GLFW_BLUE_BITS, 8); // Framebuffer blue color component bits - //glfwWindowHint(GLFW_ALPHA_BITS, 8); // Framebuffer alpha color component bits - //glfwWindowHint(GLFW_DEPTH_BITS, 24); // Depthbuffer bits - //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window - //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // OpenGL API to use. Alternative: GLFW_OPENGL_ES_API - //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers - - // Check window creation flags - if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true; - - if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window - else glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); // Window initially hidden - - if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window - else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); // Decorated window - - if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window - else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // Avoid window being resizable - - // Disable FLAG_WINDOW_MINIMIZED, not supported on initialization - if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; - - // Disable FLAG_WINDOW_MAXIMIZED, not supported on initialization - if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; - - if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE); - else glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); - - if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE); - else glfwWindowHint(GLFW_FLOATING, GLFW_FALSE); - - // NOTE: Some GLFW flags are not supported on HTML5 -#if defined(PLATFORM_DESKTOP) - if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer - else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer - - if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) - { - // Resize window content area based on the monitor content scale. - // NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11. - // On platforms like macOS the resolution of the framebuffer is changed independently of the window size. - glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on - #if defined(__APPLE__) - glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE); - #endif - } - else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE); - - // Mouse passthrough - if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE); - else glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE); -#endif - - if (CORE.Window.flags & FLAG_MSAA_4X_HINT) - { - // NOTE: MSAA is only enabled for main framebuffer, not user-created FBOs - TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4"); - glfwWindowHint(GLFW_SAMPLES, 4); // Tries to enable multisampling x4 (MSAA), default is 0 - } - - // NOTE: When asking for an OpenGL context version, most drivers provide the highest supported version - // with backward compatibility to older OpenGL versions. - // For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context. - - // Check selection OpenGL version - if (rlGetVersion() == RL_OPENGL_21) - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); // Choose OpenGL major version (just hint) - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); // Choose OpenGL minor version (just hint) - } - else if (rlGetVersion() == RL_OPENGL_33) - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint) - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint) - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above! - // Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE -#if defined(__APPLE__) - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); // OSX Requires forward compatibility -#else - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); // Forward Compatibility Hint: Only 3.3 and above! -#endif - //glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context - } - else if (rlGetVersion() == RL_OPENGL_43) - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Choose OpenGL major version (just hint) - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint) - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) - glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Enable OpenGL Debug Context -#endif - } - else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); -#if defined(PLATFORM_DESKTOP) - glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); -#else - glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); -#endif - } - else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context - { - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); -#if defined(PLATFORM_DESKTOP) - glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); -#else - glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); -#endif - } - -#if defined(PLATFORM_DESKTOP) - // NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions. - // Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn. - // The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience. - // REF: https://github.com/raysan5/raylib/issues/1554 - if (MAX_GAMEPADS > 0) glfwSetJoystickCallback(NULL); -#endif - -#if defined(PLATFORM_DESKTOP) - // Find monitor resolution - GLFWmonitor *monitor = glfwGetPrimaryMonitor(); - if (!monitor) - { - TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor"); - return false; - } - - const GLFWvidmode *mode = glfwGetVideoMode(monitor); - - CORE.Window.display.width = mode->width; - CORE.Window.display.height = mode->height; - - // Set screen width/height to the display width/height if they are 0 - if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width; - if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height; -#endif // PLATFORM_DESKTOP - -#if defined(PLATFORM_WEB) - // NOTE: Getting video modes is not implemented in emscripten GLFW3 version - CORE.Window.display.width = CORE.Window.screen.width; - CORE.Window.display.height = CORE.Window.screen.height; -#endif // PLATFORM_WEB - - if (CORE.Window.fullscreen) - { - // remember center for switchinging from fullscreen to window - if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width)) - { - // If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed. - // Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11. - CORE.Window.position.x = CORE.Window.display.width/4; - CORE.Window.position.y = CORE.Window.display.height/4; - } - else - { - CORE.Window.position.x = CORE.Window.display.width/2 - CORE.Window.screen.width/2; - CORE.Window.position.y = CORE.Window.display.height/2 - CORE.Window.screen.height/2; - } - - if (CORE.Window.position.x < 0) CORE.Window.position.x = 0; - if (CORE.Window.position.y < 0) CORE.Window.position.y = 0; - - // Obtain recommended CORE.Window.display.width/CORE.Window.display.height from a valid videomode for the monitor - int count = 0; - const GLFWvidmode *modes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count); - - // Get closest video mode to desired CORE.Window.screen.width/CORE.Window.screen.height - for (int i = 0; i < count; i++) - { - if ((unsigned int)modes[i].width >= CORE.Window.screen.width) - { - if ((unsigned int)modes[i].height >= CORE.Window.screen.height) - { - CORE.Window.display.width = modes[i].width; - CORE.Window.display.height = modes[i].height; - break; - } - } - } - TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height); - - // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example, - // for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3), - // framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched - // by the sides to fit all monitor space... - - // Try to setup the most appropriate fullscreen framebuffer for the requested screenWidth/screenHeight - // It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset) - // Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale - // TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed... - // HighDPI monitors are properly considered in a following similar function: SetupViewport() - SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); - - CORE.Window.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", glfwGetPrimaryMonitor(), NULL); - - // NOTE: Full-screen change, not working properly... - //glfwSetWindowMonitor(CORE.Window.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); - } - else - { -#if defined(PLATFORM_DESKTOP) - // If we are windowed fullscreen, ensures that window does not minimize when focus is lost - if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width)) - { - glfwWindowHint(GLFW_AUTO_ICONIFY, 0); - } -#endif - // No-fullscreen window creation - CORE.Window.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL); - - if (CORE.Window.handle) - { - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - } - } - - if (!CORE.Window.handle) - { - glfwTerminate(); - TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window"); - return false; - } - -// glfwCreateWindow title doesn't work with emscripten. -#if defined(PLATFORM_WEB) - emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " "); -#endif - - // Set window callback events - glfwSetWindowSizeCallback(CORE.Window.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! -#if !defined(PLATFORM_WEB) - glfwSetWindowMaximizeCallback(CORE.Window.handle, WindowMaximizeCallback); -#endif - glfwSetWindowIconifyCallback(CORE.Window.handle, WindowIconifyCallback); - glfwSetWindowFocusCallback(CORE.Window.handle, WindowFocusCallback); - glfwSetDropCallback(CORE.Window.handle, WindowDropCallback); - - // Set input callback events - glfwSetKeyCallback(CORE.Window.handle, KeyCallback); - glfwSetCharCallback(CORE.Window.handle, CharCallback); - glfwSetMouseButtonCallback(CORE.Window.handle, MouseButtonCallback); - glfwSetCursorPosCallback(CORE.Window.handle, MouseCursorPosCallback); // Track mouse position changes - glfwSetScrollCallback(CORE.Window.handle, MouseScrollCallback); - glfwSetCursorEnterCallback(CORE.Window.handle, CursorEnterCallback); - - glfwMakeContextCurrent(CORE.Window.handle); - -#if !defined(PLATFORM_WEB) - glfwSetInputMode(CORE.Window.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM) - - glfwSwapInterval(0); // No V-Sync by default -#endif - - // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) - // NOTE: V-Sync can be enabled by graphic driver configuration, it doesn't need - // to be activated on web platforms since VSync is enforced there. -#if !defined(PLATFORM_WEB) - if (CORE.Window.flags & FLAG_VSYNC_HINT) - { - // WARNING: It seems to hit a critical render path in Intel HD Graphics - glfwSwapInterval(1); - TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC"); - } -#endif - - int fbWidth = CORE.Window.screen.width; - int fbHeight = CORE.Window.screen.height; - -#if defined(PLATFORM_DESKTOP) - if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) - { - // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling. - // Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE); - #if !defined(__APPLE__) - glfwGetFramebufferSize(CORE.Window.handle, &fbWidth, &fbHeight); - - // Screen scaling matrix is required in case desired screen area is different from display area - CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f); - - // Mouse input scaling for the new screen size - SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight); - #endif - } -#endif - - CORE.Window.render.width = fbWidth; - CORE.Window.render.height = fbHeight; - CORE.Window.currentFbo.width = fbWidth; - CORE.Window.currentFbo.height = fbHeight; - - TRACELOG(LOG_INFO, "DISPLAY: 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); - -#endif // PLATFORM_DESKTOP || PLATFORM_WEB - -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM) CORE.Window.fullscreen = true; CORE.Window.flags |= FLAG_FULLSCREEN_MODE; -#if defined(PLATFORM_DRM) - CORE.Window.fd = -1; - CORE.Window.connector = NULL; - CORE.Window.modeIndex = -1; - CORE.Window.crtc = NULL; - CORE.Window.gbmDevice = NULL; - CORE.Window.gbmSurface = NULL; - CORE.Window.prevBO = NULL; - CORE.Window.prevFB = 0; - -#if defined(DEFAULT_GRAPHIC_DEVICE_DRM) - CORE.Window.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR); -#else - TRACELOG(LOG_INFO, "DISPLAY: No graphic card set, trying platform-gpu-card"); - CORE.Window.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4) - - if ((-1 == CORE.Window.fd) || (drmModeGetResources(CORE.Window.fd) == NULL)) - { - TRACELOG(LOG_INFO, "DISPLAY: Failed to open platform-gpu-card, trying card1"); - CORE.Window.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded - } - - if ((-1 == CORE.Window.fd) || (drmModeGetResources(CORE.Window.fd) == NULL)) - { - TRACELOG(LOG_INFO, "DISPLAY: Failed to open graphic card1, trying card0"); - CORE.Window.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3) - } -#endif - if (-1 == CORE.Window.fd) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card"); - return false; - } - - drmModeRes *res = drmModeGetResources(CORE.Window.fd); - if (!res) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources"); - return false; - } - - TRACELOG(LOG_TRACE, "DISPLAY: Connectors found: %i", res->count_connectors); - for (size_t i = 0; i < res->count_connectors; i++) - { - TRACELOG(LOG_TRACE, "DISPLAY: Connector index %i", i); - drmModeConnector *con = drmModeGetConnector(CORE.Window.fd, res->connectors[i]); - TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes); - if ((con->connection == DRM_MODE_CONNECTED) && (con->encoder_id)) - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); - CORE.Window.connector = con; - break; - } - else - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); - drmModeFreeConnector(con); - } - } - - if (!CORE.Window.connector) - { - TRACELOG(LOG_WARNING, "DISPLAY: No suitable DRM connector found"); - drmModeFreeResources(res); - return false; - } - - drmModeEncoder *enc = drmModeGetEncoder(CORE.Window.fd, CORE.Window.connector->encoder_id); - if (!enc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); - drmModeFreeResources(res); - return false; - } - - CORE.Window.crtc = drmModeGetCrtc(CORE.Window.fd, enc->crtc_id); - if (!CORE.Window.crtc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); - drmModeFreeEncoder(enc); - drmModeFreeResources(res); - return false; - } - - // If InitWindow should use the current mode find it in the connector's mode list - if ((CORE.Window.screen.width <= 0) || (CORE.Window.screen.height <= 0)) - { - TRACELOG(LOG_TRACE, "DISPLAY: Selecting DRM connector mode for current used mode..."); - - CORE.Window.modeIndex = FindMatchingConnectorMode(CORE.Window.connector, &CORE.Window.crtc->mode); - - if (CORE.Window.modeIndex < 0) - { - TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found"); - drmModeFreeEncoder(enc); - drmModeFreeResources(res); - return false; - } - - CORE.Window.screen.width = CORE.Window.display.width; - CORE.Window.screen.height = CORE.Window.display.height; - } - - const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT; - const int fps = (CORE.Time.target > 0) ? (1.0/CORE.Time.target) : 60; - - // Try to find an exact matching mode - CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); - - // If nothing found, try to find a nearly matching mode - if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced); - - // If nothing found, try to find an exactly matching mode including interlaced - if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindExactConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); - - // If nothing found, try to find a nearly matching mode including interlaced - if (CORE.Window.modeIndex < 0) CORE.Window.modeIndex = FindNearestConnectorMode(CORE.Window.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, true); - - // If nothing found, there is no suitable mode - if (CORE.Window.modeIndex < 0) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode"); - drmModeFreeEncoder(enc); - drmModeFreeResources(res); - return false; - } - - CORE.Window.display.width = CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay; - CORE.Window.display.height = CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay; - - TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", CORE.Window.connector->modes[CORE.Window.modeIndex].name, - CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, - (CORE.Window.connector->modes[CORE.Window.modeIndex].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p', - CORE.Window.connector->modes[CORE.Window.modeIndex].vrefresh); - - // Use the width and height of the surface for render - CORE.Window.render.width = CORE.Window.screen.width; - CORE.Window.render.height = CORE.Window.screen.height; - - drmModeFreeEncoder(enc); - enc = NULL; - - drmModeFreeResources(res); - res = NULL; - - CORE.Window.gbmDevice = gbm_create_device(CORE.Window.fd); - if (!CORE.Window.gbmDevice) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM device"); - return false; - } - - CORE.Window.gbmSurface = gbm_surface_create(CORE.Window.gbmDevice, CORE.Window.connector->modes[CORE.Window.modeIndex].hdisplay, - CORE.Window.connector->modes[CORE.Window.modeIndex].vdisplay, GBM_FORMAT_ARGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - if (!CORE.Window.gbmSurface) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create GBM surface"); - return false; - } -#endif - EGLint samples = 0; EGLint sampleBuffer = 0; if (CORE.Window.flags & FLAG_MSAA_4X_HINT) @@ -653,15 +160,9 @@ static bool InitGraphicsDevice(int width, int height) const EGLint framebufferAttribs[] = { EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support -#if defined(PLATFORM_DRM) - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android! -#endif EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5) EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) -#if defined(PLATFORM_DRM) - EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer) -#endif //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI) EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!) //EGL_STENCIL_SIZE, 8, // Stencil buffer size @@ -676,15 +177,10 @@ static bool InitGraphicsDevice(int width, int height) EGL_NONE }; -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM) EGLint numConfigs = 0; // Get an EGL device connection -#if defined(PLATFORM_DRM) - CORE.Window.device = eglGetDisplay((EGLNativeDisplayType)CORE.Window.gbmDevice); -#else CORE.Window.device = eglGetDisplay(EGL_DEFAULT_DISPLAY); -#endif if (CORE.Window.device == EGL_NO_DISPLAY) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); @@ -699,63 +195,8 @@ static bool InitGraphicsDevice(int width, int height) return false; } -#if defined(PLATFORM_DRM) - if (!eglChooseConfig(CORE.Window.device, NULL, NULL, 0, &numConfigs)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError()); - return false; - } - - TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs); - - EGLConfig *configs = RL_CALLOC(numConfigs, sizeof(*configs)); - if (!configs) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs"); - return false; - } - - EGLint matchingNumConfigs = 0; - if (!eglChooseConfig(CORE.Window.device, framebufferAttribs, configs, numConfigs, &matchingNumConfigs)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to choose EGL config: 0x%x", eglGetError()); - free(configs); - return false; - } - - TRACELOG(LOG_TRACE, "DISPLAY: EGL matching configs available: %d", matchingNumConfigs); - - // find the EGL config that matches the previously setup GBM format - int found = 0; - for (EGLint i = 0; i < matchingNumConfigs; ++i) - { - EGLint id = 0; - if (!eglGetConfigAttrib(CORE.Window.device, configs[i], EGL_NATIVE_VISUAL_ID, &id)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config attribute: 0x%x", eglGetError()); - continue; - } - - if (GBM_FORMAT_ARGB8888 == id) - { - TRACELOG(LOG_TRACE, "DISPLAY: Using EGL config: %d", i); - CORE.Window.config = configs[i]; - found = 1; - break; - } - } - - RL_FREE(configs); - - if (!found) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable EGL config"); - return false; - } -#else // Get an appropriate EGL framebuffer configuration eglChooseConfig(CORE.Window.device, framebufferAttribs, &CORE.Window.config, 1, &numConfigs); -#endif // Set rendering API eglBindAPI(EGL_OPENGL_ES_API); @@ -767,11 +208,9 @@ static bool InitGraphicsDevice(int width, int height) TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); return false; } -#endif // Create an EGL window surface //--------------------------------------------------------------------------------- -#if defined(PLATFORM_ANDROID) EGLint displayFormat = 0; // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry() @@ -789,23 +228,6 @@ static bool InitGraphicsDevice(int width, int height) //ANativeWindow_setBuffersGeometry(CORE.Android.app->window, 0, 0, displayFormat); // Force use of native display size CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, CORE.Android.app->window, NULL); -#endif // PLATFORM_ANDROID - -#if defined(PLATFORM_DRM) - CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, (EGLNativeWindowType)CORE.Window.gbmSurface, NULL); - if (EGL_NO_SURFACE == CORE.Window.surface) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL window surface: 0x%04x", eglGetError()); - return false; - } - - // 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); -#endif // PLATFORM_DRM // There must be at least one frame displayed before the buffers are swapped //eglSwapInterval(CORE.Window.device, 1); @@ -828,15 +250,10 @@ static bool InitGraphicsDevice(int width, int 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); } -#endif // PLATFORM_ANDROID || PLATFORM_DRM // Load OpenGL extensions // NOTE: GL procedures address loader is required to load extensions -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - rlLoadExtensions(glfwGetProcAddress); -#else rlLoadExtensions(eglGetProcAddress); -#endif // Initialize OpenGL context (states and resources) // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl @@ -846,9 +263,7 @@ static bool InitGraphicsDevice(int width, int height) // NOTE: It updated CORE.Window.render.width and CORE.Window.render.height SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); -#if defined(PLATFORM_ANDROID) CORE.Window.ready = true; -#endif if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow(); @@ -1513,6 +928,7 @@ const char *GetMonitorName(int monitor) // Set clipboard text content void SetClipboardText(const char *text) { + TRACELOG(LOG_INFO, "SetClipboardText not implemented in rcore_android.c"); } @@ -1628,18 +1044,27 @@ void OpenURL(const char *url) } } -// Get gamepad internal name id -const char *GetGamepadName(int gamepad) -{ - return NULL; -} - // Get selected monitor physical width in millimetres int GetMonitorPhysicalWidth(int monitor) { return 0; } +// Set a custom key to exit program +// NOTE: default exitKey is ESCAPE +void SetExitKey(int key) +{ + TRACELOG(LOG_INFO, "SetExitKey not implemented in rcore_android.c"); +} + +// Get gamepad internal name id +const char *GetGamepadName(int gamepad) +{ + TRACELOG(LOG_INFO, "GetGamepadName not implemented in rcore_android.c"); + + return NULL; +} + // Get gamepad axis count int GetGamepadAxisCount(int gamepad) { @@ -1649,6 +1074,8 @@ int GetGamepadAxisCount(int gamepad) // Set internal gamepad mappings int SetGamepadMappings(const char *mappings) { + TRACELOG(LOG_INFO, "SetGamepadMappings not implemented in rcore_android.c"); + return 0; } diff --git a/src/rcore_desktop.c b/src/rcore_desktop.c index 6658f04db..6934a02ec 100644 --- a/src/rcore_desktop.c +++ b/src/rcore_desktop.c @@ -711,7 +711,6 @@ void ToggleBorderlessWindowed(void) glfwGetMonitorPos(monitors[monitor], &monitorPosX, &monitorPosY); const int monitorWidth = mode->width; const int monitorHeight = mode->height; - glfwSetWindowSize(CORE.Window.handle, monitorWidth, monitorHeight); // Set screen position and size glfwSetWindowPos(CORE.Window.handle, monitorPosX, monitorPosY); @@ -1150,11 +1149,11 @@ static void ErrorCallback(int error, const char *description) // Get native window handle void *GetWindowHandle(void) { -#if defined(PLATFORM_DESKTOP) && defined(_WIN32) +#if defined(_WIN32) // NOTE: Returned handle is: void *HWND (windows.h) return glfwGetWin32Window(CORE.Window.handle); #endif -#if defined(PLATFORM_DESKTOP) && defined(__linux__) +#if defined(__linux__) // NOTE: Returned handle is: unsigned long Window (X.h) // typedef unsigned long XID; // typedef XID Window; @@ -1497,16 +1496,6 @@ void OpenURL(const char *url) } } -// Get gamepad internal name id -const char *GetGamepadName(int gamepad) -{ - const char *name = NULL; - - if (CORE.Input.Gamepad.ready[gamepad]) name = glfwGetJoystickName(gamepad); - - return name; -} - // Get selected monitor physical width in millimetres int GetMonitorPhysicalWidth(int monitor) { @@ -1523,6 +1512,23 @@ int GetMonitorPhysicalWidth(int monitor) return 0; } +// Set a custom key to exit program +// NOTE: default exitKey is ESCAPE +void SetExitKey(int key) +{ + CORE.Input.Keyboard.exitKey = key; +} + +// Get gamepad internal name id +const char *GetGamepadName(int gamepad) +{ + const char *name = NULL; + + if (CORE.Input.Gamepad.ready[gamepad]) name = glfwGetJoystickName(gamepad); + + return name; +} + // Get gamepad axis count int GetGamepadAxisCount(int gamepad) { @@ -1752,3 +1758,261 @@ void PollInputEvents(void) if (CORE.Window.eventWaiting) glfwWaitEvents(); // Wait for in input events before continue (drawing is paused) else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) } + +// GLFW3 WindowSize Callback, runs when window is resizedLastFrame +// NOTE: Window resizing not allowed by default +static void WindowSizeCallback(GLFWwindow *window, int width, int height) +{ + // Reset viewport and projection matrix for new size + SetupViewport(width, height); + + CORE.Window.currentFbo.width = width; + CORE.Window.currentFbo.height = height; + CORE.Window.resizedLastFrame = true; + + if (IsWindowFullscreen()) return; + + // Set current screen size +#if defined(__APPLE__) + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; +#else + if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) + { + Vector2 windowScaleDPI = GetWindowScaleDPI(); + + CORE.Window.screen.width = (unsigned int)(width/windowScaleDPI.x); + CORE.Window.screen.height = (unsigned int)(height/windowScaleDPI.y); + } + else + { + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; + } +#endif + + // NOTE: Postprocessing texture is not scaled to new size +} + +// GLFW3 WindowIconify Callback, runs when window is minimized/restored +static void WindowIconifyCallback(GLFWwindow *window, int iconified) +{ + if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified + else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored +} + +// GLFW3 WindowFocus Callback, runs when window get/lose focus +static void WindowFocusCallback(GLFWwindow *window, int focused) +{ + if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused + else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus +} + +// GLFW3 Keyboard Callback, runs on key pressed +static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if (key < 0) return; // Security check, macOS fn key generates -1 + + // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 + // to work properly with our implementation (IsKeyDown/IsKeyUp checks) + if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; + else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1; + else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; + + // WARNING: Check if CAPS/NUM key modifiers are enabled and force down state for those keys + if (((key == KEY_CAPS_LOCK) && ((mods & GLFW_MOD_CAPS_LOCK) > 0)) || + ((key == KEY_NUM_LOCK) && ((mods & GLFW_MOD_NUM_LOCK) > 0))) CORE.Input.Keyboard.currentKeyState[key] = 1; + + // Check if there is space available in the key queue + if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS)) + { + // Add character to the queue + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; + CORE.Input.Keyboard.keyPressedQueueCount++; + } + + // Check the exit key to set close window + if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(CORE.Window.handle, GLFW_TRUE); + +#if defined(SUPPORT_SCREEN_CAPTURE) + if ((key == GLFW_KEY_F12) && (action == GLFW_PRESS)) + { +#if defined(SUPPORT_GIF_RECORDING) + if (mods & GLFW_MOD_CONTROL) + { + if (gifRecording) + { + gifRecording = false; + + MsfGifResult result = msf_gif_end(&gifState); + + SaveFileData(TextFormat("%s/screenrec%03i.gif", CORE.Storage.basePath, screenshotCounter), result.data, (unsigned int)result.dataSize); + msf_gif_free(result); + + TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording"); + } + else + { + gifRecording = true; + gifFrameCounter = 0; + + Vector2 scale = GetWindowScaleDPI(); + msf_gif_begin(&gifState, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); + screenshotCounter++; + + TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter)); + } + } + else +#endif // SUPPORT_GIF_RECORDING + { + TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); + screenshotCounter++; + } + } +#endif // SUPPORT_SCREEN_CAPTURE + +#if defined(SUPPORT_EVENTS_AUTOMATION) + if ((key == GLFW_KEY_F11) && (action == GLFW_PRESS)) + { + eventsRecording = !eventsRecording; + + // On finish recording, we export events into a file + if (!eventsRecording) ExportAutomationEvents("eventsrec.rep"); + } + else if ((key == GLFW_KEY_F9) && (action == GLFW_PRESS)) + { + LoadAutomationEvents("eventsrec.rep"); + eventsPlaying = true; + + TRACELOG(LOG_WARNING, "eventsPlaying enabled!"); + } +#endif +} + +// GLFW3 Char Key Callback, runs on key down (gets equivalent unicode char value) +static void CharCallback(GLFWwindow *window, unsigned int key) +{ + //TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key); + + // NOTE: Registers any key down considering OS keyboard layout but + // does not detect action events, those should be managed by user... + // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 + // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char + + // Check if there is space available in the queue + if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) + { + // Add character to the queue + CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = key; + CORE.Input.Keyboard.charPressedQueueCount++; + } +} + +// GLFW3 Mouse Button Callback, runs on mouse button pressed +static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) +{ + // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, + // but future releases may add more actions (i.e. GLFW_REPEAT) + CORE.Input.Mouse.currentButtonState[button] = action; + +#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent = { 0 }; + + // Register touch actions + if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN; + else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP; + + // NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback() + + // Assign a pointer ID + gestureEvent.pointId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = GetMousePosition(); + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures-system for processing + ProcessGestureEvent(gestureEvent); + +#endif +} + +// GLFW3 Cursor Position Callback, runs on mouse move +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) +{ + CORE.Input.Mouse.currentPosition.x = (float)x; + CORE.Input.Mouse.currentPosition.y = (float)y; + CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; + +#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent = { 0 }; + + gestureEvent.touchAction = TOUCH_ACTION_MOVE; + + // Assign a pointer ID + gestureEvent.pointId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = CORE.Input.Touch.position[0]; + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures-system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +// GLFW3 Scrolling Callback, runs on mouse wheel +static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) +{ + CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset }; +} + +// GLFW3 CursorEnter Callback, when cursor enters the window +static void CursorEnterCallback(GLFWwindow *window, int enter) +{ + if (enter == true) CORE.Input.Mouse.cursorOnScreen = true; + else CORE.Input.Mouse.cursorOnScreen = false; +} + +// GLFW3 Window Drop Callback, runs when drop files into window +static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) +{ + if (count > 0) + { + // In case previous dropped filepaths have not been freed, we free them + if (CORE.Window.dropFileCount > 0) + { + for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); + + RL_FREE(CORE.Window.dropFilepaths); + + CORE.Window.dropFileCount = 0; + CORE.Window.dropFilepaths = NULL; + } + + // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy + CORE.Window.dropFileCount = count; + CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); + + for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) + { + CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); + strcpy(CORE.Window.dropFilepaths[i], paths[i]); + } + } +} diff --git a/src/rcore_web.c b/src/rcore_web.c index d6015aea7..e7998e255 100644 --- a/src/rcore_web.c +++ b/src/rcore_web.c @@ -186,151 +186,6 @@ void InitWindow(int width, int height, const char *title) #endif } -// Register fullscreen change events -static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData) -{ - // TODO: Implement EmscriptenFullscreenChangeCallback()? - - return 1; // The event was consumed by the callback handler -} - -// Register window resize event -static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData) -{ - // TODO: Implement EmscriptenWindowResizedCallback()? - - return 1; // The event was consumed by the callback handler -} - -EM_JS(int, GetWindowInnerWidth, (), { return window.innerWidth; }); -EM_JS(int, GetWindowInnerHeight, (), { return window.innerHeight; }); - -// Register DOM element resize event -static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData) -{ - // Don't resize non-resizeable windows - if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1; - - // This event is called whenever the window changes sizes, - // so the size of the canvas object is explicitly retrieved below - int width = GetWindowInnerWidth(); - int height = GetWindowInnerHeight(); - - if (width < CORE.Window.screenMin.width) width = CORE.Window.screenMin.width; - else if (width > CORE.Window.screenMax.width && CORE.Window.screenMax.width > 0) width = CORE.Window.screenMax.width; - - if (height < CORE.Window.screenMin.height) height = CORE.Window.screenMin.height; - else if (height > CORE.Window.screenMax.height && CORE.Window.screenMax.height > 0) height = CORE.Window.screenMax.height; - - emscripten_set_canvas_element_size("#canvas", width, height); - - SetupViewport(width, height); // Reset viewport and projection matrix for new size - - CORE.Window.currentFbo.width = width; - CORE.Window.currentFbo.height = height; - CORE.Window.resizedLastFrame = true; - - if (IsWindowFullscreen()) return 1; - - // Set current screen size - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; - - // NOTE: Postprocessing texture is not scaled to new size - - return 0; -} - -// Register mouse input events -static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) -{ - // This is only for registering mouse click events with emscripten and doesn't need to do anything - - return 1; // The event was consumed by the callback handler -} - -// Register connected/disconnected gamepads events -static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) -{ - /* - TRACELOGD("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"", - eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state", - gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping); - - for (int i = 0; i < gamepadEvent->numAxes; ++i) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]); - for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]); - */ - - if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) - { - CORE.Input.Gamepad.ready[gamepadEvent->index] = true; - sprintf(CORE.Input.Gamepad.name[gamepadEvent->index], "%s", gamepadEvent->id); - } - else CORE.Input.Gamepad.ready[gamepadEvent->index] = false; - - return 1; // The event was consumed by the callback handler -} - -// Register touch input events -static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) -{ - // Register touch points count - CORE.Input.Touch.pointCount = touchEvent->numTouches; - - double canvasWidth = 0.0; - double canvasHeight = 0.0; - // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but - // we are looking for actual CSS size: canvas.style.width and canvas.style.height - // EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight); - emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight); - - for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++) - { - // Register touch points id - CORE.Input.Touch.pointId[i] = touchEvent->touches[i].identifier; - - // Register touch points position - CORE.Input.Touch.position[i] = (Vector2){touchEvent->touches[i].targetX, touchEvent->touches[i].targetY}; - - // Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height - CORE.Input.Touch.position[i].x *= ((float)GetScreenWidth() / (float)canvasWidth); - CORE.Input.Touch.position[i].y *= ((float)GetScreenHeight() / (float)canvasHeight); - - if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1; - else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0; - } - -#if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_WEB - GestureEvent gestureEvent = {0}; - - gestureEvent.pointCount = CORE.Input.Touch.pointCount; - - // Register touch actions - if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_ACTION_DOWN; - else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_ACTION_UP; - else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE; - else if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL; - - for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++) - { - gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i]; - gestureEvent.position[i] = CORE.Input.Touch.position[i]; - - // Normalize gestureEvent.position[i] - gestureEvent.position[i].x /= (float)GetScreenWidth(); - gestureEvent.position[i].y /= (float)GetScreenHeight(); - } - - // Gesture data is sent to gestures system for processing - ProcessGestureEvent(gestureEvent); - - // Reset the pointCount for web, if it was the last Touch End event - if (eventType == EMSCRIPTEN_EVENT_TOUCHEND && CORE.Input.Touch.pointCount == 1) CORE.Input.Touch.pointCount = 0; -#endif - - return 1; // The event was consumed by the callback handler -} - // Initialize display device and framebuffer // NOTE: width and height represent the screen (framebuffer) desired size, not actual display size // If width or height are 0, default display size will be used for framebuffer size @@ -1035,6 +890,21 @@ void OpenURL(const char *url) } } +// Get selected monitor physical width in millimetres +int GetMonitorPhysicalWidth(int monitor) +{ + return 0; +} + +// Set a custom key to exit program +// NOTE: default exitKey is ESCAPE +void SetExitKey(int key) +{ + CORE.Input.Keyboard.exitKey = key; +} + +// NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) + // Get gamepad internal name id const char *GetGamepadName(int gamepad) { @@ -1045,12 +915,6 @@ const char *GetGamepadName(int gamepad) return name; } -// Get selected monitor physical width in millimetres -int GetMonitorPhysicalWidth(int monitor) -{ - return 0; -} - // Get gamepad axis count int GetGamepadAxisCount(int gamepad) { @@ -1060,6 +924,8 @@ int GetGamepadAxisCount(int gamepad) // Set internal gamepad mappings int SetGamepadMappings(const char *mappings) { + TRACELOG(LOG_INFO, "SetGamepadMappings not implemented in rcore_web.c"); + return 0; } @@ -1261,3 +1127,402 @@ void PollInputEvents(void) } } } + +// GLFW3 WindowSize Callback, runs when window is resizedLastFrame +// NOTE: Window resizing not allowed by default +static void WindowSizeCallback(GLFWwindow *window, int width, int height) +{ + // Reset viewport and projection matrix for new size + SetupViewport(width, height); + + CORE.Window.currentFbo.width = width; + CORE.Window.currentFbo.height = height; + CORE.Window.resizedLastFrame = true; + + if (IsWindowFullscreen()) return; + + // Set current screen size + if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) + { + Vector2 windowScaleDPI = GetWindowScaleDPI(); + + CORE.Window.screen.width = (unsigned int)(width/windowScaleDPI.x); + CORE.Window.screen.height = (unsigned int)(height/windowScaleDPI.y); + } + else + { + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; + } + + // NOTE: Postprocessing texture is not scaled to new size +} + +// GLFW3 WindowIconify Callback, runs when window is minimized/restored +static void WindowIconifyCallback(GLFWwindow *window, int iconified) +{ + if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified + else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored +} + +// GLFW3 WindowFocus Callback, runs when window get/lose focus +static void WindowFocusCallback(GLFWwindow *window, int focused) +{ + if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused + else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus +} + +// GLFW3 Keyboard Callback, runs on key pressed +static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if (key < 0) return; // Security check, macOS fn key generates -1 + + // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 + // to work properly with our implementation (IsKeyDown/IsKeyUp checks) + if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; + else if(action == GLFW_PRESS) CORE.Input.Keyboard.currentKeyState[key] = 1; + else if(action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1; + + // Check if there is space available in the key queue + if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS)) + { + // Add character to the queue + CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = key; + CORE.Input.Keyboard.keyPressedQueueCount++; + } + + // Check the exit key to set close window + if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(CORE.Window.handle, GLFW_TRUE); + +#if defined(SUPPORT_SCREEN_CAPTURE) + if ((key == GLFW_KEY_F12) && (action == GLFW_PRESS)) + { +#if defined(SUPPORT_GIF_RECORDING) + if (mods & GLFW_MOD_CONTROL) + { + if (gifRecording) + { + gifRecording = false; + + MsfGifResult result = msf_gif_end(&gifState); + + SaveFileData(TextFormat("%s/screenrec%03i.gif", CORE.Storage.basePath, screenshotCounter), result.data, (unsigned int)result.dataSize); + msf_gif_free(result); + + // Download file from MEMFS (emscripten memory filesystem) + // saveFileFromMEMFSToDisk() function is defined in raylib/templates/web_shel/shell.html + emscripten_run_script(TextFormat("saveFileFromMEMFSToDisk('%s','%s')", TextFormat("screenrec%03i.gif", screenshotCounter - 1), TextFormat("screenrec%03i.gif", screenshotCounter - 1))); + + TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording"); + } + else + { + gifRecording = true; + gifFrameCounter = 0; + + Vector2 scale = GetWindowScaleDPI(); + msf_gif_begin(&gifState, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); + screenshotCounter++; + + TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter)); + } + } + else +#endif // SUPPORT_GIF_RECORDING + { + TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter)); + screenshotCounter++; + } + } +#endif // SUPPORT_SCREEN_CAPTURE + +#if defined(SUPPORT_EVENTS_AUTOMATION) + if ((key == GLFW_KEY_F11) && (action == GLFW_PRESS)) + { + eventsRecording = !eventsRecording; + + // On finish recording, we export events into a file + if (!eventsRecording) ExportAutomationEvents("eventsrec.rep"); + } + else if ((key == GLFW_KEY_F9) && (action == GLFW_PRESS)) + { + LoadAutomationEvents("eventsrec.rep"); + eventsPlaying = true; + + TRACELOG(LOG_WARNING, "eventsPlaying enabled!"); + } +#endif +} + +// GLFW3 Char Key Callback, runs on key down (gets equivalent unicode char value) +static void CharCallback(GLFWwindow *window, unsigned int key) +{ + //TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key); + + // NOTE: Registers any key down considering OS keyboard layout but + // does not detect action events, those should be managed by user... + // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 + // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char + + // Check if there is space available in the queue + if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) + { + // Add character to the queue + CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = key; + CORE.Input.Keyboard.charPressedQueueCount++; + } +} + +// GLFW3 Mouse Button Callback, runs on mouse button pressed +static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) +{ + // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, + // but future releases may add more actions (i.e. GLFW_REPEAT) + CORE.Input.Mouse.currentButtonState[button] = action; + +#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent = { 0 }; + + // Register touch actions + if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN; + else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP; + + // NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback() + + // Assign a pointer ID + gestureEvent.pointId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = GetMousePosition(); + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures-system for processing + // Prevent calling ProcessGestureEvent() when Emscripten is present and there's a touch gesture, so EmscriptenTouchCallback() can handle it itself + if (GetMouseX() != 0 || GetMouseY() != 0) ProcessGestureEvent(gestureEvent); + +#endif +} + +// GLFW3 Cursor Position Callback, runs on mouse move +static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) +{ + CORE.Input.Mouse.currentPosition.x = (float)x; + CORE.Input.Mouse.currentPosition.y = (float)y; + CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; + +#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP + // Process mouse events as touches to be able to use mouse-gestures + GestureEvent gestureEvent = { 0 }; + + gestureEvent.touchAction = TOUCH_ACTION_MOVE; + + // Assign a pointer ID + gestureEvent.pointId[0] = 0; + + // Register touch points count + gestureEvent.pointCount = 1; + + // Register touch points position, only one point registered + gestureEvent.position[0] = CORE.Input.Touch.position[0]; + + // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height + gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].y /= (float)GetScreenHeight(); + + // Gesture data is sent to gestures-system for processing + ProcessGestureEvent(gestureEvent); +#endif +} + +// GLFW3 Scrolling Callback, runs on mouse wheel +static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) +{ + CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset }; +} + +// GLFW3 CursorEnter Callback, when cursor enters the window +static void CursorEnterCallback(GLFWwindow *window, int enter) +{ + if (enter == true) CORE.Input.Mouse.cursorOnScreen = true; + else CORE.Input.Mouse.cursorOnScreen = false; +} + +// GLFW3 Window Drop Callback, runs when drop files into window +static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) +{ + if (count > 0) + { + // In case previous dropped filepaths have not been freed, we free them + if (CORE.Window.dropFileCount > 0) + { + for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]); + + RL_FREE(CORE.Window.dropFilepaths); + + CORE.Window.dropFileCount = 0; + CORE.Window.dropFilepaths = NULL; + } + + // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy + CORE.Window.dropFileCount = count; + CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *)); + + for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) + { + CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); + strcpy(CORE.Window.dropFilepaths[i], paths[i]); + } + } +} + +// Register fullscreen change events +static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData) +{ + // TODO: Implement EmscriptenFullscreenChangeCallback()? + + return 1; // The event was consumed by the callback handler +} + +// Register window resize event +static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData) +{ + // TODO: Implement EmscriptenWindowResizedCallback()? + + return 1; // The event was consumed by the callback handler +} + +EM_JS(int, GetWindowInnerWidth, (), { return window.innerWidth; }); +EM_JS(int, GetWindowInnerHeight, (), { return window.innerHeight; }); + +// Register DOM element resize event +static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData) +{ + // Don't resize non-resizeable windows + if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1; + + // This event is called whenever the window changes sizes, + // so the size of the canvas object is explicitly retrieved below + int width = GetWindowInnerWidth(); + int height = GetWindowInnerHeight(); + + if (width < CORE.Window.screenMin.width) width = CORE.Window.screenMin.width; + else if (width > CORE.Window.screenMax.width && CORE.Window.screenMax.width > 0) width = CORE.Window.screenMax.width; + + if (height < CORE.Window.screenMin.height) height = CORE.Window.screenMin.height; + else if (height > CORE.Window.screenMax.height && CORE.Window.screenMax.height > 0) height = CORE.Window.screenMax.height; + + emscripten_set_canvas_element_size("#canvas", width, height); + + SetupViewport(width, height); // Reset viewport and projection matrix for new size + + CORE.Window.currentFbo.width = width; + CORE.Window.currentFbo.height = height; + CORE.Window.resizedLastFrame = true; + + if (IsWindowFullscreen()) return 1; + + // Set current screen size + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; + + // NOTE: Postprocessing texture is not scaled to new size + + return 0; +} + +// Register mouse input events +static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) +{ + // This is only for registering mouse click events with emscripten and doesn't need to do anything + + return 1; // The event was consumed by the callback handler +} + +// Register connected/disconnected gamepads events +static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) +{ + /* + TRACELOGD("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"", + eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state", + gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping); + + for (int i = 0; i < gamepadEvent->numAxes; ++i) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]); + for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]); + */ + + if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) + { + CORE.Input.Gamepad.ready[gamepadEvent->index] = true; + sprintf(CORE.Input.Gamepad.name[gamepadEvent->index], "%s", gamepadEvent->id); + } + else CORE.Input.Gamepad.ready[gamepadEvent->index] = false; + + return 1; // The event was consumed by the callback handler +} + +// Register touch input events +static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) +{ + // Register touch points count + CORE.Input.Touch.pointCount = touchEvent->numTouches; + + double canvasWidth = 0.0; + double canvasHeight = 0.0; + // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but + // we are looking for actual CSS size: canvas.style.width and canvas.style.height + // EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight); + emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight); + + for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++) + { + // Register touch points id + CORE.Input.Touch.pointId[i] = touchEvent->touches[i].identifier; + + // Register touch points position + CORE.Input.Touch.position[i] = (Vector2){touchEvent->touches[i].targetX, touchEvent->touches[i].targetY}; + + // Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height + CORE.Input.Touch.position[i].x *= ((float)GetScreenWidth() / (float)canvasWidth); + CORE.Input.Touch.position[i].y *= ((float)GetScreenHeight() / (float)canvasHeight); + + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0; + } + +#if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_WEB + GestureEvent gestureEvent = {0}; + + gestureEvent.pointCount = CORE.Input.Touch.pointCount; + + // Register touch actions + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_ACTION_DOWN; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_ACTION_UP; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL; + + for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++) + { + gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i]; + gestureEvent.position[i] = CORE.Input.Touch.position[i]; + + // Normalize gestureEvent.position[i] + gestureEvent.position[i].x /= (float)GetScreenWidth(); + gestureEvent.position[i].y /= (float)GetScreenHeight(); + } + + // Gesture data is sent to gestures system for processing + ProcessGestureEvent(gestureEvent); + + // Reset the pointCount for web, if it was the last Touch End event + if (eventType == EMSCRIPTEN_EVENT_TOUCHEND && CORE.Input.Touch.pointCount == 1) CORE.Input.Touch.pointCount = 0; +#endif + + return 1; // The event was consumed by the callback handler +}