2014-09-16 22:51:31 +02:00
/**********************************************************************************************
2013-11-18 23:38:44 +01:00
*
2021-09-22 00:15:06 +02:00
* rcore - Basic functions to manage windows , OpenGL context and input on multiple platforms
2014-09-03 16:51:28 +02:00
*
2018-11-06 15:10:50 +01:00
* PLATFORMS SUPPORTED :
2017-11-10 12:37:53 +01:00
* - PLATFORM_DESKTOP : Windows ( Win32 , Win64 )
* - PLATFORM_DESKTOP : Linux ( X11 desktop mode )
2018-06-23 00:33:48 +02:00
* - PLATFORM_DESKTOP : FreeBSD , OpenBSD , NetBSD , DragonFly ( X11 desktop )
2017-11-10 12:37:53 +01:00
* - PLATFORM_DESKTOP : OSX / macOS
2021-06-28 14:23:45 +02:00
* - PLATFORM_ANDROID : Android ( ARM , ARM64 )
* - PLATFORM_RPI : Raspberry Pi 0 , 1 , 2 , 3 ( Raspbian , native mode )
2020-09-27 10:18:43 +02:00
* - PLATFORM_DRM : Linux native mode , including Raspberry Pi 4 with V3D fkms driver
2021-06-28 14:23:45 +02:00
* - PLATFORM_WEB : HTML5 with WebAssembly
2013-11-18 23:38:44 +01:00
*
2017-02-16 00:50:02 +01:00
* CONFIGURATION :
*
* # define PLATFORM_DESKTOP
2018-06-23 00:33:48 +02:00
* Windowing and input system configured for desktop platforms : Windows , Linux , OSX , FreeBSD , OpenBSD , NetBSD , DragonFly
2020-03-30 14:38:16 +02:00
* NOTE : Oculus Rift CV1 requires PLATFORM_DESKTOP for mirror rendering - View [ rlgl ] module to enable it
2017-02-16 00:50:02 +01:00
*
* # define PLATFORM_ANDROID
* Windowing and input system configured for Android device , app activity managed internally in this module .
* NOTE : OpenGL ES 2.0 is required and graphic device is managed by EGL
*
2022-06-25 12:10:28 +02:00
* # define PLATFORM_RPI ( deprecated - RPI OS Buster only )
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
* Windowing and input system configured for Raspberry Pi in native mode ( no XWindow required ) ,
* graphic device is managed by EGL and inputs are processed is raw mode , reading from / dev / input /
2022-06-25 12:10:28 +02:00
* WARNING : This platform is deprecated , since RPI OS Bullseye , the old Dispmanx libraries are not
* supported and you must be using PLATFORM_DRM
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
*
* # define PLATFORM_DRM
* Windowing and input system configured for DRM native mode ( RPI4 and other devices )
2017-12-05 14:01:35 +01:00
* graphic device is managed by EGL and inputs are processed is raw mode , reading from / dev / input /
2017-02-16 00:50:02 +01:00
*
* # define PLATFORM_WEB
* Windowing and input system configured for HTML5 ( run on browser ) , code converted from C to asm . js
* using emscripten compiler . OpenGL ES 2.0 required for direct translation to WebGL equivalent code .
*
2017-03-21 13:22:59 +01:00
* # define SUPPORT_DEFAULT_FONT ( default )
2017-02-16 00:50:02 +01:00
* Default font is loaded on window initialization to be available for the user to render simple text .
* NOTE : If enabled , uses external module functions to load default raylib font ( module : text )
*
2017-03-21 13:22:59 +01:00
* # define SUPPORT_CAMERA_SYSTEM
2021-09-22 00:15:06 +02:00
* Camera module is included ( rcamera . h ) and multiple predefined cameras are available : free , 1 st / 3 rd person , orbital
2017-02-16 00:50:02 +01:00
*
2017-03-21 13:22:59 +01:00
* # define SUPPORT_GESTURES_SYSTEM
2021-09-22 00:15:06 +02:00
* Gestures module is included ( rgestures . h ) to support gestures detection : tap , hold , swipe , drag
2017-02-16 00:50:02 +01:00
*
* # define SUPPORT_MOUSE_GESTURES
* Mouse gestures are directly mapped like touches and processed by gestures system .
*
2019-05-02 09:46:01 +02:00
* # define SUPPORT_TOUCH_AS_MOUSE
* Touch input and mouse input are shared . Mouse functions also return touch information .
*
2019-05-21 20:59:13 +02:00
* # define SUPPORT_SSH_KEYBOARD_RPI ( Raspberry Pi only )
* Reconfigure standard input to receive key inputs , works with SSH connection .
* WARNING : Reconfiguring standard input could lead to undesired effects , like breaking other running processes or
2021-07-03 21:25:30 +02:00
* blocking the device if not restored properly . Use with care .
2019-05-21 20:59:13 +02:00
*
2021-06-17 11:17:39 +02:00
* # define SUPPORT_MOUSE_CURSOR_POINT
2020-09-27 10:18:43 +02:00
* Draw a mouse pointer on screen
2019-08-20 20:39:22 +02:00
*
2017-05-08 02:37:37 +02:00
* # define SUPPORT_BUSY_WAIT_LOOP
2018-04-07 22:29:53 +02:00
* Use busy wait loop for timing sync , if not defined , a high - resolution timer is setup and used
2017-05-08 02:37:37 +02:00
*
2021-05-07 10:49:44 -07:00
* # define SUPPORT_PARTIALBUSY_WAIT_LOOP
* Use a partial - busy wait loop , in this case frame sleeps for most of the time and runs a busy - wait - loop at the end
2020-01-19 17:31:55 +01:00
*
2018-10-31 23:19:29 +01:00
* # define SUPPORT_EVENTS_WAITING
* Wait for events passively ( sleeping while no events ) instead of polling them actively every frame
*
2018-04-29 11:37:39 +02:00
* # define SUPPORT_SCREEN_CAPTURE
* Allow automatic screen capture of current screen pressing F12 , defined in KeyCallback ( )
*
2017-05-18 18:57:11 +02:00
* # define SUPPORT_GIF_RECORDING
* Allow automatic gif recording of current screen pressing CTRL + F12 , defined in KeyCallback ( )
*
2019-09-09 21:56:16 +02:00
* # define SUPPORT_COMPRESSION_API
* Support CompressData ( ) and DecompressData ( ) functions , those functions use zlib implementation
* provided by stb_image and stb_image_write libraries , so , those libraries must be enabled on textures module
* for linkage
*
2021-06-11 12:27:46 +02:00
* # define SUPPORT_EVENTS_AUTOMATION
* Support automatic generated events , loading and recording of those events when required
2020-02-27 13:18:15 +01:00
*
2017-02-16 00:50:02 +01:00
* DEPENDENCIES :
2018-06-23 00:33:48 +02:00
* rglfw - Manage graphic device , OpenGL context and inputs on PLATFORM_DESKTOP ( Windows , Linux , OSX . FreeBSD , OpenBSD , NetBSD , DragonFly )
2017-12-05 14:01:35 +01:00
* raymath - 3 D math functionality ( Vector2 , Vector3 , Matrix , Quaternion )
2017-01-28 23:02:30 +01:00
* camera - Multiple 3 D camera modes ( free , orbital , 1 st person , 3 rd person )
2016-11-16 18:46:13 +01:00
* gestures - Gestures system for touch - ready devices ( or simulated from mouse inputs )
2014-09-16 22:51:31 +02:00
*
2016-11-16 18:46:13 +01:00
*
2017-02-16 00:50:02 +01:00
* LICENSE : zlib / libpng
2016-11-16 18:46:13 +01:00
*
2021-12-31 20:06:22 +01:00
* Copyright ( c ) 2013 - 2022 Ramon Santamaria ( @ raysan5 )
2014-09-03 16:51:28 +02:00
*
* This software is provided " as-is " , without any express or implied warranty . In no event
2013-11-23 13:30:54 +01:00
* will the authors be held liable for any damages arising from the use of this software .
2013-11-18 23:38:44 +01:00
*
2014-09-03 16:51:28 +02:00
* Permission is granted to anyone to use this software for any purpose , including commercial
2013-11-23 13:30:54 +01:00
* applications , and to alter it and redistribute it freely , subject to the following restrictions :
2013-11-18 23:38:44 +01:00
*
2014-09-03 16:51:28 +02:00
* 1. The origin of this software must not be misrepresented ; you must not claim that you
* wrote the original software . If you use this software in a product , an acknowledgment
2013-11-23 13:30:54 +01:00
* in the product documentation would be appreciated but is not required .
2013-11-18 23:38:44 +01:00
*
2013-11-23 13:30:54 +01:00
* 2. Altered source versions must be plainly marked as such , and must not be misrepresented
* as being the original software .
2013-11-18 23:38:44 +01:00
*
2013-11-23 13:30:54 +01:00
* 3. This notice may not be removed or altered from any source distribution .
2013-11-18 23:38:44 +01:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-05-01 17:31:44 +02:00
# include "raylib.h" // Declares module functions
2016-12-17 19:05:40 +01:00
2018-12-18 00:20:08 +01:00
// Check if config flags have been externally provided on compilation line
# if !defined(EXTERNAL_CONFIG_FLAGS)
2020-05-01 17:31:44 +02:00
# include "config.h" // Defines module configuration flags
2018-12-18 00:20:08 +01:00
# endif
2021-07-29 21:57:50 +02:00
# include "utils.h" // Required for: TRACELOG() macros
2020-02-03 19:13:24 +01:00
2021-07-29 21:57:50 +02:00
# define RLGL_IMPLEMENTATION
# include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
2017-11-22 22:47:57 +01:00
2021-07-09 17:36:20 +02:00
# define RAYMATH_IMPLEMENTATION // Define external out-of-line implementation
# include "raymath.h" // Vector3, Quaternion and Matrix functionality
raymath.h: Use C99 inline semantics
RAYMATH_EXTERN_INLINE was renamed to RAYMATH_HEADER_ONLY, which user code
may define if they want to use it as header-only library. If multiple
files in the same project define RAYMATH_HEADER_ONLY, they might each
have duplicate out-of-line definitions of the same functions.
By default, raymath.h exposes inline definitions, which instructs the
compiler _not_ to generate out-of-line definitons, if out-of-line
definitions are required, those of the file defined with
RAYLIB_IMPLEMENTATION are used instead. There may be only one such file.
In C++ mode, the compiler will select only one out-of-line definition
automatically, so no need to define a RAYLIB_IMPLEMENTATION.
Unfortunately, we have to remove raymath function declaration from
raylib.h as those declarations would lead to duplicate out-of-line
definitions which would yield linker errors. This problem didn't
exist with GNU89 or C++, because there multiple defintions are ok,
but in C99 they aren't.
2018-02-22 02:05:00 +01:00
2017-03-21 13:22:59 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM)
# define GESTURES_IMPLEMENTATION
2021-09-22 00:15:06 +02:00
# include "rgestures.h" // Gestures detection functionality
2017-03-21 13:22:59 +01:00
# endif
2016-08-06 16:32:46 +02:00
2019-07-24 22:39:33 +02:00
# if defined(SUPPORT_CAMERA_SYSTEM)
2016-08-26 19:40:37 +02:00
# define CAMERA_IMPLEMENTATION
2021-09-22 00:15:06 +02:00
# include "rcamera.h" // Camera system functionality
2017-05-18 18:57:11 +02:00
# endif
# if defined(SUPPORT_GIF_RECORDING)
2021-07-09 17:36:20 +02:00
# define MSF_GIF_MALLOC(contextPointer, newSize) RL_MALLOC(newSize)
# define MSF_GIF_REALLOC(contextPointer, oldMemory, oldSize, newSize) RL_REALLOC(oldMemory, newSize)
# define MSF_GIF_FREE(contextPointer, oldMemory, oldSize) RL_FREE(oldMemory)
2020-03-25 19:41:51 +01:00
2020-11-20 00:34:18 +01:00
# define MSF_GIF_IMPL
2021-07-09 17:36:20 +02:00
# include "external/msf_gif.h" // GIF recording functionality
2016-08-26 19:40:37 +02:00
# endif
2016-08-10 12:55:54 +02:00
2021-01-12 21:15:11 +01:00
# if defined(SUPPORT_COMPRESSION_API)
# define SINFL_IMPLEMENTATION
2021-10-06 21:13:17 +02:00
# define SINFL_NO_SIMD
2021-07-09 17:36:20 +02:00
# include "external/sinfl.h" // Deflate (RFC 1951) decompressor
2021-03-19 19:43:44 +01:00
2021-01-12 21:15:11 +01:00
# define SDEFL_IMPLEMENTATION
2021-07-09 17:36:20 +02:00
# include "external/sdefl.h" // Deflate (RFC 1951) compressor
2021-01-12 21:15:11 +01:00
# endif
2021-07-30 12:14:31 +02:00
# if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L
# undef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext.
# endif
2022-01-10 13:54:51 +01:00
// Platform specific defines to handle GetApplicationDirectory()
2022-01-08 10:47:52 -08:00
# if defined (PLATFORM_DESKTOP)
# if defined(_WIN32)
# ifndef MAX_PATH
# define MAX_PATH 1025
# endif
2022-01-18 14:30:19 -03:00
__declspec ( dllimport ) unsigned long __stdcall GetModuleFileNameA ( void * hModule , void * lpFilename , unsigned long nSize ) ;
__declspec ( dllimport ) unsigned long __stdcall GetModuleFileNameW ( void * hModule , void * lpFilename , unsigned long nSize ) ;
__declspec ( dllimport ) int __stdcall WideCharToMultiByte ( unsigned int cp , unsigned long flags , void * widestr , int cchwide , void * str , int cbmb , void * defchar , int * used_default ) ;
2022-01-08 10:47:52 -08:00
# elif defined(__linux__)
# include <unistd.h>
# elif defined(__APPLE__)
# include <sys/syslimits.h>
2022-01-22 17:25:53 +01:00
# include <mach-o/dyld.h>
2022-01-08 10:47:52 -08:00
# endif // OSs
# endif // PLATFORM_DESKTOP
2020-05-01 17:31:44 +02:00
# include <stdlib.h> // Required for: srand(), rand(), atexit()
# include <stdio.h> // Required for: sprintf() [Used in OpenURL()]
2022-04-24 11:02:50 +02:00
# include <string.h> // Required for: strrchr(), strcmp(), strlen(), memset()
2020-05-01 17:31:44 +02:00
# include <time.h> // Required for: time() [Used in InitTimer()]
2021-04-06 23:06:03 +02:00
# include <math.h> // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
2020-02-04 16:55:24 +01:00
2022-06-11 23:24:13 +02:00
# define _CRT_INTERNAL_NONSTDC_NAMES 1
# include <sys/stat.h> // Required for: stat(), S_ISREG [Used in GetFileModTime(), IsFilePath()]
# if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
# endif
2018-10-08 16:25:47 +02:00
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_DESKTOP) && defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__))
2020-03-17 13:40:07 +01:00
# define DIRENT_MALLOC RL_MALLOC
# define DIRENT_FREE RL_FREE
2020-03-25 19:41:51 +01:00
2022-06-06 20:30:24 +02:00
# include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()]
2018-10-08 16:25:47 +02:00
# else
2022-06-06 20:30:24 +02:00
# include <dirent.h> // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()]
2018-10-08 16:25:47 +02:00
# endif
2013-11-18 23:38:44 +01:00
2017-12-24 16:12:52 +01:00
# if defined(_WIN32)
2017-05-11 16:24:40 +02:00
# include <direct.h> // Required for: _getch(), _chdir()
# define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir()
# define CHDIR _chdir
2021-07-09 17:36:20 +02:00
# include <io.h> // Required for: _access() [Used in FileExists()]
2017-05-11 16:24:40 +02:00
# else
2020-02-09 16:11:11 +01:00
# include <unistd.h> // Required for: getch(), chdir() (POSIX), access()
2017-05-11 16:24:40 +02:00
# define GETCWD getcwd
# define CHDIR chdir
# endif
2018-10-08 16:12:09 +02:00
# if defined(PLATFORM_DESKTOP)
2018-10-08 18:08:39 +02:00
# define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3
// NOTE: Already provided by rlgl implementation (on glad.h)
2021-01-30 13:22:14 -08:00
# include "GLFW/glfw3.h" // GLFW3 library: Windows, OpenGL context and Input management
2018-05-04 23:03:56 +02:00
// NOTE: GLFW3 already includes gl.h (OpenGL) headers
2018-10-08 16:12:09 +02:00
2018-10-08 12:29:02 +02:00
// Support retrieving native window handlers
# if defined(_WIN32)
2018-10-08 13:29:42 +02:00
# define GLFW_EXPOSE_NATIVE_WIN32
2021-01-30 13:22:14 -08:00
# include "GLFW/glfw3native.h" // WARNING: It requires customization to avoid windows.h inclusion!
2018-11-06 15:10:50 +01:00
2021-03-12 17:18:48 +01:00
# if defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
2018-10-08 16:12:09 +02:00
// NOTE: Those functions require linking with winmm library
unsigned int __stdcall timeBeginPeriod ( unsigned int uPeriod ) ;
unsigned int __stdcall timeEndPeriod ( unsigned int uPeriod ) ;
# endif
2021-03-02 12:44:53 +01:00
# endif
2022-05-16 19:24:16 +02:00
# if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
2020-05-01 17:31:44 +02:00
# include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
2018-11-06 15:10:50 +01:00
2020-05-01 17:31:44 +02:00
//#define GLFW_EXPOSE_NATIVE_X11 // WARNING: Exposing Xlib.h > X.h results in dup symbols for Font type
2018-10-08 16:12:09 +02:00
//#define GLFW_EXPOSE_NATIVE_WAYLAND
//#define GLFW_EXPOSE_NATIVE_MIR
2021-01-30 13:22:14 -08:00
# include "GLFW/glfw3native.h" // Required for: glfwGetX11Window()
2021-03-02 12:44:53 +01:00
# endif
# if defined(__APPLE__)
2020-05-01 17:31:44 +02:00
# include <unistd.h> // Required for: usleep()
2018-11-06 15:10:50 +01:00
2020-05-01 17:31:44 +02:00
//#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition
2021-01-30 13:22:14 -08:00
# include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow()
2018-10-25 16:16:44 +02:00
# endif
# endif
2014-09-16 22:51:31 +02:00
# if defined(PLATFORM_ANDROID)
2021-07-09 17:36:20 +02:00
//#include <android/sensor.h> // Required for: Android sensors functions (accelerometer, gyroscope, light...)
# include <android/window.h> // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
# include <android_native_app_glue.h> // Required for: android_app struct and activity management
2022-03-18 07:41:41 -03:00
# include <jni.h> // Required for: JNIEnv and JavaVM [Used in OpenURL()]
2014-03-25 12:40:35 +01:00
2021-04-27 11:05:05 +02:00
# include <EGL/egl.h> // Native platform windowing system interface
2021-06-28 14:23:45 +02:00
//#include <GLES2/gl2.h> // OpenGL ES 2.0 library (not required in this module, only in rlgl)
2014-09-16 22:51:31 +02:00
# endif
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-05-01 17:31:44 +02:00
# include <fcntl.h> // POSIX file control definitions - open(), creat(), fcntl()
# include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
# include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
# include <pthread.h> // POSIX threads management (inputs reading)
# include <dirent.h> // POSIX directory browsing
2020-11-03 23:47:33 +01:00
2021-07-09 17:36:20 +02:00
# include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
2020-05-01 17:31:44 +02:00
# include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
# include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...)
# include <linux/joystick.h> // Linux: Joystick support library
2020-11-03 23:47:33 +01:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI)
2020-05-01 17:31:44 +02:00
# include "bcm_host.h" // Raspberry Pi VideoCore IV access functions
2020-09-27 10:18:43 +02:00
# endif
# if defined(PLATFORM_DRM)
2021-07-06 17:16:50 +02:00
# include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
2020-09-27 10:18:43 +02:00
# include <xf86drm.h> // Direct Rendering Manager user-level library interface
2021-07-06 17:16:50 +02:00
# include <xf86drmMode.h> // Direct Rendering Manager mode setting (KMS) interface
2020-09-27 10:18:43 +02:00
# endif
2020-11-03 23:47:33 +01:00
2021-04-27 11:05:05 +02:00
# include "EGL/egl.h" // Native platform windowing system interface
# include "EGL/eglext.h" // EGL extensions
2021-06-28 14:23:45 +02:00
//#include "GLES2/gl2.h" // OpenGL ES 2.0 library (not required in this module, only in rlgl)
2014-09-16 22:51:31 +02:00
# endif
2013-11-18 23:38:44 +01:00
2015-10-30 11:30:32 +01:00
# if defined(PLATFORM_WEB)
2020-05-01 17:31:44 +02:00
# define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL)
2021-07-09 17:36:20 +02:00
# include "GLFW/glfw3.h" // GLFW3: Windows, OpenGL context and Input management
2020-05-01 17:31:44 +02:00
# include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
2018-11-06 15:10:50 +01:00
2021-07-09 17:36:20 +02:00
# include <emscripten/emscripten.h> // Emscripten functionality for C
2018-10-08 16:12:09 +02:00
# include <emscripten/html5.h> // Emscripten HTML5 library
2015-10-30 11:30:32 +01:00
# endif
2013-11-18 23:38:44 +01:00
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2018-10-22 11:48:16 +02:00
# define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
2021-06-10 17:11:31 +02:00
# define DEFAULT_GAMEPAD_DEV " / dev / input / js" // Gamepad input (base dev for all gamepads: js0, js1, ...)
# define DEFAULT_EVDEV_PATH " / dev / input / " // Path to the linux input events
2016-02-19 00:16:16 +01:00
# endif
2022-06-12 11:32:10 +02:00
# ifndef MAX_FILEPATH_CAPACITY
# define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
# endif
2020-05-01 17:31:44 +02:00
# ifndef MAX_FILEPATH_LENGTH
2022-06-11 23:24:13 +02:00
# define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
2020-05-01 17:31:44 +02:00
# endif
2016-10-14 11:14:41 +02:00
2021-06-10 17:11:31 +02:00
# ifndef MAX_KEYBOARD_KEYS
# define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
# endif
# ifndef MAX_MOUSE_BUTTONS
# define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
# endif
2020-05-01 17:31:44 +02:00
# ifndef MAX_GAMEPADS
2021-06-10 17:11:31 +02:00
# define MAX_GAMEPADS 4 // Maximum number of gamepads supported
2020-05-01 17:31:44 +02:00
# endif
# ifndef MAX_GAMEPAD_AXIS
2021-06-10 17:11:31 +02:00
# define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
2020-05-01 17:31:44 +02:00
# endif
# ifndef MAX_GAMEPAD_BUTTONS
2021-06-10 17:11:31 +02:00
# define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
2020-05-01 17:31:44 +02:00
# endif
# ifndef MAX_TOUCH_POINTS
2021-09-10 15:19:12 +02:00
# define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
2020-05-01 17:31:44 +02:00
# endif
# ifndef MAX_KEY_PRESSED_QUEUE
2021-06-10 17:11:31 +02:00
# define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
2020-12-18 18:58:02 +01:00
# endif
# ifndef MAX_CHAR_PRESSED_QUEUE
2021-06-10 17:11:31 +02:00
# define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
2020-05-01 17:31:44 +02:00
# endif
2019-11-24 13:39:45 +01:00
2021-04-02 13:43:10 +02:00
# ifndef MAX_DECOMPRESSION_SIZE
2021-06-10 17:11:31 +02:00
# define MAX_DECOMPRESSION_SIZE 64 // Maximum size allocated for decompression in MB
2021-04-02 13:43:10 +02:00
# endif
2020-11-23 00:49:27 +01:00
// Flags operation macros
2020-12-23 15:03:26 +01:00
# define FLAG_SET(n, f) ((n) |= (f))
# define FLAG_CLEAR(n, f) ((n) &= ~(f))
# define FLAG_TOGGLE(n, f) ((n) ^= (f))
2020-11-23 00:49:27 +01:00
# define FLAG_CHECK(n, f) ((n) & (f))
2013-11-18 23:38:44 +01:00
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-01-08 17:19:06 +01:00
typedef struct {
2020-02-27 13:33:09 +01:00
pthread_t threadId ; // Event reading thread id
int fd ; // File descriptor to the device it is assigned to
int eventNum ; // Number of 'event<N>' device
Rectangle absRange ; // Range of values for absolute pointing devices (touchscreens)
int touchSlot ; // Hold the touch slot number of the currently being sent multitouch block
bool isMouse ; // True if device supports relative X Y movements
bool isTouch ; // True if device supports absolute X Y movements and has BTN_TOUCH
bool isMultitouch ; // True if device supports multiple absolute movevents and has BTN_TOUCH
bool isKeyboard ; // True if device has letter keycodes
bool isGamepad ; // True if device has gamepad buttons
2020-01-08 17:19:06 +01:00
} InputEventWorker ;
# endif
2013-11-18 23:38:44 +01:00
2020-02-03 18:31:30 +01:00
typedef struct { int x ; int y ; } Point ;
2020-02-13 00:13:56 +01:00
typedef struct { unsigned int width ; unsigned int height ; } Size ;
2020-02-03 18:31:30 +01:00
2020-03-23 20:24:09 +01:00
// Core global state context data
2020-02-03 18:31:30 +01:00
typedef struct CoreData {
struct {
2014-12-15 01:08:30 +01:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2021-06-24 18:13:25 +02:00
GLFWwindow * handle ; // GLFW window handle (graphic device)
2016-06-03 00:53:51 +02:00
# endif
2018-10-08 12:29:02 +02:00
# if defined(PLATFORM_RPI)
2020-02-03 18:31:30 +01:00
EGL_DISPMANX_WINDOW_T handle ; // Native window handle (graphic device)
2018-10-08 12:29:02 +02:00
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
2021-07-16 16:10:53 +02:00
int fd ; // File descriptor for /dev/dri/...
2020-09-27 10:18:43 +02:00
drmModeConnector * connector ; // Direct Rendering Manager (DRM) mode connector
2021-07-06 17:16:50 +02:00
drmModeCrtc * crtc ; // CRT Controller
2021-07-03 21:48:35 +02:00
int modeIndex ; // Index of the used mode of connector->modes
2021-07-06 17:16:50 +02:00
struct gbm_device * gbmDevice ; // GBM device
2021-07-03 21:48:35 +02:00
struct gbm_surface * gbmSurface ; // GBM surface
struct gbm_bo * prevBO ; // Previous GBM buffer object (during frame swapping)
uint32_t prevFB ; // Previous GBM framebufer (during frame swapping)
# endif // PLATFORM_DRM
2020-02-03 18:31:30 +01:00
EGLDisplay device ; // Native display device (physical screen connection)
EGLSurface surface ; // Surface to draw on, framebuffers (connected to context)
EGLContext context ; // Graphic context, mode in which drawing can be done
EGLConfig config ; // Graphic config
# endif
const char * title ; // Window text title const pointer
2020-11-23 00:49:27 +01:00
unsigned int flags ; // Configuration flags (bit based), keeps window state
bool ready ; // Check if window has been initialized successfully
bool fullscreen ; // Check if fullscreen mode is enabled
bool shouldClose ; // Check if window set for closing
bool resizedLastFrame ; // Check if window has been resized last frame
2022-05-12 16:51:46 +02:00
bool eventWaiting ; // Wait for events before ending frame
2020-02-03 18:31:30 +01:00
Point position ; // Window position on screen (required on fullscreen toggle)
Size display ; // Display width and height (monitor, device-screen, LCD, ...)
Size screen ; // Screen width and height (used render area)
2021-06-17 11:17:39 +02:00
Size currentFbo ; // Current render width and height (depends on active fbo)
2020-02-03 18:31:30 +01:00
Size render ; // Framebuffer width and height (render area, including black bars if required)
Point renderOffset ; // Offset from render area (must be divided by 2)
Matrix screenScale ; // Matrix to scale screen (framebuffer rendering)
2020-02-03 19:26:28 +01:00
2022-06-18 16:22:42 +02:00
char * * dropFilepaths ; // Store dropped files paths pointers (provided by GLFW)
2022-06-11 23:24:13 +02:00
unsigned int dropFileCount ; // Count dropped files strings
2018-10-07 00:47:57 +02:00
2020-02-03 18:31:30 +01:00
} Window ;
2016-06-03 00:53:51 +02:00
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
struct {
bool appEnabled ; // Flag to detect if app is active ** = true
struct android_app * app ; // Android activity
struct android_poll_source * source ; // Android events polling source
bool contextRebindRequired ; // Used to know context rebind required
} Android ;
2020-04-30 18:48:39 +01:00
# endif
struct {
2021-06-24 18:13:25 +02:00
const char * basePath ; // Base path for data storage
} Storage ;
2020-02-03 18:31:30 +01:00
struct {
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-02-03 18:31:30 +01:00
InputEventWorker eventWorker [ 10 ] ; // List of worker threads for every monitored "/dev/input/event<N>"
2016-06-03 00:53:51 +02:00
# endif
2020-02-03 18:31:30 +01:00
struct {
int exitKey ; // Default exit key
2021-06-10 17:11:31 +02:00
char currentKeyState [ MAX_KEYBOARD_KEYS ] ; // Registers current frame key state
char previousKeyState [ MAX_KEYBOARD_KEYS ] ; // Registers previous frame key state
2020-12-23 15:03:26 +01:00
2020-12-18 18:58:02 +01:00
int keyPressedQueue [ MAX_KEY_PRESSED_QUEUE ] ; // Input keys queue
int keyPressedQueueCount ; // Input keys queue count
2016-06-03 00:53:51 +02:00
2021-09-01 23:09:30 +02:00
int charPressedQueue [ MAX_CHAR_PRESSED_QUEUE ] ; // Input characters queue (unicode)
2020-12-18 18:58:02 +01:00
int charPressedQueueCount ; // Input characters queue count
2020-12-23 15:03:26 +01:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-02-03 18:31:30 +01:00
int defaultMode ; // Default keyboard mode
2021-07-17 15:27:48 -03:00
# if defined(SUPPORT_SSH_KEYBOARD_RPI)
bool evtMode ; // Keyboard in event mode
# endif
int defaultFileFlags ; // Default IO file flags
2020-02-03 18:31:30 +01:00
struct termios defaultSettings ; // Default keyboard settings
2021-01-06 19:46:12 +00:00
int fd ; // File descriptor for the evdev keyboard
2020-02-03 18:31:30 +01:00
# endif
} Keyboard ;
struct {
Vector2 offset ; // Mouse offset
Vector2 scale ; // Mouse scaling
2021-06-10 18:03:25 +02:00
Vector2 currentPosition ; // Mouse position on screen
Vector2 previousPosition ; // Previous mouse position
2020-02-03 18:31:30 +01:00
2020-10-21 11:08:37 +02:00
int cursor ; // Tracks current mouse cursor
2020-02-03 18:31:30 +01:00
bool cursorHidden ; // Track if cursor is hidden
bool cursorOnScreen ; // Tracks if cursor is inside client area
2020-07-10 18:23:17 +02:00
2021-06-10 17:11:31 +02:00
char currentButtonState [ MAX_MOUSE_BUTTONS ] ; // Registers current mouse button state
char previousButtonState [ MAX_MOUSE_BUTTONS ] ; // Registers previous mouse button state
2022-06-12 11:30:07 -04:00
Vector2 currentWheelMove ; // Registers current mouse wheel variation
Vector2 previousWheelMove ; // Registers previous mouse wheel variation
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-10-22 12:20:42 +02:00
// NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update
char currentButtonStateEvdev [ MAX_MOUSE_BUTTONS ] ; // Holds the new mouse state for the next polling event to grab
2020-02-03 18:31:30 +01:00
# endif
} Mouse ;
struct {
2021-09-10 15:19:12 +02:00
int pointCount ; // Number of touch points active
int pointId [ MAX_TOUCH_POINTS ] ; // Point identifiers
2020-02-29 22:10:23 +01:00
Vector2 position [ MAX_TOUCH_POINTS ] ; // Touch position on screen
char currentTouchState [ MAX_TOUCH_POINTS ] ; // Registers current touch state
char previousTouchState [ MAX_TOUCH_POINTS ] ; // Registers previous touch state
2020-02-03 18:31:30 +01:00
} Touch ;
struct {
int lastButtonPressed ; // Register last gamepad button pressed
int axisCount ; // Register number of available gamepad axis
bool ready [ MAX_GAMEPADS ] ; // Flag to know if gamepad is ready
2021-10-22 12:20:42 +02:00
char name [ MAX_GAMEPADS ] [ 64 ] ; // Gamepad name holder
2021-06-10 17:11:31 +02:00
char currentButtonState [ MAX_GAMEPADS ] [ MAX_GAMEPAD_BUTTONS ] ; // Current gamepad buttons state
char previousButtonState [ MAX_GAMEPADS ] [ MAX_GAMEPAD_BUTTONS ] ; // Previous gamepad buttons state
float axisState [ MAX_GAMEPADS ] [ MAX_GAMEPAD_AXIS ] ; // Gamepad axis state
2021-10-22 12:20:42 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-02-03 18:31:30 +01:00
pthread_t threadId ; // Gamepad reading thread id
int streamId [ MAX_GAMEPADS ] ; // Gamepad device file descriptor
# endif
} Gamepad ;
} Input ;
struct {
double current ; // Current time measure
double previous ; // Previous time measure
double update ; // Time measure for frame update
double draw ; // Time measure for frame draw
double frame ; // Time measure for one frame
double target ; // Desired time for one frame, if 0 not applied
2021-06-24 18:13:25 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-02-03 18:31:30 +01:00
unsigned long long base ; // Base time measure for hi-res timer
2015-05-11 00:15:46 +02:00
# endif
2021-06-11 12:27:46 +02:00
unsigned int frameCounter ; // Frame counter
2020-02-03 18:31:30 +01:00
} Time ;
} CoreData ;
2020-01-24 19:45:51 +01:00
2020-02-03 18:31:30 +01:00
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
2021-12-06 19:53:09 +01:00
const char * raylibVersion = RAYLIB_VERSION ; // raylib version symbol, it could be required for some bindings
2022-06-11 23:24:13 +02:00
static CoreData CORE = { 0 } ; // Global CORE state context
2018-04-29 11:49:10 +02:00
# if defined(SUPPORT_SCREEN_CAPTURE)
static int screenshotCounter = 0 ; // Screenshots counter
# endif
2017-05-18 18:57:11 +02:00
# if defined(SUPPORT_GIF_RECORDING)
2021-11-17 13:36:28 +01:00
static int gifFrameCounter = 0 ; // GIF frames counter
2018-04-29 11:49:10 +02:00
static bool gifRecording = false ; // GIF recording state
2020-11-20 00:34:18 +01:00
static MsfGifState gifState = { 0 } ; // MSGIF context state
2017-05-18 18:57:11 +02:00
# endif
2021-06-11 12:27:46 +02:00
# if defined(SUPPORT_EVENTS_AUTOMATION)
# define MAX_CODE_AUTOMATION_EVENTS 16384
typedef enum AutomationEventType {
EVENT_NONE = 0 ,
// Input events
INPUT_KEY_UP , // param[0]: key
INPUT_KEY_DOWN , // param[0]: key
INPUT_KEY_PRESSED , // param[0]: key
INPUT_KEY_RELEASED , // param[0]: key
INPUT_MOUSE_BUTTON_UP , // param[0]: button
INPUT_MOUSE_BUTTON_DOWN , // param[0]: button
INPUT_MOUSE_POSITION , // param[0]: x, param[1]: y
2022-06-12 11:30:07 -04:00
INPUT_MOUSE_WHEEL_MOTION , // param[0]: x delta, param[1]: y delta
2021-06-11 12:27:46 +02:00
INPUT_GAMEPAD_CONNECT , // param[0]: gamepad
INPUT_GAMEPAD_DISCONNECT , // param[0]: gamepad
INPUT_GAMEPAD_BUTTON_UP , // param[0]: button
INPUT_GAMEPAD_BUTTON_DOWN , // param[0]: button
INPUT_GAMEPAD_AXIS_MOTION , // param[0]: axis, param[1]: delta
INPUT_TOUCH_UP , // param[0]: id
INPUT_TOUCH_DOWN , // param[0]: id
INPUT_TOUCH_POSITION , // param[0]: x, param[1]: y
INPUT_GESTURE , // param[0]: gesture
// Window events
WINDOW_CLOSE , // no params
WINDOW_MAXIMIZE , // no params
WINDOW_MINIMIZE , // no params
WINDOW_RESIZE , // param[0]: width, param[1]: height
// Custom events
ACTION_TAKE_SCREENSHOT ,
ACTION_SETTARGETFPS
} AutomationEventType ;
// Event type
// Used to enable events flags
typedef enum {
EVENT_INPUT_KEYBOARD = 0 ,
EVENT_INPUT_MOUSE = 1 ,
EVENT_INPUT_GAMEPAD = 2 ,
EVENT_INPUT_TOUCH = 4 ,
EVENT_INPUT_GESTURE = 8 ,
EVENT_WINDOW = 16 ,
EVENT_CUSTOM = 32
} EventType ;
static const char * autoEventTypeName [ ] = {
" EVENT_NONE " ,
2021-06-13 17:08:30 +02:00
" INPUT_KEY_UP " ,
" INPUT_KEY_DOWN " ,
" INPUT_KEY_PRESSED " ,
" INPUT_KEY_RELEASED " ,
" INPUT_MOUSE_BUTTON_UP " ,
" INPUT_MOUSE_BUTTON_DOWN " ,
" INPUT_MOUSE_POSITION " ,
" INPUT_MOUSE_WHEEL_MOTION " ,
" INPUT_GAMEPAD_CONNECT " ,
" INPUT_GAMEPAD_DISCONNECT " ,
" INPUT_GAMEPAD_BUTTON_UP " ,
2021-06-11 12:27:46 +02:00
" INPUT_GAMEPAD_BUTTON_DOWN " ,
" INPUT_GAMEPAD_AXIS_MOTION " ,
2021-06-13 17:08:30 +02:00
" INPUT_TOUCH_UP " ,
" INPUT_TOUCH_DOWN " ,
" INPUT_TOUCH_POSITION " ,
" INPUT_GESTURE " ,
" WINDOW_CLOSE " ,
" WINDOW_MAXIMIZE " ,
" WINDOW_MINIMIZE " ,
" WINDOW_RESIZE " ,
2021-06-11 12:27:46 +02:00
" ACTION_TAKE_SCREENSHOT " ,
" ACTION_SETTARGETFPS "
} ;
// Automation Event (20 bytes)
typedef struct AutomationEvent {
unsigned int frame ; // Event frame
unsigned int type ; // Event type (AutoEventType)
int params [ 3 ] ; // Event parameters (if required)
} AutomationEvent ;
static AutomationEvent * events = NULL ; // Events array
static unsigned int eventCount = 0 ; // Events count
static bool eventsPlaying = false ; // Play events
static bool eventsRecording = false ; // Record events
//static short eventsEnabled = 0b0000001111111111; // Events enabled for checking
# endif
2018-10-08 12:29:02 +02:00
//-----------------------------------------------------------------------------------
2017-05-18 18:57:11 +02:00
2013-11-18 23:38:44 +01:00
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by core)
//----------------------------------------------------------------------------------
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
2019-06-16 23:42:51 +02:00
extern void LoadFontDefault ( void ) ; // [Module: text] Loads default font on InitWindow()
extern void UnloadFontDefault ( void ) ; // [Module: text] Unloads default font from GPU memory
2016-10-09 13:09:08 +02:00
# endif
2016-08-06 16:32:46 +02:00
2013-11-18 23:38:44 +01:00
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
2021-06-22 20:26:59 +02:00
static void InitTimer ( void ) ; // Initialize timer (hi-resolution if available)
2018-02-03 12:12:50 +01:00
static bool InitGraphicsDevice ( int width , int height ) ; // Initialize graphics device
2018-10-08 12:29:02 +02:00
static void SetupFramebuffer ( int width , int height ) ; // Setup main framebuffer
2019-05-01 14:30:36 +02:00
static void SetupViewport ( int width , int height ) ; // Set viewport for a provided width and height
2018-10-08 12:29:02 +02:00
2022-06-11 23:24:13 +02:00
static void ScanDirectoryFiles ( const char * basePath , FilePathList * list , const char * filter ) ; // Scan all files and directories in a base path
static void ScanDirectoryFilesRecursively ( const char * basePath , FilePathList * list , const char * filter ) ; // Scan all files and directories recursively from a base path
2014-12-15 01:08:30 +01:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2013-11-23 13:30:54 +01:00
static void ErrorCallback ( int error , const char * description ) ; // GLFW3 Error Callback, runs on GLFW3 error
2020-12-18 18:58:02 +01:00
// Window callbacks events
2014-09-16 22:51:31 +02:00
static void WindowSizeCallback ( GLFWwindow * window , int width , int height ) ; // GLFW3 WindowSize Callback, runs when window is resized
2020-12-18 19:32:52 +01:00
# if !defined(PLATFORM_WEB)
2020-12-18 18:58:02 +01:00
static void WindowMaximizeCallback ( GLFWwindow * window , int maximized ) ; // GLFW3 Window Maximize Callback, runs when window is maximized
2020-12-18 19:32:52 +01:00
# endif
2015-07-29 21:44:27 +02:00
static void WindowIconifyCallback ( GLFWwindow * window , int iconified ) ; // GLFW3 WindowIconify Callback, runs when window is minimized/restored
2020-04-27 17:41:29 +02:00
static void WindowFocusCallback ( GLFWwindow * window , int focused ) ; // GLFW3 WindowFocus Callback, runs when window get/lose focus
2015-07-29 21:44:27 +02:00
static void WindowDropCallback ( GLFWwindow * window , int count , const char * * paths ) ; // GLFW3 Window Drop Callback, runs when drop files into window
2020-12-18 18:58:02 +01:00
// Input callbacks events
static void KeyCallback ( GLFWwindow * window , int key , int scancode , int action , int mods ) ; // GLFW3 Keyboard Callback, runs on key pressed
static void CharCallback ( GLFWwindow * window , unsigned int key ) ; // GLFW3 Char Key Callback, runs on key pressed (get char value)
static void MouseButtonCallback ( GLFWwindow * window , int button , int action , int mods ) ; // GLFW3 Mouse Button Callback, runs on mouse button pressed
static void MouseCursorPosCallback ( GLFWwindow * window , double x , double y ) ; // GLFW3 Cursor Position Callback, runs on mouse move
static void MouseScrollCallback ( GLFWwindow * window , double xoffset , double yoffset ) ; // GLFW3 Srolling Callback, runs on mouse wheel
static void CursorEnterCallback ( GLFWwindow * window , int enter ) ; // GLFW3 Cursor Enter Callback, cursor enters client area
2014-12-15 01:08:30 +01:00
# endif
2014-09-16 22:51:31 +02:00
# if defined(PLATFORM_ANDROID)
2015-04-22 17:34:42 +02:00
static void AndroidCommandCallback ( struct android_app * app , int32_t cmd ) ; // Process Android activity lifecycle commands
2016-01-03 13:01:21 +01:00
static int32_t AndroidInputCallback ( struct android_app * app , AInputEvent * event ) ; // Process Android inputs
2014-09-16 22:51:31 +02:00
# endif
2013-11-18 23:38:44 +01:00
2015-10-30 11:30:32 +01:00
# if defined(PLATFORM_WEB)
2021-12-31 17:46:31 +01:00
static EM_BOOL EmscriptenFullscreenChangeCallback ( int eventType , const EmscriptenFullscreenChangeEvent * event , void * userData ) ;
static EM_BOOL EmscriptenWindowResizedCallback ( int eventType , const EmscriptenUiEvent * event , void * userData ) ;
static EM_BOOL EmscriptenResizeCallback ( int eventType , const EmscriptenUiEvent * event , void * userData ) ;
2021-07-28 15:38:31 -04:00
static EM_BOOL EmscriptenMouseCallback ( int eventType , const EmscriptenMouseEvent * mouseEvent , void * userData ) ;
2017-04-08 00:16:03 +02:00
static EM_BOOL EmscriptenTouchCallback ( int eventType , const EmscriptenTouchEvent * touchEvent , void * userData ) ;
2016-12-25 20:42:22 +01:00
static EM_BOOL EmscriptenGamepadCallback ( int eventType , const EmscriptenGamepadEvent * gamepadEvent , void * userData ) ;
2015-10-30 11:30:32 +01:00
# endif
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-07-06 18:25:00 +02:00
static void InitKeyboard ( void ) ; // Initialize raw keyboard system
static void RestoreKeyboard ( void ) ; // Restore keyboard system
2019-05-21 20:59:13 +02:00
# if defined(SUPPORT_SSH_KEYBOARD_RPI)
static void ProcessKeyboard ( void ) ; // Process keyboard events
# endif
2021-06-24 18:13:25 +02:00
static void InitEvdevInput ( void ) ; // Initialize evdev inputs
2021-01-06 19:46:12 +00:00
static void ConfigureEvdevDevice ( char * device ) ; // Identifies a input device and configures it for use if appropriate
static void PollKeyboardEvents ( void ) ; // Process evdev keyboard events.
2019-04-28 16:45:23 +02:00
static void * EventThread ( void * arg ) ; // Input device events reading thread
2021-06-24 18:13:25 +02:00
static void InitGamepad ( void ) ; // Initialize raw gamepad input
2016-05-02 14:11:57 +02:00
static void * GamepadThread ( void * arg ) ; // Mouse reading thread
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
static int FindMatchingConnectorMode ( const drmModeConnector * connector , const drmModeModeInfo * mode ) ; // Search matching DRM mode in connector's mode list
static int FindExactConnectorMode ( const drmModeConnector * connector , uint width , uint height , uint fps , bool allowInterlaced ) ; // Search exactly matching DRM connector mode in connector's list
static int FindNearestConnectorMode ( const drmModeConnector * connector , uint width , uint height , uint fps , bool allowInterlaced ) ; // Search the nearest matching DRM connector mode in connector's list
# endif
# endif // PLATFORM_RPI || PLATFORM_DRM
2016-05-02 14:11:57 +02:00
2021-06-11 12:27:46 +02:00
# if defined(SUPPORT_EVENTS_AUTOMATION)
2021-06-24 18:13:25 +02:00
static void LoadAutomationEvents ( const char * fileName ) ; // Load automation events from file
static void ExportAutomationEvents ( const char * fileName ) ; // Export recorded automation events into a file
static void RecordAutomationEvent ( unsigned int frame ) ; // Record frame events (to internal events array)
static void PlayAutomationEvent ( unsigned int frame ) ; // Play frame events (from internal events array)
2021-06-11 12:27:46 +02:00
# endif
2017-01-28 00:56:45 +01:00
# if defined(_WIN32)
2021-06-24 18:13:25 +02:00
// NOTE: We declare Sleep() function symbol to avoid including windows.h (kernel32.lib linkage required)
2021-07-09 17:36:20 +02:00
void __stdcall Sleep ( unsigned long msTimeout ) ; // Required for: WaitTime()
2017-01-28 00:56:45 +01:00
# endif
2021-12-04 19:56:02 +01:00
# if !defined(SUPPORT_MODULE_RTEXT)
const char * TextFormat ( const char * text , . . . ) ; // Formatting of text with variables to 'embed'
# endif // !SUPPORT_MODULE_RTEXT
2013-11-18 23:38:44 +01:00
//----------------------------------------------------------------------------------
// Module Functions Definition - Window and OpenGL Context Functions
//----------------------------------------------------------------------------------
2018-04-02 14:49:01 +02:00
# if defined(PLATFORM_ANDROID)
2018-11-06 15:10:50 +01:00
// To allow easier porting to android, we allow the user to define a
2018-04-02 14:49:01 +02:00
// main function which we call from android_main, defined by ourselves
extern int main ( int argc , char * argv [ ] ) ;
void android_main ( struct android_app * app )
{
char arg0 [ ] = " raylib " ; // NOTE: argv[] are mutable
2020-02-03 18:31:30 +01:00
CORE . Android . app = app ;
2018-04-02 14:49:01 +02:00
2021-10-13 23:45:57 +02:00
// NOTE: Return codes != 0 are skipped
2018-10-18 16:00:11 +02:00
( void ) main ( 1 , ( char * [ ] ) { arg0 , NULL } ) ;
2018-04-02 14:49:01 +02:00
}
2021-10-13 23:45:57 +02:00
// NOTE: Add this to header (if apps really need it)
2018-04-02 14:49:01 +02:00
struct android_app * GetAndroidApp ( void )
{
2020-02-03 18:31:30 +01:00
return CORE . Android . app ;
2018-04-02 14:49:01 +02:00
}
# endif
2021-07-03 21:25:30 +02:00
2017-05-09 22:03:46 +02:00
// Initialize window and OpenGL context
2017-11-12 11:45:35 +01:00
// NOTE: data parameter could be used to pass any kind of required data to the initialization
2018-04-02 14:49:01 +02:00
void InitWindow ( int width , int height , const char * title )
2013-12-19 12:08:06 +01:00
{
2020-02-03 19:13:24 +01:00
TRACELOG ( LOG_INFO , " Initializing raylib %s " , RAYLIB_VERSION ) ;
2022-02-18 20:30:46 +01:00
2021-12-06 12:02:57 +01:00
TRACELOG ( LOG_INFO , " Supported raylib modules: " ) ;
TRACELOG ( LOG_INFO , " > rcore:..... loaded (mandatory) " ) ;
TRACELOG ( LOG_INFO , " > rlgl:...... loaded (mandatory) " ) ;
# if defined(SUPPORT_MODULE_RSHAPES)
TRACELOG ( LOG_INFO , " > rshapes:... loaded (optional) " ) ;
# else
TRACELOG ( LOG_INFO , " > rshapes:... not loaded (optional) " ) ;
# endif
2022-02-18 20:30:46 +01:00
# if defined(SUPPORT_MODULE_RTEXTURES)
2021-12-06 12:02:57 +01:00
TRACELOG ( LOG_INFO , " > rtextures:. loaded (optional) " ) ;
# else
TRACELOG ( LOG_INFO , " > rtextures:. not loaded (optional) " ) ;
2022-02-18 20:30:46 +01:00
# endif
# if defined(SUPPORT_MODULE_RTEXT)
2021-12-06 12:02:57 +01:00
TRACELOG ( LOG_INFO , " > rtext:..... loaded (optional) " ) ;
# else
TRACELOG ( LOG_INFO , " > rtext:..... not loaded (optional) " ) ;
# endif
# if defined(SUPPORT_MODULE_RMODELS)
TRACELOG ( LOG_INFO , " > rmodels:... loaded (optional) " ) ;
# else
TRACELOG ( LOG_INFO , " > rmodels:... not loaded (optional) " ) ;
# endif
2022-02-18 20:30:46 +01:00
# if defined(SUPPORT_MODULE_RAUDIO)
2021-12-06 12:02:57 +01:00
TRACELOG ( LOG_INFO , " > raudio:.... loaded (optional) " ) ;
# else
TRACELOG ( LOG_INFO , " > raudio:.... not loaded (optional) " ) ;
# endif
2015-02-02 00:57:08 +01:00
2020-07-24 18:20:37 +02:00
if ( ( title ! = NULL ) & & ( title [ 0 ] ! = 0 ) ) CORE . Window . title = title ;
2022-05-05 20:39:14 +02:00
2022-04-24 11:02:50 +02:00
// Initialize global input state
memset ( & CORE . Input , 0 , sizeof ( CORE . Input ) ) ;
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . exitKey = KEY_ESCAPE ;
CORE . Input . Mouse . scale = ( Vector2 ) { 1.0f , 1.0f } ;
2020-10-21 03:55:52 -05:00
CORE . Input . Mouse . cursor = MOUSE_CURSOR_ARROW ;
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . lastButtonPressed = - 1 ;
2022-05-12 16:51:46 +02:00
# if defined(SUPPORT_EVENTS_WAITING)
CORE . Window . eventWaiting = true ;
# endif
2020-11-03 23:47:33 +01:00
2018-04-02 14:49:01 +02:00
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
CORE . Window . screen . width = width ;
CORE . Window . screen . height = height ;
CORE . Window . currentFbo . width = width ;
CORE . Window . currentFbo . height = height ;
2017-11-10 12:37:53 +01:00
2018-04-02 14:49:01 +02:00
// Set desired windows flags before initializing anything
2020-02-03 18:31:30 +01:00
ANativeActivity_setWindowFlags ( CORE . Android . app - > activity , AWINDOW_FLAG_FULLSCREEN , 0 ) ; //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
2018-04-02 14:49:01 +02:00
2020-02-03 18:31:30 +01:00
int orientation = AConfiguration_getOrientation ( CORE . Android . app - > config ) ;
2013-12-19 12:08:06 +01:00
2020-03-27 18:06:09 +01:00
if ( orientation = = ACONFIGURATION_ORIENTATION_PORT ) TRACELOG ( LOG_INFO , " ANDROID: Window orientation set as portrait " ) ;
else if ( orientation = = ACONFIGURATION_ORIENTATION_LAND ) TRACELOG ( LOG_INFO , " ANDROID: Window orientation set as landscape " ) ;
2018-04-02 14:49:01 +02:00
// TODO: Automatic orientation doesn't seem to work
if ( width < = height )
{
2020-02-03 18:31:30 +01:00
AConfiguration_setOrientation ( CORE . Android . app - > config , ACONFIGURATION_ORIENTATION_PORT ) ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " ANDROID: Window orientation changed to portrait " ) ;
2018-04-02 14:49:01 +02:00
}
else
{
2020-02-03 18:31:30 +01:00
AConfiguration_setOrientation ( CORE . Android . app - > config , ACONFIGURATION_ORIENTATION_LAND ) ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " ANDROID: Window orientation changed to landscape " ) ;
2018-04-02 14:49:01 +02:00
}
2020-02-03 18:31:30 +01:00
//AConfiguration_getDensity(CORE.Android.app->config);
//AConfiguration_getKeyboard(CORE.Android.app->config);
//AConfiguration_getScreenSize(CORE.Android.app->config);
//AConfiguration_getScreenLong(CORE.Android.app->config);
2018-04-02 14:49:01 +02:00
2021-07-06 17:16:50 +02:00
// Initialize App command system
// NOTE: On APP_CMD_INIT_WINDOW -> InitGraphicsDevice(), InitTimer(), LoadFontDefault()...
2020-02-03 18:31:30 +01:00
CORE . Android . app - > onAppCmd = AndroidCommandCallback ;
2021-07-16 16:10:53 +02:00
2021-07-06 17:16:50 +02:00
// Initialize input events system
2020-02-03 18:31:30 +01:00
CORE . Android . app - > onInputEvent = AndroidInputCallback ;
2018-04-02 14:49:01 +02:00
2021-06-24 18:13:25 +02:00
// Initialize assets manager
2020-03-05 18:12:41 +01:00
InitAssetManager ( CORE . Android . app - > activity - > assetManager , CORE . Android . app - > activity - > internalDataPath ) ;
2021-06-30 16:39:07 +02:00
2021-06-24 18:13:25 +02:00
// Initialize base path for storage
CORE . Storage . basePath = CORE . Android . app - > activity - > internalDataPath ;
2018-04-02 14:49:01 +02:00
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " ANDROID: App initialized successfully " ) ;
2018-04-02 14:49:01 +02:00
2020-02-03 18:31:30 +01:00
// Android ALooper_pollAll() variables
int pollResult = 0 ;
int pollEvents = 0 ;
2018-04-02 14:49:01 +02:00
// Wait for window to be initialized (display and context)
2020-02-03 18:31:30 +01:00
while ( ! CORE . Window . ready )
2018-04-02 14:49:01 +02:00
{
// Process events loop
2020-02-03 18:31:30 +01:00
while ( ( pollResult = ALooper_pollAll ( 0 , NULL , & pollEvents , ( void * * ) & CORE . Android . source ) ) > = 0 )
2018-04-02 14:49:01 +02:00
{
// Process this event
2020-02-03 18:31:30 +01:00
if ( CORE . Android . source ! = NULL ) CORE . Android . source - > process ( CORE . Android . app , CORE . Android . source ) ;
2018-04-02 14:49:01 +02:00
// NOTE: Never close window, native activity is controlled by the system!
2020-02-03 18:31:30 +01:00
//if (CORE.Android.app->destroyRequested != 0) CORE.Window.shouldClose = true;
2018-04-02 14:49:01 +02:00
}
}
2020-11-23 00:49:27 +01:00
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-06-24 18:13:25 +02:00
// Initialize graphics device (display device and OpenGL context)
2018-02-04 12:26:28 +01:00
// NOTE: returns true if window and graphic device has been initialized successfully
2020-02-03 18:31:30 +01:00
CORE . Window . ready = InitGraphicsDevice ( width , height ) ;
2020-04-29 20:55:17 +02:00
2021-05-30 18:02:06 +02:00
// If graphic device is no properly initialized, we end program
2021-06-13 17:08:30 +02:00
if ( ! CORE . Window . ready )
2021-05-30 18:02:06 +02:00
{
TRACELOG ( LOG_FATAL , " Failed to initialize Graphic Device " ) ;
return ;
}
2014-09-03 16:51:28 +02:00
2021-06-24 18:13:25 +02:00
// Initialize hi-res timer
2018-03-31 12:22:44 +02:00
InitTimer ( ) ;
2021-06-30 16:39:07 +02:00
2021-06-22 20:26:59 +02:00
// Initialize random seed
srand ( ( unsigned int ) time ( NULL ) ) ;
2021-06-30 16:39:07 +02:00
2021-06-24 18:13:25 +02:00
// Initialize base path for storage
CORE . Storage . basePath = GetWorkingDirectory ( ) ;
2018-03-31 12:22:44 +02:00
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
2016-10-09 13:09:08 +02:00
// Load default font
2021-12-04 19:56:02 +01:00
// WARNING: External function: Module required: rtext
2019-06-16 23:42:51 +02:00
LoadFontDefault ( ) ;
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RSHAPES)
2020-02-12 13:48:50 +01:00
Rectangle rec = GetFontDefault ( ) . recs [ 95 ] ;
2020-02-20 13:46:49 +01:00
// NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
2021-12-04 19:56:02 +01:00
SetShapesTexture ( GetFontDefault ( ) . texture , ( Rectangle ) { rec . x + 1 , rec . y + 1 , rec . width - 2 , rec . height - 2 } ) ; // WARNING: Module required: rshapes
# endif
2021-04-04 14:59:17 +02:00
# else
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RSHAPES)
2021-07-29 21:57:50 +02:00
// Set default texture and rectangle to be used for shapes drawing
// NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
Texture2D texture = { rlGetTextureIdDefault ( ) , 1 , 1 , 1 , PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 } ;
2021-12-04 19:56:02 +01:00
SetShapesTexture ( texture , ( Rectangle ) { 0.0f , 0.0f , 1.0f , 1.0f } ) ; // WARNING: Module required: rshapes
# endif
2016-10-09 13:09:08 +02:00
# endif
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
2020-11-23 00:49:27 +01:00
if ( ( CORE . Window . flags & FLAG_WINDOW_HIGHDPI ) > 0 )
{
// Set default font texture filter for HighDPI (blurry)
2021-12-04 19:56:02 +01:00
// RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
rlTextureParameters ( GetFontDefault ( ) . texture . id , RL_TEXTURE_MIN_FILTER , RL_TEXTURE_FILTER_LINEAR ) ;
rlTextureParameters ( GetFontDefault ( ) . texture . id , RL_TEXTURE_MAG_FILTER , RL_TEXTURE_FILTER_LINEAR ) ;
2020-11-23 00:49:27 +01:00
}
2020-01-26 18:53:34 +01:00
# endif
2014-09-03 16:51:28 +02:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-06-24 18:13:25 +02:00
// Initialize raw input system
2019-04-28 16:45:23 +02:00
InitEvdevInput ( ) ; // Evdev inputs initialization
2014-09-16 22:51:31 +02:00
InitGamepad ( ) ; // Gamepad init
2021-07-06 18:25:00 +02:00
InitKeyboard ( ) ; // Keyboard init (stdin)
2014-03-25 12:40:35 +01:00
# endif
2015-04-22 17:34:42 +02:00
2015-10-30 11:30:32 +01:00
# if defined(PLATFORM_WEB)
2021-12-31 17:46:31 +01:00
// Setup callback funtions for the DOM events
emscripten_set_fullscreenchange_callback ( " #canvas " , NULL , 1 , EmscriptenFullscreenChangeCallback ) ;
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
2021-07-09 17:36:20 +02:00
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
2021-07-09 18:49:29 +02:00
//emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
2021-07-09 17:36:20 +02:00
// Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
2021-12-31 17:46:31 +01:00
//emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
2021-06-22 09:25:52 -07:00
// Trigger this once to get initial window sizing
2021-12-31 17:46:31 +01:00
//EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
2022-02-18 20:30:46 +01:00
2021-12-31 17:46:31 +01:00
// Support keyboard events -> Not used, GLFW.JS takes care of that
2020-05-14 17:35:26 +02:00
//emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
2021-04-02 13:46:56 +02:00
//emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
2017-04-08 00:16:03 +02:00
2021-07-28 15:38:31 -04:00
// Support mouse events
emscripten_set_click_callback ( " #canvas " , NULL , 1 , EmscriptenMouseCallback ) ;
2017-04-08 00:16:03 +02:00
// Support touch events
emscripten_set_touchstart_callback ( " #canvas " , NULL , 1 , EmscriptenTouchCallback ) ;
emscripten_set_touchend_callback ( " #canvas " , NULL , 1 , EmscriptenTouchCallback ) ;
emscripten_set_touchmove_callback ( " #canvas " , NULL , 1 , EmscriptenTouchCallback ) ;
emscripten_set_touchcancel_callback ( " #canvas " , NULL , 1 , EmscriptenTouchCallback ) ;
2016-08-16 11:09:55 +02:00
2017-04-08 00:16:03 +02:00
// Support gamepad events (not provided by GLFW3 on emscripten)
2016-12-25 20:42:22 +01:00
emscripten_set_gamepadconnected_callback ( NULL , 1 , EmscriptenGamepadCallback ) ;
emscripten_set_gamepaddisconnected_callback ( NULL , 1 , EmscriptenGamepadCallback ) ;
2015-10-30 11:30:32 +01:00
# endif
2021-06-10 18:03:25 +02:00
CORE . Input . Mouse . currentPosition . x = ( float ) CORE . Window . screen . width / 2.0f ;
CORE . Input . Mouse . currentPosition . y = ( float ) CORE . Window . screen . height / 2.0f ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
# if defined(SUPPORT_EVENTS_AUTOMATION)
events = ( AutomationEvent * ) malloc ( MAX_CODE_AUTOMATION_EVENTS * sizeof ( AutomationEvent ) ) ;
CORE . Time . frameCounter = 0 ;
# endif
2021-06-13 17:08:30 +02:00
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# endif // PLATFORM_DESKTOP || PLATFORM_WEB || PLATFORM_RPI || PLATFORM_DRM
2014-09-16 22:51:31 +02:00
}
2013-11-18 23:38:44 +01:00
2017-05-09 22:03:46 +02:00
// Close window and unload OpenGL context
2014-09-03 17:06:10 +02:00
void CloseWindow ( void )
2013-11-18 23:38:44 +01:00
{
2017-05-18 18:57:11 +02:00
# if defined(SUPPORT_GIF_RECORDING)
if ( gifRecording )
{
2020-11-20 00:34:18 +01:00
MsfGifResult result = msf_gif_end ( & gifState ) ;
msf_gif_free ( result ) ;
2017-05-18 18:57:11 +02:00
gifRecording = false ;
}
# endif
2018-11-06 15:10:50 +01:00
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
UnloadFontDefault ( ) ; // WARNING: Module required: rtext
2016-10-09 13:09:08 +02:00
# endif
2014-09-03 16:51:28 +02:00
2014-09-16 22:51:31 +02:00
rlglClose ( ) ; // De-init rlgl
2013-11-18 23:38:44 +01:00
2014-12-15 01:08:30 +01:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2020-02-03 18:31:30 +01:00
glfwDestroyWindow ( CORE . Window . handle ) ;
2013-11-23 13:30:54 +01:00
glfwTerminate ( ) ;
2016-06-03 00:53:51 +02:00
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
2017-05-08 02:37:37 +02:00
timeEndPeriod ( 1 ) ; // Restore time period
# endif
2021-07-06 17:16:50 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
// Close surface, context and display
if ( CORE . Window . device ! = EGL_NO_DISPLAY )
{
eglMakeCurrent ( CORE . Window . device , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
if ( CORE . Window . surface ! = EGL_NO_SURFACE )
{
eglDestroySurface ( CORE . Window . device , CORE . Window . surface ) ;
CORE . Window . surface = EGL_NO_SURFACE ;
}
if ( CORE . Window . context ! = EGL_NO_CONTEXT )
{
eglDestroyContext ( CORE . Window . device , CORE . Window . context ) ;
CORE . Window . context = EGL_NO_CONTEXT ;
}
eglTerminate ( CORE . Window . device ) ;
CORE . Window . device = EGL_NO_DISPLAY ;
}
# endif
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
if ( CORE . Window . prevFB )
{
drmModeRmFB ( CORE . Window . fd , CORE . Window . prevFB ) ;
CORE . Window . prevFB = 0 ;
}
if ( CORE . Window . prevBO )
{
gbm_surface_release_buffer ( CORE . Window . gbmSurface , CORE . Window . prevBO ) ;
CORE . Window . prevBO = NULL ;
}
if ( CORE . Window . gbmSurface )
{
gbm_surface_destroy ( CORE . Window . gbmSurface ) ;
CORE . Window . gbmSurface = NULL ;
}
if ( CORE . Window . gbmDevice )
{
gbm_device_destroy ( CORE . Window . gbmDevice ) ;
CORE . Window . gbmDevice = NULL ;
}
2020-11-03 23:47:33 +01:00
if ( CORE . Window . crtc )
2020-09-27 10:18:43 +02:00
{
if ( CORE . Window . connector )
{
drmModeSetCrtc ( CORE . Window . fd , CORE . Window . crtc - > crtc_id , CORE . Window . crtc - > buffer_id ,
CORE . Window . crtc - > x , CORE . Window . crtc - > y , & CORE . Window . connector - > connector_id , 1 , & CORE . Window . crtc - > mode ) ;
drmModeFreeConnector ( CORE . Window . connector ) ;
CORE . Window . connector = NULL ;
}
drmModeFreeCrtc ( CORE . Window . crtc ) ;
CORE . Window . crtc = NULL ;
}
if ( CORE . Window . fd ! = - 1 )
{
close ( CORE . Window . fd ) ;
CORE . Window . fd = - 1 ;
}
2014-09-16 22:51:31 +02:00
// Close surface, context and display
2020-02-03 18:31:30 +01:00
if ( CORE . Window . device ! = EGL_NO_DISPLAY )
2014-09-16 22:51:31 +02:00
{
2020-02-03 18:31:30 +01:00
if ( CORE . Window . surface ! = EGL_NO_SURFACE )
2014-09-16 22:51:31 +02:00
{
2020-02-03 18:31:30 +01:00
eglDestroySurface ( CORE . Window . device , CORE . Window . surface ) ;
CORE . Window . surface = EGL_NO_SURFACE ;
2014-09-16 22:51:31 +02:00
}
2020-02-03 18:31:30 +01:00
if ( CORE . Window . context ! = EGL_NO_CONTEXT )
2014-09-16 22:51:31 +02:00
{
2020-02-03 18:31:30 +01:00
eglDestroyContext ( CORE . Window . device , CORE . Window . context ) ;
CORE . Window . context = EGL_NO_CONTEXT ;
2014-09-16 22:51:31 +02:00
}
2020-02-03 18:31:30 +01:00
eglTerminate ( CORE . Window . device ) ;
CORE . Window . device = EGL_NO_DISPLAY ;
2016-08-16 11:09:55 +02:00
}
2016-06-24 19:34:47 +02:00
# endif
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2016-06-24 19:34:47 +02:00
// Wait for mouse and gamepad threads to finish before closing
// NOTE: Those threads should already have finished at this point
2020-02-03 18:31:30 +01:00
// because they are controlled by CORE.Window.shouldClose variable
2017-01-28 23:02:30 +01:00
2020-02-03 18:31:30 +01:00
CORE . Window . shouldClose = true ; // Added to force threads to exit when the close window is called
2017-01-28 23:02:30 +01:00
2021-01-06 19:46:12 +00:00
// Close the evdev keyboard
if ( CORE . Input . Keyboard . fd ! = - 1 )
{
close ( CORE . Input . Keyboard . fd ) ;
CORE . Input . Keyboard . fd = - 1 ;
}
2021-03-19 19:43:44 +01:00
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < sizeof ( CORE . Input . eventWorker ) / sizeof ( InputEventWorker ) ; + + i )
2018-10-21 00:09:17 +01:00
{
2020-02-03 18:31:30 +01:00
if ( CORE . Input . eventWorker [ i ] . threadId )
2018-10-21 00:09:17 +01:00
{
2020-02-03 18:31:30 +01:00
pthread_join ( CORE . Input . eventWorker [ i ] . threadId , NULL ) ;
2018-10-21 00:09:17 +01:00
}
}
2021-03-19 19:43:44 +01:00
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Gamepad . threadId ) pthread_join ( CORE . Input . Gamepad . threadId , NULL ) ;
2014-09-16 22:51:31 +02:00
# endif
2021-06-11 12:27:46 +02:00
# if defined(SUPPORT_EVENTS_AUTOMATION)
free ( events ) ;
# endif
2021-05-05 19:08:15 +02:00
CORE . Window . ready = false ;
2020-02-03 19:13:24 +01:00
TRACELOG ( LOG_INFO , " Window closed successfully " ) ;
2013-11-18 23:38:44 +01:00
}
2017-05-09 22:03:46 +02:00
// Check if KEY_ESCAPE pressed or Close icon pressed
2014-09-16 22:51:31 +02:00
bool WindowShouldClose ( void )
2015-02-02 00:57:08 +01:00
{
2018-07-21 17:13:59 +02:00
# if defined(PLATFORM_WEB)
// Emterpreter-Async required to run sync code
2019-02-21 18:45:19 +01:00
// https://github.com/emscripten-core/emscripten/wiki/Emterpreter#emterpreter-async-run-synchronous-code
2018-07-21 17:13:59 +02:00
// By default, this function is never called on a web-ready raylib example because we encapsulate
// frame code in a UpdateDrawFrame() function, to allow browser manage execution asynchronously
// but now emscripten allows sync code to be executed in an interpreted way, using emterpreter!
emscripten_sleep ( 16 ) ;
return false ;
# endif
2018-11-06 15:10:50 +01:00
2018-07-21 17:13:59 +02:00
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
if ( CORE . Window . ready )
2018-02-04 12:31:16 +01:00
{
// While window minimized, stop loop execution
2020-11-23 23:46:05 +01:00
while ( IsWindowState ( FLAG_WINDOW_MINIMIZED ) & & ! IsWindowState ( FLAG_WINDOW_ALWAYS_RUN ) ) glfwWaitEvents ( ) ;
2015-01-21 00:13:17 +01:00
2020-02-03 18:31:30 +01:00
CORE . Window . shouldClose = glfwWindowShouldClose ( CORE . Window . handle ) ;
2020-11-03 23:47:33 +01:00
2020-08-06 11:47:46 +02:00
// Reset close status for next frame
glfwSetWindowShouldClose ( CORE . Window . handle , GLFW_FALSE ) ;
2020-02-03 19:26:28 +01:00
2020-02-03 18:31:30 +01:00
return CORE . Window . shouldClose ;
2018-02-04 12:31:16 +01:00
}
else return true ;
2016-06-03 00:53:51 +02:00
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-02-03 18:31:30 +01:00
if ( CORE . Window . ready ) return CORE . Window . shouldClose ;
2018-02-04 12:31:16 +01:00
else return true ;
2014-09-16 22:51:31 +02:00
# endif
}
2020-11-23 00:49:27 +01:00
// Check if window has been initialized successfully
bool IsWindowReady ( void )
{
return CORE . Window . ready ;
}
// Check if window is currently fullscreen
bool IsWindowFullscreen ( void )
{
return CORE . Window . fullscreen ;
}
// Check if window is currently hidden
bool IsWindowHidden ( void )
{
# if defined(PLATFORM_DESKTOP)
return ( ( CORE . Window . flags & FLAG_WINDOW_HIDDEN ) > 0 ) ;
# endif
return false ;
}
2020-04-27 17:41:29 +02:00
// Check if window has been minimized
2015-07-29 21:44:27 +02:00
bool IsWindowMinimized ( void )
{
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2020-11-23 00:49:27 +01:00
return ( ( CORE . Window . flags & FLAG_WINDOW_MINIMIZED ) > 0 ) ;
2015-07-29 21:44:27 +02:00
# else
return false ;
# endif
}
2020-09-01 19:29:13 +01:00
// Check if window has been maximized (only PLATFORM_DESKTOP)
bool IsWindowMaximized ( void )
{
# if defined(PLATFORM_DESKTOP)
2020-11-23 00:49:27 +01:00
return ( ( CORE . Window . flags & FLAG_WINDOW_MAXIMIZED ) > 0 ) ;
2020-09-01 19:29:13 +01:00
# else
return false ;
# endif
}
2020-04-27 17:41:29 +02:00
// Check if window has the focus
bool IsWindowFocused ( void )
{
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2021-09-23 00:18:47 +02:00
return ( ( CORE . Window . flags & FLAG_WINDOW_UNFOCUSED ) = = 0 ) ;
2020-04-27 17:41:29 +02:00
# else
2020-11-23 00:49:27 +01:00
return true ;
2020-04-27 17:41:29 +02:00
# endif
}
2020-11-23 00:49:27 +01:00
// Check if window has been resizedLastFrame
2019-03-04 22:58:20 +01:00
bool IsWindowResized ( void )
{
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2020-11-23 00:49:27 +01:00
return CORE . Window . resizedLastFrame ;
2019-03-04 22:58:20 +01:00
# else
return false ;
2019-04-04 13:50:52 +02:00
# endif
2019-03-04 22:58:20 +01:00
}
2020-11-23 00:49:27 +01:00
// Check if one specific window flag is enabled
bool IsWindowState ( unsigned int flag )
2019-01-10 17:06:26 +01:00
{
2020-11-23 00:49:27 +01:00
return ( ( CORE . Window . flags & flag ) > 0 ) ;
2020-03-25 18:52:38 +01:00
}
2017-05-09 22:03:46 +02:00
// Toggle fullscreen mode (only PLATFORM_DESKTOP)
2014-09-16 22:51:31 +02:00
void ToggleFullscreen ( void )
{
2020-02-22 10:37:43 +01:00
# if defined(PLATFORM_DESKTOP)
2020-05-14 17:35:26 +02:00
if ( ! CORE . Window . fullscreen )
2019-12-01 13:58:29 +01:00
{
// Store previous window position (in case we exit fullscreen)
2020-02-03 18:31:30 +01:00
glfwGetWindowPos ( CORE . Window . handle , & CORE . Window . position . x , & CORE . Window . position . y ) ;
2019-12-01 14:46:09 +02:00
2021-03-08 09:08:37 -08:00
int monitorCount = 0 ;
int monitorIndex = GetCurrentMonitor ( ) ;
2022-05-05 20:39:14 +02:00
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2021-04-18 23:50:32 +02:00
2021-04-06 13:04:15 +02:00
// Use current monitor, so we correctly get the display the window is on
2022-04-23 23:40:56 +02:00
GLFWmonitor * monitor = ( monitorIndex < monitorCount ) ? monitors [ monitorIndex ] : NULL ;
2021-03-08 09:08:37 -08:00
2022-04-23 23:40:56 +02:00
if ( monitor = = NULL )
2019-12-01 14:46:09 +02:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " GLFW: Failed to get monitor " ) ;
2021-03-19 19:43:44 +01:00
2022-04-23 23:40:56 +02:00
CORE . Window . fullscreen = false ;
2021-03-08 23:51:10 +02:00
CORE . Window . flags & = ~ FLAG_FULLSCREEN_MODE ;
2021-03-19 19:43:44 +01:00
2021-03-08 23:51:10 +02:00
glfwSetWindowMonitor ( CORE . Window . handle , NULL , 0 , 0 , CORE . Window . screen . width , CORE . Window . screen . height , GLFW_DONT_CARE ) ;
2019-12-01 14:46:09 +02:00
}
2022-04-23 23:40:56 +02:00
else
{
CORE . Window . fullscreen = true ;
CORE . Window . flags | = FLAG_FULLSCREEN_MODE ;
2021-03-19 19:43:44 +01:00
2022-04-23 23:40:56 +02:00
glfwSetWindowMonitor ( CORE . Window . handle , monitor , 0 , 0 , CORE . Window . screen . width , CORE . Window . screen . height , GLFW_DONT_CARE ) ;
}
2019-12-01 14:46:09 +02:00
}
2021-02-07 21:55:27 +02:00
else
{
2022-04-23 23:40:56 +02:00
CORE . Window . fullscreen = false ;
2021-03-08 23:51:10 +02:00
CORE . Window . flags & = ~ FLAG_FULLSCREEN_MODE ;
2021-03-19 19:43:44 +01:00
2021-02-07 21:55:27 +02:00
glfwSetWindowMonitor ( CORE . Window . handle , NULL , CORE . Window . position . x , CORE . Window . position . y , CORE . Window . screen . width , CORE . Window . screen . height , GLFW_DONT_CARE ) ;
}
2020-11-23 00:49:27 +01:00
2021-03-22 20:45:04 +01:00
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
2021-03-08 09:08:37 -08:00
// NOTE: V-Sync can be enabled by graphic driver configuration
if ( CORE . Window . flags & FLAG_VSYNC_HINT ) glfwSwapInterval ( 1 ) ;
2016-06-03 00:53:51 +02:00
# endif
2020-02-22 10:37:43 +01:00
# if defined(PLATFORM_WEB)
2021-12-31 17:46:31 +01:00
/*
2021-04-02 13:46:56 +02:00
EM_ASM
(
// This strategy works well while using raylib minimal web shell for emscripten,
// it re-scales the canvas to fullscreen using monitor resolution, for tools this
// is a good strategy but maybe games prefer to keep current canvas resolution and
// display it in fullscreen, adjusting monitor resolution if possible
2020-05-14 17:35:26 +02:00
if ( document . fullscreenElement ) document . exitFullscreen ( ) ;
2021-12-31 17:46:31 +01:00
else Module . requestFullscreen ( true , true ) ; //false, true);
2020-05-14 17:35:26 +02:00
) ;
2021-12-31 17:46:31 +01:00
*/
//EM_ASM(Module.requestFullscreen(false, false););
2021-04-02 13:46:56 +02:00
/*
2020-05-14 17:35:26 +02:00
if ( ! CORE . Window . fullscreen )
{
2021-04-02 13:46:56 +02:00
// Option 1: Request fullscreen for the canvas element
2021-12-31 17:46:31 +01:00
// This option does not seem to work at all:
// emscripten_request_pointerlock() and emscripten_request_fullscreen() are affected by web security,
// the user must click once on the canvas to hide the pointer or transition to full screen
2021-04-02 13:46:56 +02:00
//emscripten_request_fullscreen("#canvas", false);
2021-04-18 23:50:32 +02:00
2021-04-02 13:46:56 +02:00
// Option 2: Request fullscreen for the canvas element with strategy
// This option does not seem to work at all
// Ref: https://github.com/emscripten-core/emscripten/issues/5124
// EmscriptenFullscreenStrategy strategy = {
// .scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH, //EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT,
// .canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF,
// .filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT,
// .canvasResizedCallback = EmscriptenWindowResizedCallback,
// .canvasResizedCallbackUserData = NULL
// };
//emscripten_request_fullscreen_strategy("#canvas", EM_FALSE, &strategy);
2021-04-18 23:50:32 +02:00
// Option 3: Request fullscreen for the canvas element with strategy
2021-04-02 13:46:56 +02:00
// It works as expected but only inside the browser (client area)
2020-05-14 17:35:26 +02:00
EmscriptenFullscreenStrategy strategy = {
2021-04-02 13:46:56 +02:00
. scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT ,
2020-05-14 17:35:26 +02:00
. canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF ,
. filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT ,
2021-04-02 13:46:56 +02:00
. canvasResizedCallback = EmscriptenWindowResizedCallback ,
2020-05-14 17:35:26 +02:00
. canvasResizedCallbackUserData = NULL
} ;
2021-04-02 13:46:56 +02:00
emscripten_enter_soft_fullscreen ( " #canvas " , & strategy ) ;
2020-11-03 23:47:33 +01:00
2021-04-02 13:46:56 +02:00
int width , height ;
emscripten_get_canvas_element_size ( " #canvas " , & width , & height ) ;
TRACELOG ( LOG_WARNING , " Emscripten: Enter fullscreen: Canvas size: %i x %i " , width , height ) ;
2021-12-31 17:46:31 +01:00
CORE . Window . fullscreen = true ; // Toggle fullscreen flag
CORE . Window . flags | = FLAG_FULLSCREEN_MODE ;
2020-05-14 17:35:26 +02:00
}
2020-11-03 23:47:33 +01:00
else
2020-05-14 17:35:26 +02:00
{
2021-04-02 13:46:56 +02:00
//emscripten_exit_fullscreen();
2021-12-31 17:46:31 +01:00
//emscripten_exit_soft_fullscreen();
2021-04-18 23:50:32 +02:00
2021-04-02 13:46:56 +02:00
int width , height ;
emscripten_get_canvas_element_size ( " #canvas " , & width , & height ) ;
2021-04-18 23:50:32 +02:00
TRACELOG ( LOG_WARNING , " Emscripten: Exit fullscreen: Canvas size: %i x %i " , width , height ) ;
2022-02-18 20:30:46 +01:00
2021-12-31 17:46:31 +01:00
CORE . Window . fullscreen = false ; // Toggle fullscreen flag
CORE . Window . flags & = ~ FLAG_FULLSCREEN_MODE ;
2020-05-14 17:35:26 +02:00
}
2021-04-02 13:46:56 +02:00
*/
2020-11-23 00:49:27 +01:00
CORE . Window . fullscreen = ! CORE . Window . fullscreen ; // Toggle fullscreen flag
2020-02-22 10:37:43 +01:00
# endif
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " SYSTEM: Failed to toggle to windowed mode " ) ;
2014-09-16 22:51:31 +02:00
# endif
2020-11-23 00:49:27 +01:00
}
2020-05-14 17:35:26 +02:00
2020-11-23 00:49:27 +01:00
// Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
void MaximizeWindow ( void )
{
# if defined(PLATFORM_DESKTOP)
if ( glfwGetWindowAttrib ( CORE . Window . handle , GLFW_RESIZABLE ) = = GLFW_TRUE )
{
glfwMaximizeWindow ( CORE . Window . handle ) ;
CORE . Window . flags | = FLAG_WINDOW_MAXIMIZED ;
}
# endif
}
// Set window state: minimized (only PLATFORM_DESKTOP)
void MinimizeWindow ( void )
{
# if defined(PLATFORM_DESKTOP)
2020-12-03 20:16:35 +01:00
// NOTE: Following function launches callback that sets appropiate flag!
2020-11-23 00:49:27 +01:00
glfwIconifyWindow ( CORE . Window . handle ) ;
# endif
}
// Set window state: not minimized/maximized (only PLATFORM_DESKTOP)
void RestoreWindow ( void )
{
# if defined(PLATFORM_DESKTOP)
if ( glfwGetWindowAttrib ( CORE . Window . handle , GLFW_RESIZABLE ) = = GLFW_TRUE )
{
// Restores the specified window if it was previously iconified (minimized) or maximized
glfwRestoreWindow ( CORE . Window . handle ) ;
CORE . Window . flags & = ~ FLAG_WINDOW_MINIMIZED ;
CORE . Window . flags & = ~ FLAG_WINDOW_MAXIMIZED ;
}
# endif
}
// Set window configuration state using flags
void SetWindowState ( unsigned int flags )
{
2020-12-23 17:05:07 +01:00
# if defined(PLATFORM_DESKTOP)
2020-11-23 00:49:27 +01:00
// Check previous state and requested state to apply required changes
// NOTE: In most cases the functions already change the flags internally
2020-11-23 23:46:05 +01:00
// State change: FLAG_VSYNC_HINT
if ( ( ( CORE . Window . flags & FLAG_VSYNC_HINT ) ! = ( flags & FLAG_VSYNC_HINT ) ) & & ( ( flags & FLAG_VSYNC_HINT ) > 0 ) )
{
glfwSwapInterval ( 1 ) ;
CORE . Window . flags | = FLAG_VSYNC_HINT ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_FULLSCREEN_MODE
2020-11-23 23:46:05 +01:00
if ( ( CORE . Window . flags & FLAG_FULLSCREEN_MODE ) ! = ( flags & FLAG_FULLSCREEN_MODE ) )
{
ToggleFullscreen ( ) ; // NOTE: Window state flag updated inside function
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_WINDOW_RESIZABLE
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_RESIZABLE ) ! = ( flags & FLAG_WINDOW_RESIZABLE ) ) & & ( ( flags & FLAG_WINDOW_RESIZABLE ) > 0 ) )
2020-11-23 00:49:27 +01:00
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_RESIZABLE , GLFW_TRUE ) ;
CORE . Window . flags | = FLAG_WINDOW_RESIZABLE ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_WINDOW_UNDECORATED
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_UNDECORATED ) ! = ( flags & FLAG_WINDOW_UNDECORATED ) ) & & ( flags & FLAG_WINDOW_UNDECORATED ) )
2020-11-23 00:49:27 +01:00
{
2020-11-23 23:46:05 +01:00
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_DECORATED , GLFW_FALSE ) ;
CORE . Window . flags | = FLAG_WINDOW_UNDECORATED ;
2020-11-23 00:49:27 +01:00
}
// State change: FLAG_WINDOW_HIDDEN
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_HIDDEN ) ! = ( flags & FLAG_WINDOW_HIDDEN ) ) & & ( ( flags & FLAG_WINDOW_HIDDEN ) > 0 ) )
2020-11-23 23:46:05 +01:00
{
glfwHideWindow ( CORE . Window . handle ) ;
CORE . Window . flags | = FLAG_WINDOW_HIDDEN ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_WINDOW_MINIMIZED
2020-11-23 23:46:05 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_MINIMIZED ) ! = ( flags & FLAG_WINDOW_MINIMIZED ) ) & & ( ( flags & FLAG_WINDOW_MINIMIZED ) > 0 ) )
{
2020-12-23 15:03:26 +01:00
//GLFW_ICONIFIED
2020-11-23 23:46:05 +01:00
MinimizeWindow ( ) ; // NOTE: Window state flag updated inside function
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_WINDOW_MAXIMIZED
2020-11-23 23:46:05 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_MAXIMIZED ) ! = ( flags & FLAG_WINDOW_MAXIMIZED ) ) & & ( ( flags & FLAG_WINDOW_MAXIMIZED ) > 0 ) )
{
//GLFW_MAXIMIZED
MaximizeWindow ( ) ; // NOTE: Window state flag updated inside function
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_WINDOW_UNFOCUSED
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_UNFOCUSED ) ! = ( flags & FLAG_WINDOW_UNFOCUSED ) ) & & ( ( flags & FLAG_WINDOW_UNFOCUSED ) > 0 ) )
2020-11-23 00:49:27 +01:00
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_FOCUS_ON_SHOW , GLFW_FALSE ) ;
CORE . Window . flags | = FLAG_WINDOW_UNFOCUSED ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_WINDOW_TOPMOST
if ( ( ( CORE . Window . flags & FLAG_WINDOW_TOPMOST ) ! = ( flags & FLAG_WINDOW_TOPMOST ) ) & & ( ( flags & FLAG_WINDOW_TOPMOST ) > 0 ) )
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_FLOATING , GLFW_TRUE ) ;
CORE . Window . flags | = FLAG_WINDOW_TOPMOST ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_ALWAYS_RUN
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_ALWAYS_RUN ) ! = ( flags & FLAG_WINDOW_ALWAYS_RUN ) ) & & ( ( flags & FLAG_WINDOW_ALWAYS_RUN ) > 0 ) )
2020-11-23 23:46:05 +01:00
{
CORE . Window . flags | = FLAG_WINDOW_ALWAYS_RUN ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// The following states can not be changed after window creation
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_TRANSPARENT
if ( ( ( CORE . Window . flags & FLAG_WINDOW_TRANSPARENT ) ! = ( flags & FLAG_WINDOW_TRANSPARENT ) ) & & ( ( flags & FLAG_WINDOW_TRANSPARENT ) > 0 ) )
{
TRACELOG ( LOG_WARNING , " WINDOW: Framebuffer transparency can only by configured before window initialization " ) ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_WINDOW_HIGHDPI
if ( ( ( CORE . Window . flags & FLAG_WINDOW_HIGHDPI ) ! = ( flags & FLAG_WINDOW_HIGHDPI ) ) & & ( ( flags & FLAG_WINDOW_HIGHDPI ) > 0 ) )
{
2020-11-23 23:46:05 +01:00
TRACELOG ( LOG_WARNING , " WINDOW: High DPI can only by configured before window initialization " ) ;
}
2022-06-11 23:24:13 +02:00
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
if ( ( ( CORE . Window . flags & FLAG_WINDOW_MOUSE_PASSTHROUGH ) ! = ( flags & FLAG_WINDOW_MOUSE_PASSTHROUGH ) ) & & ( ( flags & FLAG_WINDOW_MOUSE_PASSTHROUGH ) > 0 ) )
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_MOUSE_PASSTHROUGH , GLFW_TRUE ) ;
CORE . Window . flags | = FLAG_WINDOW_MOUSE_PASSTHROUGH ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_MSAA_4X_HINT
if ( ( ( CORE . Window . flags & FLAG_MSAA_4X_HINT ) ! = ( flags & FLAG_MSAA_4X_HINT ) ) & & ( ( flags & FLAG_MSAA_4X_HINT ) > 0 ) )
{
TRACELOG ( LOG_WARNING , " WINDOW: MSAA can only by configured before window initialization " ) ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_INTERLACED_HINT
if ( ( ( CORE . Window . flags & FLAG_INTERLACED_HINT ) ! = ( flags & FLAG_INTERLACED_HINT ) ) & & ( ( flags & FLAG_INTERLACED_HINT ) > 0 ) )
{
TRACELOG ( LOG_WARNING , " RPI: Interlaced mode can only by configured before window initialization " ) ;
}
2020-12-23 17:05:07 +01:00
# endif
2020-11-23 23:46:05 +01:00
}
// Clear window configuration state flags
void ClearWindowState ( unsigned int flags )
{
2020-12-23 17:05:07 +01:00
# if defined(PLATFORM_DESKTOP)
2020-11-23 23:46:05 +01:00
// Check previous state and requested state to apply required changes
// NOTE: In most cases the functions already change the flags internally
// State change: FLAG_VSYNC_HINT
if ( ( ( CORE . Window . flags & FLAG_VSYNC_HINT ) > 0 ) & & ( ( flags & FLAG_VSYNC_HINT ) > 0 ) )
{
glfwSwapInterval ( 0 ) ;
2020-12-03 20:33:46 +01:00
CORE . Window . flags & = ~ FLAG_VSYNC_HINT ;
2020-11-23 23:46:05 +01:00
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_FULLSCREEN_MODE
if ( ( ( CORE . Window . flags & FLAG_FULLSCREEN_MODE ) > 0 ) & & ( ( flags & FLAG_FULLSCREEN_MODE ) > 0 ) )
{
ToggleFullscreen ( ) ; // NOTE: Window state flag updated inside function
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_RESIZABLE
if ( ( ( CORE . Window . flags & FLAG_WINDOW_RESIZABLE ) > 0 ) & & ( ( flags & FLAG_WINDOW_RESIZABLE ) > 0 ) )
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_RESIZABLE , GLFW_FALSE ) ;
CORE . Window . flags & = ~ FLAG_WINDOW_RESIZABLE ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_UNDECORATED
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_UNDECORATED ) > 0 ) & & ( ( flags & FLAG_WINDOW_UNDECORATED ) > 0 ) )
2020-11-23 23:46:05 +01:00
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_DECORATED , GLFW_TRUE ) ;
CORE . Window . flags & = ~ FLAG_WINDOW_UNDECORATED ;
2020-11-23 00:49:27 +01:00
}
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_HIDDEN
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_HIDDEN ) > 0 ) & & ( ( flags & FLAG_WINDOW_HIDDEN ) > 0 ) )
2020-11-23 23:46:05 +01:00
{
glfwShowWindow ( CORE . Window . handle ) ;
CORE . Window . flags & = ~ FLAG_WINDOW_HIDDEN ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_MINIMIZED
if ( ( ( CORE . Window . flags & FLAG_WINDOW_MINIMIZED ) > 0 ) & & ( ( flags & FLAG_WINDOW_MINIMIZED ) > 0 ) )
{
RestoreWindow ( ) ; // NOTE: Window state flag updated inside function
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_MAXIMIZED
if ( ( ( CORE . Window . flags & FLAG_WINDOW_MAXIMIZED ) > 0 ) & & ( ( flags & FLAG_WINDOW_MAXIMIZED ) > 0 ) )
{
RestoreWindow ( ) ; // NOTE: Window state flag updated inside function
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_UNFOCUSED
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_UNFOCUSED ) > 0 ) & & ( ( flags & FLAG_WINDOW_UNFOCUSED ) > 0 ) )
2020-11-23 23:46:05 +01:00
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_FOCUS_ON_SHOW , GLFW_TRUE ) ;
CORE . Window . flags & = ~ FLAG_WINDOW_UNFOCUSED ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_TOPMOST
if ( ( ( CORE . Window . flags & FLAG_WINDOW_TOPMOST ) > 0 ) & & ( ( flags & FLAG_WINDOW_TOPMOST ) > 0 ) )
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_FLOATING , GLFW_FALSE ) ;
CORE . Window . flags & = ~ FLAG_WINDOW_TOPMOST ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_WINDOW_ALWAYS_RUN
2020-12-23 15:03:26 +01:00
if ( ( ( CORE . Window . flags & FLAG_WINDOW_ALWAYS_RUN ) > 0 ) & & ( ( flags & FLAG_WINDOW_ALWAYS_RUN ) > 0 ) )
2020-11-23 23:46:05 +01:00
{
CORE . Window . flags & = ~ FLAG_WINDOW_ALWAYS_RUN ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// The following states can not be changed after window creation
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_TRANSPARENT
if ( ( ( CORE . Window . flags & FLAG_WINDOW_TRANSPARENT ) > 0 ) & & ( ( flags & FLAG_WINDOW_TRANSPARENT ) > 0 ) )
2020-11-23 00:49:27 +01:00
{
2020-11-23 23:46:05 +01:00
TRACELOG ( LOG_WARNING , " WINDOW: Framebuffer transparency can only by configured before window initialization " ) ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
// State change: FLAG_WINDOW_HIGHDPI
if ( ( ( CORE . Window . flags & FLAG_WINDOW_HIGHDPI ) > 0 ) & & ( ( flags & FLAG_WINDOW_HIGHDPI ) > 0 ) )
{
TRACELOG ( LOG_WARNING , " WINDOW: High DPI can only by configured before window initialization " ) ;
2020-11-23 00:49:27 +01:00
}
2022-06-11 23:24:13 +02:00
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
if ( ( ( CORE . Window . flags & FLAG_WINDOW_MOUSE_PASSTHROUGH ) > 0 ) & & ( ( flags & FLAG_WINDOW_MOUSE_PASSTHROUGH ) > 0 ) )
{
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_MOUSE_PASSTHROUGH , GLFW_FALSE ) ;
CORE . Window . flags & = ~ FLAG_WINDOW_MOUSE_PASSTHROUGH ;
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_MSAA_4X_HINT
2020-11-23 23:46:05 +01:00
if ( ( ( CORE . Window . flags & FLAG_MSAA_4X_HINT ) > 0 ) & & ( ( flags & FLAG_MSAA_4X_HINT ) > 0 ) )
2020-11-23 00:49:27 +01:00
{
2020-11-23 23:46:05 +01:00
TRACELOG ( LOG_WARNING , " WINDOW: MSAA can only by configured before window initialization " ) ;
2020-11-23 00:49:27 +01:00
}
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
// State change: FLAG_INTERLACED_HINT
2020-11-23 23:46:05 +01:00
if ( ( ( CORE . Window . flags & FLAG_INTERLACED_HINT ) > 0 ) & & ( ( flags & FLAG_INTERLACED_HINT ) > 0 ) )
2020-11-23 00:49:27 +01:00
{
2020-11-23 23:46:05 +01:00
TRACELOG ( LOG_WARNING , " RPI: Interlaced mode can only by configured before window initialization " ) ;
2020-11-23 00:49:27 +01:00
}
2020-12-23 17:05:07 +01:00
# endif
2014-09-16 22:51:31 +02:00
}
2017-02-05 03:00:35 +01:00
// Set icon for window (only PLATFORM_DESKTOP)
2019-03-16 13:00:46 +01:00
// NOTE: Image must be in RGBA format, 8bit per channel
2017-02-05 03:00:35 +01:00
void SetWindowIcon ( Image image )
{
# if defined(PLATFORM_DESKTOP)
2021-03-14 11:05:51 +01:00
if ( image . format = = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 )
2019-03-16 13:00:46 +01:00
{
GLFWimage icon [ 1 ] = { 0 } ;
2017-02-05 03:00:35 +01:00
2019-03-16 13:00:46 +01:00
icon [ 0 ] . width = image . width ;
icon [ 0 ] . height = image . height ;
icon [ 0 ] . pixels = ( unsigned char * ) image . data ;
2017-02-05 03:00:35 +01:00
2019-03-16 13:00:46 +01:00
// NOTE 1: We only support one image icon
// NOTE 2: The specified image data is copied before this function returns
2020-02-03 18:31:30 +01:00
glfwSetWindowIcon ( CORE . Window . handle , 1 , icon ) ;
2019-03-16 13:00:46 +01:00
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Window icon image must be in R8G8B8A8 pixel format " ) ;
2017-02-05 03:00:35 +01:00
# endif
}
2017-09-08 09:35:54 +02:00
// Set title for window (only PLATFORM_DESKTOP)
void SetWindowTitle ( const char * title )
{
2020-02-03 18:31:30 +01:00
CORE . Window . title = title ;
2017-09-08 09:35:54 +02:00
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwSetWindowTitle ( CORE . Window . handle , title ) ;
2017-09-08 09:35:54 +02:00
# endif
}
2017-03-05 10:55:29 +01:00
// Set window position on screen (windowed mode)
void SetWindowPosition ( int x , int y )
{
2017-03-09 13:13:13 +01:00
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwSetWindowPos ( CORE . Window . handle , x , y ) ;
2017-03-09 13:13:13 +01:00
# endif
2017-03-05 10:55:29 +01:00
}
// Set monitor for the current window (fullscreen mode)
void SetWindowMonitor ( int monitor )
{
2017-03-09 13:13:13 +01:00
# if defined(PLATFORM_DESKTOP)
2020-03-27 18:06:09 +01:00
int monitorCount = 0 ;
2018-10-22 11:48:16 +02:00
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2018-11-06 15:10:50 +01:00
if ( ( monitor > = 0 ) & & ( monitor < monitorCount ) )
2017-03-05 10:55:29 +01:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " GLFW: Selected fullscreen monitor: [%i] %s " , monitor , glfwGetMonitorName ( monitors [ monitor ] ) ) ;
2019-12-10 00:18:29 +01:00
const GLFWvidmode * mode = glfwGetVideoMode ( monitors [ monitor ] ) ;
2020-02-03 18:31:30 +01:00
glfwSetWindowMonitor ( CORE . Window . handle , monitors [ monitor ] , 0 , 0 , mode - > width , mode - > height , mode - > refreshRate ) ;
2017-03-05 10:55:29 +01:00
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find selected monitor " ) ;
2017-03-09 13:13:13 +01:00
# endif
2017-03-05 10:55:29 +01:00
}
2017-05-09 22:03:46 +02:00
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
2017-05-02 15:04:32 +02:00
void SetWindowMinSize ( int width , int height )
{
# if defined(PLATFORM_DESKTOP)
const GLFWvidmode * mode = glfwGetVideoMode ( glfwGetPrimaryMonitor ( ) ) ;
2020-02-03 18:31:30 +01:00
glfwSetWindowSizeLimits ( CORE . Window . handle , width , height , mode - > width , mode - > height ) ;
2017-05-02 15:04:32 +02:00
# endif
}
2018-03-09 11:43:53 +01:00
// Set window dimensions
void SetWindowSize ( int width , int height )
{
2021-06-23 01:02:18 -07:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2020-02-03 18:31:30 +01:00
glfwSetWindowSize ( CORE . Window . handle , width , height ) ;
2018-03-09 11:43:53 +01:00
# endif
}
2021-12-30 17:43:50 +05:30
// Set window opacity, value opacity is between 0.0 and 1.0
void SetWindowOpacity ( float opacity )
{
# if defined(PLATFORM_DESKTOP)
if ( opacity > = 1.0f ) opacity = 1.0f ;
else if ( opacity < = 0.0f ) opacity = 0.0f ;
glfwSetWindowOpacity ( CORE . Window . handle , opacity ) ;
# endif
}
2014-09-16 22:51:31 +02:00
// Get current screen width
int GetScreenWidth ( void )
2013-11-18 23:38:44 +01:00
{
2021-10-10 22:34:56 +02:00
return CORE . Window . screen . width ;
2013-11-18 23:38:44 +01:00
}
2014-09-16 22:51:31 +02:00
// Get current screen height
int GetScreenHeight ( void )
2013-11-18 23:38:44 +01:00
{
2021-10-10 22:34:56 +02:00
return CORE . Window . screen . height ;
}
// Get current render width which is equal to screen width * dpi scale
int GetRenderWidth ( void )
{
return CORE . Window . render . width ;
}
// Get current screen height which is equal to screen height * dpi scale
int GetRenderHeight ( void )
{
return CORE . Window . render . height ;
2013-11-18 23:38:44 +01:00
}
2018-10-08 12:29:02 +02:00
// Get native window handle
void * GetWindowHandle ( void )
{
UWP Support Overhaul (#819)
* Working build
* Fix build again, stop deleting files
* Hotfix crash, needs investigating
* Remove VS2015.UWP, I cannot update the project
* Lots of UWP work, added keyboard and mouse press support. Still need to finish scroll wheel, mouse position and cursor hiding, plus other stuff that I haven't seen yet.
* Implemented a ton more things, added BaseApp.h to provide common code to UWP apps.
* Remove constant window dimensions
* Enable and Disable cursor support.
* Actually use mouse delta
* Gamepad Support
* Cleaning and small tweaks
* Restore original example.
* Update comment
* Use 'Messages' to handle the cursor functions so code is more portable.
* Comment
* Comment unused message fields and use vector for mouse pos instead.
* Move messages to utils.h and use messages for everything. No more plat-specific code in raylib.h
* Working build
* Fix build again, stop deleting files
* Hotfix crash, needs investigating
* Remove VS2015.UWP, I cannot update the project
* Lots of UWP work, added keyboard and mouse press support. Still need to finish scroll wheel, mouse position and cursor hiding, plus other stuff that I haven't seen yet.
* Implemented a ton more things, added BaseApp.h to provide common code to UWP apps.
* Remove constant window dimensions
* Enable and Disable cursor support.
* Actually use mouse delta
* Gamepad Support
* Cleaning and small tweaks
* Restore original example.
* Update comment
* Use 'Messages' to handle the cursor functions so code is more portable.
* Comment
* Comment unused message fields and use vector for mouse pos instead.
* Move messages to utils.h and use messages for everything. No more plat-specific code in raylib.h
* Tested some desktop stuff and added projection matrix updates for window resizing.
* Fixed big bad mouse bug
* Fix alt buttons and add hack to combat flickery key presses (far from perfect)
* Remove debug code
* Final commit
* Well, so I thought
* Wow, i am bad
* Remove packages folder
* Remove useless include
* Apply requested changes and fix linux build
* Try to stop packages folder
* Have we fixed the formatting properly?
* Third time's the charm?
* Where did this come from?
* Re-fix
* Autoformat is gonna kill
* Fixed XBOX ONE Support
* Fix tabs
2019-04-27 19:33:51 +01:00
# if defined(PLATFORM_DESKTOP) && defined(_WIN32)
2018-10-08 12:29:02 +02:00
// NOTE: Returned handle is: void *HWND (windows.h)
2020-02-03 18:31:30 +01:00
return glfwGetWin32Window ( CORE . Window . handle ) ;
2021-03-02 12:45:23 +01:00
# endif
# if defined(__linux__)
2018-10-08 12:29:02 +02:00
// NOTE: Returned handle is: unsigned long Window (X.h)
// typedef unsigned long XID;
// typedef XID Window;
2018-10-08 13:14:15 +02:00
//unsigned long id = (unsigned long)glfwGetX11Window(window);
2018-10-08 12:29:02 +02:00
return NULL ; // TODO: Find a way to return value... cast to void *?
2021-03-02 12:45:23 +01:00
# endif
# if defined(__APPLE__)
2018-10-08 18:08:39 +02:00
// NOTE: Returned handle is: (objc_object *)
2018-10-08 18:51:41 +02:00
return NULL ; // TODO: return (void *)glfwGetCocoaWindow(window);
2018-10-08 12:29:02 +02:00
# endif
2021-03-02 12:45:23 +01:00
return NULL ;
2018-10-08 12:29:02 +02:00
}
2018-09-27 15:52:56 +01:00
// Get number of monitors
int GetMonitorCount ( void )
{
2018-09-29 14:10:29 +01:00
# if defined(PLATFORM_DESKTOP)
2018-09-27 16:23:11 +01:00
int monitorCount ;
glfwGetMonitors ( & monitorCount ) ;
return monitorCount ;
2018-09-29 14:28:07 +01:00
# else
2018-09-29 14:10:29 +01:00
return 1 ;
2018-09-29 14:28:07 +01:00
# endif
2018-09-27 15:52:56 +01:00
}
2020-12-29 14:37:08 +02:00
// Get number of monitors
int GetCurrentMonitor ( void )
{
# if defined(PLATFORM_DESKTOP)
2020-12-29 15:08:56 -08:00
int monitorCount ;
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2020-12-30 08:29:39 -08:00
GLFWmonitor * monitor = NULL ;
2020-12-29 15:08:56 -08:00
2020-12-30 08:29:39 -08:00
if ( monitorCount = = 1 ) // easy out
return 0 ;
if ( IsWindowFullscreen ( ) )
{
monitor = glfwGetWindowMonitor ( CORE . Window . handle ) ;
for ( int i = 0 ; i < monitorCount ; i + + )
{
if ( monitors [ i ] = = monitor )
return i ;
}
return 0 ;
}
else
2020-12-29 15:08:56 -08:00
{
2020-12-30 08:29:39 -08:00
int x = 0 ;
int y = 0 ;
glfwGetWindowPos ( CORE . Window . handle , & x , & y ) ;
2021-03-19 19:43:44 +01:00
2020-12-30 08:29:39 -08:00
for ( int i = 0 ; i < monitorCount ; i + + )
{
int mx = 0 ;
int my = 0 ;
int width = 0 ;
int height = 0 ;
monitor = monitors [ i ] ;
glfwGetMonitorWorkarea ( monitor , & mx , & my , & width , & height ) ;
if ( x > = mx & & x < = ( mx + width ) & & y > = my & & y < = ( my + height ) )
return i ;
}
2020-12-29 15:08:56 -08:00
}
return 0 ;
2020-12-29 14:37:08 +02:00
# else
return 0 ;
# endif
}
2022-06-09 21:00:04 +02:00
// Get selected monitor position
2020-12-05 12:51:20 -08:00
Vector2 GetMonitorPosition ( int monitor )
{
# if defined(PLATFORM_DESKTOP)
2020-12-18 18:58:02 +01:00
int monitorCount ;
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2020-12-05 12:51:20 -08:00
2020-12-18 18:58:02 +01:00
if ( ( monitor > = 0 ) & & ( monitor < monitorCount ) )
{
2020-12-05 12:51:20 -08:00
int x , y ;
glfwGetMonitorPos ( monitors [ monitor ] , & x , & y ) ;
2020-12-23 15:03:26 +01:00
2020-12-18 18:58:02 +01:00
return ( Vector2 ) { ( float ) x , ( float ) y } ;
}
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find selected monitor " ) ;
2020-12-05 12:51:20 -08:00
# endif
return ( Vector2 ) { 0 , 0 } ;
}
2022-06-09 21:00:04 +02:00
// Get selected monitor width (currently used by monitor)
2018-09-30 15:20:02 +01:00
int GetMonitorWidth ( int monitor )
2018-11-06 15:10:50 +01:00
{
2018-09-29 14:10:29 +01:00
# if defined(PLATFORM_DESKTOP)
2018-09-30 15:20:02 +01:00
int monitorCount ;
2018-10-22 11:48:16 +02:00
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2018-11-06 15:10:50 +01:00
if ( ( monitor > = 0 ) & & ( monitor < monitorCount ) )
2018-09-30 15:20:02 +01:00
{
2022-06-09 21:00:04 +02:00
const GLFWvidmode * mode = glfwGetVideoMode ( monitors [ monitor ] ) ;
2022-06-09 21:01:51 +02:00
if ( mode ) return mode - > width ;
2021-02-07 20:47:40 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find video mode for selected monitor " ) ;
2018-09-30 15:20:02 +01:00
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find selected monitor " ) ;
2018-09-29 14:28:07 +01:00
# endif
2018-09-30 15:20:02 +01:00
return 0 ;
2018-09-27 15:52:56 +01:00
}
2022-06-09 21:00:04 +02:00
// Get selected monitor height (currently used by monitor)
2018-09-30 15:20:02 +01:00
int GetMonitorHeight ( int monitor )
2018-11-06 15:10:50 +01:00
{
2018-09-29 14:10:29 +01:00
# if defined(PLATFORM_DESKTOP)
2018-09-30 15:20:02 +01:00
int monitorCount ;
2018-10-22 11:48:16 +02:00
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2018-11-06 15:10:50 +01:00
if ( ( monitor > = 0 ) & & ( monitor < monitorCount ) )
2018-09-30 15:20:02 +01:00
{
2022-06-09 21:00:04 +02:00
const GLFWvidmode * mode = glfwGetVideoMode ( monitors [ monitor ] ) ;
2022-06-09 21:01:51 +02:00
if ( mode ) return mode - > height ;
2021-02-07 20:47:40 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find video mode for selected monitor " ) ;
2018-09-30 15:20:02 +01:00
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find selected monitor " ) ;
2018-09-29 14:28:07 +01:00
# endif
2018-09-30 15:20:02 +01:00
return 0 ;
2018-09-27 15:52:56 +01:00
}
2020-12-05 12:51:20 -08:00
// Get selected monitor physical width in millimetres
2018-09-30 15:20:02 +01:00
int GetMonitorPhysicalWidth ( int monitor )
2018-09-27 15:52:56 +01:00
{
2018-09-29 14:10:29 +01:00
# if defined(PLATFORM_DESKTOP)
2018-09-30 15:20:02 +01:00
int monitorCount ;
2018-10-22 11:48:16 +02:00
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2018-11-06 15:10:50 +01:00
if ( ( monitor > = 0 ) & & ( monitor < monitorCount ) )
2018-09-30 15:20:02 +01:00
{
int physicalWidth ;
glfwGetMonitorPhysicalSize ( monitors [ monitor ] , & physicalWidth , NULL ) ;
return physicalWidth ;
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find selected monitor " ) ;
2018-09-29 14:28:07 +01:00
# endif
2018-09-30 15:20:02 +01:00
return 0 ;
2018-09-27 15:52:56 +01:00
}
// Get primary monitor physical height in millimetres
2018-09-30 15:20:02 +01:00
int GetMonitorPhysicalHeight ( int monitor )
2018-09-27 15:52:56 +01:00
{
2018-09-30 15:20:02 +01:00
# if defined(PLATFORM_DESKTOP)
int monitorCount ;
2018-10-22 11:48:16 +02:00
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2018-11-06 15:10:50 +01:00
if ( ( monitor > = 0 ) & & ( monitor < monitorCount ) )
2018-09-30 15:20:02 +01:00
{
int physicalHeight ;
glfwGetMonitorPhysicalSize ( monitors [ monitor ] , NULL , & physicalHeight ) ;
return physicalHeight ;
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find selected monitor " ) ;
2018-09-29 14:28:07 +01:00
# endif
2018-09-30 15:20:02 +01:00
return 0 ;
2018-09-27 15:52:56 +01:00
}
2020-06-24 12:28:57 -04:00
int GetMonitorRefreshRate ( int monitor )
{
# if defined(PLATFORM_DESKTOP)
int monitorCount ;
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
if ( ( monitor > = 0 ) & & ( monitor < monitorCount ) )
{
const GLFWvidmode * vidmode = glfwGetVideoMode ( monitors [ monitor ] ) ;
return vidmode - > refreshRate ;
}
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find selected monitor " ) ;
2020-09-27 10:18:43 +02:00
# endif
# if defined(PLATFORM_DRM)
if ( ( CORE . Window . connector ) & & ( CORE . Window . modeIndex > = 0 ) )
{
return CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . vrefresh ;
}
2020-06-24 12:28:57 -04:00
# endif
return 0 ;
}
2019-09-10 12:43:44 +02:00
// Get window position XY on monitor
Vector2 GetWindowPosition ( void )
{
int x = 0 ;
int y = 0 ;
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwGetWindowPos ( CORE . Window . handle , & x , & y ) ;
2019-09-10 12:43:44 +02:00
# endif
return ( Vector2 ) { ( float ) x , ( float ) y } ;
}
2020-04-24 23:17:32 +02:00
// Get window scale DPI factor
Vector2 GetWindowScaleDPI ( void )
{
Vector2 scale = { 1.0f , 1.0f } ;
2020-11-03 23:47:33 +01:00
2020-04-24 23:17:32 +02:00
# if defined(PLATFORM_DESKTOP)
2020-10-29 19:29:59 +01:00
float xdpi = 1.0 ;
float ydpi = 1.0 ;
Vector2 windowPos = GetWindowPosition ( ) ;
2020-11-03 23:47:33 +01:00
2020-10-29 19:29:59 +01:00
int monitorCount = 0 ;
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2020-04-24 23:17:32 +02:00
2020-10-29 19:29:59 +01:00
// Check window monitor
for ( int i = 0 ; i < monitorCount ; i + + )
{
glfwGetMonitorContentScale ( monitors [ i ] , & xdpi , & ydpi ) ;
2020-11-03 23:47:33 +01:00
2020-10-29 19:29:59 +01:00
int xpos , ypos , width , height ;
glfwGetMonitorWorkarea ( monitors [ i ] , & xpos , & ypos , & width , & height ) ;
2020-11-03 23:47:33 +01:00
if ( ( windowPos . x > = xpos ) & & ( windowPos . x < xpos + width ) & &
( windowPos . y > = ypos ) & & ( windowPos . y < ypos + height ) )
2020-10-29 19:29:59 +01:00
{
scale . x = xdpi ;
scale . y = ydpi ;
break ;
}
}
2020-04-24 23:17:32 +02:00
# endif
return scale ;
}
2018-09-27 15:52:56 +01:00
// Get the human-readable, UTF-8 encoded name of the primary monitor
2018-09-30 15:20:02 +01:00
const char * GetMonitorName ( int monitor )
2018-09-27 15:52:56 +01:00
{
2018-11-06 15:10:50 +01:00
# if defined(PLATFORM_DESKTOP)
2018-09-30 15:20:02 +01:00
int monitorCount ;
2018-10-22 11:48:16 +02:00
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2018-11-06 15:10:50 +01:00
if ( ( monitor > = 0 ) & & ( monitor < monitorCount ) )
2018-09-30 15:20:02 +01:00
{
return glfwGetMonitorName ( monitors [ monitor ] ) ;
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " GLFW: Failed to find selected monitor " ) ;
2018-09-29 14:28:07 +01:00
# endif
2018-09-30 15:20:02 +01:00
return " " ;
2018-09-27 15:52:56 +01:00
}
2022-05-12 16:51:46 +02:00
// Set clipboard text content
void SetClipboardText ( const char * text )
2019-02-11 18:03:06 +01:00
{
# if defined(PLATFORM_DESKTOP)
2022-05-12 16:51:46 +02:00
glfwSetClipboardString ( CORE . Window . handle , text ) ;
2019-02-11 18:03:06 +01:00
# endif
2022-02-20 22:07:52 +01:00
# if defined(PLATFORM_WEB)
2022-05-12 16:51:46 +02:00
emscripten_run_script ( TextFormat ( " navigator.clipboard.writeText('%s') " , text ) ) ;
2022-02-20 22:07:52 +01:00
# endif
2019-02-11 18:03:06 +01:00
}
2022-05-12 16:51:46 +02:00
// Enable waiting for events on EndDrawing(), no automatic event polling
void EnableEventWaiting ( void )
{
CORE . Window . eventWaiting = true ;
}
// Disable waiting for events on EndDrawing(), automatic events polling
RLAPI void DisableEventWaiting ( void )
{
CORE . Window . eventWaiting = false ;
}
// Get clipboard text content
// NOTE: returned string is allocated and freed by GLFW
const char * GetClipboardText ( void )
2019-02-11 18:03:06 +01:00
{
# if defined(PLATFORM_DESKTOP)
2022-05-12 16:51:46 +02:00
return glfwGetClipboardString ( CORE . Window . handle ) ;
2019-02-11 18:03:06 +01:00
# endif
2022-02-20 22:07:52 +01:00
# if defined(PLATFORM_WEB)
2022-05-12 16:51:46 +02:00
return emscripten_run_script_string ( " navigator.clipboard.readText() " ) ;
2022-02-20 22:07:52 +01:00
# endif
2022-05-12 16:51:46 +02:00
return NULL ;
2019-02-11 18:03:06 +01:00
}
2022-05-12 16:51:46 +02:00
2016-10-17 18:18:13 +02:00
// Show mouse cursor
2019-01-14 13:49:56 +01:00
void ShowCursor ( void )
2016-10-17 18:18:13 +02:00
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwSetInputMode ( CORE . Window . handle , GLFW_CURSOR , GLFW_CURSOR_NORMAL ) ;
UWP Support Overhaul (#819)
* Working build
* Fix build again, stop deleting files
* Hotfix crash, needs investigating
* Remove VS2015.UWP, I cannot update the project
* Lots of UWP work, added keyboard and mouse press support. Still need to finish scroll wheel, mouse position and cursor hiding, plus other stuff that I haven't seen yet.
* Implemented a ton more things, added BaseApp.h to provide common code to UWP apps.
* Remove constant window dimensions
* Enable and Disable cursor support.
* Actually use mouse delta
* Gamepad Support
* Cleaning and small tweaks
* Restore original example.
* Update comment
* Use 'Messages' to handle the cursor functions so code is more portable.
* Comment
* Comment unused message fields and use vector for mouse pos instead.
* Move messages to utils.h and use messages for everything. No more plat-specific code in raylib.h
* Working build
* Fix build again, stop deleting files
* Hotfix crash, needs investigating
* Remove VS2015.UWP, I cannot update the project
* Lots of UWP work, added keyboard and mouse press support. Still need to finish scroll wheel, mouse position and cursor hiding, plus other stuff that I haven't seen yet.
* Implemented a ton more things, added BaseApp.h to provide common code to UWP apps.
* Remove constant window dimensions
* Enable and Disable cursor support.
* Actually use mouse delta
* Gamepad Support
* Cleaning and small tweaks
* Restore original example.
* Update comment
* Use 'Messages' to handle the cursor functions so code is more portable.
* Comment
* Comment unused message fields and use vector for mouse pos instead.
* Move messages to utils.h and use messages for everything. No more plat-specific code in raylib.h
* Tested some desktop stuff and added projection matrix updates for window resizing.
* Fixed big bad mouse bug
* Fix alt buttons and add hack to combat flickery key presses (far from perfect)
* Remove debug code
* Final commit
* Well, so I thought
* Wow, i am bad
* Remove packages folder
* Remove useless include
* Apply requested changes and fix linux build
* Try to stop packages folder
* Have we fixed the formatting properly?
* Third time's the charm?
* Where did this come from?
* Re-fix
* Autoformat is gonna kill
* Fixed XBOX ONE Support
* Fix tabs
2019-04-27 19:33:51 +01:00
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . cursorHidden = false ;
2016-10-17 18:18:13 +02:00
}
2017-05-09 22:03:46 +02:00
// Hides mouse cursor
2019-01-14 13:49:56 +01:00
void HideCursor ( void )
2016-10-17 18:18:13 +02:00
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwSetInputMode ( CORE . Window . handle , GLFW_CURSOR , GLFW_CURSOR_HIDDEN ) ;
UWP Support Overhaul (#819)
* Working build
* Fix build again, stop deleting files
* Hotfix crash, needs investigating
* Remove VS2015.UWP, I cannot update the project
* Lots of UWP work, added keyboard and mouse press support. Still need to finish scroll wheel, mouse position and cursor hiding, plus other stuff that I haven't seen yet.
* Implemented a ton more things, added BaseApp.h to provide common code to UWP apps.
* Remove constant window dimensions
* Enable and Disable cursor support.
* Actually use mouse delta
* Gamepad Support
* Cleaning and small tweaks
* Restore original example.
* Update comment
* Use 'Messages' to handle the cursor functions so code is more portable.
* Comment
* Comment unused message fields and use vector for mouse pos instead.
* Move messages to utils.h and use messages for everything. No more plat-specific code in raylib.h
* Working build
* Fix build again, stop deleting files
* Hotfix crash, needs investigating
* Remove VS2015.UWP, I cannot update the project
* Lots of UWP work, added keyboard and mouse press support. Still need to finish scroll wheel, mouse position and cursor hiding, plus other stuff that I haven't seen yet.
* Implemented a ton more things, added BaseApp.h to provide common code to UWP apps.
* Remove constant window dimensions
* Enable and Disable cursor support.
* Actually use mouse delta
* Gamepad Support
* Cleaning and small tweaks
* Restore original example.
* Update comment
* Use 'Messages' to handle the cursor functions so code is more portable.
* Comment
* Comment unused message fields and use vector for mouse pos instead.
* Move messages to utils.h and use messages for everything. No more plat-specific code in raylib.h
* Tested some desktop stuff and added projection matrix updates for window resizing.
* Fixed big bad mouse bug
* Fix alt buttons and add hack to combat flickery key presses (far from perfect)
* Remove debug code
* Final commit
* Well, so I thought
* Wow, i am bad
* Remove packages folder
* Remove useless include
* Apply requested changes and fix linux build
* Try to stop packages folder
* Have we fixed the formatting properly?
* Third time's the charm?
* Where did this come from?
* Re-fix
* Autoformat is gonna kill
* Fixed XBOX ONE Support
* Fix tabs
2019-04-27 19:33:51 +01:00
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . cursorHidden = true ;
2016-10-17 18:18:13 +02:00
}
2017-05-09 22:03:46 +02:00
// Check if cursor is not visible
2019-01-14 13:49:56 +01:00
bool IsCursorHidden ( void )
2016-10-17 18:18:13 +02:00
{
2020-02-03 18:31:30 +01:00
return CORE . Input . Mouse . cursorHidden ;
2016-10-17 18:18:13 +02:00
}
2017-05-09 22:03:46 +02:00
// Enables cursor (unlock cursor)
2019-01-14 13:49:56 +01:00
void EnableCursor ( void )
2016-10-17 18:18:13 +02:00
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwSetInputMode ( CORE . Window . handle , GLFW_CURSOR , GLFW_CURSOR_NORMAL ) ;
2017-05-08 21:03:48 +02:00
# endif
2021-01-22 11:57:57 +01:00
# if defined(PLATFORM_WEB)
emscripten_exit_pointerlock ( ) ;
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . cursorHidden = false ;
2016-10-17 18:18:13 +02:00
}
2017-05-09 22:03:46 +02:00
// Disables cursor (lock cursor)
2019-01-14 13:49:56 +01:00
void DisableCursor ( void )
2016-10-17 18:18:13 +02:00
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwSetInputMode ( CORE . Window . handle , GLFW_CURSOR , GLFW_CURSOR_DISABLED ) ;
2017-05-08 21:03:48 +02:00
# endif
2021-01-22 11:57:57 +01:00
# if defined(PLATFORM_WEB)
emscripten_request_pointerlock ( " #canvas " , 1 ) ;
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . cursorHidden = true ;
2016-10-17 18:18:13 +02:00
}
2020-05-26 10:59:25 +01:00
// Check if cursor is on the current screen.
bool IsCursorOnScreen ( void )
{
return CORE . Input . Mouse . cursorOnScreen ;
}
2017-05-09 22:03:46 +02:00
// Set background color (framebuffer clear color)
2013-11-18 23:38:44 +01:00
void ClearBackground ( Color color )
{
2018-01-06 02:43:38 +01:00
rlClearColor ( color . r , color . g , color . b , color . a ) ; // Set clear color
rlClearScreenBuffers ( ) ; // Clear current framebuffers
2013-11-18 23:38:44 +01:00
}
2017-05-09 22:03:46 +02:00
// Setup canvas (framebuffer) to start drawing
2014-09-03 17:06:10 +02:00
void BeginDrawing ( void )
2013-11-18 23:38:44 +01:00
{
2021-06-23 01:25:09 +02:00
// WARNING: Previously to BeginDrawing() other render textures drawing could happen,
// consequently the measure for update vs draw is not accurate (only the total frame time is accurate)
2021-06-30 16:39:07 +02:00
2021-06-23 01:25:09 +02:00
CORE . Time . current = GetTime ( ) ; // Number of elapsed seconds since InitTimer()
2020-02-03 18:31:30 +01:00
CORE . Time . update = CORE . Time . current - CORE . Time . previous ;
CORE . Time . previous = CORE . Time . current ;
2016-08-16 11:09:55 +02:00
2020-04-05 17:50:37 +02:00
rlLoadIdentity ( ) ; // Reset current matrix (modelview)
2020-02-03 18:31:30 +01:00
rlMultMatrixf ( MatrixToFloat ( CORE . Window . screenScale ) ) ; // Apply screen scaling
2014-09-16 22:51:31 +02:00
2015-02-02 00:57:08 +01:00
//rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL 1.1
2014-03-25 12:40:35 +01:00
// NOTE: Not required with OpenGL 3.3+
2013-11-18 23:38:44 +01:00
}
2017-05-09 22:03:46 +02:00
// End canvas drawing and swap buffers (double buffering)
2014-09-03 17:06:10 +02:00
void EndDrawing ( void )
2013-11-18 23:38:44 +01:00
{
2021-06-17 11:17:39 +02:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2021-06-22 20:14:44 +02:00
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RSHAPES) && defined(SUPPORT_MOUSE_CURSOR_POINT)
2021-06-17 11:17:39 +02:00
// Draw a small rectangle on mouse position for user reference
2020-09-27 10:18:43 +02:00
if ( ! CORE . Input . Mouse . cursorHidden )
{
2021-12-04 19:56:02 +01:00
DrawRectangle ( CORE . Input . Mouse . currentPosition . x , CORE . Input . Mouse . currentPosition . y , 3 , 3 , MAROON ) ; // WARNING: Module required: rshapes
2021-06-17 11:17:39 +02:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2020-09-27 10:18:43 +02:00
}
2019-08-20 20:39:22 +02:00
# endif
2019-10-17 17:18:03 +02:00
2017-05-18 18:57:11 +02:00
# if defined(SUPPORT_GIF_RECORDING)
2021-06-17 11:17:39 +02:00
// Draw record indicator
2017-05-18 18:57:11 +02:00
if ( gifRecording )
{
2021-06-17 11:17:39 +02:00
# define GIF_RECORD_FRAMERATE 10
2021-09-01 23:09:30 +02:00
gifFrameCounter + + ;
2018-11-06 15:10:50 +01:00
2017-05-18 18:57:11 +02:00
// NOTE: We record one gif frame every 10 game frames
2021-09-01 23:09:30 +02:00
if ( ( gifFrameCounter % GIF_RECORD_FRAMERATE ) = = 0 )
2017-05-18 18:57:11 +02:00
{
// Get image data for the current frame (from backbuffer)
2020-11-20 00:34:18 +01:00
// NOTE: This process is quite slow... :(
2022-05-20 17:25:47 +02:00
Vector2 scale = GetWindowScaleDPI ( ) ;
2022-06-07 10:04:24 +02:00
unsigned char * screenData = rlReadScreenPixels ( ( int ) ( ( float ) CORE . Window . render . width * scale . x ) , ( int ) ( ( float ) CORE . Window . render . height * scale . y ) ) ;
msf_gif_frame ( & gifState , screenData , 10 , 16 , ( int ) ( ( float ) CORE . Window . render . width * scale . x ) * 4 ) ;
2018-11-06 15:10:50 +01:00
2021-03-21 01:29:31 +01:00
RL_FREE ( screenData ) ; // Free image data
2017-05-18 18:57:11 +02:00
}
2018-11-06 15:10:50 +01:00
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RSHAPES) && defined(SUPPORT_MODULE_RTEXT)
2021-09-01 23:09:30 +02:00
if ( ( ( gifFrameCounter / 15 ) % 2 ) = = 1 )
2017-05-18 18:57:11 +02:00
{
2021-12-04 19:56:02 +01:00
DrawCircle ( 30 , CORE . Window . screen . height - 20 , 10 , MAROON ) ; // WARNING: Module required: rshapes
DrawText ( " GIF RECORDING " , 50 , CORE . Window . screen . height - 25 , 10 , RED ) ; // WARNING: Module required: rtext
2021-06-11 12:27:46 +02:00
}
2021-12-04 19:56:02 +01:00
# endif
2021-06-11 12:27:46 +02:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
}
# endif
# if defined(SUPPORT_EVENTS_AUTOMATION)
2021-06-17 11:17:39 +02:00
// Draw record/play indicator
2021-06-11 12:27:46 +02:00
if ( eventsRecording )
{
2021-09-01 23:09:30 +02:00
gifFrameCounter + + ;
2021-06-11 12:27:46 +02:00
2021-09-01 23:09:30 +02:00
if ( ( ( gifFrameCounter / 15 ) % 2 ) = = 1 )
2021-06-11 12:27:46 +02:00
{
DrawCircle ( 30 , CORE . Window . screen . height - 20 , 10 , MAROON ) ;
DrawText ( " EVENTS RECORDING " , 50 , CORE . Window . screen . height - 25 , 10 , RED ) ;
}
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
}
else if ( eventsPlaying )
{
2021-09-01 23:09:30 +02:00
gifFrameCounter + + ;
2021-06-11 12:27:46 +02:00
2021-09-01 23:09:30 +02:00
if ( ( ( gifFrameCounter / 15 ) % 2 ) = = 1 )
2021-06-11 12:27:46 +02:00
{
DrawCircle ( 30 , CORE . Window . screen . height - 20 , 10 , LIME ) ;
DrawText ( " EVENTS PLAYING " , 50 , CORE . Window . screen . height - 25 , 10 , GREEN ) ;
2017-05-18 18:57:11 +02:00
}
2018-11-06 15:10:50 +01:00
2021-03-21 01:29:31 +01:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2017-05-18 18:57:11 +02:00
}
# endif
2018-11-06 15:10:50 +01:00
2021-06-17 12:17:50 +02:00
# if !defined(SUPPORT_CUSTOM_FRAME_CONTROL)
2021-06-17 12:47:03 +02:00
SwapScreenBuffer ( ) ; // Copy back buffer to front buffer (screen)
2021-06-22 20:14:44 +02:00
2016-04-01 10:39:33 +02:00
// Frame time control system
2020-02-03 18:31:30 +01:00
CORE . Time . current = GetTime ( ) ;
CORE . Time . draw = CORE . Time . current - CORE . Time . previous ;
CORE . Time . previous = CORE . Time . current ;
2018-11-06 15:10:50 +01:00
2020-02-03 18:31:30 +01:00
CORE . Time . frame = CORE . Time . update + CORE . Time . draw ;
2020-02-03 19:26:28 +01:00
2017-01-28 00:56:45 +01:00
// Wait for some milliseconds...
2020-02-03 18:31:30 +01:00
if ( CORE . Time . frame < CORE . Time . target )
2013-11-23 13:30:54 +01:00
{
2022-06-06 20:18:37 +02:00
WaitTime ( CORE . Time . target - CORE . Time . frame ) ;
2017-01-28 23:02:30 +01:00
2020-02-03 18:31:30 +01:00
CORE . Time . current = GetTime ( ) ;
double waitTime = CORE . Time . current - CORE . Time . previous ;
CORE . Time . previous = CORE . Time . current ;
2017-01-28 23:02:30 +01:00
2021-06-10 17:11:31 +02:00
CORE . Time . frame + = waitTime ; // Total frame time: update + draw + wait
2013-11-23 13:30:54 +01:00
}
2021-02-08 08:57:19 -07:00
2021-06-23 01:25:09 +02:00
PollInputEvents ( ) ; // Poll user events (before next frame update)
2021-06-17 12:17:50 +02:00
# endif
2021-06-22 20:14:44 +02:00
2021-06-11 12:27:46 +02:00
# if defined(SUPPORT_EVENTS_AUTOMATION)
2021-06-17 11:17:39 +02:00
// Events recording and playing logic
2021-06-11 12:27:46 +02:00
if ( eventsRecording ) RecordAutomationEvent ( CORE . Time . frameCounter ) ;
2021-06-17 11:17:39 +02:00
else if ( eventsPlaying )
2021-06-11 12:27:46 +02:00
{
2021-06-17 11:17:39 +02:00
// TODO: When should we play? After/before/replace PollInputEvents()?
2021-06-11 12:27:46 +02:00
if ( CORE . Time . frameCounter > = eventCount ) eventsPlaying = false ;
PlayAutomationEvent ( CORE . Time . frameCounter ) ;
}
# endif
CORE . Time . frameCounter + + ;
2013-11-18 23:38:44 +01:00
}
2017-05-09 22:03:46 +02:00
// Initialize 2D mode with custom camera (2D)
2018-05-04 16:54:05 +02:00
void BeginMode2D ( Camera2D camera )
2016-05-02 00:37:33 +02:00
{
2021-03-21 01:29:31 +01:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2016-05-02 00:37:33 +02:00
2021-03-21 01:29:31 +01:00
rlLoadIdentity ( ) ; // Reset current matrix (modelview)
2019-10-17 17:18:03 +02:00
2019-08-27 13:15:56 +02:00
// Apply 2d camera transformation to modelview
rlMultMatrixf ( MatrixToFloat ( GetCameraMatrix2D ( camera ) ) ) ;
2020-02-03 19:26:28 +01:00
2020-01-27 16:32:28 +01:00
// Apply screen scaling if required
2020-02-03 18:31:30 +01:00
rlMultMatrixf ( MatrixToFloat ( CORE . Window . screenScale ) ) ;
2016-05-02 00:37:33 +02:00
}
2017-05-09 22:03:46 +02:00
// Ends 2D mode with custom camera
2018-05-04 16:54:05 +02:00
void EndMode2D ( void )
2016-05-02 00:37:33 +02:00
{
2021-03-21 01:29:31 +01:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2016-05-02 00:37:33 +02:00
2021-03-21 01:29:31 +01:00
rlLoadIdentity ( ) ; // Reset current matrix (modelview)
2020-02-03 18:31:30 +01:00
rlMultMatrixf ( MatrixToFloat ( CORE . Window . screenScale ) ) ; // Apply screen scaling if required
2016-05-02 00:37:33 +02:00
}
2017-05-09 22:03:46 +02:00
// Initializes 3D mode with custom camera (3D)
2018-05-04 16:54:05 +02:00
void BeginMode3D ( Camera3D camera )
2013-11-18 23:38:44 +01:00
{
2021-03-21 01:29:31 +01:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2018-11-06 15:10:50 +01:00
2021-03-21 01:29:31 +01:00
rlMatrixMode ( RL_PROJECTION ) ; // Switch to projection matrix
rlPushMatrix ( ) ; // Save previous matrix, which contains the settings for the 2d ortho projection
rlLoadIdentity ( ) ; // Reset current matrix (projection)
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
float aspect = ( float ) CORE . Window . currentFbo . width / ( float ) CORE . Window . currentFbo . height ;
2021-03-19 19:43:44 +01:00
2021-03-19 21:55:47 +01:00
// NOTE: zNear and zFar values are important when computing depth buffer values
if ( camera . projection = = CAMERA_PERSPECTIVE )
{
// Setup perspective projection
double top = RL_CULL_DISTANCE_NEAR * tan ( camera . fovy * 0.5 * DEG2RAD ) ;
double right = top * aspect ;
2018-03-27 19:59:54 +02:00
2021-03-19 21:55:47 +01:00
rlFrustum ( - right , right , - top , top , RL_CULL_DISTANCE_NEAR , RL_CULL_DISTANCE_FAR ) ;
}
else if ( camera . projection = = CAMERA_ORTHOGRAPHIC )
{
// Setup orthographic projection
double top = camera . fovy / 2.0 ;
double right = top * aspect ;
2013-11-23 13:30:54 +01:00
2021-03-19 21:55:47 +01:00
rlOrtho ( - right , right , - top , top , RL_CULL_DISTANCE_NEAR , RL_CULL_DISTANCE_FAR ) ;
}
2014-09-03 16:51:28 +02:00
2021-03-21 01:29:31 +01:00
rlMatrixMode ( RL_MODELVIEW ) ; // Switch back to modelview matrix
rlLoadIdentity ( ) ; // Reset current matrix (modelview)
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
// Setup Camera view
2017-07-21 17:19:28 +02:00
Matrix matView = MatrixLookAt ( camera . position , camera . target , camera . up ) ;
2020-04-05 17:50:37 +02:00
rlMultMatrixf ( MatrixToFloat ( matView ) ) ; // Multiply modelview matrix by view matrix (camera)
2016-08-16 11:09:55 +02:00
2021-03-21 01:29:31 +01:00
rlEnableDepthTest ( ) ; // Enable DEPTH_TEST for 3D
2013-11-18 23:38:44 +01:00
}
// Ends 3D mode and returns to default 2D orthographic mode
2018-05-04 16:54:05 +02:00
void EndMode3D ( void )
2016-08-16 11:09:55 +02:00
{
2021-03-21 01:29:31 +01:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2016-08-16 11:09:55 +02:00
2021-03-21 01:29:31 +01:00
rlMatrixMode ( RL_PROJECTION ) ; // Switch to projection matrix
rlPopMatrix ( ) ; // Restore previous matrix (projection) from matrix stack
2014-09-03 16:51:28 +02:00
2021-03-21 01:29:31 +01:00
rlMatrixMode ( RL_MODELVIEW ) ; // Switch back to modelview matrix
rlLoadIdentity ( ) ; // Reset current matrix (modelview)
2014-09-03 16:51:28 +02:00
2020-02-03 18:31:30 +01:00
rlMultMatrixf ( MatrixToFloat ( CORE . Window . screenScale ) ) ; // Apply screen scaling if required
2019-05-01 14:30:36 +02:00
2021-03-21 01:29:31 +01:00
rlDisableDepthTest ( ) ; // Disable DEPTH_TEST for 2D
2013-11-18 23:38:44 +01:00
}
2016-03-30 20:09:16 +02:00
// Initializes render texture for drawing
void BeginTextureMode ( RenderTexture2D target )
{
2021-03-21 01:29:31 +01:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2016-03-30 20:09:16 +02:00
2021-03-21 01:29:31 +01:00
rlEnableFramebuffer ( target . id ) ; // Enable render target
2018-11-06 15:10:50 +01:00
2022-04-24 12:37:50 +02:00
// Set viewport and RLGL internal framebuffer size
2016-08-16 11:09:55 +02:00
rlViewport ( 0 , 0 , target . texture . width , target . texture . height ) ;
2022-04-24 12:37:50 +02:00
rlSetFramebufferWidth ( target . texture . width ) ;
rlSetFramebufferHeight ( target . texture . height ) ;
2016-08-16 11:09:55 +02:00
2021-03-21 01:29:31 +01:00
rlMatrixMode ( RL_PROJECTION ) ; // Switch to projection matrix
rlLoadIdentity ( ) ; // Reset current matrix (projection)
2016-03-30 20:09:16 +02:00
2016-05-29 11:49:13 +02:00
// Set orthographic projection to current framebuffer size
// NOTE: Configured top-left corner as (0, 0)
2016-08-16 11:09:55 +02:00
rlOrtho ( 0 , target . texture . width , target . texture . height , 0 , 0.0f , 1.0f ) ;
2016-05-29 11:49:13 +02:00
2021-03-21 01:29:31 +01:00
rlMatrixMode ( RL_MODELVIEW ) ; // Switch back to modelview matrix
rlLoadIdentity ( ) ; // Reset current matrix (modelview)
2016-05-29 11:49:13 +02:00
2021-03-21 01:29:31 +01:00
//rlScalef(0.0f, -1.0f, 0.0f); // Flip Y-drawing (?)
2019-02-21 18:45:19 +01:00
2019-02-04 17:10:12 +01:00
// Setup current width/height for proper aspect ratio
// calculation when using BeginMode3D()
2020-02-03 18:31:30 +01:00
CORE . Window . currentFbo . width = target . texture . width ;
CORE . Window . currentFbo . height = target . texture . height ;
2016-03-30 20:09:16 +02:00
}
// Ends drawing to render texture
void EndTextureMode ( void )
{
2021-03-21 01:29:31 +01:00
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
2016-03-30 20:09:16 +02:00
2021-03-21 01:29:31 +01:00
rlDisableFramebuffer ( ) ; // Disable render target (fbo)
2016-05-29 11:49:13 +02:00
2019-05-01 14:30:36 +02:00
// Set viewport to default framebuffer size
2020-02-03 18:31:30 +01:00
SetupViewport ( CORE . Window . render . width , CORE . Window . render . height ) ;
2019-05-08 18:33:09 +02:00
2021-03-01 23:51:32 +01:00
// Reset current fbo to screen size
2021-10-10 22:34:56 +02:00
CORE . Window . currentFbo . width = CORE . Window . render . width ;
CORE . Window . currentFbo . height = CORE . Window . render . height ;
2016-03-30 20:09:16 +02:00
}
2021-04-06 22:49:41 +02:00
// Begin custom shader mode
void BeginShaderMode ( Shader shader )
{
2021-07-29 21:57:50 +02:00
rlSetShader ( shader . id , shader . locs ) ;
2021-04-06 22:49:41 +02:00
}
// End custom shader mode (returns to default shader)
void EndShaderMode ( void )
{
2021-07-29 21:57:50 +02:00
rlSetShader ( rlGetShaderIdDefault ( ) , rlGetShaderLocsDefault ( ) ) ;
2021-04-06 22:49:41 +02:00
}
2021-06-01 10:00:19 -03:00
// Begin blending mode (alpha, additive, multiplied, subtract, custom)
// NOTE: Blend modes supported are enumerated in BlendMode enum
2021-04-06 22:49:41 +02:00
void BeginBlendMode ( int mode )
{
rlSetBlendMode ( mode ) ;
}
// End blending mode (reset to default: alpha blending)
void EndBlendMode ( void )
{
rlSetBlendMode ( BLEND_ALPHA ) ;
}
// Begin scissor mode (define screen area for following drawing)
// NOTE: Scissor rec refers to bottom-left corner, we change it to upper-left
void BeginScissorMode ( int x , int y , int width , int height )
{
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
rlEnableScissorTest ( ) ;
2021-10-10 22:34:56 +02:00
2021-11-25 01:03:20 +01:00
# if defined(__APPLE__)
Vector2 scale = GetWindowScaleDPI ( ) ;
2021-11-25 01:07:54 +01:00
rlScissor ( ( int ) ( x * scale . x ) , ( int ) ( GetScreenHeight ( ) * scale . y - ( ( ( y + height ) * scale . y ) ) ) , ( int ) ( width * scale . x ) , ( int ) ( height * scale . y ) ) ;
2021-11-25 01:03:20 +01:00
# else
2021-10-10 22:38:58 +02:00
if ( ( CORE . Window . flags & FLAG_WINDOW_HIGHDPI ) > 0 )
{
2021-10-10 22:34:56 +02:00
Vector2 scale = GetWindowScaleDPI ( ) ;
2021-10-25 01:18:42 -07:00
rlScissor ( ( int ) ( x * scale . x ) , ( int ) ( CORE . Window . currentFbo . height - ( y + height ) * scale . y ) , ( int ) ( width * scale . x ) , ( int ) ( height * scale . y ) ) ;
2021-10-14 00:11:37 +02:00
}
2021-10-10 22:38:58 +02:00
else
{
2021-10-10 22:34:56 +02:00
rlScissor ( x , CORE . Window . currentFbo . height - ( y + height ) , width , height ) ;
}
2021-11-25 01:03:20 +01:00
# endif
2021-04-06 22:49:41 +02:00
}
// End scissor mode
void EndScissorMode ( void )
{
rlDrawRenderBatchActive ( ) ; // Update and draw internal render batch
rlDisableScissorTest ( ) ;
}
// Begin VR drawing configuration
2021-04-06 23:23:03 +02:00
void BeginVrStereoMode ( VrStereoConfig config )
2021-04-06 22:49:41 +02:00
{
rlEnableStereoRender ( ) ;
2021-04-18 23:50:32 +02:00
2021-04-06 22:49:41 +02:00
// Set stereo render matrices
2021-07-30 12:54:54 +02:00
rlSetMatrixProjectionStereo ( config . projection [ 0 ] , config . projection [ 1 ] ) ;
rlSetMatrixViewOffsetStereo ( config . viewOffset [ 0 ] , config . viewOffset [ 1 ] ) ;
2021-04-06 22:49:41 +02:00
}
// End VR drawing process (and desktop mirror)
void EndVrStereoMode ( void )
{
rlDisableStereoRender ( ) ;
}
// Load VR stereo config for VR simulator device parameters
2021-04-06 23:06:03 +02:00
VrStereoConfig LoadVrStereoConfig ( VrDeviceInfo device )
2021-04-06 22:49:41 +02:00
{
VrStereoConfig config = { 0 } ;
2021-04-18 23:50:32 +02:00
2021-10-18 13:25:59 +02:00
if ( ( rlGetVersion ( ) = = OPENGL_33 ) | | ( rlGetVersion ( ) = = OPENGL_ES_20 ) )
{
// Compute aspect ratio
float aspect = ( ( float ) device . hResolution * 0.5f ) / ( float ) device . vResolution ;
// Compute lens parameters
float lensShift = ( device . hScreenSize * 0.25f - device . lensSeparationDistance * 0.5f ) / device . hScreenSize ;
config . leftLensCenter [ 0 ] = 0.25f + lensShift ;
config . leftLensCenter [ 1 ] = 0.5f ;
config . rightLensCenter [ 0 ] = 0.75f - lensShift ;
config . rightLensCenter [ 1 ] = 0.5f ;
config . leftScreenCenter [ 0 ] = 0.25f ;
config . leftScreenCenter [ 1 ] = 0.5f ;
config . rightScreenCenter [ 0 ] = 0.75f ;
config . rightScreenCenter [ 1 ] = 0.5f ;
// Compute distortion scale parameters
// NOTE: To get lens max radius, lensShift must be normalized to [-1..1]
float lensRadius = fabsf ( - 1.0f - 4.0f * lensShift ) ;
float lensRadiusSq = lensRadius * lensRadius ;
float distortionScale = device . lensDistortionValues [ 0 ] +
device . lensDistortionValues [ 1 ] * lensRadiusSq +
device . lensDistortionValues [ 2 ] * lensRadiusSq * lensRadiusSq +
device . lensDistortionValues [ 3 ] * lensRadiusSq * lensRadiusSq * lensRadiusSq ;
float normScreenWidth = 0.5f ;
float normScreenHeight = 1.0f ;
config . scaleIn [ 0 ] = 2.0f / normScreenWidth ;
config . scaleIn [ 1 ] = 2.0f / normScreenHeight / aspect ;
config . scale [ 0 ] = normScreenWidth * 0.5f / distortionScale ;
config . scale [ 1 ] = normScreenHeight * 0.5f * aspect / distortionScale ;
// Fovy is normally computed with: 2*atan2f(device.vScreenSize, 2*device.eyeToScreenDistance)
// ...but with lens distortion it is increased (see Oculus SDK Documentation)
2022-04-24 10:48:50 +01:00
float fovy = 2.0f * atan2f ( device . vScreenSize * 0.5f * distortionScale , device . eyeToScreenDistance ) ; // Really need distortionScale?
// float fovy = 2.0f*(float)atan2f(device.vScreenSize*0.5f, device.eyeToScreenDistance);
2021-10-18 13:25:59 +02:00
// Compute camera projection matrices
float projOffset = 4.0f * lensShift ; // Scaled to projection space coordinates [-1..1]
Matrix proj = MatrixPerspective ( fovy , aspect , RL_CULL_DISTANCE_NEAR , RL_CULL_DISTANCE_FAR ) ;
config . projection [ 0 ] = MatrixMultiply ( proj , MatrixTranslate ( projOffset , 0.0f , 0.0f ) ) ;
config . projection [ 1 ] = MatrixMultiply ( proj , MatrixTranslate ( - projOffset , 0.0f , 0.0f ) ) ;
// Compute camera transformation matrices
// NOTE: Camera movement might seem more natural if we model the head.
// Our axis of rotation is the base of our head, so we might want to add
// some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions.
config . viewOffset [ 0 ] = MatrixTranslate ( - device . interpupillaryDistance * 0.5f , 0.075f , 0.045f ) ;
config . viewOffset [ 1 ] = MatrixTranslate ( device . interpupillaryDistance * 0.5f , 0.075f , 0.045f ) ;
// Compute eyes Viewports
/*
config . eyeViewportRight [ 0 ] = 0 ;
config . eyeViewportRight [ 1 ] = 0 ;
config . eyeViewportRight [ 2 ] = device . hResolution / 2 ;
config . eyeViewportRight [ 3 ] = device . vResolution ;
config . eyeViewportLeft [ 0 ] = device . hResolution / 2 ;
config . eyeViewportLeft [ 1 ] = 0 ;
config . eyeViewportLeft [ 2 ] = device . hResolution / 2 ;
config . eyeViewportLeft [ 3 ] = device . vResolution ;
*/
}
else TRACELOG ( LOG_WARNING , " RLGL: VR Simulator not supported on OpenGL 1.1 " ) ;
2021-04-06 22:49:41 +02:00
return config ;
}
2021-04-18 23:50:32 +02:00
// Unload VR stereo config properties
2021-04-06 22:49:41 +02:00
void UnloadVrStereoConfig ( VrStereoConfig config )
{
//...
}
2021-03-21 01:29:31 +01:00
// Load shader from files and bind default locations
// NOTE: If shader string is NULL, using default vertex/fragment shaders
Shader LoadShader ( const char * vsFileName , const char * fsFileName )
{
Shader shader = { 0 } ;
2021-08-22 01:07:37 +02:00
char * vShaderStr = NULL ;
char * fShaderStr = NULL ;
2021-10-03 12:09:59 +02:00
2021-08-22 01:07:37 +02:00
if ( vsFileName ! = NULL ) vShaderStr = LoadFileText ( vsFileName ) ;
if ( fsFileName ! = NULL ) fShaderStr = LoadFileText ( fsFileName ) ;
2021-03-21 01:29:31 +01:00
2021-06-25 00:46:14 +02:00
shader = LoadShaderFromMemory ( vShaderStr , fShaderStr ) ;
2021-04-01 20:24:33 +02:00
2021-06-25 00:46:14 +02:00
UnloadFileText ( vShaderStr ) ;
UnloadFileText ( fShaderStr ) ;
2021-03-28 20:12:48 +02:00
return shader ;
}
// Load shader from code strings and bind default locations
RLAPI Shader LoadShaderFromMemory ( const char * vsCode , const char * fsCode )
{
Shader shader = { 0 } ;
2021-07-31 19:46:44 +02:00
shader . locs = ( int * ) RL_CALLOC ( RL_MAX_SHADER_LOCATIONS , sizeof ( int ) ) ;
2021-06-30 16:39:07 +02:00
2021-06-25 00:46:14 +02:00
// NOTE: All locations must be reseted to -1 (no location)
2021-07-31 19:46:44 +02:00
for ( int i = 0 ; i < RL_MAX_SHADER_LOCATIONS ; i + + ) shader . locs [ i ] = - 1 ;
2021-04-01 20:24:33 +02:00
2021-03-28 20:12:48 +02:00
shader . id = rlLoadShaderCode ( vsCode , fsCode ) ;
2021-04-01 20:24:33 +02:00
2021-03-28 20:12:48 +02:00
// After shader loading, we TRY to set default location names
if ( shader . id > 0 )
2021-03-22 20:45:04 +01:00
{
2021-06-25 00:46:14 +02:00
// Default shader attribute locations have been binded before linking:
2021-03-22 20:45:04 +01:00
// vertex position location = 0
// vertex texcoord location = 1
// vertex normal location = 2
// vertex color location = 3
// vertex tangent location = 4
// vertex texcoord2 location = 5
2021-04-01 20:24:33 +02:00
2021-03-22 20:45:04 +01:00
// NOTE: If any location is not found, loc point becomes -1
// Get handles to GLSL input attibute locations
2021-07-30 13:44:52 +02:00
shader . locs [ SHADER_LOC_VERTEX_POSITION ] = rlGetLocationAttrib ( shader . id , RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION ) ;
shader . locs [ SHADER_LOC_VERTEX_TEXCOORD01 ] = rlGetLocationAttrib ( shader . id , RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD ) ;
shader . locs [ SHADER_LOC_VERTEX_TEXCOORD02 ] = rlGetLocationAttrib ( shader . id , RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 ) ;
shader . locs [ SHADER_LOC_VERTEX_NORMAL ] = rlGetLocationAttrib ( shader . id , RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL ) ;
shader . locs [ SHADER_LOC_VERTEX_TANGENT ] = rlGetLocationAttrib ( shader . id , RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT ) ;
shader . locs [ SHADER_LOC_VERTEX_COLOR ] = rlGetLocationAttrib ( shader . id , RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR ) ;
2021-03-22 20:45:04 +01:00
// Get handles to GLSL uniform locations (vertex shader)
2021-07-30 13:44:52 +02:00
shader . locs [ SHADER_LOC_MATRIX_MVP ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_UNIFORM_NAME_MVP ) ;
shader . locs [ SHADER_LOC_MATRIX_VIEW ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW ) ;
shader . locs [ SHADER_LOC_MATRIX_PROJECTION ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION ) ;
shader . locs [ SHADER_LOC_MATRIX_MODEL ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL ) ;
shader . locs [ SHADER_LOC_MATRIX_NORMAL ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL ) ;
2021-03-22 20:45:04 +01:00
// Get handles to GLSL uniform locations (fragment shader)
2021-07-30 13:44:52 +02:00
shader . locs [ SHADER_LOC_COLOR_DIFFUSE ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR ) ;
shader . locs [ SHADER_LOC_MAP_DIFFUSE ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 ) ; // SHADER_LOC_MAP_ALBEDO
shader . locs [ SHADER_LOC_MAP_SPECULAR ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 ) ; // SHADER_LOC_MAP_METALNESS
shader . locs [ SHADER_LOC_MAP_NORMAL ] = rlGetLocationUniform ( shader . id , RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 ) ;
2021-03-22 20:45:04 +01:00
}
2021-03-21 01:29:31 +01:00
return shader ;
}
// Unload shader from GPU memory (VRAM)
void UnloadShader ( Shader shader )
{
2021-07-29 21:57:50 +02:00
if ( shader . id ! = rlGetShaderIdDefault ( ) )
2021-03-21 01:29:31 +01:00
{
rlUnloadShaderProgram ( shader . id ) ;
RL_FREE ( shader . locs ) ;
}
}
// Get shader uniform location
int GetShaderLocation ( Shader shader , const char * uniformName )
{
2021-03-22 20:45:04 +01:00
return rlGetLocationUniform ( shader . id , uniformName ) ;
2021-03-21 01:29:31 +01:00
}
// Get shader attribute location
int GetShaderLocationAttrib ( Shader shader , const char * attribName )
{
2021-03-22 20:45:04 +01:00
return rlGetLocationAttrib ( shader . id , attribName ) ;
2021-03-21 01:29:31 +01:00
}
// Set shader uniform value
void SetShaderValue ( Shader shader , int locIndex , const void * value , int uniformType )
{
SetShaderValueV ( shader , locIndex , value , uniformType , 1 ) ;
}
// Set shader uniform value vector
void SetShaderValueV ( Shader shader , int locIndex , const void * value , int uniformType , int count )
{
rlEnableShader ( shader . id ) ;
rlSetUniform ( locIndex , value , uniformType , count ) ;
//rlDisableShader(); // Avoid reseting current shader program, in case other uniforms are set
}
// Set shader uniform value (matrix 4x4)
void SetShaderValueMatrix ( Shader shader , int locIndex , Matrix mat )
{
rlEnableShader ( shader . id ) ;
2021-07-30 12:54:54 +02:00
rlSetUniformMatrix ( locIndex , mat ) ;
2021-03-21 01:29:31 +01:00
//rlDisableShader();
}
// Set shader uniform value for texture
void SetShaderValueTexture ( Shader shader , int locIndex , Texture2D texture )
{
rlEnableShader ( shader . id ) ;
2021-03-25 14:28:12 +01:00
rlSetUniformSampler ( locIndex , texture . id ) ;
2021-03-21 01:29:31 +01:00
//rlDisableShader();
}
2021-06-10 17:43:58 +02:00
// Get a ray trace from mouse position
2020-02-03 18:31:30 +01:00
Ray GetMouseRay ( Vector2 mouse , Camera camera )
2017-05-09 22:03:46 +02:00
{
2021-05-14 14:01:42 +02:00
Ray ray = { 0 } ;
2017-05-09 22:03:46 +02:00
// Calculate normalized device coordinates
// NOTE: y value is negative
2020-02-03 18:31:30 +01:00
float x = ( 2.0f * mouse . x ) / ( float ) GetScreenWidth ( ) - 1.0f ;
float y = 1.0f - ( 2.0f * mouse . y ) / ( float ) GetScreenHeight ( ) ;
2017-05-09 22:03:46 +02:00
float z = 1.0f ;
// Store values in a vector
Vector3 deviceCoords = { x , y , z } ;
// Calculate view matrix from camera look at
Matrix matView = MatrixLookAt ( camera . position , camera . target , camera . up ) ;
2018-05-17 00:58:58 +02:00
Matrix matProj = MatrixIdentity ( ) ;
2018-03-24 23:31:06 +01:00
2021-03-19 13:56:46 +01:00
if ( camera . projection = = CAMERA_PERSPECTIVE )
2018-03-24 23:31:06 +01:00
{
// Calculate projection matrix from perspective
2020-05-01 17:31:44 +02:00
matProj = MatrixPerspective ( camera . fovy * DEG2RAD , ( ( double ) GetScreenWidth ( ) / ( double ) GetScreenHeight ( ) ) , RL_CULL_DISTANCE_NEAR , RL_CULL_DISTANCE_FAR ) ;
2018-03-24 23:31:06 +01:00
}
2021-03-19 13:56:46 +01:00
else if ( camera . projection = = CAMERA_ORTHOGRAPHIC )
2018-03-24 23:31:06 +01:00
{
2020-02-03 18:31:30 +01:00
float aspect = ( float ) CORE . Window . screen . width / ( float ) CORE . Window . screen . height ;
2018-03-24 23:31:06 +01:00
double top = camera . fovy / 2.0 ;
double right = top * aspect ;
2018-11-06 15:10:50 +01:00
2018-03-24 23:31:06 +01:00
// Calculate projection matrix from orthographic
matProj = MatrixOrtho ( - right , right , - top , top , 0.01 , 1000.0 ) ;
}
2017-07-22 11:02:40 +02:00
// Unproject far/near points
2020-09-01 21:08:45 +02:00
Vector3 nearPoint = Vector3Unproject ( ( Vector3 ) { deviceCoords . x , deviceCoords . y , 0.0f } , matProj , matView ) ;
Vector3 farPoint = Vector3Unproject ( ( Vector3 ) { deviceCoords . x , deviceCoords . y , 1.0f } , matProj , matView ) ;
2017-05-09 22:03:46 +02:00
2018-03-24 23:31:06 +01:00
// Unproject the mouse cursor in the near plane.
2018-11-06 15:10:50 +01:00
// We need this as the source position because orthographic projects, compared to perspect doesn't have a
2018-03-24 23:31:06 +01:00
// convergence point, meaning that the "eye" of the camera is more like a plane than a point.
2020-09-01 21:08:45 +02:00
Vector3 cameraPlanePointerPos = Vector3Unproject ( ( Vector3 ) { deviceCoords . x , deviceCoords . y , - 1.0f } , matProj , matView ) ;
2018-03-24 23:31:06 +01:00
2017-05-09 22:03:46 +02:00
// Calculate normalized direction vector
2018-04-02 15:16:45 +02:00
Vector3 direction = Vector3Normalize ( Vector3Subtract ( farPoint , nearPoint ) ) ;
2017-05-09 22:03:46 +02:00
2021-03-19 13:56:46 +01:00
if ( camera . projection = = CAMERA_PERSPECTIVE ) ray . position = camera . position ;
else if ( camera . projection = = CAMERA_ORTHOGRAPHIC ) ray . position = cameraPlanePointerPos ;
2018-03-24 23:31:06 +01:00
2017-05-09 22:03:46 +02:00
// Apply calculated vectors to ray
ray . direction = direction ;
return ray ;
}
2019-08-27 13:15:56 +02:00
// Get transform matrix for camera
Matrix GetCameraMatrix ( Camera camera )
{
return MatrixLookAt ( camera . position , camera . target , camera . up ) ;
}
2021-06-10 17:43:58 +02:00
// Get camera 2d transform matrix
2019-10-17 17:18:03 +02:00
Matrix GetCameraMatrix2D ( Camera2D camera )
2019-08-27 13:15:56 +02:00
{
Matrix matTransform = { 0 } ;
// The camera in world-space is set by
// 1. Move it to target
// 2. Rotate by -rotation and scale by (1/zoom)
// When setting higher scale, it's more intuitive for the world to become bigger (= camera become smaller),
// not for the camera getting bigger, hence the invert. Same deal with rotation.
// 3. Move it by (-offset);
// Offset defines target transform relative to screen, but since we're effectively "moving" screen (camera)
// we need to do it into opposite direction (inverse transform)
// Having camera transform in world-space, inverse of it gives the modelview transform.
// Since (A*B*C)' = C'*B'*A', the modelview is
// 1. Move to offset
// 2. Rotate and Scale
// 3. Move by -target
Matrix matOrigin = MatrixTranslate ( - camera . target . x , - camera . target . y , 0.0f ) ;
Matrix matRotation = MatrixRotate ( ( Vector3 ) { 0.0f , 0.0f , 1.0f } , camera . rotation * DEG2RAD ) ;
Matrix matScale = MatrixScale ( camera . zoom , camera . zoom , 1.0f ) ;
Matrix matTranslation = MatrixTranslate ( camera . offset . x , camera . offset . y , 0.0f ) ;
2019-10-17 17:18:03 +02:00
2019-08-27 13:15:56 +02:00
matTransform = MatrixMultiply ( MatrixMultiply ( matOrigin , MatrixMultiply ( matScale , matRotation ) ) , matTranslation ) ;
2019-10-17 17:18:03 +02:00
2019-08-27 13:15:56 +02:00
return matTransform ;
}
2021-06-10 17:43:58 +02:00
// Get the screen space position from a 3d world space position
2017-05-09 22:03:46 +02:00
Vector2 GetWorldToScreen ( Vector3 position , Camera camera )
{
2020-01-24 18:54:53 +01:00
Vector2 screenPosition = GetWorldToScreenEx ( position , camera , GetScreenWidth ( ) , GetScreenHeight ( ) ) ;
2018-03-24 23:31:06 +01:00
2020-01-24 18:54:53 +01:00
return screenPosition ;
}
2018-11-06 15:10:50 +01:00
2021-06-10 17:43:58 +02:00
// Get size position for a 3d world space position (useful for texture drawing)
2020-01-24 18:54:53 +01:00
Vector2 GetWorldToScreenEx ( Vector3 position , Camera camera , int width , int height )
{
2020-02-03 18:31:30 +01:00
// Calculate projection matrix (from perspective instead of frustum
Matrix matProj = MatrixIdentity ( ) ;
2017-05-09 22:03:46 +02:00
2021-03-19 13:56:46 +01:00
if ( camera . projection = = CAMERA_PERSPECTIVE )
2020-02-03 18:31:30 +01:00
{
// Calculate projection matrix from perspective
2021-03-31 17:55:46 +02:00
matProj = MatrixPerspective ( camera . fovy * DEG2RAD , ( ( double ) width / ( double ) height ) , RL_CULL_DISTANCE_NEAR , RL_CULL_DISTANCE_FAR ) ;
2020-02-03 18:31:30 +01:00
}
2021-03-19 13:56:46 +01:00
else if ( camera . projection = = CAMERA_ORTHOGRAPHIC )
2020-02-03 18:31:30 +01:00
{
float aspect = ( float ) CORE . Window . screen . width / ( float ) CORE . Window . screen . height ;
double top = camera . fovy / 2.0 ;
double right = top * aspect ;
// Calculate projection matrix from orthographic
2020-05-01 17:31:44 +02:00
matProj = MatrixOrtho ( - right , right , - top , top , RL_CULL_DISTANCE_NEAR , RL_CULL_DISTANCE_FAR ) ;
2020-02-03 18:31:30 +01:00
}
2017-05-09 22:03:46 +02:00
2020-02-03 18:31:30 +01:00
// Calculate view matrix from camera look at (and transpose it)
Matrix matView = MatrixLookAt ( camera . position , camera . target , camera . up ) ;
2017-05-09 22:03:46 +02:00
2021-10-03 12:09:59 +02:00
// TODO: Why not use Vector3Transform(Vector3 v, Matrix mat)?
2020-02-03 18:31:30 +01:00
// Convert world position vector to quaternion
Quaternion worldPos = { position . x , position . y , position . z , 1.0f } ;
2017-05-09 22:03:46 +02:00
2020-02-03 18:31:30 +01:00
// Transform world position to view
worldPos = QuaternionTransform ( worldPos , matView ) ;
2017-05-09 22:03:46 +02:00
2020-02-03 18:31:30 +01:00
// Transform result to projection (clip space position)
worldPos = QuaternionTransform ( worldPos , matProj ) ;
2017-05-09 22:03:46 +02:00
2020-02-03 18:31:30 +01:00
// Calculate normalized device coordinates (inverted y)
Vector3 ndcPos = { worldPos . x / worldPos . w , - worldPos . y / worldPos . w , worldPos . z / worldPos . w } ;
2020-01-24 18:54:53 +01:00
2020-02-03 18:31:30 +01:00
// Calculate 2d screen position vector
2020-02-03 19:26:28 +01:00
Vector2 screenPosition = { ( ndcPos . x + 1.0f ) / 2.0f * ( float ) width , ( ndcPos . y + 1.0f ) / 2.0f * ( float ) height } ;
2020-01-24 18:54:53 +01:00
2020-02-03 18:31:30 +01:00
return screenPosition ;
2017-05-09 22:03:46 +02:00
}
2021-06-10 17:43:58 +02:00
// Get the screen space position for a 2d camera world space position
2019-10-17 17:18:03 +02:00
Vector2 GetWorldToScreen2D ( Vector2 position , Camera2D camera )
2017-05-09 22:03:46 +02:00
{
2019-08-27 13:15:56 +02:00
Matrix matCamera = GetCameraMatrix2D ( camera ) ;
Vector3 transform = Vector3Transform ( ( Vector3 ) { position . x , position . y , 0 } , matCamera ) ;
2019-10-17 17:18:03 +02:00
2019-08-27 13:15:56 +02:00
return ( Vector2 ) { transform . x , transform . y } ;
2019-08-27 14:05:28 +03:00
}
2021-06-10 17:43:58 +02:00
// Get the world space position for a 2d camera screen space position
2019-10-17 17:18:03 +02:00
Vector2 GetScreenToWorld2D ( Vector2 position , Camera2D camera )
2019-08-27 13:15:56 +02:00
{
Matrix invMatCamera = MatrixInvert ( GetCameraMatrix2D ( camera ) ) ;
Vector3 transform = Vector3Transform ( ( Vector3 ) { position . x , position . y , 0 } , invMatCamera ) ;
2019-10-17 17:18:03 +02:00
2019-08-27 13:15:56 +02:00
return ( Vector2 ) { transform . x , transform . y } ;
2019-08-27 14:05:28 +03:00
}
2017-05-09 22:03:46 +02:00
// Set target FPS (maximum)
2013-11-18 23:38:44 +01:00
void SetTargetFPS ( int fps )
{
2020-02-03 18:31:30 +01:00
if ( fps < 1 ) CORE . Time . target = 0.0 ;
else CORE . Time . target = 1.0 / ( double ) fps ;
2014-09-03 16:51:28 +02:00
2022-03-20 12:15:51 +01:00
TRACELOG ( LOG_INFO , " TIMER: Target time per frame: %02.03f milliseconds " , ( float ) CORE . Time . target * 1000.0f ) ;
2013-11-18 23:38:44 +01:00
}
2021-06-10 17:43:58 +02:00
// Get current FPS
2020-02-19 12:20:15 +01:00
// NOTE: We calculate an average framerate
2017-01-28 00:56:45 +01:00
int GetFPS ( void )
2013-11-18 23:38:44 +01:00
{
2021-06-21 00:46:30 +02:00
int fps = 0 ;
2021-06-22 20:14:44 +02:00
# if !defined(SUPPORT_CUSTOM_FRAME_CONTROL)
2020-02-19 12:20:15 +01:00
# define FPS_CAPTURE_FRAMES_COUNT 30 // 30 captures
# define FPS_AVERAGE_TIME_SECONDS 0.5f // 500 millisecondes
# define FPS_STEP (FPS_AVERAGE_TIME_SECONDS / FPS_CAPTURE_FRAMES_COUNT)
static int index = 0 ;
static float history [ FPS_CAPTURE_FRAMES_COUNT ] = { 0 } ;
static float average = 0 , last = 0 ;
float fpsFrame = GetFrameTime ( ) ;
2020-02-26 23:42:06 +01:00
2020-02-19 12:20:15 +01:00
if ( fpsFrame = = 0 ) return 0 ;
if ( ( GetTime ( ) - last ) > FPS_STEP )
{
2020-05-06 19:12:09 +02:00
last = ( float ) GetTime ( ) ;
2020-02-19 12:20:15 +01:00
index = ( index + 1 ) % FPS_CAPTURE_FRAMES_COUNT ;
average - = history [ index ] ;
history [ index ] = fpsFrame / FPS_CAPTURE_FRAMES_COUNT ;
average + = history [ index ] ;
}
2021-06-22 20:14:44 +02:00
2021-06-21 00:46:30 +02:00
fps = ( int ) roundf ( 1.0f / average ) ;
# endif
2020-02-26 23:42:06 +01:00
2021-06-21 00:46:30 +02:00
return fps ;
2013-11-18 23:38:44 +01:00
}
2021-06-10 17:43:58 +02:00
// Get time in seconds for last frame drawn (delta time)
2014-09-03 17:06:10 +02:00
float GetFrameTime ( void )
2013-11-18 23:38:44 +01:00
{
2020-02-03 18:31:30 +01:00
return ( float ) CORE . Time . frame ;
2013-11-18 23:38:44 +01:00
}
2017-12-19 14:06:54 +01:00
// Get elapsed time measure in seconds since InitTimer()
// NOTE: On PLATFORM_DESKTOP InitTimer() is called on InitWindow()
// NOTE: On PLATFORM_DESKTOP, timer is initialized on glfwInit()
double GetTime ( void )
{
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2021-06-24 18:13:25 +02:00
return glfwGetTime ( ) ; // Elapsed time since glfwInit()
2017-12-19 14:06:54 +01:00
# endif
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-07-03 21:31:52 +02:00
struct timespec ts = { 0 } ;
2017-12-19 14:06:54 +01:00
clock_gettime ( CLOCK_MONOTONIC , & ts ) ;
2020-02-04 16:55:24 +01:00
unsigned long long int time = ( unsigned long long int ) ts . tv_sec * 1000000000LLU + ( unsigned long long int ) ts . tv_nsec ;
2017-12-19 14:06:54 +01:00
2020-02-03 18:31:30 +01:00
return ( double ) ( time - CORE . Time . base ) * 1e-9 ; // Elapsed time since InitTimer()
2017-12-19 14:06:54 +01:00
# endif
}
2017-05-09 22:03:46 +02:00
// Setup window configuration flags (view FLAGS)
2020-11-23 00:49:27 +01:00
// NOTE: This function is expected to be called before window creation,
// because it setups some flags for the window creation process.
// To configure window states after creation, just use SetWindowState()
2019-06-14 17:18:33 +02:00
void SetConfigFlags ( unsigned int flags )
2014-10-17 21:11:58 +02:00
{
2020-11-23 00:49:27 +01:00
// Selected flags are set but not evaluated at this point,
// flag evaluation happens at InitWindow() or SetWindowState()
CORE . Window . flags | = flags ;
2014-10-17 21:11:58 +02:00
}
2020-02-03 19:13:24 +01:00
// NOTE TRACELOG() function is located in [utils.h]
2017-05-09 22:03:46 +02:00
2017-05-11 16:24:40 +02:00
// Takes a screenshot of current screen (saved a .png)
void TakeScreenshot ( const char * fileName )
2017-04-16 13:47:49 +02:00
{
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RTEXTURES)
2022-05-20 17:25:47 +02:00
Vector2 scale = GetWindowScaleDPI ( ) ;
2022-06-07 10:04:24 +02:00
unsigned char * imgData = rlReadScreenPixels ( ( int ) ( ( float ) CORE . Window . render . width * scale . x ) , ( int ) ( ( float ) CORE . Window . render . height * scale . y ) ) ;
Image image = { imgData , ( int ) ( ( float ) CORE . Window . render . width * scale . x ) , ( int ) ( ( float ) CORE . Window . render . height * scale . y ) , 1 , PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 } ;
2019-01-23 20:07:47 -05:00
2021-11-18 10:25:28 +01:00
char path [ 2048 ] = { 0 } ;
2021-06-24 18:13:25 +02:00
strcpy ( path , TextFormat ( " %s/%s " , CORE . Storage . basePath , fileName ) ) ;
2022-02-18 20:30:46 +01:00
2021-12-04 19:56:02 +01:00
ExportImage ( image , path ) ; // WARNING: Module required: rtextures
2019-04-23 14:55:35 +02:00
RL_FREE ( imgData ) ;
2019-01-23 20:07:47 -05:00
2019-01-05 18:03:09 +01:00
# if defined(PLATFORM_WEB)
// Download file from MEMFS (emscripten memory filesystem)
2019-05-22 16:12:47 +02:00
// saveFileFromMEMFSToDisk() function is defined in raylib/src/shell.html
emscripten_run_script ( TextFormat ( " saveFileFromMEMFSToDisk('%s','%s') " , GetFileName ( path ) , GetFileName ( path ) ) ) ;
2017-04-16 13:47:49 +02:00
# endif
2019-01-05 18:03:09 +01:00
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " SYSTEM: [%s] Screenshot taken successfully " , path ) ;
2021-12-04 19:56:02 +01:00
# else
TRACELOG ( LOG_WARNING , " IMAGE: ExportImage() requires module: rtextures " ) ;
# endif
2017-04-16 13:47:49 +02:00
}
2021-06-10 17:43:58 +02:00
// Get a random value between min and max (both included)
2020-06-15 12:02:50 +02:00
int GetRandomValue ( int min , int max )
{
if ( min > max )
{
int tmp = max ;
max = min ;
min = tmp ;
}
return ( rand ( ) % ( abs ( max - min ) + 1 ) + min ) ;
}
2021-09-17 22:26:21 +03:00
// Set the seed for the random number generator
void SetRandomSeed ( unsigned int seed )
{
srand ( seed ) ;
}
2018-10-16 10:53:01 +02:00
// Check if the file exists
bool FileExists ( const char * fileName )
{
bool result = false ;
# if defined(_WIN32)
2019-01-05 18:03:09 +01:00
if ( _access ( fileName , 0 ) ! = - 1 ) result = true ;
2018-10-16 10:53:01 +02:00
# else
2019-01-05 18:03:09 +01:00
if ( access ( fileName , F_OK ) ! = - 1 ) result = true ;
2018-10-16 10:53:01 +02:00
# endif
2021-11-17 13:36:28 +01:00
// NOTE: Alternatively, stat() can be used instead of access()
//#include <sys/stat.h>
2022-02-18 20:30:46 +01:00
//struct stat statbuf;
2021-11-17 13:36:28 +01:00
//if (stat(filename, &statbuf) == 0) result = true;
2018-10-16 10:53:01 +02:00
return result ;
}
2017-03-29 00:35:42 +02:00
// Check file extension
2020-01-09 10:43:21 +01:00
// NOTE: Extensions checking is not case-sensitive
2017-03-29 00:35:42 +02:00
bool IsFileExtension ( const char * fileName , const char * ext )
2014-07-23 00:06:24 +02:00
{
2022-06-18 20:44:15 +02:00
# define MAX_FILE_EXTENSION_SIZE 16
2017-03-29 00:35:42 +02:00
bool result = false ;
2020-09-13 14:07:08 +02:00
const char * fileExt = GetFileExtension ( fileName ) ;
2019-10-17 17:18:03 +02:00
2019-10-21 17:37:43 +02:00
if ( fileExt ! = NULL )
2018-03-16 13:09:49 +01:00
{
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_TEXT_MANIPULATION)
2019-10-21 17:37:43 +02:00
int extCount = 0 ;
2022-06-18 20:44:15 +02:00
const char * * checkExts = TextSplit ( ext , ' ; ' , & extCount ) ; // WARNING: Module required: rtext
2020-02-03 19:26:28 +01:00
2022-06-18 20:44:15 +02:00
char fileExtLower [ MAX_FILE_EXTENSION_SIZE ] = { 0 } ;
strncpy ( fileExtLower , TextToLower ( fileExt ) , MAX_FILE_EXTENSION_SIZE ) ; // WARNING: Module required: rtext
2019-10-21 17:37:43 +02:00
for ( int i = 0 ; i < extCount ; i + + )
2018-03-16 13:09:49 +01:00
{
2021-12-04 19:56:02 +01:00
if ( strcmp ( fileExtLower , TextToLower ( checkExts [ i ] ) ) = = 0 )
2019-10-21 17:37:43 +02:00
{
result = true ;
break ;
}
2018-03-16 13:09:49 +01:00
}
2020-05-09 13:05:54 +02:00
# else
if ( strcmp ( fileExt , ext ) = = 0 ) result = true ;
# endif
2018-03-16 13:09:49 +01:00
}
2017-03-29 00:35:42 +02:00
return result ;
2014-07-23 00:06:24 +02:00
}
2019-08-07 00:26:33 +02:00
// Check if a directory path exists
bool DirectoryExists ( const char * dirPath )
{
bool result = false ;
DIR * dir = opendir ( dirPath ) ;
if ( dir ! = NULL )
{
result = true ;
closedir ( dir ) ;
}
return result ;
}
2022-01-28 00:23:28 +01:00
// Get file length in bytes
// NOTE: GetFileSize() conflicts with windows.h
int GetFileLength ( const char * fileName )
2022-01-27 14:07:05 +01:00
{
int size = 0 ;
2022-02-18 20:30:46 +01:00
2022-01-27 14:07:05 +01:00
FILE * file = fopen ( fileName , " rb " ) ;
2022-02-18 20:30:46 +01:00
2022-01-27 14:07:05 +01:00
if ( file ! = NULL )
{
fseek ( file , 0L , SEEK_END ) ;
size = ( int ) ftell ( file ) ;
fclose ( file ) ;
}
return size ;
}
2021-03-02 01:07:08 +01:00
// Get pointer to extension for a filename string (includes the dot: .png)
2020-09-13 14:07:08 +02:00
const char * GetFileExtension ( const char * fileName )
2017-09-08 09:35:54 +02:00
{
const char * dot = strrchr ( fileName , ' . ' ) ;
2018-11-06 15:10:50 +01:00
2018-03-09 11:43:53 +01:00
if ( ! dot | | dot = = fileName ) return NULL ;
2018-11-06 15:10:50 +01:00
2021-03-02 01:07:08 +01:00
return dot ;
2017-09-08 09:35:54 +02:00
}
2018-08-25 17:55:25 +02:00
// String pointer reverse break: returns right-most occurrence of charset in s
2018-08-25 09:20:36 +02:00
static const char * strprbrk ( const char * s , const char * charset )
{
2018-08-25 17:55:25 +02:00
const char * latestMatch = NULL ;
for ( ; s = strpbrk ( s , charset ) , s ! = NULL ; latestMatch = s + + ) { }
return latestMatch ;
2018-08-25 09:20:36 +02:00
}
2018-01-02 02:26:05 +01:00
// Get pointer to filename for a path string
const char * GetFileName ( const char * filePath )
{
2019-09-08 01:11:53 +02:00
const char * fileName = NULL ;
if ( filePath ! = NULL ) fileName = strprbrk ( filePath , " \\ / " ) ;
2018-08-25 09:20:36 +02:00
2021-01-16 06:33:13 -03:00
if ( ! fileName ) return filePath ;
2018-01-02 02:26:05 +01:00
return fileName + 1 ;
}
2019-08-21 18:59:15 +02:00
// Get filename string without extension (uses static string)
2018-10-10 12:01:59 +02:00
const char * GetFileNameWithoutExt ( const char * filePath )
{
2022-05-12 16:35:28 +02:00
# define MAX_FILENAMEWITHOUTEXT_LENGTH 256
2019-04-04 13:50:52 +02:00
2021-07-03 21:31:52 +02:00
static char fileName [ MAX_FILENAMEWITHOUTEXT_LENGTH ] = { 0 } ;
2019-03-13 10:07:01 +01:00
memset ( fileName , 0 , MAX_FILENAMEWITHOUTEXT_LENGTH ) ;
2019-04-04 13:50:52 +02:00
2019-09-08 01:11:53 +02:00
if ( filePath ! = NULL ) strcpy ( fileName , GetFileName ( filePath ) ) ; // Get filename with extension
2019-04-04 13:50:52 +02:00
2021-09-01 23:40:51 +02:00
int size = ( int ) strlen ( fileName ) ; // Get size in bytes
2019-04-04 13:50:52 +02:00
2021-09-01 23:40:51 +02:00
for ( int i = 0 ; ( i < size ) & & ( i < MAX_FILENAMEWITHOUTEXT_LENGTH ) ; i + + )
2018-10-10 12:01:59 +02:00
{
2019-03-13 10:07:01 +01:00
if ( fileName [ i ] = = ' . ' )
2018-10-10 12:01:59 +02:00
{
2019-03-13 10:07:01 +01:00
// NOTE: We break on first '.' found
fileName [ i ] = ' \0 ' ;
break ;
2018-11-06 15:10:50 +01:00
}
2018-10-10 12:01:59 +02:00
}
2019-03-13 10:07:01 +01:00
return fileName ;
2018-10-10 12:01:59 +02:00
}
2018-01-02 02:26:05 +01:00
2019-08-11 12:04:54 +02:00
// Get directory for a given filePath
const char * GetDirectoryPath ( const char * filePath )
2017-05-11 16:24:40 +02:00
{
2020-01-26 13:01:35 +01:00
/*
// NOTE: Directory separator is different in Windows and other platforms,
// fortunately, Windows also support the '/' separator, that's the one should be used
# if defined(_WIN32)
char separator = ' \\ ' ;
# else
char separator = ' / ' ;
# endif
*/
2018-08-25 09:20:36 +02:00
const char * lastSlash = NULL ;
2021-07-03 21:31:52 +02:00
static char dirPath [ MAX_FILEPATH_LENGTH ] = { 0 } ;
2019-08-11 12:04:54 +02:00
memset ( dirPath , 0 , MAX_FILEPATH_LENGTH ) ;
2020-02-03 19:26:28 +01:00
2021-01-16 06:33:13 -03:00
// In case provided path does not contain a root drive letter (C:\, D:\) nor leading path separator (\, /),
2020-02-11 19:12:49 +01:00
// we add the current directory path to dirPath
2021-01-16 06:33:13 -03:00
if ( filePath [ 1 ] ! = ' : ' & & filePath [ 0 ] ! = ' \\ ' & & filePath [ 0 ] ! = ' / ' )
2020-02-11 19:12:49 +01:00
{
// For security, we set starting path to current directory,
// obtained path will be concated to this
dirPath [ 0 ] = ' . ' ;
dirPath [ 1 ] = ' / ' ;
}
2018-08-25 09:20:36 +02:00
2019-08-11 12:04:54 +02:00
lastSlash = strprbrk ( filePath , " \\ / " ) ;
2020-01-26 13:01:35 +01:00
if ( lastSlash )
{
2021-01-16 06:33:13 -03:00
if ( lastSlash = = filePath )
{
// The last and only slash is the leading one: path is in a root directory
dirPath [ 0 ] = filePath [ 0 ] ;
dirPath [ 1 ] = ' \0 ' ;
}
else
{
// NOTE: Be careful, strncpy() is not safe, it does not care about '\0'
memcpy ( dirPath + ( filePath [ 1 ] ! = ' : ' & & filePath [ 0 ] ! = ' \\ ' & & filePath [ 0 ] ! = ' / ' ? 2 : 0 ) , filePath , strlen ( filePath ) - ( strlen ( lastSlash ) - 1 ) ) ;
dirPath [ strlen ( filePath ) - strlen ( lastSlash ) + ( filePath [ 1 ] ! = ' : ' & & filePath [ 0 ] ! = ' \\ ' & & filePath [ 0 ] ! = ' / ' ? 2 : 0 ) ] = ' \0 ' ; // Add '\0' manually
}
2020-01-26 13:01:35 +01:00
}
2018-08-25 09:20:36 +02:00
2019-08-11 12:04:54 +02:00
return dirPath ;
2017-05-11 16:24:40 +02:00
}
2019-08-07 00:26:33 +02:00
// Get previous directory path for a given path
2019-08-11 12:04:54 +02:00
const char * GetPrevDirectoryPath ( const char * dirPath )
2019-08-07 00:26:33 +02:00
{
2021-07-03 21:31:52 +02:00
static char prevDirPath [ MAX_FILEPATH_LENGTH ] = { 0 } ;
2019-08-11 12:04:54 +02:00
memset ( prevDirPath , 0 , MAX_FILEPATH_LENGTH ) ;
2020-05-06 19:12:09 +02:00
int pathLen = ( int ) strlen ( dirPath ) ;
2019-10-17 17:18:03 +02:00
2019-08-11 12:04:54 +02:00
if ( pathLen < = 3 ) strcpy ( prevDirPath , dirPath ) ;
2019-10-17 17:18:03 +02:00
2020-05-14 18:30:32 +03:00
for ( int i = ( pathLen - 1 ) ; ( i > = 0 ) & & ( pathLen > 3 ) ; i - - )
2019-08-07 00:26:33 +02:00
{
2019-08-11 12:04:54 +02:00
if ( ( dirPath [ i ] = = ' \\ ' ) | | ( dirPath [ i ] = = ' / ' ) )
2019-08-07 00:26:33 +02:00
{
2020-05-14 17:37:54 +02:00
// Check for root: "C:\" or "/"
if ( ( ( i = = 2 ) & & ( dirPath [ 1 ] = = ' : ' ) ) | | ( i = = 0 ) ) i + + ;
2020-11-03 23:47:33 +01:00
2019-08-11 12:04:54 +02:00
strncpy ( prevDirPath , dirPath , i ) ;
break ;
2019-08-07 00:26:33 +02:00
}
}
2019-10-17 17:18:03 +02:00
2019-08-11 12:04:54 +02:00
return prevDirPath ;
2019-08-07 00:26:33 +02:00
}
2017-05-11 16:24:40 +02:00
// Get current working directory
const char * GetWorkingDirectory ( void )
{
2021-07-03 21:31:52 +02:00
static char currentDir [ MAX_FILEPATH_LENGTH ] = { 0 } ;
2018-10-25 16:09:38 +02:00
memset ( currentDir , 0 , MAX_FILEPATH_LENGTH ) ;
2018-11-06 15:10:50 +01:00
2021-06-24 18:13:25 +02:00
char * path = GETCWD ( currentDir , MAX_FILEPATH_LENGTH - 1 ) ;
2018-11-06 15:10:50 +01:00
2021-06-24 18:13:25 +02:00
return path ;
2017-05-11 16:24:40 +02:00
}
2022-01-10 13:54:51 +01:00
const char * GetApplicationDirectory ( void )
2022-01-08 10:47:52 -08:00
{
2022-01-14 11:16:25 -08:00
static char appDir [ MAX_FILEPATH_LENGTH ] = { 0 } ;
memset ( appDir , 0 , MAX_FILEPATH_LENGTH ) ;
2022-01-08 10:47:52 -08:00
# if defined(_WIN32)
2022-01-14 11:16:25 -08:00
int len = 0 ;
2022-01-08 10:47:52 -08:00
# if defined (UNICODE)
2022-01-14 11:16:25 -08:00
unsigned short widePath [ MAX_PATH ] ;
len = GetModuleFileNameW ( NULL , widePath , MAX_PATH ) ;
len = WideCharToMultiByte ( 0 , 0 , widePath , len , appDir , MAX_PATH , NULL , NULL ) ;
2022-01-08 10:47:52 -08:00
# else
2022-01-14 11:16:25 -08:00
len = GetModuleFileNameA ( NULL , appDir , MAX_PATH ) ;
2022-01-08 10:47:52 -08:00
# endif
2022-01-14 11:16:25 -08:00
if ( len > 0 )
{
for ( int i = len ; i > = 0 ; - - i )
{
if ( appDir [ i ] = = ' \\ ' )
{
appDir [ i + 1 ] = ' \0 ' ;
2022-01-17 09:05:48 -08:00
break ;
2022-01-14 11:16:25 -08:00
}
}
}
else
{
appDir [ 0 ] = ' . ' ;
appDir [ 1 ] = ' \\ ' ;
}
2022-01-08 10:47:52 -08:00
# elif defined(__linux__)
2022-01-14 11:16:25 -08:00
unsigned int size = sizeof ( appDir ) ;
ssize_t len = readlink ( " /proc/self/exe " , appDir , size ) ;
if ( len > 0 )
{
for ( int i = len ; i > = 0 ; - - i )
{
if ( appDir [ i ] = = ' / ' )
{
appDir [ i + 1 ] = ' \0 ' ;
2022-01-17 09:05:48 -08:00
break ;
2022-01-14 11:16:25 -08:00
}
}
}
else
{
appDir [ 0 ] = ' . ' ;
appDir [ 1 ] = ' / ' ;
}
2022-01-08 10:47:52 -08:00
# elif defined(__APPLE__)
2022-01-14 11:16:25 -08:00
uint32_t size = sizeof ( appDir ) ;
if ( _NSGetExecutablePath ( appDir , & size ) = = 0 )
{
int len = strlen ( appDir ) ;
for ( int i = len ; i > = 0 ; - - i )
{
if ( appDir [ i ] = = ' / ' )
{
appDir [ i + 1 ] = ' \0 ' ;
2022-01-17 09:05:48 -08:00
break ;
2022-01-14 11:16:25 -08:00
}
}
}
else
{
appDir [ 0 ] = ' . ' ;
appDir [ 1 ] = ' / ' ;
}
2022-01-08 10:47:52 -08:00
# endif
return appDir ;
}
2022-06-06 20:39:37 +02:00
// Load directory filepaths
2022-06-11 23:24:13 +02:00
// NOTE: Base path is prepended to the scanned filepaths
// WARNING: Directory is scanned twice, first time to get files count
// No recursive scanning is done!
FilePathList LoadDirectoryFiles ( const char * dirPath )
2018-10-08 12:29:02 +02:00
{
2022-06-11 23:24:13 +02:00
FilePathList files = { 0 } ;
unsigned int fileCounter = 0 ;
2020-03-09 18:45:37 +01:00
struct dirent * entity ;
2018-10-08 12:29:02 +02:00
DIR * dir = opendir ( dirPath ) ;
2018-11-06 15:10:50 +01:00
2021-11-10 13:52:30 -05:00
if ( dir ! = NULL ) // It's a directory
2018-10-08 12:29:02 +02:00
{
2022-06-11 23:24:13 +02:00
// SCAN 1: Count files
while ( ( entity = readdir ( dir ) ) ! = NULL )
{
// NOTE: We skip '.' (current dir) and '..' (parent dir) filepaths
if ( ( strcmp ( entity - > d_name , " . " ) ! = 0 ) & & ( strcmp ( entity - > d_name , " .. " ) ! = 0 ) ) fileCounter + + ;
}
2021-11-10 13:52:30 -05:00
// Memory allocation for dirFileCount
2022-06-12 11:32:10 +02:00
files . capacity = fileCounter ;
files . paths = ( char * * ) RL_MALLOC ( files . capacity * sizeof ( char * ) ) ;
for ( int i = 0 ; i < files . capacity ; i + + ) files . paths [ i ] = ( char * ) RL_MALLOC ( MAX_FILEPATH_LENGTH * sizeof ( char ) ) ;
2018-11-06 15:10:50 +01:00
2018-10-08 12:29:02 +02:00
closedir ( dir ) ;
2022-06-11 23:24:13 +02:00
// SCAN 2: Read filepaths
// NOTE: Directory paths are also registered
ScanDirectoryFiles ( dirPath , & files , NULL ) ;
// Security check: read files.count should match fileCounter
2022-06-12 11:32:10 +02:00
if ( files . count ! = files . capacity ) TRACELOG ( LOG_WARNING , " FILEIO: Read files count do not match capacity allocated " ) ;
2018-10-08 12:29:02 +02:00
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " FILEIO: Failed to open requested directory " ) ; // Maybe it's a file...
2022-06-11 23:24:13 +02:00
return files ;
}
// Load directory filepaths with extension filtering and recursive directory scan
2022-06-12 11:32:10 +02:00
// NOTE: On recursive loading we do not pre-scan for file count, we use MAX_FILEPATH_CAPACITY
2022-06-11 23:24:13 +02:00
FilePathList LoadDirectoryFilesEx ( const char * basePath , const char * filter , bool scanSubdirs )
{
FilePathList files = { 0 } ;
2022-06-12 11:32:10 +02:00
files . capacity = MAX_FILEPATH_CAPACITY ;
files . paths = ( char * * ) RL_CALLOC ( files . capacity , sizeof ( char * ) ) ;
for ( int i = 0 ; i < files . capacity ; i + + ) files . paths [ i ] = ( char * ) RL_CALLOC ( MAX_FILEPATH_LENGTH , sizeof ( char ) ) ;
2022-06-11 23:24:13 +02:00
// WARNING: basePath is always prepended to scanned paths
if ( scanSubdirs ) ScanDirectoryFilesRecursively ( basePath , & files , filter ) ;
else ScanDirectoryFiles ( basePath , & files , filter ) ;
return files ;
2018-10-08 12:29:02 +02:00
}
2022-06-06 20:39:37 +02:00
// Unload directory filepaths
2022-06-11 23:24:13 +02:00
void UnloadDirectoryFiles ( FilePathList files )
2018-10-08 12:29:02 +02:00
{
2022-06-12 11:32:10 +02:00
if ( files . capacity > 0 )
2019-10-23 00:46:41 +02:00
{
2022-06-12 11:32:10 +02:00
for ( int i = 0 ; i < files . capacity ; i + + ) RL_FREE ( files . paths [ i ] ) ;
2018-10-08 12:29:02 +02:00
2022-06-11 23:24:13 +02:00
RL_FREE ( files . paths ) ;
2019-10-23 00:46:41 +02:00
}
2018-10-08 12:29:02 +02:00
}
2020-11-01 19:06:21 +01:00
// Change working directory, returns true on success
bool ChangeDirectory ( const char * dir )
2017-05-11 16:24:40 +02:00
{
2020-11-01 18:14:55 +01:00
bool result = CHDIR ( dir ) ;
2020-11-03 23:47:33 +01:00
2020-11-01 18:14:55 +01:00
if ( result ! = 0 ) TRACELOG ( LOG_WARNING , " SYSTEM: Failed to change to directory: %s " , dir ) ;
2020-11-03 23:47:33 +01:00
2020-11-01 19:06:21 +01:00
return ( result = = 0 ) ;
2017-05-11 16:24:40 +02:00
}
2022-06-11 23:24:13 +02:00
// Check if a given path point to a file
bool IsPathFile ( const char * path )
{
struct stat pathStat = { 0 } ;
stat ( path , & pathStat ) ;
return S_ISREG ( pathStat . st_mode ) ;
}
2017-05-09 22:03:46 +02:00
// Check if a file has been dropped into window
2015-07-29 21:44:27 +02:00
bool IsFileDropped ( void )
{
2021-09-01 23:09:30 +02:00
if ( CORE . Window . dropFileCount > 0 ) return true ;
2015-07-29 21:44:27 +02:00
else return false ;
}
2022-06-06 20:39:37 +02:00
// Load dropped filepaths
2022-06-11 23:24:13 +02:00
FilePathList LoadDroppedFiles ( void )
2015-07-29 21:44:27 +02:00
{
2022-06-11 23:24:13 +02:00
FilePathList files = { 0 } ;
2022-06-17 12:06:58 +02:00
files . count = CORE . Window . dropFileCount ;
files . paths = CORE . Window . dropFilepaths ;
2022-06-11 23:24:13 +02:00
return files ;
2015-07-29 21:44:27 +02:00
}
2022-06-06 20:39:37 +02:00
// Unload dropped filepaths
2022-06-11 23:24:13 +02:00
void UnloadDroppedFiles ( FilePathList files )
2015-07-29 21:44:27 +02:00
{
2022-06-17 12:06:58 +02:00
// WARNING: files pointers are the same as internal ones
2022-06-11 23:24:13 +02:00
if ( files . count > 0 )
2015-07-29 21:44:27 +02:00
{
2022-06-11 23:24:13 +02:00
for ( int i = 0 ; i < files . count ; i + + ) RL_FREE ( files . paths [ i ] ) ;
2016-08-16 11:09:55 +02:00
2022-06-11 23:24:13 +02:00
RL_FREE ( files . paths ) ;
2022-06-17 12:06:58 +02:00
CORE . Window . dropFileCount = 0 ;
CORE . Window . dropFilepaths = NULL ;
2015-07-29 21:44:27 +02:00
}
2018-04-29 11:49:10 +02:00
}
2015-07-29 21:44:27 +02:00
2018-10-13 15:59:17 +02:00
// Get file modification time (last write time)
2018-11-26 17:15:00 +01:00
long GetFileModTime ( const char * fileName )
2018-10-12 13:53:36 +01:00
{
2018-10-13 15:59:17 +02:00
struct stat result = { 0 } ;
2018-11-06 15:10:50 +01:00
2018-10-12 13:53:36 +01:00
if ( stat ( fileName , & result ) = = 0 )
{
time_t mod = result . st_mtime ;
2018-11-06 15:10:50 +01:00
2018-10-13 15:59:17 +02:00
return ( long ) mod ;
2018-10-12 13:53:36 +01:00
}
2018-11-06 15:10:50 +01:00
2018-10-12 13:53:36 +01:00
return 0 ;
}
2022-05-07 18:04:34 +02:00
// Compress data (DEFLATE algorithm)
2022-04-06 20:50:50 +02:00
unsigned char * CompressData ( const unsigned char * data , int dataSize , int * compDataSize )
2019-09-09 21:56:16 +02:00
{
# define COMPRESSION_QUALITY_DEFLATE 8
2019-10-17 17:18:03 +02:00
2019-09-09 21:56:16 +02:00
unsigned char * compData = NULL ;
2019-10-17 17:18:03 +02:00
2019-09-09 21:56:16 +02:00
# if defined(SUPPORT_COMPRESSION_API)
2021-01-12 21:15:11 +01:00
// Compress data and generate a valid DEFLATE stream
struct sdefl sdefl = { 0 } ;
2022-04-06 20:50:50 +02:00
int bounds = sdefl_bound ( dataSize ) ;
2021-01-12 21:15:11 +01:00
compData = ( unsigned char * ) RL_CALLOC ( bounds , 1 ) ;
2022-04-06 20:50:50 +02:00
* compDataSize = sdeflate ( & sdefl , compData , data , dataSize , COMPRESSION_QUALITY_DEFLATE ) ; // Compression level 8, same as stbwi
2021-03-19 19:43:44 +01:00
2022-04-06 20:50:50 +02:00
TraceLog ( LOG_INFO , " SYSTEM: Compress data: Original size: %i -> Comp. size: %i " , dataSize , * compDataSize ) ;
2019-09-09 21:56:16 +02:00
# endif
return compData ;
}
2022-05-07 18:04:34 +02:00
// Decompress data (DEFLATE algorithm)
2022-04-06 20:50:50 +02:00
unsigned char * DecompressData ( const unsigned char * compData , int compDataSize , int * dataSize )
2019-09-09 21:56:16 +02:00
{
2021-02-05 14:35:43 +01:00
unsigned char * data = NULL ;
2019-10-17 17:18:03 +02:00
2019-09-09 21:56:16 +02:00
# if defined(SUPPORT_COMPRESSION_API)
2021-01-12 21:15:11 +01:00
// Decompress data from a valid DEFLATE stream
2021-01-14 20:42:01 +01:00
data = RL_CALLOC ( MAX_DECOMPRESSION_SIZE * 1024 * 1024 , 1 ) ;
2022-07-03 11:11:50 +02:00
int length = sinflate ( data , MAX_DECOMPRESSION_SIZE * 1024 * 1024 , compData , compDataSize ) ;
2021-02-05 13:52:01 +01:00
unsigned char * temp = RL_REALLOC ( data , length ) ;
2021-03-19 19:43:44 +01:00
2021-02-05 13:52:01 +01:00
if ( temp ! = NULL ) data = temp ;
else TRACELOG ( LOG_WARNING , " SYSTEM: Failed to re-allocate required decompression memory " ) ;
2021-03-19 19:43:44 +01:00
2022-04-06 20:50:50 +02:00
* dataSize = length ;
2021-01-12 21:15:11 +01:00
2022-04-06 20:50:50 +02:00
TraceLog ( LOG_INFO , " SYSTEM: Decompress data: Comp. size: %i -> Original size: %i " , compDataSize , * dataSize ) ;
2019-09-09 21:56:16 +02:00
# endif
2021-02-05 14:35:43 +01:00
return data ;
2019-09-09 21:56:16 +02:00
}
2021-10-18 14:10:51 +02:00
// Encode data to Base64 string
2022-04-06 20:50:50 +02:00
char * EncodeDataBase64 ( const unsigned char * data , int dataSize , int * outputSize )
2021-10-18 14:10:51 +02:00
{
static const unsigned char base64encodeTable [ ] = {
' A ' , ' B ' , ' C ' , ' D ' , ' E ' , ' F ' , ' G ' , ' H ' , ' I ' , ' J ' , ' K ' , ' L ' , ' M ' , ' N ' , ' O ' , ' P ' , ' Q ' , ' R ' , ' S ' , ' T ' , ' U ' , ' V ' , ' W ' , ' X ' ,
' Y ' , ' Z ' , ' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' , ' g ' , ' h ' , ' i ' , ' j ' , ' k ' , ' l ' , ' m ' , ' n ' , ' o ' , ' p ' , ' q ' , ' r ' , ' s ' , ' t ' , ' u ' , ' v ' ,
' w ' , ' x ' , ' y ' , ' z ' , ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' , ' 8 ' , ' 9 ' , ' + ' , ' / '
} ;
static const int modTable [ ] = { 0 , 2 , 1 } ;
2022-04-06 20:50:50 +02:00
* outputSize = 4 * ( ( dataSize + 2 ) / 3 ) ;
2021-10-18 14:10:51 +02:00
2022-04-06 20:50:50 +02:00
char * encodedData = RL_MALLOC ( * outputSize ) ;
2021-10-18 14:10:51 +02:00
if ( encodedData = = NULL ) return NULL ;
2022-04-06 20:50:50 +02:00
for ( int i = 0 , j = 0 ; i < dataSize ; )
2021-10-18 14:10:51 +02:00
{
2022-04-06 20:50:50 +02:00
unsigned int octetA = ( i < dataSize ) ? ( unsigned char ) data [ i + + ] : 0 ;
unsigned int octetB = ( i < dataSize ) ? ( unsigned char ) data [ i + + ] : 0 ;
unsigned int octetC = ( i < dataSize ) ? ( unsigned char ) data [ i + + ] : 0 ;
2021-10-18 14:10:51 +02:00
unsigned int triple = ( octetA < < 0x10 ) + ( octetB < < 0x08 ) + octetC ;
encodedData [ j + + ] = base64encodeTable [ ( triple > > 3 * 6 ) & 0x3F ] ;
encodedData [ j + + ] = base64encodeTable [ ( triple > > 2 * 6 ) & 0x3F ] ;
encodedData [ j + + ] = base64encodeTable [ ( triple > > 1 * 6 ) & 0x3F ] ;
encodedData [ j + + ] = base64encodeTable [ ( triple > > 0 * 6 ) & 0x3F ] ;
}
2022-04-06 20:50:50 +02:00
for ( int i = 0 ; i < modTable [ dataSize % 3 ] ; i + + ) encodedData [ * outputSize - 1 - i ] = ' = ' ; // Padding character
2021-10-18 14:10:51 +02:00
return encodedData ;
}
// Decode Base64 string data
2022-04-06 20:50:50 +02:00
unsigned char * DecodeDataBase64 ( const unsigned char * data , int * outputSize )
2021-10-18 14:10:51 +02:00
{
static const unsigned char base64decodeTable [ ] = {
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 62 , 0 , 0 , 0 , 63 , 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,
11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 0 , 0 , 0 , 0 , 0 , 0 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 ,
37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51
} ;
// Get output size of Base64 input data
2022-04-06 20:50:50 +02:00
int outSize = 0 ;
2021-10-18 14:10:51 +02:00
for ( int i = 0 ; data [ 4 * i ] ! = 0 ; i + + )
{
if ( data [ 4 * i + 3 ] = = ' = ' )
{
2022-04-06 20:50:50 +02:00
if ( data [ 4 * i + 2 ] = = ' = ' ) outSize + = 1 ;
else outSize + = 2 ;
2021-10-18 14:10:51 +02:00
}
2022-04-06 20:50:50 +02:00
else outSize + = 3 ;
2021-10-18 14:10:51 +02:00
}
// Allocate memory to store decoded Base64 data
2022-04-06 20:50:50 +02:00
unsigned char * decodedData = ( unsigned char * ) RL_MALLOC ( outSize ) ;
2021-10-18 14:10:51 +02:00
2022-04-06 20:50:50 +02:00
for ( int i = 0 ; i < outSize / 3 ; i + + )
2021-10-18 14:10:51 +02:00
{
unsigned char a = base64decodeTable [ ( int ) data [ 4 * i ] ] ;
unsigned char b = base64decodeTable [ ( int ) data [ 4 * i + 1 ] ] ;
unsigned char c = base64decodeTable [ ( int ) data [ 4 * i + 2 ] ] ;
unsigned char d = base64decodeTable [ ( int ) data [ 4 * i + 3 ] ] ;
decodedData [ 3 * i ] = ( a < < 2 ) | ( b > > 4 ) ;
decodedData [ 3 * i + 1 ] = ( b < < 4 ) | ( c > > 2 ) ;
decodedData [ 3 * i + 2 ] = ( c < < 6 ) | d ;
}
2022-04-06 20:50:50 +02:00
if ( outSize % 3 = = 1 )
2021-10-18 14:10:51 +02:00
{
2022-04-06 20:50:50 +02:00
int n = outSize / 3 ;
2021-10-18 14:10:51 +02:00
unsigned char a = base64decodeTable [ ( int ) data [ 4 * n ] ] ;
unsigned char b = base64decodeTable [ ( int ) data [ 4 * n + 1 ] ] ;
2022-04-06 20:50:50 +02:00
decodedData [ outSize - 1 ] = ( a < < 2 ) | ( b > > 4 ) ;
2021-10-18 14:10:51 +02:00
}
2022-04-06 20:50:50 +02:00
else if ( outSize % 3 = = 2 )
2021-10-18 14:10:51 +02:00
{
2022-04-06 20:50:50 +02:00
int n = outSize / 3 ;
2021-10-18 14:10:51 +02:00
unsigned char a = base64decodeTable [ ( int ) data [ 4 * n ] ] ;
unsigned char b = base64decodeTable [ ( int ) data [ 4 * n + 1 ] ] ;
unsigned char c = base64decodeTable [ ( int ) data [ 4 * n + 2 ] ] ;
2022-04-06 20:50:50 +02:00
decodedData [ outSize - 2 ] = ( a < < 2 ) | ( b > > 4 ) ;
decodedData [ outSize - 1 ] = ( b < < 4 ) | ( c > > 2 ) ;
2021-10-18 14:10:51 +02:00
}
2022-04-06 20:50:50 +02:00
* outputSize = outSize ;
2021-10-18 14:10:51 +02:00
return decodedData ;
}
2018-11-09 23:09:02 +01:00
// Open URL with default system browser (if available)
2019-06-24 10:48:46 -03:00
// NOTE: This function is only safe to use if you control the URL given.
2018-11-12 12:32:41 +01:00
// A user could craft a malicious string performing another action.
2018-11-12 14:59:31 +01:00
// Only call this function yourself not with user input or make sure to check the string yourself.
2020-11-23 00:49:27 +01:00
// Ref: https://github.com/raysan5/raylib/issues/686
2018-11-09 23:09:02 +01:00
void OpenURL ( const char * url )
{
2019-01-23 20:07:47 -05:00
// Small security check trying to avoid (partially) malicious code...
2018-11-12 14:59:31 +01:00
// sorry for the inconvenience when you hit this point...
2018-11-13 10:53:49 +01:00
if ( strchr ( url , ' \' ' ) ! = NULL )
2018-11-12 14:59:31 +01:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " SYSTEM: Provided URL is not valid " ) ;
2019-01-23 20:07:47 -05:00
}
else
2019-01-05 18:03:09 +01:00
{
2020-02-21 01:13:41 +01:00
# if defined(PLATFORM_DESKTOP)
2019-04-23 14:55:35 +02:00
char * cmd = ( char * ) RL_CALLOC ( strlen ( url ) + 10 , sizeof ( char ) ) ;
2020-02-21 01:13:41 +01:00
# if defined(_WIN32)
2022-03-14 15:31:37 +01:00
sprintf ( cmd , " explorer \" %s \" " , url ) ;
2021-03-02 12:45:23 +01:00
# endif
2022-05-16 19:24:16 +02:00
# if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
2018-11-12 14:59:31 +01:00
sprintf ( cmd , " xdg-open '%s' " , url ) ; // Alternatives: firefox, x-www-browser
2021-03-02 12:45:23 +01:00
# endif
# if defined(__APPLE__)
2018-11-12 14:59:31 +01:00
sprintf ( cmd , " open '%s' " , url ) ;
2020-02-21 01:13:41 +01:00
# endif
2021-12-06 12:02:57 +01:00
int result = system ( cmd ) ;
2021-12-16 00:19:09 +01:00
if ( result = = - 1 ) TRACELOG ( LOG_WARNING , " OpenURL() child process could not be created " ) ;
2019-04-23 14:55:35 +02:00
RL_FREE ( cmd ) ;
2020-02-21 01:13:41 +01:00
# endif
# if defined(PLATFORM_WEB)
emscripten_run_script ( TextFormat ( " window.open('%s', '_blank') " , url ) ) ;
2022-03-18 07:41:41 -03:00
# endif
# if defined(PLATFORM_ANDROID)
JNIEnv * env = NULL ;
JavaVM * vm = CORE . Android . app - > activity - > vm ;
( * vm ) - > AttachCurrentThread ( vm , & env , NULL ) ;
jstring urlString = ( * env ) - > NewStringUTF ( env , url ) ;
jclass uriClass = ( * env ) - > FindClass ( env , " android/net/Uri " ) ;
jmethodID uriParse = ( * env ) - > GetStaticMethodID ( env , uriClass , " parse " , " (Ljava/lang/String;)Landroid/net/Uri; " ) ;
jobject uri = ( * env ) - > CallStaticObjectMethod ( env , uriClass , uriParse , urlString ) ;
jclass intentClass = ( * env ) - > FindClass ( env , " android/content/Intent " ) ;
jfieldID actionViewId = ( * env ) - > GetStaticFieldID ( env , intentClass , " ACTION_VIEW " , " Ljava/lang/String; " ) ;
jobject actionView = ( * env ) - > GetStaticObjectField ( env , intentClass , actionViewId ) ;
jmethodID newIntent = ( * env ) - > GetMethodID ( env , intentClass , " <init> " , " (Ljava/lang/String;Landroid/net/Uri;)V " ) ;
jobject intent = ( * env ) - > AllocObject ( env , intentClass ) ;
( * env ) - > CallVoidMethod ( env , intent , newIntent , actionView , uri ) ;
jclass activityClass = ( * env ) - > FindClass ( env , " android/app/Activity " ) ;
jmethodID startActivity = ( * env ) - > GetMethodID ( env , activityClass , " startActivity " , " (Landroid/content/Intent;)V " ) ;
( * env ) - > CallVoidMethod ( env , CORE . Android . app - > activity - > clazz , startActivity , intent ) ;
( * vm ) - > DetachCurrentThread ( vm ) ;
2020-02-21 01:13:41 +01:00
# endif
2018-11-12 14:59:31 +01:00
}
2018-11-09 23:09:02 +01:00
}
2013-11-18 23:38:44 +01:00
//----------------------------------------------------------------------------------
// Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions
//----------------------------------------------------------------------------------
2021-06-10 17:49:55 +02:00
// Check if a key has been pressed once
2013-11-18 23:38:44 +01:00
bool IsKeyPressed ( int key )
2014-09-03 16:51:28 +02:00
{
2014-04-09 20:25:26 +02:00
bool pressed = false ;
2013-11-28 19:59:56 +01:00
2020-03-03 16:10:31 +01:00
if ( ( CORE . Input . Keyboard . previousKeyState [ key ] = = 0 ) & & ( CORE . Input . Keyboard . currentKeyState [ key ] = = 1 ) ) pressed = true ;
2014-09-03 16:51:28 +02:00
2014-04-09 20:25:26 +02:00
return pressed ;
2013-11-28 19:59:56 +01:00
}
2021-06-10 17:49:55 +02:00
// Check if a key is being pressed (key held down)
2013-11-28 19:59:56 +01:00
bool IsKeyDown ( int key )
2013-11-18 23:38:44 +01:00
{
2020-02-29 22:10:23 +01:00
if ( CORE . Input . Keyboard . currentKeyState [ key ] = = 1 ) return true ;
2013-11-23 13:30:54 +01:00
else return false ;
2013-11-18 23:38:44 +01:00
}
2021-06-10 17:49:55 +02:00
// Check if a key has been released once
2013-11-18 23:38:44 +01:00
bool IsKeyReleased ( int key )
2014-09-03 16:51:28 +02:00
{
2014-04-09 20:25:26 +02:00
bool released = false ;
2017-01-28 23:02:30 +01:00
2020-03-03 16:10:31 +01:00
if ( ( CORE . Input . Keyboard . previousKeyState [ key ] = = 1 ) & & ( CORE . Input . Keyboard . currentKeyState [ key ] = = 0 ) ) released = true ;
2014-09-03 16:51:28 +02:00
2014-04-09 20:25:26 +02:00
return released ;
2013-11-28 19:59:56 +01:00
}
2021-06-10 17:49:55 +02:00
// Check if a key is NOT being pressed (key not held down)
2013-11-28 19:59:56 +01:00
bool IsKeyUp ( int key )
2013-11-18 23:38:44 +01:00
{
2020-02-29 22:10:23 +01:00
if ( CORE . Input . Keyboard . currentKeyState [ key ] = = 0 ) return true ;
2013-11-23 13:30:54 +01:00
else return false ;
2013-11-18 23:38:44 +01:00
}
2015-01-04 18:05:50 +01:00
// Get the last key pressed
int GetKeyPressed ( void )
{
2019-11-24 13:39:45 +01:00
int value = 0 ;
2015-01-04 18:05:50 +01:00
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Keyboard . keyPressedQueueCount > 0 )
2019-11-24 20:46:00 +09:00
{
2019-11-24 13:39:45 +01:00
// Get character from the queue head
2020-02-03 18:31:30 +01:00
value = CORE . Input . Keyboard . keyPressedQueue [ 0 ] ;
2019-11-24 20:46:00 +09:00
2019-11-24 13:39:45 +01:00
// Shift elements 1 step toward the head.
2020-12-23 15:03:26 +01:00
for ( int i = 0 ; i < ( CORE . Input . Keyboard . keyPressedQueueCount - 1 ) ; i + + )
2020-12-18 18:58:02 +01:00
CORE . Input . Keyboard . keyPressedQueue [ i ] = CORE . Input . Keyboard . keyPressedQueue [ i + 1 ] ;
2019-11-24 20:46:00 +09:00
2019-11-24 13:39:45 +01:00
// Reset last character in the queue
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = 0 ;
CORE . Input . Keyboard . keyPressedQueueCount - - ;
2019-11-24 13:39:45 +01:00
}
2019-11-24 20:46:00 +09:00
2019-11-24 13:39:45 +01:00
return value ;
2019-11-24 20:46:00 +09:00
}
2020-12-18 18:58:02 +01:00
// Get the last char pressed
int GetCharPressed ( void )
{
int value = 0 ;
if ( CORE . Input . Keyboard . charPressedQueueCount > 0 )
{
// Get character from the queue head
value = CORE . Input . Keyboard . charPressedQueue [ 0 ] ;
// Shift elements 1 step toward the head.
2020-12-23 15:03:26 +01:00
for ( int i = 0 ; i < ( CORE . Input . Keyboard . charPressedQueueCount - 1 ) ; i + + )
2020-12-18 18:58:02 +01:00
CORE . Input . Keyboard . charPressedQueue [ i ] = CORE . Input . Keyboard . charPressedQueue [ i + 1 ] ;
// Reset last character in the queue
CORE . Input . Keyboard . charPressedQueue [ CORE . Input . Keyboard . charPressedQueueCount ] = 0 ;
CORE . Input . Keyboard . charPressedQueueCount - - ;
}
return value ;
}
2016-04-17 11:19:32 +02:00
// Set a custom key to exit program
// NOTE: default exitKey is ESCAPE
void SetExitKey ( int key )
2014-01-28 21:21:29 +01:00
{
2016-10-17 18:18:13 +02:00
# if !defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . exitKey = key ;
2015-02-03 05:47:28 +03:00
# endif
}
2016-02-18 14:05:48 +01:00
// NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB)
2021-06-10 17:49:55 +02:00
// Check if a gamepad is available
2013-11-18 23:38:44 +01:00
bool IsGamepadAvailable ( int gamepad )
{
2016-02-18 14:05:48 +01:00
bool result = false ;
2017-01-28 23:02:30 +01:00
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] ) result = true ;
2014-09-03 16:51:28 +02:00
2016-02-18 14:05:48 +01:00
return result ;
2013-11-18 23:38:44 +01:00
}
2021-06-10 17:49:55 +02:00
// Get gamepad internal name id
2016-10-14 00:47:43 +02:00
const char * GetGamepadName ( int gamepad )
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Gamepad . ready [ gamepad ] ) return glfwGetJoystickName ( gamepad ) ;
2016-10-14 00:47:43 +02:00
else return NULL ;
2021-03-02 12:45:23 +01:00
# endif
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-09-12 12:02:54 -04:00
if ( CORE . Input . Gamepad . ready [ gamepad ] ) ioctl ( CORE . Input . Gamepad . streamId [ gamepad ] , JSIOCGNAME ( 64 ) , & CORE . Input . Gamepad . name [ gamepad ] ) ;
return CORE . Input . Gamepad . name [ gamepad ] ;
# endif
# if defined(PLATFORM_WEB)
return CORE . Input . Gamepad . name [ gamepad ] ;
2016-10-14 00:47:43 +02:00
# endif
2021-03-02 12:45:23 +01:00
return NULL ;
2016-10-14 00:47:43 +02:00
}
2021-06-10 17:49:55 +02:00
// Get gamepad axis count
2016-11-01 14:39:57 +01:00
int GetGamepadAxisCount ( int gamepad )
{
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2016-11-02 13:39:48 +01:00
int axisCount = 0 ;
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Gamepad . ready [ gamepad ] ) ioctl ( CORE . Input . Gamepad . streamId [ gamepad ] , JSIOCGAXES , & axisCount ) ;
CORE . Input . Gamepad . axisCount = axisCount ;
2016-11-02 13:39:48 +01:00
# endif
2021-01-31 03:07:26 +01:00
2020-02-03 18:31:30 +01:00
return CORE . Input . Gamepad . axisCount ;
2016-11-01 14:39:57 +01:00
}
2021-06-10 17:49:55 +02:00
// Get axis movement vector for a gamepad
2016-03-16 17:52:09 +01:00
float GetGamepadAxisMovement ( int gamepad , int axis )
2013-11-18 23:38:44 +01:00
{
2016-03-16 17:52:09 +01:00
float value = 0 ;
2017-01-28 23:02:30 +01:00
2020-05-09 12:39:41 +02:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( axis < MAX_GAMEPAD_AXIS ) & &
2021-01-31 03:07:26 +01:00
( fabsf ( CORE . Input . Gamepad . axisState [ gamepad ] [ axis ] ) > 0.1f ) ) value = CORE . Input . Gamepad . axisState [ gamepad ] [ axis ] ; // 0.1f = GAMEPAD_AXIS_MINIMUM_DRIFT/DELTA
2013-11-23 13:30:54 +01:00
2016-03-16 17:52:09 +01:00
return value ;
2013-11-18 23:38:44 +01:00
}
2021-06-10 17:49:55 +02:00
// Check if a gamepad button has been pressed once
2013-11-18 23:38:44 +01:00
bool IsGamepadButtonPressed ( int gamepad , int button )
2013-11-28 19:59:56 +01:00
{
2014-04-09 20:25:26 +02:00
bool pressed = false ;
2016-10-31 13:56:57 +01:00
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( button < MAX_GAMEPAD_BUTTONS ) & &
2021-06-10 17:11:31 +02:00
( CORE . Input . Gamepad . previousButtonState [ gamepad ] [ button ] = = 0 ) & & ( CORE . Input . Gamepad . currentButtonState [ gamepad ] [ button ] = = 1 ) ) pressed = true ;
2014-09-03 16:51:28 +02:00
2014-04-09 20:25:26 +02:00
return pressed ;
2013-11-28 19:59:56 +01:00
}
2021-06-10 17:49:55 +02:00
// Check if a gamepad button is being pressed
2013-11-28 19:59:56 +01:00
bool IsGamepadButtonDown ( int gamepad , int button )
2013-11-18 23:38:44 +01:00
{
2016-02-18 14:05:48 +01:00
bool result = false ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( button < MAX_GAMEPAD_BUTTONS ) & &
2021-06-10 17:11:31 +02:00
( CORE . Input . Gamepad . currentButtonState [ gamepad ] [ button ] = = 1 ) ) result = true ;
2016-08-16 11:09:55 +02:00
2016-02-18 14:05:48 +01:00
return result ;
2013-11-18 23:38:44 +01:00
}
2021-06-10 17:49:55 +02:00
// Check if a gamepad button has NOT been pressed once
2013-11-18 23:38:44 +01:00
bool IsGamepadButtonReleased ( int gamepad , int button )
2013-11-28 19:59:56 +01:00
{
2014-04-09 20:25:26 +02:00
bool released = false ;
2017-01-28 23:02:30 +01:00
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( button < MAX_GAMEPAD_BUTTONS ) & &
2021-06-10 17:11:31 +02:00
( CORE . Input . Gamepad . previousButtonState [ gamepad ] [ button ] = = 1 ) & & ( CORE . Input . Gamepad . currentButtonState [ gamepad ] [ button ] = = 0 ) ) released = true ;
2013-11-28 19:59:56 +01:00
2014-04-09 20:25:26 +02:00
return released ;
2013-11-28 19:59:56 +01:00
}
2021-06-10 17:49:55 +02:00
// Check if a gamepad button is NOT being pressed
2013-11-28 19:59:56 +01:00
bool IsGamepadButtonUp ( int gamepad , int button )
2013-11-18 23:38:44 +01:00
{
2016-02-18 14:05:48 +01:00
bool result = false ;
2014-09-03 16:51:28 +02:00
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( button < MAX_GAMEPAD_BUTTONS ) & &
2021-06-10 17:11:31 +02:00
( CORE . Input . Gamepad . currentButtonState [ gamepad ] [ button ] = = 0 ) ) result = true ;
2014-09-16 22:51:31 +02:00
2016-02-18 14:05:48 +01:00
return result ;
}
2016-10-27 13:41:43 +02:00
// Get the last gamepad button pressed
int GetGamepadButtonPressed ( void )
{
2020-02-03 18:31:30 +01:00
return CORE . Input . Gamepad . lastButtonPressed ;
2016-10-27 13:41:43 +02:00
}
2021-01-21 14:39:03 +01:00
// Set internal gamepad mappings
int SetGamepadMappings ( const char * mappings )
{
2021-01-28 18:37:52 +01:00
int result = 0 ;
2021-01-21 14:39:03 +01:00
# if defined(PLATFORM_DESKTOP)
2021-01-28 18:37:52 +01:00
result = glfwUpdateGamepadMappings ( mappings ) ;
2021-01-21 14:39:03 +01:00
# endif
2021-01-28 18:37:52 +01:00
return result ;
2021-01-21 14:39:03 +01:00
}
2021-06-10 17:49:55 +02:00
// Check if a mouse button has been pressed once
2016-04-17 11:19:32 +02:00
bool IsMouseButtonPressed ( int button )
{
bool pressed = false ;
2016-08-16 11:09:55 +02:00
2020-03-03 14:58:54 +01:00
if ( ( CORE . Input . Mouse . currentButtonState [ button ] = = 1 ) & & ( CORE . Input . Mouse . previousButtonState [ button ] = = 0 ) ) pressed = true ;
2020-02-29 22:10:23 +01:00
// Map touches to mouse buttons checking
2020-03-03 14:58:54 +01:00
if ( ( CORE . Input . Touch . currentTouchState [ button ] = = 1 ) & & ( CORE . Input . Touch . previousTouchState [ button ] = = 0 ) ) pressed = true ;
2020-01-24 19:45:51 +01:00
2016-04-17 11:19:32 +02:00
return pressed ;
}
2021-06-10 17:49:55 +02:00
// Check if a mouse button is being pressed
2016-04-17 11:19:32 +02:00
bool IsMouseButtonDown ( int button )
{
bool down = false ;
2016-08-16 11:09:55 +02:00
2020-03-03 14:58:54 +01:00
if ( CORE . Input . Mouse . currentButtonState [ button ] = = 1 ) down = true ;
2020-02-29 22:10:23 +01:00
// Map touches to mouse buttons checking
if ( CORE . Input . Touch . currentTouchState [ button ] = = 1 ) down = true ;
2016-08-16 11:09:55 +02:00
2016-04-17 11:19:32 +02:00
return down ;
}
2021-06-10 17:49:55 +02:00
// Check if a mouse button has been released once
2016-04-17 11:19:32 +02:00
bool IsMouseButtonReleased ( int button )
{
bool released = false ;
2016-08-16 11:09:55 +02:00
2020-03-03 14:58:54 +01:00
if ( ( CORE . Input . Mouse . currentButtonState [ button ] = = 0 ) & & ( CORE . Input . Mouse . previousButtonState [ button ] = = 1 ) ) released = true ;
2020-03-25 19:41:51 +01:00
2020-02-29 22:10:23 +01:00
// Map touches to mouse buttons checking
2020-03-03 14:58:54 +01:00
if ( ( CORE . Input . Touch . currentTouchState [ button ] = = 0 ) & & ( CORE . Input . Touch . previousTouchState [ button ] = = 1 ) ) released = true ;
2016-04-17 11:19:32 +02:00
return released ;
}
2021-06-10 17:49:55 +02:00
// Check if a mouse button is NOT being pressed
2016-04-17 11:19:32 +02:00
bool IsMouseButtonUp ( int button )
{
2020-03-24 23:23:34 +11:00
return ! IsMouseButtonDown ( button ) ;
2016-04-17 11:19:32 +02:00
}
2021-06-10 17:43:58 +02:00
// Get mouse position X
2016-04-17 11:19:32 +02:00
int GetMouseX ( void )
{
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
return ( int ) CORE . Input . Touch . position [ 0 ] . x ;
2016-04-17 11:19:32 +02:00
# else
2021-06-10 18:03:25 +02:00
return ( int ) ( ( CORE . Input . Mouse . currentPosition . x + CORE . Input . Mouse . offset . x ) * CORE . Input . Mouse . scale . x ) ;
2016-04-17 11:19:32 +02:00
# endif
}
2021-06-10 17:43:58 +02:00
// Get mouse position Y
2016-04-17 11:19:32 +02:00
int GetMouseY ( void )
{
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
return ( int ) CORE . Input . Touch . position [ 0 ] . y ;
2016-04-17 11:19:32 +02:00
# else
2021-06-10 18:03:25 +02:00
return ( int ) ( ( CORE . Input . Mouse . currentPosition . y + CORE . Input . Mouse . offset . y ) * CORE . Input . Mouse . scale . y ) ;
2016-04-17 11:19:32 +02:00
# endif
}
2021-06-10 17:43:58 +02:00
// Get mouse position XY
2016-04-17 11:19:32 +02:00
Vector2 GetMousePosition ( void )
{
2020-02-29 22:10:23 +01:00
Vector2 position = { 0 } ;
2019-05-02 09:46:01 +02:00
2020-01-27 15:31:43 +01:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
2019-05-02 09:46:01 +02:00
position = GetTouchPosition ( 0 ) ;
2016-04-17 11:19:32 +02:00
# else
2021-06-10 18:03:25 +02:00
position . x = ( CORE . Input . Mouse . currentPosition . x + CORE . Input . Mouse . offset . x ) * CORE . Input . Mouse . scale . x ;
position . y = ( CORE . Input . Mouse . currentPosition . y + CORE . Input . Mouse . offset . y ) * CORE . Input . Mouse . scale . y ;
2016-04-17 11:19:32 +02:00
# endif
2019-05-08 18:33:09 +02:00
2019-05-02 09:46:01 +02:00
return position ;
2016-04-17 11:19:32 +02:00
}
2021-06-21 00:11:27 +02:00
// Get mouse delta between frames
Vector2 GetMouseDelta ( void )
{
Vector2 delta = { 0 } ;
delta . x = CORE . Input . Mouse . currentPosition . x - CORE . Input . Mouse . previousPosition . x ;
delta . y = CORE . Input . Mouse . currentPosition . y - CORE . Input . Mouse . previousPosition . y ;
return delta ;
}
2016-04-17 11:19:32 +02:00
// Set mouse position XY
2019-01-03 13:53:20 +01:00
void SetMousePosition ( int x , int y )
2016-04-17 11:19:32 +02:00
{
2021-06-10 18:03:25 +02:00
CORE . Input . Mouse . currentPosition = ( Vector2 ) { ( float ) x , ( float ) y } ;
2016-04-17 11:19:32 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// NOTE: emscripten not implemented
2021-06-10 18:03:25 +02:00
glfwSetCursorPos ( CORE . Window . handle , CORE . Input . Mouse . currentPosition . x , CORE . Input . Mouse . currentPosition . y ) ;
2016-04-17 11:19:32 +02:00
# endif
}
2019-01-03 13:53:20 +01:00
// Set mouse offset
2018-03-09 11:43:53 +01:00
// NOTE: Useful when rendering to different size targets
2019-01-03 13:53:20 +01:00
void SetMouseOffset ( int offsetX , int offsetY )
2018-03-09 11:43:53 +01:00
{
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . offset = ( Vector2 ) { ( float ) offsetX , ( float ) offsetY } ;
2019-01-02 10:14:55 +00:00
}
2018-03-09 11:43:53 +01:00
// Set mouse scaling
// NOTE: Useful when rendering to different size targets
2019-01-03 13:53:20 +01:00
void SetMouseScale ( float scaleX , float scaleY )
2018-03-09 11:43:53 +01:00
{
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . scale = ( Vector2 ) { scaleX , scaleY } ;
2018-03-09 11:43:53 +01:00
}
2021-06-10 17:43:58 +02:00
// Get mouse wheel movement Y
2020-10-06 05:16:23 +11:00
float GetMouseWheelMove ( void )
2016-04-17 11:19:32 +02:00
{
2022-06-12 20:51:31 +02:00
float result = 0.0f ;
# if !defined(PLATFORM_ANDROID)
if ( fabsf ( CORE . Input . Mouse . currentWheelMove . x ) > fabsf ( CORE . Input . Mouse . currentWheelMove . y ) ) result = ( float ) CORE . Input . Mouse . currentWheelMove . x ;
else result = ( float ) CORE . Input . Mouse . currentWheelMove . y ;
2021-03-02 12:45:23 +01:00
# endif
2022-06-12 11:30:07 -04:00
2021-03-02 12:45:23 +01:00
# if defined(PLATFORM_WEB)
2022-06-12 22:56:24 +02:00
result / = 100.0f ;
2022-06-12 11:30:07 -04:00
# endif
return result ;
}
// Get mouse wheel movement X/Y as a vector
Vector2 GetMouseWheelMoveV ( void )
{
# if defined(PLATFORM_ANDROID)
return ( Vector2 ) { 0.0f , 0.0f } ;
# endif
# if defined(PLATFORM_WEB)
Vector2 result = CORE . Input . Mouse . currentWheelMove ;
result . x / = 100.0f ;
result . y / = 100.0f ;
2016-04-17 11:19:32 +02:00
# endif
2021-03-02 12:45:23 +01:00
2022-01-01 17:49:07 +01:00
return CORE . Input . Mouse . currentWheelMove ;
2016-04-17 11:19:32 +02:00
}
2020-10-21 03:55:52 -05:00
// Set mouse cursor
// NOTE: This is a no-op on platforms other than PLATFORM_DESKTOP
2020-10-21 11:08:37 +02:00
void SetMouseCursor ( int cursor )
2020-10-21 03:55:52 -05:00
{
# if defined(PLATFORM_DESKTOP)
CORE . Input . Mouse . cursor = cursor ;
2020-10-21 11:08:37 +02:00
if ( cursor = = MOUSE_CURSOR_DEFAULT ) glfwSetCursor ( CORE . Window . handle , NULL ) ;
2020-10-21 03:55:52 -05:00
else
{
2020-10-21 11:08:37 +02:00
// NOTE: We are relating internal GLFW enum values to our MouseCursor enum values
glfwSetCursor ( CORE . Window . handle , glfwCreateStandardCursor ( 0x00036000 + cursor ) ) ;
2020-10-21 03:55:52 -05:00
}
# endif
}
2021-06-10 17:43:58 +02:00
// Get touch position X for touch point 0 (relative to screen size)
2015-10-30 11:30:32 +01:00
int GetTouchX ( void )
{
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
2020-02-03 18:31:30 +01:00
return ( int ) CORE . Input . Touch . position [ 0 ] . x ;
2020-09-27 10:18:43 +02:00
# else // PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM
2016-01-24 19:17:08 +01:00
return GetMouseX ( ) ;
# endif
2015-10-30 11:30:32 +01:00
}
2021-06-10 17:43:58 +02:00
// Get touch position Y for touch point 0 (relative to screen size)
2015-10-30 11:30:32 +01:00
int GetTouchY ( void )
{
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
2020-02-03 18:31:30 +01:00
return ( int ) CORE . Input . Touch . position [ 0 ] . y ;
2020-09-27 10:18:43 +02:00
# else // PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM
2016-01-24 19:17:08 +01:00
return GetMouseY ( ) ;
# endif
2015-10-30 11:30:32 +01:00
}
2021-06-10 17:43:58 +02:00
// Get touch position XY for a touch point index (relative to screen size)
2016-02-12 12:22:56 +01:00
// TODO: Touch position should be scaled depending on display size and render size
2016-02-10 10:31:06 +01:00
Vector2 GetTouchPosition ( int index )
2015-10-30 11:30:32 +01:00
{
2016-02-10 10:31:06 +01:00
Vector2 position = { - 1.0f , - 1.0f } ;
2016-08-16 11:09:55 +02:00
2021-03-02 12:45:23 +01:00
# if defined(PLATFORM_DESKTOP)
// TODO: GLFW does not support multi-touch input just yet
// https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
// https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
if ( index = = 0 ) position = GetMousePosition ( ) ;
# endif
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
if ( index < MAX_TOUCH_POINTS ) position = CORE . Input . Touch . position [ index ] ;
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " INPUT: Required touch point out of range (Max touch points: %i) " , MAX_TOUCH_POINTS) ;
2015-10-30 11:30:32 +01:00
2020-02-03 18:31:30 +01:00
if ( ( CORE . Window . screen . width > CORE . Window . display . width ) | | ( CORE . Window . screen . height > CORE . Window . display . height ) )
2015-10-30 11:30:32 +01:00
{
2020-02-03 18:31:30 +01:00
position . x = position . x * ( ( float ) CORE . Window . screen . width / ( float ) ( CORE . Window . display . width - CORE . Window . renderOffset . x ) ) - CORE . Window . renderOffset . x / 2 ;
position . y = position . y * ( ( float ) CORE . Window . screen . height / ( float ) ( CORE . Window . display . height - CORE . Window . renderOffset . y ) ) - CORE . Window . renderOffset . y / 2 ;
2015-10-30 11:30:32 +01:00
}
else
{
2020-02-03 18:31:30 +01:00
position . x = position . x * ( ( float ) CORE . Window . render . width / ( float ) CORE . Window . display . width ) - CORE . Window . renderOffset . x / 2 ;
position . y = position . y * ( ( float ) CORE . Window . render . height / ( float ) CORE . Window . display . height ) - CORE . Window . renderOffset . y / 2 ;
2015-10-30 11:30:32 +01:00
}
2021-03-02 12:45:23 +01:00
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-03-02 12:45:23 +01:00
if ( index < MAX_TOUCH_POINTS ) position = CORE . Input . Touch . position [ index ] ;
else TRACELOG ( LOG_WARNING , " INPUT: Required touch point out of range (Max touch points: %i) " , MAX_TOUCH_POINTS) ;
2016-01-24 19:17:08 +01:00
# endif
2015-10-30 11:30:32 +01:00
return position ;
}
2016-01-04 21:00:20 +01:00
2021-09-21 15:11:33 +02:00
// Get touch point identifier for given index
int GetTouchPointId ( int index )
{
int id = - 1 ;
2021-10-03 12:09:59 +02:00
2021-09-21 15:11:33 +02:00
if ( index < MAX_TOUCH_POINTS ) id = CORE . Input . Touch . pointId [ index ] ;
2021-10-03 12:09:59 +02:00
2021-09-21 15:11:33 +02:00
return id ;
}
2021-09-10 15:19:12 +02:00
// Get number of touch points
int GetTouchPointCount ( void )
{
return CORE . Input . Touch . pointCount ;
}
2013-11-18 23:38:44 +01:00
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
2014-09-16 22:51:31 +02:00
// 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
2018-02-04 12:26:28 +01:00
// NOTE: returns false in case graphic device could not be created
2018-02-03 12:12:50 +01:00
static bool InitGraphicsDevice ( int width , int height )
2014-09-16 22:51:31 +02:00
{
2020-02-03 18:31:30 +01:00
CORE . Window . screen . width = width ; // User desired width
CORE . Window . screen . height = height ; // User desired height
CORE . Window . screenScale = MatrixIdentity ( ) ; // No draw scaling required by default
2019-05-01 14:30:36 +02:00
2020-02-03 18:31:30 +01:00
// NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars...
2014-09-16 22:51:31 +02:00
// ...in top-down or left-right to match display aspect ratio (no weird scalings)
2014-12-15 01:08:30 +01:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2014-09-16 22:51:31 +02:00
glfwSetErrorCallback ( ErrorCallback ) ;
2021-11-01 01:08:55 +01:00
/*
// TODO: Setup GLFW custom allocators to match raylib ones
2021-08-22 01:08:11 +02:00
const GLFWallocator allocator = {
. allocate = MemAlloc ,
. deallocate = MemFree ,
. reallocate = MemRealloc ,
. user = NULL
} ;
glfwInitAllocator ( & allocator ) ;
2021-11-01 01:08:55 +01:00
*/
2018-07-29 18:24:46 +02:00
# if defined(__APPLE__)
glfwInitHint ( GLFW_COCOA_CHDIR_RESOURCES , GLFW_FALSE ) ;
# endif
2018-02-03 12:12:50 +01:00
if ( ! glfwInit ( ) )
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " GLFW: Failed to initialize GLFW " ) ;
2018-02-03 12:12:50 +01:00
return false ;
}
2014-09-16 22:51:31 +02:00
2014-12-15 01:08:30 +01:00
// NOTE: Getting video modes is not implemented in emscripten GLFW3 version
# if defined(PLATFORM_DESKTOP)
2014-09-16 22:51:31 +02:00
// Find monitor resolution
2018-02-08 12:00:27 +01:00
GLFWmonitor * monitor = glfwGetPrimaryMonitor ( ) ;
if ( ! monitor )
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " GLFW: Failed to get primary monitor " ) ;
2018-02-08 12:00:27 +01:00
return false ;
}
const GLFWvidmode * mode = glfwGetVideoMode ( monitor ) ;
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
CORE . Window . display . width = mode - > width ;
CORE . Window . display . height = mode - > height ;
2014-09-16 22:51:31 +02:00
2021-05-30 18:33:38 +02:00
// Set screen width/height to the display width/height if they are 0
2020-12-31 13:29:35 +01:00
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 ;
2019-04-28 16:45:23 +02:00
# endif // PLATFORM_DESKTOP
2016-04-17 11:19:32 +02:00
# if defined(PLATFORM_WEB)
2020-02-03 18:31:30 +01:00
CORE . Window . display . width = CORE . Window . screen . width ;
CORE . Window . display . height = CORE . Window . screen . height ;
2019-04-28 16:45:23 +02:00
# endif // PLATFORM_WEB
2015-02-02 00:57:08 +01:00
2020-11-23 00:49:27 +01:00
glfwDefaultWindowHints ( ) ; // Set default windows hints
2018-06-02 18:26:57 +02:00
//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
2014-09-16 22:51:31 +02:00
2020-11-23 00:49:27 +01:00
// Check window creation flags
if ( ( CORE . Window . flags & FLAG_FULLSCREEN_MODE ) > 0 ) CORE . Window . fullscreen = true ;
2020-11-23 23:46:05 +01:00
if ( ( CORE . Window . flags & FLAG_WINDOW_HIDDEN ) > 0 ) glfwWindowHint ( GLFW_VISIBLE , GLFW_FALSE ) ; // Visible window
2020-04-05 17:50:37 +02:00
else glfwWindowHint ( GLFW_VISIBLE , GLFW_TRUE ) ; // Window initially hidden
2020-12-23 15:03:26 +01:00
2020-11-23 23:46:05 +01:00
if ( ( CORE . Window . flags & FLAG_WINDOW_UNDECORATED ) > 0 ) glfwWindowHint ( GLFW_DECORATED , GLFW_FALSE ) ; // Border and buttons on Window
2020-11-23 00:49:27 +01:00
else glfwWindowHint ( GLFW_DECORATED , GLFW_TRUE ) ; // Decorated window
2019-01-10 14:54:55 +01:00
2020-11-23 23:46:05 +01:00
if ( ( CORE . Window . flags & FLAG_WINDOW_RESIZABLE ) > 0 ) glfwWindowHint ( GLFW_RESIZABLE , GLFW_TRUE ) ; // Resizable window
2020-04-05 17:50:37 +02:00
else glfwWindowHint ( GLFW_RESIZABLE , GLFW_FALSE ) ; // Avoid window being resizable
2020-12-23 15:03:26 +01:00
2020-12-03 20:16:35 +01:00
// 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 ;
2020-11-23 00:49:27 +01:00
if ( ( CORE . Window . flags & FLAG_WINDOW_UNFOCUSED ) > 0 ) glfwWindowHint ( GLFW_FOCUSED , GLFW_FALSE ) ;
else glfwWindowHint ( GLFW_FOCUSED , GLFW_TRUE ) ;
2020-12-23 15:03:26 +01:00
2020-11-23 00:49:27 +01:00
if ( ( CORE . Window . flags & FLAG_WINDOW_TOPMOST ) > 0 ) glfwWindowHint ( GLFW_FLOATING , GLFW_TRUE ) ;
else glfwWindowHint ( GLFW_FLOATING , GLFW_FALSE ) ;
2017-03-05 10:55:29 +01:00
2020-11-23 00:49:27 +01:00
// 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
2018-06-02 18:26:57 +02:00
else glfwWindowHint ( GLFW_TRANSPARENT_FRAMEBUFFER , GLFW_FALSE ) ; // Opaque framebuffer
2020-11-23 00:49:27 +01:00
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
2021-03-20 13:02:44 +01:00
# if defined(__APPLE__)
2020-11-23 00:49:27 +01:00
glfwWindowHint ( GLFW_COCOA_RETINA_FRAMEBUFFER , GLFW_TRUE ) ;
# endif
}
else glfwWindowHint ( GLFW_SCALE_TO_MONITOR , GLFW_FALSE ) ;
2022-06-11 12:08:16 +02:00
// Mouse passthrough
if ( ( CORE . Window . flags & FLAG_WINDOW_MOUSE_PASSTHROUGH ) > 0 ) glfwWindowHint ( GLFW_MOUSE_PASSTHROUGH , GLFW_TRUE ) ;
else glfwWindowHint ( GLFW_MOUSE_PASSTHROUGH , GLFW_FALSE ) ;
2018-06-12 13:21:36 +02:00
# endif
2017-01-28 23:02:30 +01:00
2021-03-19 19:43:44 +01:00
if ( CORE . Window . flags & FLAG_MSAA_4X_HINT )
2021-01-31 03:07:26 +01:00
{
2021-03-20 13:02:44 +01:00
// NOTE: MSAA is only enabled for main framebuffer, not user-created FBOs
2021-01-31 03:07:26 +01:00
TRACELOG ( LOG_INFO , " DISPLAY: Trying to enable MSAA x4 " ) ;
glfwWindowHint ( GLFW_SAMPLES , 4 ) ; // Tries to enable multisampling x4 (MSAA), default is 0
}
2018-07-29 07:51:17 +02:00
2015-02-02 00:57:08 +01:00
// NOTE: When asking for an OpenGL context version, most drivers provide highest supported version
2014-09-16 22:51:31 +02:00
// with forward compatibility to older OpenGL versions.
2017-03-05 10:55:29 +01:00
// For example, if using OpenGL 1.1, driver can provide a 4.3 context forward compatible.
2015-02-02 00:57:08 +01:00
2016-06-16 20:25:50 +02:00
// Check selection OpenGL version
if ( rlGetVersion ( ) = = OPENGL_21 )
{
2018-12-24 17:09:46 +01:00
glfwWindowHint ( GLFW_CONTEXT_VERSION_MAJOR , 2 ) ; // Choose OpenGL major version (just hint)
glfwWindowHint ( GLFW_CONTEXT_VERSION_MINOR , 1 ) ; // Choose OpenGL minor version (just hint)
2016-06-16 20:25:50 +02:00
}
else if ( rlGetVersion ( ) = = OPENGL_33 )
{
2018-12-24 17:09:46 +01:00
glfwWindowHint ( GLFW_CONTEXT_VERSION_MAJOR , 3 ) ; // Choose OpenGL major version (just hint)
glfwWindowHint ( GLFW_CONTEXT_VERSION_MINOR , 3 ) ; // Choose OpenGL minor version (just hint)
2015-10-06 17:13:40 +02:00
glfwWindowHint ( GLFW_OPENGL_PROFILE , GLFW_OPENGL_CORE_PROFILE ) ; // Profiles Hint: Only 3.3 and above!
2018-11-06 15:10:50 +01:00
// Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
2017-05-08 02:47:44 +02:00
# if defined(__APPLE__)
2018-12-24 17:09:46 +01:00
glfwWindowHint ( GLFW_OPENGL_FORWARD_COMPAT , GLFW_TRUE ) ; // OSX Requires fordward compatibility
2016-05-14 01:10:05 +01:00
# else
2018-12-24 17:09:46 +01:00
glfwWindowHint ( GLFW_OPENGL_FORWARD_COMPAT , GLFW_FALSE ) ; // Fordward Compatibility Hint: Only 3.3 and above!
2016-05-14 01:10:05 +01:00
# endif
2018-12-24 17:09:46 +01:00
//glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context
}
2021-10-16 23:49:31 +02:00
else if ( rlGetVersion ( ) = = 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 ) ;
2021-10-19 20:43:27 +10:00
# if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT)
glfwWindowHint ( GLFW_OPENGL_DEBUG_CONTEXT , GLFW_TRUE ) ; // Enable OpenGL Debug Context
# endif
2021-10-16 23:49:31 +02:00
}
2018-12-24 17:09:46 +01:00
else if ( rlGetVersion ( ) = = 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 ) ;
2019-06-06 15:03:03 +05:30
# if defined(PLATFORM_DESKTOP)
2019-10-17 17:18:03 +02:00
glfwWindowHint ( GLFW_CONTEXT_CREATION_API , GLFW_EGL_CONTEXT_API ) ;
2019-06-06 15:03:03 +05:30
# else
2019-10-17 17:18:03 +02:00
glfwWindowHint ( GLFW_CONTEXT_CREATION_API , GLFW_NATIVE_CONTEXT_API ) ;
2019-06-06 15:03:03 +05:30
# endif
2014-09-16 22:51:31 +02:00
}
2021-02-07 16:49:37 -03:00
# if defined(PLATFORM_DESKTOP)
2021-03-19 19:43:44 +01:00
// NOTE: GLFW 3.4+ defers initialization of the Joystick subsystem on the first call to any Joystick related functions.
2021-10-22 11:53:47 +02:00
// Forcing this initialization here avoids doing it on PollInputEvents() called by EndDrawing() after first frame has been just drawn.
2021-02-07 20:52:11 +01:00
// 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
2021-02-07 16:49:37 -03:00
2020-02-03 18:31:30 +01:00
if ( CORE . Window . fullscreen )
2014-09-16 22:51:31 +02:00
{
2019-12-01 14:46:09 +02:00
// remember center for switchinging from fullscreen to window
2020-02-03 18:31:30 +01:00
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 ;
2019-12-01 14:46:09 +02:00
2020-02-03 18:31:30 +01:00
if ( CORE . Window . position . x < 0 ) CORE . Window . position . x = 0 ;
if ( CORE . Window . position . y < 0 ) CORE . Window . position . y = 0 ;
2019-12-01 14:46:09 +02:00
2020-02-03 18:31:30 +01:00
// Obtain recommended CORE.Window.display.width/CORE.Window.display.height from a valid videomode for the monitor
2019-07-22 21:15:25 +02:00
int count = 0 ;
2016-02-13 17:39:38 +01:00
const GLFWvidmode * modes = glfwGetVideoModes ( glfwGetPrimaryMonitor ( ) , & count ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
// Get closest video mode to desired CORE.Window.screen.width/CORE.Window.screen.height
2016-02-13 17:39:38 +01:00
for ( int i = 0 ; i < count ; i + + )
{
2020-05-06 19:12:09 +02:00
if ( ( unsigned int ) modes [ i ] . width > = CORE . Window . screen . width )
2016-06-26 01:36:06 +02:00
{
2020-05-06 19:12:09 +02:00
if ( ( unsigned int ) modes [ i ] . height > = CORE . Window . screen . height )
2016-06-26 01:36:06 +02:00
{
2020-02-03 18:31:30 +01:00
CORE . Window . display . width = modes [ i ] . width ;
CORE . Window . display . height = modes [ i ] . height ;
2016-06-26 01:36:06 +02:00
break ;
}
}
2016-02-13 17:39:38 +01:00
}
2016-08-16 11:09:55 +02:00
2019-12-09 15:14:56 -08:00
# if defined(PLATFORM_DESKTOP)
2019-12-10 00:18:29 +01:00
// If we are windowed fullscreen, ensures that window does not minimize when focus is lost
2020-02-03 18:31:30 +01:00
if ( ( CORE . Window . screen . height = = CORE . Window . display . height ) & & ( CORE . Window . screen . width = = CORE . Window . display . width ) )
2019-12-09 15:14:56 -08:00
{
glfwWindowHint ( GLFW_AUTO_ICONIFY , 0 ) ;
}
# endif
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " SYSTEM: Closest fullscreen videomode: %i x %i " , CORE . Window . display . width , CORE . Window . display . height ) ;
2016-06-26 01:36:06 +02:00
// 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...
2019-05-01 14:30:36 +02:00
// Try to setup the most appropiate 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)
2020-02-03 18:31:30 +01:00
// 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
2019-05-01 14:30:36 +02:00
// 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()
2020-02-03 18:31:30 +01:00
SetupFramebuffer ( CORE . Window . display . width , CORE . Window . display . height ) ;
2016-06-26 01:36:06 +02:00
2020-07-24 18:20:37 +02:00
CORE . Window . handle = glfwCreateWindow ( CORE . Window . display . width , CORE . Window . display . height , ( CORE . Window . title ! = 0 ) ? CORE . Window . title : " " , glfwGetPrimaryMonitor ( ) , NULL ) ;
2016-08-16 11:09:55 +02:00
2016-06-26 01:36:06 +02:00
// NOTE: Full-screen change, not working properly...
2020-02-03 18:31:30 +01:00
//glfwSetWindowMonitor(CORE.Window.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
2014-09-16 22:51:31 +02:00
}
else
{
// No-fullscreen window creation
2020-07-24 18:20:37 +02:00
CORE . Window . handle = glfwCreateWindow ( CORE . Window . screen . width , CORE . Window . screen . height , ( CORE . Window . title ! = 0 ) ? CORE . Window . title : " " , NULL , NULL ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
if ( CORE . Window . handle )
2018-02-03 14:40:57 +01:00
{
2015-10-21 18:23:49 +02:00
# if defined(PLATFORM_DESKTOP)
2018-02-03 14:40:57 +01:00
// Center window on screen
2020-02-03 18:31:30 +01:00
int windowPosX = CORE . Window . display . width / 2 - CORE . Window . screen . width / 2 ;
int windowPosY = CORE . Window . display . height / 2 - CORE . Window . screen . height / 2 ;
2016-08-16 11:09:55 +02:00
2018-02-03 14:40:57 +01:00
if ( windowPosX < 0 ) windowPosX = 0 ;
if ( windowPosY < 0 ) windowPosY = 0 ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
glfwSetWindowPos ( CORE . Window . handle , windowPosX , windowPosY ) ;
2015-10-21 18:23:49 +02:00
# endif
2020-02-03 18:31:30 +01:00
CORE . Window . render . width = CORE . Window . screen . width ;
CORE . Window . render . height = CORE . Window . screen . height ;
2018-02-03 14:40:57 +01:00
}
2014-09-16 22:51:31 +02:00
}
2020-02-03 18:31:30 +01:00
if ( ! CORE . Window . handle )
2014-09-16 22:51:31 +02:00
{
glfwTerminate ( ) ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " GLFW: Failed to initialize Window " ) ;
2018-02-03 12:12:50 +01:00
return false ;
2014-09-16 22:51:31 +02:00
}
2020-12-23 15:03:26 +01:00
2020-12-18 18:58:02 +01:00
// Set window callback events
2020-02-03 18:31:30 +01:00
glfwSetWindowSizeCallback ( CORE . Window . handle , WindowSizeCallback ) ; // NOTE: Resizing not allowed by default!
2020-09-07 15:34:21 +02:00
# if !defined(PLATFORM_WEB)
2020-09-01 19:29:13 +01:00
glfwSetWindowMaximizeCallback ( CORE . Window . handle , WindowMaximizeCallback ) ;
2020-09-07 15:34:21 +02:00
# endif
2020-12-18 18:58:02 +01:00
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 ) ;
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
glfwMakeContextCurrent ( CORE . Window . handle ) ;
2018-11-06 15:10:50 +01:00
2019-01-04 15:48:25 +01:00
# if !defined(PLATFORM_WEB)
2019-12-01 13:58:29 +01:00
glfwSwapInterval ( 0 ) ; // No V-Sync by default
2019-01-04 15:48:25 +01:00
# endif
2014-09-16 22:51:31 +02:00
2017-03-05 19:17:00 +01:00
// 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
2020-02-03 18:31:30 +01:00
if ( CORE . Window . flags & FLAG_VSYNC_HINT )
2015-01-21 00:13:17 +01:00
{
2018-11-06 15:10:50 +01:00
// WARNING: It seems to hits a critical render path in Intel HD Graphics
2015-01-21 00:13:17 +01:00
glfwSwapInterval ( 1 ) ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " DISPLAY: Trying to enable VSYNC " ) ;
2016-08-16 11:09:55 +02:00
}
2022-02-18 20:30:46 +01:00
2021-11-03 13:24:56 +01:00
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 than 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 ;
2022-02-18 20:30:46 +01:00
2021-11-03 13:24:56 +01:00
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 ) ;
2021-04-18 23:50:32 +02:00
# endif // PLATFORM_DESKTOP || PLATFORM_WEB
2014-09-16 22:51:31 +02:00
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-02-03 18:31:30 +01:00
CORE . Window . fullscreen = true ;
2021-04-29 00:07:28 +02:00
CORE . Window . flags | = FLAG_FULLSCREEN_MODE ;
2014-09-16 22:51:31 +02:00
# if defined(PLATFORM_RPI)
bcm_host_init ( ) ;
2021-07-03 21:31:52 +02:00
DISPMANX_ELEMENT_HANDLE_T dispmanElement = { 0 } ;
DISPMANX_DISPLAY_HANDLE_T dispmanDisplay = { 0 } ;
DISPMANX_UPDATE_HANDLE_T dispmanUpdate = { 0 } ;
2014-09-30 18:22:21 +02:00
2021-07-03 21:31:52 +02:00
VC_RECT_T dstRect = { 0 } ;
VC_RECT_T srcRect = { 0 } ;
2014-09-16 22:51:31 +02:00
# endif
2020-09-27 10:18:43 +02:00
# 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
2021-10-04 00:59:59 +01:00
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)
2021-12-31 17:46:31 +01:00
2021-10-04 00:59:59 +01:00
if ( ( - 1 = = CORE . Window . fd ) | | ( drmModeGetResources ( CORE . Window . fd ) = = NULL ) )
{
TRACELOG ( LOG_INFO , " DISPLAY: Failed to open platform-gpu-card, trying card1 " ) ;
2021-10-06 01:20:46 +02:00
CORE . Window . fd = open ( " /dev/dri/card1 " , O_RDWR ) ; // Other Embedded
2021-10-04 00:59:59 +01:00
}
2021-12-31 17:46:31 +01:00
2021-04-22 21:01:48 +02:00
if ( ( - 1 = = CORE . Window . fd ) | | ( drmModeGetResources ( CORE . Window . fd ) = = NULL ) )
2020-09-27 10:18:43 +02:00
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_INFO , " DISPLAY: Failed to open graphic card1, trying card0 " ) ;
2020-09-27 10:18:43 +02:00
CORE . Window . fd = open ( " /dev/dri/card0 " , O_RDWR ) ; // VideoCore IV (Raspberry Pi 1-3)
}
# endif
if ( - 1 = = CORE . Window . fd )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to open graphic card " ) ;
2020-09-27 10:18:43 +02:00
return false ;
}
drmModeRes * res = drmModeGetResources ( CORE . Window . fd ) ;
if ( ! res )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed get DRM resources " ) ;
2020-09-27 10:18:43 +02:00
return false ;
}
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: Connectors found: %i " , res - > count_connectors ) ;
2020-09-27 10:18:43 +02:00
for ( size_t i = 0 ; i < res - > count_connectors ; i + + )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: Connector index %i " , i ) ;
2020-09-27 10:18:43 +02:00
drmModeConnector * con = drmModeGetConnector ( CORE . Window . fd , res - > connectors [ i ] ) ;
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: Connector modes detected: %i " , con - > count_modes ) ;
2020-09-27 10:18:43 +02:00
if ( ( con - > connection = = DRM_MODE_CONNECTED ) & & ( con - > encoder_id ) )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: DRM mode connected " ) ;
2020-09-27 10:18:43 +02:00
CORE . Window . connector = con ;
break ;
}
else
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: DRM mode NOT connected (deleting) " ) ;
2020-09-27 10:18:43 +02:00
drmModeFreeConnector ( con ) ;
}
}
if ( ! CORE . Window . connector )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: No suitable DRM connector found " ) ;
2020-09-27 10:18:43 +02:00
drmModeFreeResources ( res ) ;
return false ;
}
drmModeEncoder * enc = drmModeGetEncoder ( CORE . Window . fd , CORE . Window . connector - > encoder_id ) ;
if ( ! enc )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get DRM mode encoder " ) ;
2020-09-27 10:18:43 +02:00
drmModeFreeResources ( res ) ;
return false ;
}
CORE . Window . crtc = drmModeGetCrtc ( CORE . Window . fd , enc - > crtc_id ) ;
if ( ! CORE . Window . crtc )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get DRM mode crtc " ) ;
2020-09-27 10:18:43 +02:00
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 ) )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: Selecting DRM connector mode for current used mode... " ) ;
2020-09-27 10:18:43 +02:00
CORE . Window . modeIndex = FindMatchingConnectorMode ( CORE . Window . connector , & CORE . Window . crtc - > mode ) ;
if ( CORE . Window . modeIndex < 0 )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: No matching DRM connector mode found " ) ;
2020-09-27 10:18:43 +02:00
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 ;
2021-03-31 17:55:46 +02:00
const int fps = ( CORE . Time . target > 0 ) ? ( 1.0 / CORE . Time . target ) : 60 ;
2020-09-27 10:18:43 +02:00
// 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 )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to find a suitable DRM connector mode " ) ;
2020-09-27 10:18:43 +02:00
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 ;
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_INFO , " DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) " , CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . name ,
2020-09-27 10:18:43 +02:00
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 )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to create GBM device " ) ;
2020-09-27 10:18:43 +02:00
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 )
{
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to create GBM surface " ) ;
2020-09-27 10:18:43 +02:00
return false ;
}
# endif
2015-08-07 17:25:05 +02:00
EGLint samples = 0 ;
EGLint sampleBuffer = 0 ;
2020-02-03 18:31:30 +01:00
if ( CORE . Window . flags & FLAG_MSAA_4X_HINT )
2015-08-07 17:25:05 +02:00
{
samples = 4 ;
sampleBuffer = 1 ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " DISPLAY: Trying to enable MSAA x4 " ) ;
2015-08-07 17:25:05 +02:00
}
2016-08-16 11:09:55 +02:00
2014-09-16 22:51:31 +02:00
const EGLint framebufferAttribs [ ] =
{
2017-05-08 21:03:48 +02:00
EGL_RENDERABLE_TYPE , EGL_OPENGL_ES2_BIT , // Type of context support -> Required on RPI?
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
EGL_SURFACE_TYPE , EGL_WINDOW_BIT , // Don't use it on Android!
# endif
2014-09-19 12:34:25 +02:00
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)
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
EGL_ALPHA_SIZE , 8 , // ALPHA bit depth (required for transparent framebuffer)
# endif
2017-05-09 18:11:02 +02:00
//EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
2015-08-10 10:20:53 +02:00
EGL_DEPTH_SIZE , 16 , // Depth buffer size (Required to use Depth testing!)
2014-09-19 12:34:25 +02:00
//EGL_STENCIL_SIZE, 8, // Stencil buffer size
2015-08-07 17:25:05 +02:00
EGL_SAMPLE_BUFFERS , sampleBuffer , // Activate MSAA
2015-08-10 10:20:53 +02:00
EGL_SAMPLES , samples , // 4x Antialiasing if activated (Free on MALI GPUs)
2014-09-16 22:51:31 +02:00
EGL_NONE
} ;
2017-11-10 12:37:53 +01:00
const EGLint contextAttribs [ ] =
2014-09-16 22:51:31 +02:00
{
EGL_CONTEXT_CLIENT_VERSION , 2 ,
EGL_NONE
} ;
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2020-04-09 23:50:00 +02:00
EGLint numConfigs = 0 ;
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
// Get an EGL device connection
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
CORE . Window . device = eglGetDisplay ( ( EGLNativeDisplayType ) CORE . Window . gbmDevice ) ;
# else
2020-02-03 18:31:30 +01:00
CORE . Window . device = eglGetDisplay ( EGL_DEFAULT_DISPLAY ) ;
2020-09-27 10:18:43 +02:00
# endif
2020-02-03 18:31:30 +01:00
if ( CORE . Window . device = = EGL_NO_DISPLAY )
2018-02-04 12:26:28 +01:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to initialize EGL device " ) ;
2018-02-04 12:26:28 +01:00
return false ;
}
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
// Initialize the EGL device connection
if ( eglInitialize ( CORE . Window . device , NULL , NULL ) = = EGL_FALSE )
2018-02-04 12:26:28 +01:00
{
// If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to initialize EGL device " ) ;
2018-02-04 12:26:28 +01:00
return false ;
}
2014-09-16 22:51:31 +02:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
2021-02-05 13:55:09 +01:00
if ( ! eglChooseConfig ( CORE . Window . device , NULL , NULL , 0 , & numConfigs ) )
2020-09-27 10:18:43 +02:00
{
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get EGL config count: 0x%x " , eglGetError ( ) ) ;
return false ;
}
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: EGL configs available: %d " , numConfigs ) ;
2020-09-27 10:18:43 +02:00
2021-03-02 02:03:52 +01:00
EGLConfig * configs = RL_CALLOC ( numConfigs , sizeof ( * configs ) ) ;
2020-11-15 13:17:11 +01:00
if ( ! configs )
{
2020-09-27 10:18:43 +02:00
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 ;
}
2021-02-05 13:55:09 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: EGL matching configs available: %d " , matchingNumConfigs ) ;
2020-09-27 10:18:43 +02:00
// find the EGL config that matches the previously setup GBM format
int found = 0 ;
2020-11-15 13:17:11 +01:00
for ( EGLint i = 0 ; i < matchingNumConfigs ; + + i )
{
2020-09-27 10:18:43 +02:00
EGLint id = 0 ;
2020-11-15 13:17:11 +01:00
if ( ! eglGetConfigAttrib ( CORE . Window . device , configs [ i ] , EGL_NATIVE_VISUAL_ID , & id ) )
{
2020-09-27 10:18:43 +02:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get EGL config attribute: 0x%x " , eglGetError ( ) ) ;
continue ;
}
2020-12-23 15:03:26 +01:00
2020-11-15 13:17:11 +01:00
if ( GBM_FORMAT_ARGB8888 = = id )
{
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: Using EGL config: %d " , i ) ;
2020-09-27 10:18:43 +02:00
CORE . Window . config = configs [ i ] ;
found = 1 ;
break ;
}
}
2021-03-02 02:03:52 +01:00
RL_FREE ( configs ) ;
2020-09-27 10:18:43 +02:00
if ( ! found )
{
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to find a suitable EGL config " ) ;
return false ;
}
# else
2014-09-16 22:51:31 +02:00
// Get an appropriate EGL framebuffer configuration
2020-02-03 18:31:30 +01:00
eglChooseConfig ( CORE . Window . device , framebufferAttribs , & CORE . Window . config , 1 , & numConfigs ) ;
2020-09-27 10:18:43 +02:00
# endif
2014-09-16 22:51:31 +02:00
// Set rendering API
eglBindAPI ( EGL_OPENGL_ES_API ) ;
// Create an EGL rendering context
2020-02-03 18:31:30 +01:00
CORE . Window . context = eglCreateContext ( CORE . Window . device , CORE . Window . config , EGL_NO_CONTEXT , contextAttribs ) ;
if ( CORE . Window . context = = EGL_NO_CONTEXT )
2018-02-04 12:26:28 +01:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to create EGL context " ) ;
2018-02-04 12:26:28 +01:00
return false ;
}
2017-11-10 12:37:53 +01:00
# endif
2014-09-16 22:51:31 +02:00
// Create an EGL window surface
//---------------------------------------------------------------------------------
# if defined(PLATFORM_ANDROID)
2020-04-09 23:50:00 +02:00
EGLint displayFormat = 0 ;
2014-09-16 22:51:31 +02:00
// EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry()
// As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
2020-02-03 18:31:30 +01:00
eglGetConfigAttrib ( CORE . Window . device , CORE . Window . config , EGL_NATIVE_VISUAL_ID , & displayFormat ) ;
2014-09-16 22:51:31 +02:00
// At this point we need to manage render size vs screen size
2020-11-03 23:47:33 +01:00
// NOTE: This function use and modify global module variables:
2020-07-17 18:39:31 +02:00
// -> CORE.Window.screen.width/CORE.Window.screen.height
// -> CORE.Window.render.width/CORE.Window.render.height
// -> CORE.Window.screenScale
2020-02-03 18:31:30 +01:00
SetupFramebuffer ( CORE . Window . display . width , CORE . Window . display . height ) ;
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
ANativeWindow_setBuffersGeometry ( CORE . Android . app - > window , CORE . Window . render . width , CORE . Window . render . height , displayFormat ) ;
//ANativeWindow_setBuffersGeometry(CORE.Android.app->window, 0, 0, displayFormat); // Force use of native display size
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
CORE . Window . surface = eglCreateWindowSurface ( CORE . Window . device , CORE . Window . config , CORE . Android . app - > window , NULL ) ;
2019-04-28 16:45:23 +02:00
# endif // PLATFORM_ANDROID
2014-09-16 22:51:31 +02:00
2016-04-17 11:19:32 +02:00
# if defined(PLATFORM_RPI)
2020-02-03 18:31:30 +01:00
graphics_get_display_size ( 0 , & CORE . Window . display . width , & CORE . Window . display . height ) ;
2020-11-03 23:47:33 +01:00
2020-04-09 23:50:00 +02:00
// Screen size security check
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 ;
2014-09-16 22:51:31 +02:00
// At this point we need to manage render size vs screen size
2020-11-03 23:47:33 +01:00
// NOTE: This function use and modify global module variables:
2020-07-17 18:39:31 +02:00
// -> CORE.Window.screen.width/CORE.Window.screen.height
// -> CORE.Window.render.width/CORE.Window.render.height
2020-11-03 23:47:33 +01:00
// -> CORE.Window.screenScale
2020-02-03 18:31:30 +01:00
SetupFramebuffer ( CORE . Window . display . width , CORE . Window . display . height ) ;
2014-09-16 22:51:31 +02:00
dstRect . x = 0 ;
dstRect . y = 0 ;
2020-02-03 18:31:30 +01:00
dstRect . width = CORE . Window . display . width ;
dstRect . height = CORE . Window . display . height ;
2014-09-16 22:51:31 +02:00
srcRect . x = 0 ;
srcRect . y = 0 ;
2020-02-03 18:31:30 +01:00
srcRect . width = CORE . Window . render . width < < 16 ;
srcRect . height = CORE . Window . render . height < < 16 ;
2014-09-16 22:51:31 +02:00
2020-12-19 19:27:31 +01:00
// NOTE: RPI dispmanx windowing system takes care of source rectangle scaling to destination rectangle by hardware (no cost)
2014-09-16 22:51:31 +02:00
// Take care that renderWidth/renderHeight fit on displayWidth/displayHeight aspect ratio
2021-07-03 21:31:52 +02:00
VC_DISPMANX_ALPHA_T alpha = { 0 } ;
2014-09-30 18:22:21 +02:00
alpha . flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS ;
2020-03-12 17:47:35 +01:00
//alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE; // TODO: Allow transparent framebuffer! -> FLAG_WINDOW_TRANSPARENT
2017-05-09 18:11:02 +02:00
alpha . opacity = 255 ; // Set transparency level for framebuffer, requires EGLAttrib: EGL_TRANSPARENT_TYPE
2014-09-30 18:22:21 +02:00
alpha . mask = 0 ;
dispmanDisplay = vc_dispmanx_display_open ( 0 ) ; // LCD
2014-09-16 22:51:31 +02:00
dispmanUpdate = vc_dispmanx_update_start ( 0 ) ;
dispmanElement = vc_dispmanx_element_add ( dispmanUpdate , dispmanDisplay , 0 /*layer*/ , & dstRect , 0 /*src*/ ,
2014-09-30 18:22:21 +02:00
& srcRect , DISPMANX_PROTECTION_NONE , & alpha , 0 /*clamp*/ , DISPMANX_NO_ROTATE ) ;
2014-09-16 22:51:31 +02:00
2020-02-13 00:13:56 +01:00
CORE . Window . handle . element = dispmanElement ;
CORE . Window . handle . width = CORE . Window . render . width ;
CORE . Window . handle . height = CORE . Window . render . height ;
2014-09-16 22:51:31 +02:00
vc_dispmanx_update_submit_sync ( dispmanUpdate ) ;
2020-02-13 00:13:56 +01:00
CORE . Window . surface = eglCreateWindowSurface ( CORE . Window . device , CORE . Window . config , & CORE . Window . handle , NULL ) ;
2020-09-27 10:18:43 +02:00
const unsigned char * const renderer = glGetString ( GL_RENDERER ) ;
2020-12-24 17:56:08 +01:00
if ( renderer ) TRACELOG ( LOG_INFO , " DISPLAY: Renderer name is: %s " , renderer ) ;
else TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get renderer name " ) ;
2014-09-16 22:51:31 +02:00
//---------------------------------------------------------------------------------
2019-04-28 16:45:23 +02:00
# endif // PLATFORM_RPI
2020-09-27 10:18:43 +02:00
# 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
2020-11-03 23:47:33 +01:00
// NOTE: This function use and modify global module variables:
2020-09-27 10:18:43 +02:00
// -> CORE.Window.screen.width/CORE.Window.screen.height
// -> CORE.Window.render.width/CORE.Window.render.height
2020-11-03 23:47:33 +01:00
// -> CORE.Window.screenScale
2020-09-27 10:18:43 +02:00
SetupFramebuffer ( CORE . Window . display . width , CORE . Window . display . height ) ;
# endif // PLATFORM_DRM
2014-09-16 22:51:31 +02:00
// There must be at least one frame displayed before the buffers are swapped
2020-02-03 18:31:30 +01:00
//eglSwapInterval(CORE.Window.device, 1);
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
if ( eglMakeCurrent ( CORE . Window . device , CORE . Window . surface , CORE . Window . surface , CORE . Window . context ) = = EGL_FALSE )
2014-09-16 22:51:31 +02:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to attach EGL rendering context to EGL surface " ) ;
2018-02-04 12:26:28 +01:00
return false ;
2014-09-16 22:51:31 +02:00
}
2021-11-03 13:24:56 +01:00
else
{
CORE . Window . render . width = CORE . Window . screen . width ;
CORE . Window . render . height = CORE . Window . screen . height ;
CORE . Window . currentFbo . width = CORE . Window . render . width ;
CORE . Window . currentFbo . height = CORE . Window . render . height ;
2022-02-18 20:30:46 +01:00
2021-11-03 13:24:56 +01:00
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 ) ;
}
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM
2014-09-16 22:51:31 +02:00
2021-04-18 20:24:19 +02:00
// Load OpenGL extensions
2021-04-27 11:04:48 +02:00
// NOTE: GL procedures address loader is required to load extensions
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2021-04-18 20:24:19 +02:00
rlLoadExtensions ( glfwGetProcAddress ) ;
2021-04-27 11:04:48 +02:00
# else
2021-04-28 23:57:46 +02:00
rlLoadExtensions ( eglGetProcAddress ) ;
2021-04-27 11:04:48 +02:00
# endif
2021-04-18 20:24:19 +02:00
2021-10-10 22:34:56 +02:00
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit ( CORE . Window . currentFbo . width , CORE . Window . currentFbo . height ) ;
2019-05-01 14:30:36 +02:00
// Setup default viewport
2021-11-03 13:24:56 +01:00
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
SetupViewport ( CORE . Window . currentFbo . width , CORE . Window . currentFbo . height ) ;
2019-08-20 19:32:12 +02:00
2015-02-26 13:52:03 +01:00
ClearBackground ( RAYWHITE ) ; // Default background color for raylib games :P
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
CORE . Window . ready = true ;
2015-02-26 13:52:03 +01:00
# endif
2020-11-23 23:46:05 +01:00
if ( ( CORE . Window . flags & FLAG_WINDOW_MINIMIZED ) > 0 ) MinimizeWindow ( ) ;
2018-02-03 12:12:50 +01:00
return true ;
2015-02-26 13:52:03 +01:00
}
2015-03-01 16:00:52 +01:00
2019-05-01 14:30:36 +02:00
// Set viewport for a provided width and height
static void SetupViewport ( int width , int height )
2016-12-14 23:58:15 -08:00
{
2020-02-03 18:31:30 +01:00
CORE . Window . render . width = width ;
CORE . Window . render . height = height ;
2019-05-08 18:33:09 +02:00
2021-03-22 20:45:04 +01:00
// Set viewport width and height
// NOTE: We consider render size (scaled) and offset in case black bars are required and
// render area does not match full display area (this situation is only applicable on fullscreen mode)
2021-03-20 20:06:38 +01:00
# if defined(__APPLE__)
2021-03-20 20:58:24 +01:00
float xScale = 1.0f , yScale = 1.0f ;
glfwGetWindowContentScale ( CORE . Window . handle , & xScale , & yScale ) ;
2021-10-17 04:21:51 -04:00
rlViewport ( CORE . Window . renderOffset . x / 2 * xScale , CORE . Window . renderOffset . y / 2 * yScale , ( CORE . Window . render . width ) * xScale , ( CORE . Window . render . height ) * yScale ) ;
2021-04-01 20:24:33 +02:00
# else
2021-10-17 04:21:51 -04:00
rlViewport ( CORE . Window . renderOffset . x / 2 , CORE . Window . renderOffset . y / 2 , CORE . Window . render . width , CORE . Window . render . height ) ;
2021-03-20 20:06:38 +01:00
# endif
2019-05-01 14:30:36 +02:00
2020-04-05 17:50:37 +02:00
rlMatrixMode ( RL_PROJECTION ) ; // Switch to projection matrix
rlLoadIdentity ( ) ; // Reset current matrix (projection)
2019-05-01 14:30:36 +02:00
// Set orthographic projection to current framebuffer size
// NOTE: Configured top-left corner as (0, 0)
2020-02-03 18:31:30 +01:00
rlOrtho ( 0 , CORE . Window . render . width , CORE . Window . render . height , 0 , 0.0f , 1.0f ) ;
2019-05-01 14:30:36 +02:00
2020-04-05 17:50:37 +02:00
rlMatrixMode ( RL_MODELVIEW ) ; // Switch back to modelview matrix
rlLoadIdentity ( ) ; // Reset current matrix (modelview)
2016-12-14 23:58:15 -08:00
}
2016-05-02 14:11:57 +02:00
// Compute framebuffer size relative to screen size and display size
2020-02-03 18:31:30 +01:00
// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
2018-10-08 12:29:02 +02:00
static void SetupFramebuffer ( int width , int height )
2016-08-16 11:09:55 +02:00
{
2020-02-03 18:31:30 +01:00
// Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
if ( ( CORE . Window . screen . width > CORE . Window . display . width ) | | ( CORE . Window . screen . height > CORE . Window . display . height ) )
2016-05-02 14:11:57 +02:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i) " , CORE . Window . screen . width , CORE . Window . screen . height , CORE . Window . display . width , CORE . Window . display . height ) ;
2013-11-18 23:38:44 +01:00
2016-05-02 14:11:57 +02:00
// Downscaling to fit display with border-bars
2020-02-03 18:31:30 +01:00
float widthRatio = ( float ) CORE . Window . display . width / ( float ) CORE . Window . screen . width ;
float heightRatio = ( float ) CORE . Window . display . height / ( float ) CORE . Window . screen . height ;
2014-01-28 21:21:29 +01:00
2016-05-02 14:11:57 +02:00
if ( widthRatio < = heightRatio )
{
2020-02-03 18:31:30 +01:00
CORE . Window . render . width = CORE . Window . display . width ;
CORE . Window . render . height = ( int ) round ( ( float ) CORE . Window . screen . height * widthRatio ) ;
CORE . Window . renderOffset . x = 0 ;
CORE . Window . renderOffset . y = ( CORE . Window . display . height - CORE . Window . render . height ) ;
2016-05-02 14:11:57 +02:00
}
else
{
2020-02-03 18:31:30 +01:00
CORE . Window . render . width = ( int ) round ( ( float ) CORE . Window . screen . width * heightRatio ) ;
CORE . Window . render . height = CORE . Window . display . height ;
CORE . Window . renderOffset . x = ( CORE . Window . display . width - CORE . Window . render . width ) ;
CORE . Window . renderOffset . y = 0 ;
2016-05-02 14:11:57 +02:00
}
2014-09-03 16:51:28 +02:00
2019-04-25 11:02:13 +02:00
// Screen scaling required
2020-02-03 18:31:30 +01:00
float scaleRatio = ( float ) CORE . Window . render . width / ( float ) CORE . Window . screen . width ;
CORE . Window . screenScale = MatrixScale ( scaleRatio , scaleRatio , 1.0f ) ;
2016-05-02 14:11:57 +02:00
// NOTE: We render to full display resolution!
// We just need to calculate above parameters for downscale matrix and offsets
2020-02-03 18:31:30 +01:00
CORE . Window . render . width = CORE . Window . display . width ;
CORE . Window . render . height = CORE . Window . display . height ;
2016-05-02 14:11:57 +02:00
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i) " , CORE . Window . render . width , CORE . Window . render . height ) ;
2013-11-23 13:30:54 +01:00
}
2020-02-03 18:31:30 +01:00
else if ( ( CORE . Window . screen . width < CORE . Window . display . width ) | | ( CORE . Window . screen . height < CORE . Window . display . height ) )
2013-11-23 13:30:54 +01:00
{
2016-05-02 14:11:57 +02:00
// Required screen size is smaller than display size
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i) " , CORE . Window . screen . width , CORE . Window . screen . height , CORE . Window . display . width , CORE . Window . display . height ) ;
2020-12-23 15:03:26 +01:00
2020-11-15 13:17:11 +01:00
if ( ( CORE . Window . screen . width = = 0 ) | | ( CORE . Window . screen . height = = 0 ) )
{
2020-11-15 17:13:21 +05:00
CORE . Window . screen . width = CORE . Window . display . width ;
CORE . Window . screen . height = CORE . Window . display . height ;
}
2020-12-23 15:03:26 +01:00
2016-05-02 14:11:57 +02:00
// Upscaling to fit display with border-bars
2020-02-03 18:31:30 +01:00
float displayRatio = ( float ) CORE . Window . display . width / ( float ) CORE . Window . display . height ;
float screenRatio = ( float ) CORE . Window . screen . width / ( float ) CORE . Window . screen . height ;
2016-05-02 14:11:57 +02:00
if ( displayRatio < = screenRatio )
{
2020-02-03 18:31:30 +01:00
CORE . Window . render . width = CORE . Window . screen . width ;
CORE . Window . render . height = ( int ) round ( ( float ) CORE . Window . screen . width / displayRatio ) ;
CORE . Window . renderOffset . x = 0 ;
CORE . Window . renderOffset . y = ( CORE . Window . render . height - CORE . Window . screen . height ) ;
2016-05-02 14:11:57 +02:00
}
else
{
2020-02-03 18:31:30 +01:00
CORE . Window . render . width = ( int ) round ( ( float ) CORE . Window . screen . height * displayRatio ) ;
CORE . Window . render . height = CORE . Window . screen . height ;
CORE . Window . renderOffset . x = ( CORE . Window . render . width - CORE . Window . screen . width ) ;
CORE . Window . renderOffset . y = 0 ;
2016-05-02 14:11:57 +02:00
}
2013-11-23 13:30:54 +01:00
}
2020-02-03 18:31:30 +01:00
else
2016-03-06 19:30:16 +01:00
{
2020-02-03 18:31:30 +01:00
CORE . Window . render . width = CORE . Window . screen . width ;
CORE . Window . render . height = CORE . Window . screen . height ;
CORE . Window . renderOffset . x = 0 ;
CORE . Window . renderOffset . y = 0 ;
2016-03-06 19:30:16 +01:00
}
2014-12-31 18:03:32 +01:00
}
2016-05-02 14:11:57 +02:00
// Initialize hi-resolution timer
2021-06-22 20:26:59 +02:00
static void InitTimer ( void )
2014-12-31 18:03:32 +01:00
{
2021-03-19 19:43:44 +01:00
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
// High resolutions can also prevent the CPU power management system from entering power-saving modes.
2021-03-12 17:18:48 +01:00
// Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP)
2021-03-12 17:18:48 +01:00
timeBeginPeriod ( 1 ) ; // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
2017-05-08 02:37:37 +02:00
# endif
2016-05-02 14:11:57 +02:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-04-19 19:41:32 +02:00
struct timespec now = { 0 } ;
2016-05-02 14:11:57 +02:00
if ( clock_gettime ( CLOCK_MONOTONIC , & now ) = = 0 ) // Success
{
2020-02-04 16:55:24 +01:00
CORE . Time . base = ( unsigned long long int ) now . tv_sec * 1000000000LLU + ( unsigned long long int ) now . tv_nsec ;
2016-05-02 14:11:57 +02:00
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " TIMER: Hi-resolution timer not available " ) ;
2016-02-02 16:43:42 +01:00
# endif
2016-05-02 14:11:57 +02:00
2021-03-12 17:18:48 +01:00
CORE . Time . previous = GetTime ( ) ; // Get time as double
2016-02-02 16:43:42 +01:00
}
2022-06-06 20:18:37 +02:00
// Wait for some time (stop program execution)
2017-03-28 19:15:27 +02:00
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop
2019-12-01 12:55:33 +01:00
// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timming on Win32!
2022-06-06 20:23:14 +02:00
void WaitTime ( double seconds )
2017-03-05 19:17:00 +01:00
{
2022-06-07 21:01:29 +02:00
# if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
double destinationTime = GetTime ( ) + seconds ;
# endif
2017-01-28 00:56:45 +01:00
2022-06-07 21:01:29 +02:00
# if defined(SUPPORT_BUSY_WAIT_LOOP)
while ( GetTime ( ) < destinationTime ) { }
2017-03-05 19:17:00 +01:00
# else
2021-05-07 10:49:44 -07:00
# if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
2022-06-06 20:23:14 +02:00
double sleepSeconds = seconds - seconds * 0.05 ; // NOTE: We reserve a percentage of the time for busy waiting
2022-06-06 20:18:37 +02:00
# else
2022-06-06 20:23:14 +02:00
double sleepSeconds = seconds ;
2020-01-19 17:31:55 +01:00
# endif
2021-06-24 11:01:44 +02:00
// System halt functions
2017-05-08 02:37:37 +02:00
# if defined(_WIN32)
2022-06-07 10:04:24 +02:00
Sleep ( ( unsigned long ) ( sleepSeconds * 1000.0 ) ) ;
2021-03-02 12:44:53 +01:00
# endif
2022-05-16 19:24:16 +02:00
# if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
2017-03-05 19:17:00 +01:00
struct timespec req = { 0 } ;
2022-06-06 20:18:37 +02:00
time_t sec = sleepSeconds ;
long nsec = ( sleepSeconds - sec ) * 1000000000L ;
2017-03-05 19:17:00 +01:00
req . tv_sec = sec ;
2022-06-06 20:18:37 +02:00
req . tv_nsec = nsec ;
2017-03-05 19:17:00 +01:00
// NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated.
while ( nanosleep ( & req , & req ) = = - 1 ) continue ;
2021-03-02 12:44:53 +01:00
# endif
# if defined(__APPLE__)
2022-06-06 20:18:37 +02:00
usleep ( sleepSeconds * 1000000.0 ) ;
2017-03-05 19:17:00 +01:00
# endif
2020-02-03 19:26:28 +01:00
2021-05-07 10:49:44 -07:00
# if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
2022-06-06 20:18:37 +02:00
while ( GetTime ( ) < destinationTime ) { }
2020-01-19 17:31:55 +01:00
# endif
2017-01-28 00:56:45 +01:00
# endif
}
2021-06-17 12:17:50 +02:00
// Swap back buffer with front buffer (screen drawing)
2021-06-17 12:47:03 +02:00
void SwapScreenBuffer ( void )
2021-06-17 12:17:50 +02:00
{
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
glfwSwapBuffers ( CORE . Window . handle ) ;
# endif
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-06-17 12:17:50 +02:00
eglSwapBuffers ( CORE . Window . device , CORE . Window . surface ) ;
# if defined(PLATFORM_DRM)
2022-04-25 21:00:17 +02:00
if ( ! CORE . Window . gbmSurface | | ( - 1 = = CORE . Window . fd ) | | ! CORE . Window . connector | | ! CORE . Window . crtc ) TRACELOG ( LOG_ERROR , " DISPLAY: DRM initialization failed to swap " ) ;
2021-06-17 12:17:50 +02:00
struct gbm_bo * bo = gbm_surface_lock_front_buffer ( CORE . Window . gbmSurface ) ;
2022-04-25 21:00:17 +02:00
if ( ! bo ) TRACELOG ( LOG_ERROR , " DISPLAY: Failed GBM to lock front buffer " ) ;
2021-06-17 12:17:50 +02:00
uint32_t fb = 0 ;
2022-04-25 21:00:17 +02:00
int result = drmModeAddFB ( CORE . Window . fd , CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . hdisplay , CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . vdisplay , 24 , 32 , gbm_bo_get_stride ( bo ) , gbm_bo_get_handle ( bo ) . u32 , & fb ) ;
if ( result ! = 0 ) TRACELOG ( LOG_ERROR , " DISPLAY: drmModeAddFB() failed with result: %d " , result ) ;
2021-06-17 12:17:50 +02:00
2022-04-25 21:00:17 +02:00
result = drmModeSetCrtc ( CORE . Window . fd , CORE . Window . crtc - > crtc_id , fb , 0 , 0 , & CORE . Window . connector - > connector_id , 1 , & CORE . Window . connector - > modes [ CORE . Window . modeIndex ] ) ;
if ( result ! = 0 ) TRACELOG ( LOG_ERROR , " DISPLAY: drmModeSetCrtc() failed with result: %d " , result ) ;
2021-06-17 12:17:50 +02:00
if ( CORE . Window . prevFB )
{
result = drmModeRmFB ( CORE . Window . fd , CORE . Window . prevFB ) ;
2022-04-25 21:00:17 +02:00
if ( result ! = 0 ) TRACELOG ( LOG_ERROR , " DISPLAY: drmModeRmFB() failed with result: %d " , result ) ;
2021-06-17 12:17:50 +02:00
}
2022-05-05 20:39:14 +02:00
2021-06-17 12:17:50 +02:00
CORE . Window . prevFB = fb ;
2022-04-25 21:00:17 +02:00
if ( CORE . Window . prevBO ) gbm_surface_release_buffer ( CORE . Window . gbmSurface , CORE . Window . prevBO ) ;
2021-06-17 12:17:50 +02:00
CORE . Window . prevBO = bo ;
2022-04-25 21:00:17 +02:00
2021-06-17 12:17:50 +02:00
# endif // PLATFORM_DRM
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
# endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM
2021-06-17 12:17:50 +02:00
}
// Register all input events
void PollInputEvents ( void )
2013-11-18 23:38:44 +01:00
{
2017-03-21 13:22:59 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM)
2016-05-02 14:11:57 +02:00
// NOTE: Gestures update must be called every frame to reset gestures correctly
// because ProcessGestureEvent() is just called on an event, not every frame
UpdateGestures ( ) ;
2017-03-21 13:22:59 +01:00
# endif
2017-01-28 23:02:30 +01:00
2020-12-18 18:58:02 +01:00
// Reset keys/chars pressed registered
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueueCount = 0 ;
2020-12-18 18:58:02 +01:00
CORE . Input . Keyboard . charPressedQueueCount = 0 ;
2017-01-28 23:02:30 +01:00
2020-09-27 10:18:43 +02:00
# if !(defined(PLATFORM_RPI) || defined(PLATFORM_DRM))
2016-11-02 13:39:48 +01:00
// Reset last gamepad button/axis registered state
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . lastButtonPressed = - 1 ;
CORE . Input . Gamepad . axisCount = 0 ;
2016-11-02 13:39:48 +01:00
# endif
2016-08-16 11:09:55 +02:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2018-10-21 00:09:17 +01:00
// Register previous keys states
2021-07-17 15:27:48 -03:00
for ( int i = 0 ; i < MAX_KEYBOARD_KEYS ; i + + ) CORE . Input . Keyboard . previousKeyState [ i ] = CORE . Input . Keyboard . currentKeyState [ i ] ;
2021-03-19 19:43:44 +01:00
2021-01-06 19:46:12 +00:00
PollKeyboardEvents ( ) ;
2018-10-21 00:09:17 +01:00
// Register previous mouse states
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . previousWheelMove = CORE . Input . Mouse . currentWheelMove ;
2022-06-12 11:30:07 -04:00
CORE . Input . Mouse . currentWheelMove = ( Vector2 ) { 0.0f , 0.0f } ;
2021-10-23 09:52:04 +01:00
for ( int i = 0 ; i < MAX_MOUSE_BUTTONS ; i + + )
2018-10-21 00:09:17 +01:00
{
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . previousButtonState [ i ] = CORE . Input . Mouse . currentButtonState [ i ] ;
2020-02-13 00:13:56 +01:00
CORE . Input . Mouse . currentButtonState [ i ] = CORE . Input . Mouse . currentButtonStateEvdev [ i ] ;
2018-10-21 00:09:17 +01:00
}
2021-03-19 19:43:44 +01:00
2021-01-31 03:07:26 +01:00
// Register gamepads buttons events
for ( int i = 0 ; i < MAX_GAMEPADS ; i + + )
{
WARNING: BREAKING: REMOVED PLATFORM_UWP support
After lot of investigation, I'm afraid I'm removing official UWP support from raylib, I'll keep the current implementation in a separate branch (UWP), just in case. It seems Microsoft is trying to replace UWP in the long term, they announced lack of support for the new WinUI 3 and they seem to be moving to Windows App SDK.
Also, on current implementation, the code is divided between raylib and the example, requiring multiple callback hooks, making it difficult to follow and maintain.
And realistically speaking, raylib is probably not the best option for anyone willing to target UWP, neither Xbox consoles.
2021-07-05 12:34:23 +02:00
if ( CORE . Input . Gamepad . ready [ i ] )
2021-01-31 03:07:26 +01:00
{
// Register previous gamepad states
2021-06-10 17:11:31 +02:00
for ( int k = 0 ; k < MAX_GAMEPAD_BUTTONS ; k + + ) CORE . Input . Gamepad . previousButtonState [ i ] [ k ] = CORE . Input . Gamepad . currentButtonState [ i ] [ k ] ;
2021-01-31 03:07:26 +01:00
}
}
2018-10-21 00:09:17 +01:00
# endif
2016-05-02 14:11:57 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2020-02-29 22:10:23 +01:00
// Keyboard/Mouse input polling (automatically managed by GLFW3 through callback)
2016-05-02 14:11:57 +02:00
// Register previous keys states
2021-07-17 15:27:48 -03:00
for ( int i = 0 ; i < MAX_KEYBOARD_KEYS ; i + + ) CORE . Input . Keyboard . previousKeyState [ i ] = CORE . Input . Keyboard . currentKeyState [ i ] ;
2016-05-02 14:11:57 +02:00
// Register previous mouse states
2021-10-23 09:52:04 +01:00
for ( int i = 0 ; i < MAX_MOUSE_BUTTONS ; i + + ) CORE . Input . Mouse . previousButtonState [ i ] = CORE . Input . Mouse . currentButtonState [ i ] ;
2016-05-02 14:11:57 +02:00
2020-02-29 22:10:23 +01:00
// Register previous mouse wheel state
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . previousWheelMove = CORE . Input . Mouse . currentWheelMove ;
2022-06-12 11:30:07 -04:00
CORE . Input . Mouse . currentWheelMove = ( Vector2 ) { 0.0f , 0.0f } ;
2021-06-13 17:08:30 +02:00
2021-06-10 18:03:25 +02:00
// Register previous mouse position
CORE . Input . Mouse . previousPosition = CORE . Input . Mouse . currentPosition ;
2020-03-24 23:23:34 +11:00
# endif
2020-02-29 22:10:23 +01:00
// Register previous touch states
2020-03-03 14:58:54 +01:00
for ( int i = 0 ; i < MAX_TOUCH_POINTS ; i + + ) CORE . Input . Touch . previousTouchState [ i ] = CORE . Input . Touch . currentTouchState [ i ] ;
2022-02-18 20:30:46 +01:00
2021-10-22 11:53:47 +02:00
// Reset touch positions
// TODO: It resets on PLATFORM_WEB the mouse position and not filled again until a move-event,
// so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed!
//for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 };
2016-11-18 13:39:57 +01:00
# if defined(PLATFORM_DESKTOP)
2016-11-01 14:39:57 +01:00
// Check if gamepads are ready
2019-04-27 20:49:33 +01:00
// NOTE: We do it here in case of disconnection
2016-11-01 14:39:57 +01:00
for ( int i = 0 ; i < MAX_GAMEPADS ; i + + )
{
2020-02-03 18:31:30 +01:00
if ( glfwJoystickPresent ( i ) ) CORE . Input . Gamepad . ready [ i ] = true ;
else CORE . Input . Gamepad . ready [ i ] = false ;
2016-11-01 14:39:57 +01:00
}
2017-01-28 23:02:30 +01:00
2016-10-14 11:14:41 +02:00
// Register gamepads buttons events
for ( int i = 0 ; i < MAX_GAMEPADS ; i + + )
2016-10-14 00:47:43 +02:00
{
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Gamepad . ready [ i ] ) // Check if gamepad is available
2016-10-14 00:47:43 +02:00
{
2016-10-14 11:14:41 +02:00
// Register previous gamepad states
2021-06-10 17:11:31 +02:00
for ( int k = 0 ; k < MAX_GAMEPAD_BUTTONS ; k + + ) CORE . Input . Gamepad . previousButtonState [ i ] [ k ] = CORE . Input . Gamepad . currentButtonState [ i ] [ k ] ;
2017-01-28 23:02:30 +01:00
2016-10-14 11:14:41 +02:00
// Get current gamepad state
// NOTE: There is no callback available, so we get it manually
2019-04-28 15:59:39 +01:00
// Get remapped buttons
2020-05-09 13:05:54 +02:00
GLFWgamepadstate state = { 0 } ;
2019-04-28 16:06:56 +01:00
glfwGetGamepadState ( i , & state ) ; // This remapps all gamepads so they have their buttons mapped like an xbox controller
2020-11-03 23:47:33 +01:00
2019-04-28 16:06:56 +01:00
const unsigned char * buttons = state . buttons ;
2017-01-28 23:02:30 +01:00
2019-04-27 20:49:33 +01:00
for ( int k = 0 ; ( buttons ! = NULL ) & & ( k < GLFW_GAMEPAD_BUTTON_DPAD_LEFT + 1 ) & & ( k < MAX_GAMEPAD_BUTTONS ) ; k + + )
2016-10-14 11:14:41 +02:00
{
2021-03-19 19:43:44 +01:00
GamepadButton button = - 1 ;
2021-02-09 12:14:50 +01:00
switch ( k )
{
case GLFW_GAMEPAD_BUTTON_Y : button = GAMEPAD_BUTTON_RIGHT_FACE_UP ; break ;
case GLFW_GAMEPAD_BUTTON_B : button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT ; break ;
case GLFW_GAMEPAD_BUTTON_A : button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN ; break ;
case GLFW_GAMEPAD_BUTTON_X : button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT ; break ;
case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER : button = GAMEPAD_BUTTON_LEFT_TRIGGER_1 ; break ;
case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER : button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1 ; break ;
case GLFW_GAMEPAD_BUTTON_BACK : button = GAMEPAD_BUTTON_MIDDLE_LEFT ; break ;
case GLFW_GAMEPAD_BUTTON_GUIDE : button = GAMEPAD_BUTTON_MIDDLE ; break ;
case GLFW_GAMEPAD_BUTTON_START : button = GAMEPAD_BUTTON_MIDDLE_RIGHT ; break ;
case GLFW_GAMEPAD_BUTTON_DPAD_UP : button = GAMEPAD_BUTTON_LEFT_FACE_UP ; break ;
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT : button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT ; break ;
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN : button = GAMEPAD_BUTTON_LEFT_FACE_DOWN ; break ;
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT : button = GAMEPAD_BUTTON_LEFT_FACE_LEFT ; break ;
case GLFW_GAMEPAD_BUTTON_LEFT_THUMB : button = GAMEPAD_BUTTON_LEFT_THUMB ; break ;
case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB : button = GAMEPAD_BUTTON_RIGHT_THUMB ; break ;
default : break ;
}
2021-03-19 19:43:44 +01:00
2021-02-09 12:14:50 +01:00
if ( button ! = - 1 ) // Check for valid button
2016-10-27 13:41:43 +02:00
{
2021-02-09 12:14:50 +01:00
if ( buttons [ k ] = = GLFW_PRESS )
{
2021-06-10 17:11:31 +02:00
CORE . Input . Gamepad . currentButtonState [ i ] [ button ] = 1 ;
2021-02-09 12:14:50 +01:00
CORE . Input . Gamepad . lastButtonPressed = button ;
}
2021-06-10 17:11:31 +02:00
else CORE . Input . Gamepad . currentButtonState [ i ] [ button ] = 0 ;
2016-10-27 13:41:43 +02:00
}
2016-10-14 11:14:41 +02:00
}
2017-01-28 23:02:30 +01:00
2016-10-14 11:14:41 +02:00
// Get current axis state
2019-04-27 20:49:33 +01:00
const float * axes = state . axes ;
2017-01-28 23:02:30 +01:00
2019-04-27 20:49:33 +01:00
for ( int k = 0 ; ( axes ! = NULL ) & & ( k < GLFW_GAMEPAD_AXIS_LAST + 1 ) & & ( k < MAX_GAMEPAD_AXIS ) ; k + + )
2016-10-14 11:14:41 +02:00
{
2020-05-09 12:39:41 +02:00
CORE . Input . Gamepad . axisState [ i ] [ k ] = axes [ k ] ;
2016-10-14 11:14:41 +02:00
}
2017-01-28 23:02:30 +01:00
2019-04-28 15:59:39 +01:00
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
2022-03-20 12:15:51 +01:00
CORE . Input . Gamepad . currentButtonState [ i ] [ GAMEPAD_BUTTON_LEFT_TRIGGER_2 ] = ( char ) ( CORE . Input . Gamepad . axisState [ i ] [ GAMEPAD_AXIS_LEFT_TRIGGER ] > 0.1f ) ;
CORE . Input . Gamepad . currentButtonState [ i ] [ GAMEPAD_BUTTON_RIGHT_TRIGGER_2 ] = ( char ) ( CORE . Input . Gamepad . axisState [ i ] [ GAMEPAD_AXIS_RIGHT_TRIGGER ] > 0.1f ) ;
2019-04-27 20:49:33 +01:00
2021-04-08 23:55:47 +01:00
CORE . Input . Gamepad . axisCount = GLFW_GAMEPAD_AXIS_LAST + 1 ;
2016-10-14 00:47:43 +02:00
}
}
2019-04-04 13:50:52 +02:00
2021-10-04 07:47:41 +00:00
CORE . Window . resizedLastFrame = false ;
2022-05-12 16:51:46 +02:00
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)
2021-04-18 23:50:32 +02:00
# endif // PLATFORM_DESKTOP
2016-05-02 14:11:57 +02:00
2021-10-23 08:52:36 +00:00
# if defined(PLATFORM_WEB)
CORE . Window . resizedLastFrame = false ;
# endif // PLATFORM_WEB
2016-12-25 20:42:22 +01:00
// Gamepad support using emscripten API
// NOTE: GLFW3 joystick functionality not available in web
# if defined(PLATFORM_WEB)
// Get number of gamepads connected
2019-04-23 18:10:38 +02:00
int numGamepads = 0 ;
if ( emscripten_sample_gamepad_data ( ) = = EMSCRIPTEN_RESULT_SUCCESS ) numGamepads = emscripten_get_num_gamepads ( ) ;
2017-01-28 23:02:30 +01:00
2016-12-25 20:42:22 +01:00
for ( int i = 0 ; ( i < numGamepads ) & & ( i < MAX_GAMEPADS ) ; i + + )
{
// Register previous gamepad button states
2021-06-10 17:11:31 +02:00
for ( int k = 0 ; k < MAX_GAMEPAD_BUTTONS ; k + + ) CORE . Input . Gamepad . previousButtonState [ i ] [ k ] = CORE . Input . Gamepad . currentButtonState [ i ] [ k ] ;
2017-01-28 23:02:30 +01:00
2016-12-25 20:42:22 +01:00
EmscriptenGamepadEvent gamepadState ;
2017-01-28 23:02:30 +01:00
2016-12-25 20:42:22 +01:00
int result = emscripten_get_gamepad_status ( i , & gamepadState ) ;
2017-01-28 23:02:30 +01:00
2016-12-25 20:42:22 +01:00
if ( result = = EMSCRIPTEN_RESULT_SUCCESS )
{
// Register buttons data for every connected gamepad
for ( int j = 0 ; ( j < gamepadState . numButtons ) & & ( j < MAX_GAMEPAD_BUTTONS ) ; j + + )
{
2021-02-09 12:14:50 +01:00
GamepadButton button = - 1 ;
2021-03-19 19:43:44 +01:00
2021-02-09 12:14:50 +01:00
// Gamepad Buttons reference: https://www.w3.org/TR/gamepad/#gamepad-interface
switch ( j )
{
case 0 : button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN ; break ;
case 1 : button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT ; break ;
case 2 : button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT ; break ;
case 3 : button = GAMEPAD_BUTTON_RIGHT_FACE_UP ; break ;
case 4 : button = GAMEPAD_BUTTON_LEFT_TRIGGER_1 ; break ;
case 5 : button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1 ; break ;
case 6 : button = GAMEPAD_BUTTON_LEFT_TRIGGER_2 ; break ;
case 7 : button = GAMEPAD_BUTTON_RIGHT_TRIGGER_2 ; break ;
case 8 : button = GAMEPAD_BUTTON_MIDDLE_LEFT ; break ;
case 9 : button = GAMEPAD_BUTTON_MIDDLE_RIGHT ; break ;
case 10 : button = GAMEPAD_BUTTON_LEFT_THUMB ; break ;
case 11 : button = GAMEPAD_BUTTON_RIGHT_THUMB ; break ;
case 12 : button = GAMEPAD_BUTTON_LEFT_FACE_UP ; break ;
case 13 : button = GAMEPAD_BUTTON_LEFT_FACE_DOWN ; break ;
case 14 : button = GAMEPAD_BUTTON_LEFT_FACE_LEFT ; break ;
case 15 : button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT ; break ;
default : break ;
}
2021-03-19 19:43:44 +01:00
2021-02-09 12:14:50 +01:00
if ( button ! = - 1 ) // Check for valid button
2016-12-25 20:42:22 +01:00
{
2021-02-09 12:14:50 +01:00
if ( gamepadState . digitalButton [ j ] = = 1 )
{
2021-06-10 17:11:31 +02:00
CORE . Input . Gamepad . currentButtonState [ i ] [ button ] = 1 ;
2021-02-09 12:14:50 +01:00
CORE . Input . Gamepad . lastButtonPressed = button ;
}
2021-06-10 17:11:31 +02:00
else CORE . Input . Gamepad . currentButtonState [ i ] [ button ] = 0 ;
2016-12-25 20:42:22 +01:00
}
2017-01-28 23:02:30 +01:00
2020-03-27 18:06:09 +01:00
//TRACELOGD("INPUT: Gamepad %d, button %d: Digital: %d, Analog: %g", gamepadState.index, j, gamepadState.digitalButton[j], gamepadState.analogButton[j]);
2016-12-25 20:42:22 +01:00
}
2017-01-28 23:02:30 +01:00
2016-12-25 20:42:22 +01:00
// Register axis data for every connected gamepad
for ( int j = 0 ; ( j < gamepadState . numAxes ) & & ( j < MAX_GAMEPAD_AXIS ) ; j + + )
{
2020-05-09 12:39:41 +02:00
CORE . Input . Gamepad . axisState [ i ] [ j ] = gamepadState . axis [ j ] ;
2016-12-25 20:42:22 +01:00
}
2017-01-28 23:02:30 +01:00
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . axisCount = gamepadState . numAxes ;
2016-12-25 20:42:22 +01:00
}
}
# endif
2016-06-03 00:53:51 +02:00
# if defined(PLATFORM_ANDROID)
2016-05-02 14:11:57 +02:00
// Register previous keys states
2016-10-17 18:18:13 +02:00
// NOTE: Android supports up to 260 keys
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < 260 ; i + + ) CORE . Input . Keyboard . previousKeyState [ i ] = CORE . Input . Keyboard . currentKeyState [ i ] ;
2016-05-02 14:11:57 +02:00
2020-02-03 18:31:30 +01:00
// Android ALooper_pollAll() variables
int pollResult = 0 ;
int pollEvents = 0 ;
2020-02-03 19:26:28 +01:00
2016-05-02 14:11:57 +02:00
// Poll Events (registered events)
2020-02-03 18:31:30 +01:00
// NOTE: Activity is paused if not enabled (CORE.Android.appEnabled)
while ( ( pollResult = ALooper_pollAll ( CORE . Android . appEnabled ? 0 : - 1 , NULL , & pollEvents , ( void * * ) & CORE . Android . source ) ) > = 0 )
2016-05-02 14:11:57 +02:00
{
// Process this event
2020-02-03 18:31:30 +01:00
if ( CORE . Android . source ! = NULL ) CORE . Android . source - > process ( CORE . Android . app , CORE . Android . source ) ;
2016-05-02 14:11:57 +02:00
// NOTE: Never close window, native activity is controlled by the system!
2020-02-03 18:31:30 +01:00
if ( CORE . Android . app - > destroyRequested ! = 0 )
2016-05-02 14:11:57 +02:00
{
2020-02-03 18:31:30 +01:00
//CORE.Window.shouldClose = true;
//ANativeActivity_finish(CORE.Android.app->activity);
2016-05-02 14:11:57 +02:00
}
}
2016-06-03 00:53:51 +02:00
# endif
2016-05-02 14:11:57 +02:00
2020-09-27 10:18:43 +02:00
# if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && defined(SUPPORT_SSH_KEYBOARD_RPI)
2021-07-16 16:10:53 +02:00
// NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here.
2021-07-06 18:25:00 +02:00
// stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
2021-07-17 15:27:48 -03:00
if ( ! CORE . Input . Keyboard . evtMode ) ProcessKeyboard ( ) ;
2016-05-02 14:11:57 +02:00
2019-04-28 16:45:23 +02:00
// NOTE: Mouse input events polling is done asynchronously in another pthread - EventThread()
2016-05-02 14:11:57 +02:00
// NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread()
# endif
}
2022-06-11 23:24:13 +02:00
// Scan all files and directories in a base path
// WARNING: files.paths[] must be previously allocated and
// contain enough space to store all required paths
static void ScanDirectoryFiles ( const char * basePath , FilePathList * files , const char * filter )
{
static char path [ MAX_FILEPATH_LENGTH ] = { 0 } ;
memset ( path , 0 , MAX_FILEPATH_LENGTH ) ;
struct dirent * dp = NULL ;
DIR * dir = opendir ( basePath ) ;
if ( dir ! = NULL )
{
while ( ( dp = readdir ( dir ) ) ! = NULL )
{
if ( ( strcmp ( dp - > d_name , " . " ) ! = 0 ) & &
( strcmp ( dp - > d_name , " .. " ) ! = 0 ) )
{
sprintf ( path , " %s/%s " , basePath , dp - > d_name ) ;
if ( filter ! = NULL )
{
if ( IsFileExtension ( path , filter ) )
{
strcpy ( files - > paths [ files - > count ] , path ) ;
files - > count + + ;
}
}
else
{
strcpy ( files - > paths [ files - > count ] , path ) ;
files - > count + + ;
}
}
}
closedir ( dir ) ;
}
else TRACELOG ( LOG_WARNING , " FILEIO: Directory cannot be opened (%s) " , basePath) ;
}
// Scan all files and directories recursively from a base path
static void ScanDirectoryFilesRecursively ( const char * basePath , FilePathList * files , const char * filter )
{
static char path [ MAX_FILEPATH_LENGTH ] = { 0 } ;
memset ( path , 0 , MAX_FILEPATH_LENGTH ) ;
struct dirent * dp = NULL ;
DIR * dir = opendir ( basePath ) ;
if ( dir ! = NULL )
{
2022-06-12 11:32:10 +02:00
while ( ( ( dp = readdir ( dir ) ) ! = NULL ) & & ( files - > count < files - > capacity ) )
2022-06-11 23:24:13 +02:00
{
if ( ( strcmp ( dp - > d_name , " . " ) ! = 0 ) & & ( strcmp ( dp - > d_name , " .. " ) ! = 0 ) )
{
// Construct new path from our base path
sprintf ( path , " %s/%s " , basePath , dp - > d_name ) ;
if ( IsPathFile ( path ) )
{
if ( filter ! = NULL )
{
if ( IsFileExtension ( path , filter ) )
{
strcpy ( files - > paths [ files - > count ] , path ) ;
files - > count + + ;
}
}
else
{
strcpy ( files - > paths [ files - > count ] , path ) ;
files - > count + + ;
}
2022-06-12 11:32:10 +02:00
if ( files - > count > = files - > capacity )
{
TRACELOG ( LOG_WARNING , " FILEIO: Maximum filepath scan capacity reached (%i files) " , files - > capacity ) ;
break ;
}
2022-06-11 23:24:13 +02:00
}
else ScanDirectoryFilesRecursively ( path , files , filter ) ;
}
}
closedir ( dir ) ;
}
else TRACELOG ( LOG_WARNING , " FILEIO: Directory cannot be opened (%s) " , basePath) ;
}
2016-05-02 14:11:57 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback ( int error , const char * description )
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " GLFW: Error: %i Description: %s " , error , description ) ;
2016-05-02 14:11:57 +02:00
}
2021-06-22 20:14:44 +02:00
2020-12-18 18:58:02 +01:00
// GLFW3 WindowSize Callback, runs when window is resizedLastFrame
// NOTE: Window resizing not allowed by default
static void WindowSizeCallback ( GLFWwindow * window , int width , int height )
2016-05-02 14:11:57 +02:00
{
2021-09-10 17:23:48 +02:00
// Reset viewport and projection matrix for new size
SetupViewport ( width , height ) ;
2021-03-08 23:51:10 +02:00
CORE . Window . currentFbo . width = width ;
CORE . Window . currentFbo . height = height ;
CORE . Window . resizedLastFrame = true ;
2021-03-19 19:43:44 +01:00
2021-03-31 17:55:46 +02:00
if ( IsWindowFullscreen ( ) ) return ;
2021-03-19 19:43:44 +01:00
2020-12-18 18:58:02 +01:00
// Set current screen size
2021-10-10 22:34:56 +02:00
# if defined(__APPLE__)
2020-12-18 18:58:02 +01:00
CORE . Window . screen . width = width ;
CORE . Window . screen . height = height ;
2021-10-10 22:34:56 +02:00
# else
2021-10-10 22:38:58 +02:00
if ( ( CORE . Window . flags & FLAG_WINDOW_HIGHDPI ) > 0 )
{
2021-10-10 22:34:56 +02:00
Vector2 windowScaleDPI = GetWindowScaleDPI ( ) ;
2021-10-10 22:38:58 +02:00
2021-10-25 01:18:42 -07:00
CORE . Window . screen . width = ( unsigned int ) ( width / windowScaleDPI . x ) ;
CORE . Window . screen . height = ( unsigned int ) ( height / windowScaleDPI . y ) ;
2021-10-14 00:11:37 +02:00
}
2021-10-10 22:38:58 +02:00
else
{
2021-10-10 22:34:56 +02:00
CORE . Window . screen . width = width ;
CORE . Window . screen . height = height ;
}
# endif
2021-10-03 12:09:59 +02:00
2020-12-18 18:58:02 +01:00
// 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
}
2020-12-18 19:32:52 +01:00
# if !defined(PLATFORM_WEB)
2020-12-18 18:58:02 +01:00
// GLFW3 WindowMaximize Callback, runs when window is maximized/restored
static void WindowMaximizeCallback ( GLFWwindow * window , int maximized )
{
if ( maximized ) CORE . Window . flags | = FLAG_WINDOW_MAXIMIZED ; // The window was maximized
else CORE . Window . flags & = ~ FLAG_WINDOW_MAXIMIZED ; // The window was restored
}
2020-12-18 19:32:52 +01:00
# endif
2020-12-18 18:58:02 +01:00
// 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
2016-05-02 14:11:57 +02:00
}
// GLFW3 Keyboard Callback, runs on key pressed
static void KeyCallback ( GLFWwindow * window , int key , int scancode , int action , int mods )
{
2021-10-26 22:27:18 +02:00
// 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 CORE . Input . Keyboard . currentKeyState [ key ] = 1 ;
2020-12-18 18:58:02 +01:00
2021-10-26 22:27:18 +02:00
// Check if there is space available in the key queue
if ( ( CORE . Input . Keyboard . keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE ) & & ( action = = GLFW_PRESS ) )
2016-05-02 14:11:57 +02:00
{
2021-10-26 22:27:18 +02:00
// Add character to the queue
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = key ;
CORE . Input . Keyboard . keyPressedQueueCount + + ;
2016-05-02 14:11:57 +02:00
}
2022-02-18 20:30:46 +01:00
2021-10-26 22:27:18 +02:00
// Check the exit key to set close window
if ( ( key = = CORE . Input . Keyboard . exitKey ) & & ( action = = GLFW_PRESS ) ) glfwSetWindowShouldClose ( CORE . Window . handle , GLFW_TRUE ) ;
2021-01-20 17:06:53 +01:00
# if defined(SUPPORT_SCREEN_CAPTURE)
2021-10-26 22:27:18 +02:00
if ( ( key = = GLFW_KEY_F12 ) & & ( action = = GLFW_PRESS ) )
2017-05-11 16:24:40 +02:00
{
2019-01-05 18:03:09 +01:00
# if defined(SUPPORT_GIF_RECORDING)
2017-05-18 18:57:11 +02:00
if ( mods = = GLFW_MOD_CONTROL )
{
if ( gifRecording )
{
gifRecording = false ;
2020-12-23 15:03:26 +01:00
2020-11-20 00:34:18 +01:00
MsfGifResult result = msf_gif_end ( & gifState ) ;
2020-12-23 15:03:26 +01:00
2021-06-24 18:13:25 +02:00
SaveFileData ( TextFormat ( " %s/screenrec%03i.gif " , CORE . Storage . basePath , screenshotCounter ) , result . data , ( unsigned int ) result . dataSize ) ;
2020-11-20 00:34:18 +01:00
msf_gif_free ( result ) ;
2019-01-23 20:07:47 -05:00
2019-01-05 18:03:09 +01:00
# if defined(PLATFORM_WEB)
// Download file from MEMFS (emscripten memory filesystem)
2019-05-22 16:12:47 +02:00
// 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 ) ) ) ;
2019-01-05 18:03:09 +01:00
# endif
2018-11-06 15:10:50 +01:00
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " SYSTEM: Finish animated GIF recording " ) ;
2017-05-18 18:57:11 +02:00
}
2018-11-06 15:10:50 +01:00
else
2017-05-18 18:57:11 +02:00
{
gifRecording = true ;
2021-09-01 23:09:30 +02:00
gifFrameCounter = 0 ;
2019-01-23 20:07:47 -05:00
2022-05-20 17:25:47 +02:00
Vector2 scale = GetWindowScaleDPI ( ) ;
2022-06-07 10:04:24 +02:00
msf_gif_begin ( & gifState , ( int ) ( ( float ) CORE . Window . render . width * scale . x ) , ( int ) ( ( float ) CORE . Window . render . height * scale . y ) ) ;
2017-05-18 18:57:11 +02:00
screenshotCounter + + ;
2018-11-06 15:10:50 +01:00
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " SYSTEM: Start animated GIF recording: %s " , TextFormat ( " screenrec%03i.gif " , screenshotCounter ) ) ;
2017-05-18 18:57:11 +02:00
}
}
else
2021-03-19 19:43:44 +01:00
# endif // SUPPORT_GIF_RECORDING
2017-05-18 18:57:11 +02:00
{
2018-12-26 13:26:34 +01:00
TakeScreenshot ( TextFormat ( " screenshot%03i.png " , screenshotCounter ) ) ;
2017-05-18 18:57:11 +02:00
screenshotCounter + + ;
}
2017-05-11 16:24:40 +02:00
}
2021-01-20 17:06:53 +01:00
# endif // SUPPORT_SCREEN_CAPTURE
2021-10-26 22:27:18 +02:00
2021-06-11 12:27:46 +02:00
# if defined(SUPPORT_EVENTS_AUTOMATION)
2021-10-26 22:27:18 +02:00
if ( ( key = = GLFW_KEY_F11 ) & & ( action = = GLFW_PRESS ) )
2021-06-11 12:27:46 +02:00
{
eventsRecording = ! eventsRecording ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// On finish recording, we export events into a file
if ( ! eventsRecording ) ExportAutomationEvents ( " eventsrec.rep " ) ;
}
2021-10-26 22:27:18 +02:00
else if ( ( key = = GLFW_KEY_F9 ) & & ( action = = GLFW_PRESS ) )
2021-06-11 12:27:46 +02:00
{
LoadAutomationEvents ( " eventsrec.rep " ) ;
eventsPlaying = true ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
TRACELOG ( LOG_WARNING , " eventsPlaying enabled! " ) ;
}
# endif
2020-12-18 18:58:02 +01:00
}
// 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
// do not detects 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_KEY_PRESSED_QUEUE )
{
// Add character to the queue
CORE . Input . Keyboard . charPressedQueue [ CORE . Input . Keyboard . charPressedQueueCount ] = key ;
CORE . Input . Keyboard . charPressedQueueCount + + ;
2020-03-03 16:43:15 +01:00
}
2016-05-02 14:11:57 +02:00
}
// GLFW3 Mouse Button Callback, runs on mouse button pressed
static void MouseButtonCallback ( GLFWwindow * window , int button , int action , int mods )
{
2020-03-25 19:41:51 +01:00
// WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now,
2020-03-03 16:43:15 +01:00
// but future releases may add more actions (i.e. GLFW_REPEAT)
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . currentButtonState [ button ] = action ;
2020-03-25 19:41:51 +01:00
2021-09-10 15:19:12 +02:00
# if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP
2016-05-02 14:11:57 +02:00
// Process mouse events as touches to be able to use mouse-gestures
2020-02-12 13:16:18 +01:00
GestureEvent gestureEvent = { 0 } ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Register touch actions
2021-09-21 15:06:06 +02:00
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 ;
2020-03-25 19:41:51 +01:00
2021-09-21 15:06:06 +02:00
// NOTE: TOUCH_ACTION_MOVE event is registered in MouseCursorPosCallback()
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Assign a pointer ID
2021-09-10 15:19:12 +02:00
gestureEvent . pointId [ 0 ] = 0 ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Register touch points count
gestureEvent . pointCount = 1 ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Register touch points position, only one point registered
gestureEvent . position [ 0 ] = GetMousePosition ( ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
// Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
2016-05-31 19:12:37 +02:00
gestureEvent . position [ 0 ] . x / = ( float ) GetScreenWidth ( ) ;
2016-05-02 14:11:57 +02:00
gestureEvent . position [ 0 ] . y / = ( float ) GetScreenHeight ( ) ;
2016-05-31 19:12:37 +02:00
// Gesture data is sent to gestures system for processing
2016-05-02 14:11:57 +02:00
ProcessGestureEvent ( gestureEvent ) ;
# endif
}
// GLFW3 Cursor Position Callback, runs on mouse move
static void MouseCursorPosCallback ( GLFWwindow * window , double x , double y )
{
2021-06-10 18:03:25 +02:00
CORE . Input . Mouse . currentPosition . x = ( float ) x ;
CORE . Input . Mouse . currentPosition . y = ( float ) y ;
CORE . Input . Touch . position [ 0 ] = CORE . Input . Mouse . currentPosition ;
2020-03-25 19:41:51 +01:00
2021-09-10 15:19:12 +02:00
# if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // PLATFORM_DESKTOP
2016-05-02 14:11:57 +02:00
// Process mouse events as touches to be able to use mouse-gestures
2020-02-12 13:16:18 +01:00
GestureEvent gestureEvent = { 0 } ;
2016-05-02 14:11:57 +02:00
2021-09-21 15:06:06 +02:00
gestureEvent . touchAction = TOUCH_ACTION_MOVE ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Assign a pointer ID
2021-09-10 15:19:12 +02:00
gestureEvent . pointId [ 0 ] = 0 ;
2016-05-02 14:11:57 +02:00
// Register touch points count
gestureEvent . pointCount = 1 ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Register touch points position, only one point registered
2020-02-29 22:10:23 +01:00
gestureEvent . position [ 0 ] = CORE . Input . Touch . position [ 0 ] ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
// Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
2016-08-16 11:09:55 +02:00
gestureEvent . position [ 0 ] . x / = ( float ) GetScreenWidth ( ) ;
2016-05-02 14:11:57 +02:00
gestureEvent . position [ 0 ] . y / = ( float ) GetScreenHeight ( ) ;
// Gesture data is sent to gestures system for processing
ProcessGestureEvent ( gestureEvent ) ;
# endif
}
2022-04-24 11:16:35 +02:00
// GLFW3 Scrolling Callback, runs on mouse wheel
2020-12-18 18:58:02 +01:00
static void MouseScrollCallback ( GLFWwindow * window , double xoffset , double yoffset )
2018-11-06 15:10:50 +01:00
{
2022-06-12 11:30:07 -04:00
CORE . Input . Mouse . currentWheelMove = ( Vector2 ) { ( float ) xoffset , ( float ) yoffset } ;
2016-05-02 14:11:57 +02:00
}
// GLFW3 CursorEnter Callback, when cursor enters the window
static void CursorEnterCallback ( GLFWwindow * window , int enter )
{
2020-02-03 18:31:30 +01:00
if ( enter = = true ) CORE . Input . Mouse . cursorOnScreen = true ;
else CORE . Input . Mouse . cursorOnScreen = false ;
2016-05-02 14:11:57 +02:00
}
2015-07-29 21:44:27 +02:00
// GLFW3 Window Drop Callback, runs when drop files into window
static void WindowDropCallback ( GLFWwindow * window , int count , const char * * paths )
{
2022-06-17 12:06:58 +02:00
// In case previous dropped filepaths have not been freed, we free them
if ( CORE . Window . dropFileCount > 0 )
{
for ( 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
2021-09-01 23:09:30 +02:00
CORE . Window . dropFileCount = count ;
2022-06-17 12:06:58 +02:00
CORE . Window . dropFilepaths = ( char * * ) RL_CALLOC ( CORE . Window . dropFileCount , sizeof ( char * ) ) ;
for ( 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 ] ) ;
}
2015-01-21 00:13:17 +01:00
}
2014-09-16 22:51:31 +02:00
# endif
# if defined(PLATFORM_ANDROID)
2020-03-27 18:06:09 +01:00
// ANDROID: Process activity lifecycle commands
2015-04-22 17:34:42 +02:00
static void AndroidCommandCallback ( struct android_app * app , int32_t cmd )
2014-09-16 22:51:31 +02:00
{
switch ( cmd )
{
case APP_CMD_START :
{
//rendering = true;
} break ;
2020-01-21 00:32:35 +01:00
case APP_CMD_RESUME : break ;
2014-09-16 22:51:31 +02:00
case APP_CMD_INIT_WINDOW :
{
if ( app - > window ! = NULL )
{
2020-02-03 18:31:30 +01:00
if ( CORE . Android . contextRebindRequired )
2016-01-03 13:01:21 +01:00
{
// Reset screen scaling to full display size
2021-06-24 18:13:25 +02:00
EGLint displayFormat = 0 ;
2020-02-03 18:31:30 +01:00
eglGetConfigAttrib ( CORE . Window . device , CORE . Window . config , EGL_NATIVE_VISUAL_ID , & displayFormat ) ;
ANativeWindow_setBuffersGeometry ( app - > window , CORE . Window . render . width , CORE . Window . render . height , displayFormat ) ;
2014-09-16 22:51:31 +02:00
2016-01-03 13:01:21 +01:00
// Recreate display surface and re-attach OpenGL context
2020-02-03 18:31:30 +01:00
CORE . Window . surface = eglCreateWindowSurface ( CORE . Window . device , CORE . Window . config , app - > window , NULL ) ;
eglMakeCurrent ( CORE . Window . device , CORE . Window . surface , CORE . Window . surface , CORE . Window . context ) ;
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
CORE . Android . contextRebindRequired = false ;
2016-01-03 13:01:21 +01:00
}
else
{
2021-06-05 12:33:05 +02:00
CORE . Window . display . width = ANativeWindow_getWidth ( CORE . Android . app - > window ) ;
2020-03-16 01:56:43 +11:00
CORE . Window . display . height = ANativeWindow_getHeight ( CORE . Android . app - > window ) ;
2021-06-24 18:13:25 +02:00
// Initialize graphics device (display device and OpenGL context)
2020-02-03 18:31:30 +01:00
InitGraphicsDevice ( CORE . Window . screen . width , CORE . Window . screen . height ) ;
2018-11-06 15:10:50 +01:00
2021-06-24 18:13:25 +02:00
// Initialize hi-res timer
2017-12-19 14:06:54 +01:00
InitTimer ( ) ;
2021-06-30 16:39:07 +02:00
2021-06-22 20:26:59 +02:00
// Initialize random seed
srand ( ( unsigned int ) time ( NULL ) ) ;
2016-01-03 13:01:21 +01:00
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
2016-10-09 13:09:08 +02:00
// Load default font
2021-12-04 19:56:02 +01:00
// WARNING: External function: Module required: rtext
2019-06-16 23:42:51 +02:00
LoadFontDefault ( ) ;
2020-02-12 13:48:50 +01:00
Rectangle rec = GetFontDefault ( ) . recs [ 95 ] ;
2020-02-20 13:46:49 +01:00
// NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
2021-12-04 19:56:02 +01:00
# if defined(SUPPORT_MODULE_RSHAPES)
SetShapesTexture ( GetFontDefault ( ) . texture , ( Rectangle ) { rec . x + 1 , rec . y + 1 , rec . width - 2 , rec . height - 2 } ) ; // WARNING: Module required: rshapes
# endif
2019-01-05 18:03:09 +01:00
# endif
2016-05-31 19:12:37 +02:00
2016-01-03 13:01:21 +01:00
// TODO: GPU assets reload in case of lost focus (lost context)
// NOTE: This problem has been solved just unbinding and rebinding context from display
2016-05-31 19:12:37 +02:00
/*
2016-01-03 13:01:21 +01:00
if ( assetsReloadRequired )
{
2021-09-01 23:09:30 +02:00
for ( int i = 0 ; i < assetCount ; i + + )
2016-01-03 13:01:21 +01:00
{
// TODO: Unload old asset if required
2016-08-16 11:09:55 +02:00
2016-01-03 13:01:21 +01:00
// Load texture again to pointed texture
( * textureAsset + i ) = LoadTexture ( assetPath [ i ] ) ;
}
}
*/
2014-09-16 22:51:31 +02:00
}
}
} break ;
case APP_CMD_GAINED_FOCUS :
{
2020-02-03 18:31:30 +01:00
CORE . Android . appEnabled = true ;
2015-07-29 21:44:27 +02:00
//ResumeMusicStream();
2014-09-16 22:51:31 +02:00
} break ;
2020-01-21 00:32:35 +01:00
case APP_CMD_PAUSE : break ;
2014-09-16 22:51:31 +02:00
case APP_CMD_LOST_FOCUS :
{
2020-02-03 18:31:30 +01:00
CORE . Android . appEnabled = false ;
2015-07-29 21:44:27 +02:00
//PauseMusicStream();
2014-09-16 22:51:31 +02:00
} break ;
case APP_CMD_TERM_WINDOW :
{
2016-01-03 13:01:21 +01:00
// Dettach OpenGL context and destroy display surface
// NOTE 1: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...)
// NOTE 2: In some cases (too many context loaded), OS could unload context automatically... :(
2020-02-03 18:31:30 +01:00
eglMakeCurrent ( CORE . Window . device , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
eglDestroySurface ( CORE . Window . device , CORE . Window . surface ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
CORE . Android . contextRebindRequired = true ;
2014-09-16 22:51:31 +02:00
} break ;
2020-01-21 00:32:35 +01:00
case APP_CMD_SAVE_STATE : break ;
case APP_CMD_STOP : break ;
2014-09-16 22:51:31 +02:00
case APP_CMD_DESTROY :
{
// TODO: Finish activity?
2020-02-03 18:31:30 +01:00
//ANativeActivity_finish(CORE.Android.app->activity);
2014-09-16 22:51:31 +02:00
} break ;
case APP_CMD_CONFIG_CHANGED :
{
2020-02-03 18:31:30 +01:00
//AConfiguration_fromAssetManager(CORE.Android.app->config, CORE.Android.app->activity->assetManager);
//print_cur_config(CORE.Android.app);
2014-09-16 22:51:31 +02:00
// Check screen orientation here!
} break ;
default : break ;
}
}
2016-01-03 13:01:21 +01:00
2020-03-27 18:06:09 +01:00
// ANDROID: Get input events
2016-01-03 13:01:21 +01:00
static int32_t AndroidInputCallback ( struct android_app * app , AInputEvent * event )
{
2018-07-05 19:00:49 +02:00
// If additional inputs are required check:
// https://developer.android.com/ndk/reference/group/input
2020-02-22 10:38:32 +01:00
// https://developer.android.com/training/game-controllers/controller-input
2016-08-16 11:09:55 +02:00
2016-01-03 13:01:21 +01:00
int type = AInputEvent_getType ( event ) ;
2020-02-22 10:38:32 +01:00
int source = AInputEvent_getSource ( event ) ;
2016-01-03 13:01:21 +01:00
if ( type = = AINPUT_EVENT_TYPE_MOTION )
{
2020-11-03 23:47:33 +01:00
if ( ( ( source & AINPUT_SOURCE_JOYSTICK ) = = AINPUT_SOURCE_JOYSTICK ) | |
2020-04-24 23:17:32 +02:00
( ( source & AINPUT_SOURCE_GAMEPAD ) = = AINPUT_SOURCE_GAMEPAD ) )
2020-02-22 10:38:32 +01:00
{
// Get first touch position
CORE . Input . Touch . position [ 0 ] . x = AMotionEvent_getX ( event , 0 ) ;
CORE . Input . Touch . position [ 0 ] . y = AMotionEvent_getY ( event , 0 ) ;
2016-08-16 11:09:55 +02:00
2020-02-22 10:38:32 +01:00
// Get second touch position
CORE . Input . Touch . position [ 1 ] . x = AMotionEvent_getX ( event , 1 ) ;
CORE . Input . Touch . position [ 1 ] . y = AMotionEvent_getY ( event , 1 ) ;
2018-11-06 15:10:50 +01:00
2020-02-22 10:38:32 +01:00
int32_t keycode = AKeyEvent_getKeyCode ( event ) ;
if ( AKeyEvent_getAction ( event ) = = AKEY_EVENT_ACTION_DOWN )
{
2020-03-01 01:29:34 +01:00
CORE . Input . Keyboard . currentKeyState [ keycode ] = 1 ; // Key down
2018-11-06 15:10:50 +01:00
2020-02-22 10:38:32 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = keycode ;
CORE . Input . Keyboard . keyPressedQueueCount + + ;
}
else CORE . Input . Keyboard . currentKeyState [ keycode ] = 0 ; // Key up
2020-02-03 19:26:28 +01:00
2020-02-22 10:38:32 +01:00
// Stop processing gamepad buttons
return 1 ;
2018-07-06 13:33:46 -04:00
}
2016-01-03 13:01:21 +01:00
}
else if ( type = = AINPUT_EVENT_TYPE_KEY )
{
int32_t keycode = AKeyEvent_getKeyCode ( event ) ;
//int32_t AKeyEvent_getMetaState(event);
2016-08-16 11:09:55 +02:00
2016-01-05 12:21:40 +01:00
// Save current button and its state
2016-10-17 18:18:13 +02:00
// NOTE: Android key action is 0 for down and 1 for up
2018-07-07 10:15:19 +02:00
if ( AKeyEvent_getAction ( event ) = = AKEY_EVENT_ACTION_DOWN )
2016-10-17 18:18:13 +02:00
{
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . currentKeyState [ keycode ] = 1 ; // Key down
2020-02-03 19:26:28 +01:00
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = keycode ;
CORE . Input . Keyboard . keyPressedQueueCount + + ;
2016-10-17 18:18:13 +02:00
}
2020-02-03 18:31:30 +01:00
else CORE . Input . Keyboard . currentKeyState [ keycode ] = 0 ; // Key up
2016-01-03 13:01:21 +01:00
2016-01-05 12:21:40 +01:00
if ( keycode = = AKEYCODE_POWER )
{
// Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS
// Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS
// It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected.
// NOTE: AndroidManifest.xml must have <activity android:configChanges="orientation|keyboardHidden|screenSize" >
// Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour
return 0 ;
2016-08-16 11:09:55 +02:00
}
2016-01-05 12:21:40 +01:00
else if ( ( keycode = = AKEYCODE_BACK ) | | ( keycode = = AKEYCODE_MENU ) )
2016-01-03 13:01:21 +01:00
{
2016-01-04 21:00:20 +01:00
// Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS!
2016-01-03 13:01:21 +01:00
return 1 ;
}
else if ( ( keycode = = AKEYCODE_VOLUME_UP ) | | ( keycode = = AKEYCODE_VOLUME_DOWN ) )
{
// Set default OS behaviour
return 0 ;
}
2020-02-22 10:38:32 +01:00
return 0 ;
2016-01-03 13:01:21 +01:00
}
2021-10-03 12:09:59 +02:00
2021-09-10 15:19:12 +02:00
// Register touch points count
CORE . Input . Touch . pointCount = AMotionEvent_getPointerCount ( event ) ;
2021-10-03 12:09:59 +02:00
2021-09-10 15:19:12 +02:00
for ( int i = 0 ; ( i < CORE . Input . Touch . pointCount ) & & ( i < MAX_TOUCH_POINTS ) ; i + + )
2021-07-13 03:17:47 -07:00
{
2021-09-10 15:19:12 +02:00
// Register touch points id
CORE . Input . Touch . pointId [ i ] = AMotionEvent_getPointerId ( event , i ) ;
// Register touch points position
CORE . Input . Touch . position [ i ] = ( Vector2 ) { AMotionEvent_getX ( event , i ) , AMotionEvent_getY ( event , i ) } ;
2021-10-03 12:09:59 +02:00
2021-09-21 15:06:06 +02:00
// Normalize CORE.Input.Touch.position[x] for screenWidth and screenHeight
CORE . Input . Touch . position [ i ] . x / = ( float ) GetScreenWidth ( ) ;
CORE . Input . Touch . position [ i ] . y / = ( float ) GetScreenHeight ( ) ;
2021-07-13 03:17:47 -07:00
}
2016-01-03 13:01:21 +01:00
int32_t action = AMotionEvent_getAction ( event ) ;
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK ;
2016-08-16 11:09:55 +02:00
2021-09-10 15:19:12 +02:00
if ( flags = = AMOTION_EVENT_ACTION_DOWN | | flags = = AMOTION_EVENT_ACTION_MOVE ) CORE . Input . Touch . currentTouchState [ MOUSE_BUTTON_LEFT ] = 1 ;
else if ( flags = = AMOTION_EVENT_ACTION_UP ) CORE . Input . Touch . currentTouchState [ MOUSE_BUTTON_LEFT ] = 0 ;
2020-03-24 23:23:34 +11:00
2021-09-10 15:19:12 +02:00
# if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_ANDROID
2021-07-03 21:31:52 +02:00
GestureEvent gestureEvent = { 0 } ;
2021-10-03 12:09:59 +02:00
2021-09-10 15:19:12 +02:00
gestureEvent . pointCount = CORE . Input . Touch . pointCount ;
2016-08-16 11:09:55 +02:00
2016-01-03 13:01:21 +01:00
// Register touch actions
2021-09-21 15:06:06 +02:00
if ( flags = = AMOTION_EVENT_ACTION_DOWN ) gestureEvent . touchAction = TOUCH_ACTION_DOWN ;
else if ( flags = = AMOTION_EVENT_ACTION_UP ) gestureEvent . touchAction = TOUCH_ACTION_UP ;
else if ( flags = = AMOTION_EVENT_ACTION_MOVE ) gestureEvent . touchAction = TOUCH_ACTION_MOVE ;
else if ( flags = = AMOTION_EVENT_ACTION_CANCEL ) gestureEvent . touchAction = TOUCH_ACTION_CANCEL ;
2016-08-16 11:09:55 +02:00
2021-09-10 15:19:12 +02:00
for ( int i = 0 ; ( i < gestureEvent . pointCount ) & & ( i < MAX_TOUCH_POINTS ) ; i + + )
2018-07-07 10:15:19 +02:00
{
2021-09-10 15:19:12 +02:00
gestureEvent . pointId [ i ] = CORE . Input . Touch . pointId [ i ] ;
gestureEvent . position [ i ] = CORE . Input . Touch . position [ i ] ;
2018-07-07 10:15:19 +02:00
}
2021-09-10 15:19:12 +02:00
// Gesture data is sent to gestures system for processing
ProcessGestureEvent ( gestureEvent ) ;
2017-09-29 13:56:37 +02:00
# endif
2016-01-03 13:01:21 +01:00
2017-09-29 13:56:37 +02:00
return 0 ;
2016-01-03 13:01:21 +01:00
}
2014-09-16 22:51:31 +02:00
# endif
2016-05-02 14:11:57 +02:00
# if defined(PLATFORM_WEB)
2021-12-31 17:46:31 +01:00
// Register fullscreen change events
static EM_BOOL EmscriptenFullscreenChangeCallback ( int eventType , const EmscriptenFullscreenChangeEvent * event , void * userData )
{
2022-06-12 11:32:10 +02:00
// TODO: Implement EmscriptenFullscreenChangeCallback()?
2021-12-31 17:46:31 +01:00
return 1 ; // The event was consumed by the callback handler
}
// Register window resize event
2021-12-31 18:18:27 +01:00
static EM_BOOL EmscriptenWindowResizedCallback ( int eventType , const EmscriptenUiEvent * event , void * userData )
2021-12-31 17:46:31 +01:00
{
2022-06-12 11:32:10 +02:00
// TODO: Implement EmscriptenWindowResizedCallback()?
2021-12-31 17:46:31 +01:00
return 1 ; // The event was consumed by the callback handler
}
EM_JS ( int , GetCanvasWidth , ( ) , { return canvas . clientWidth ; } ) ;
EM_JS ( int , GetCanvasHeight , ( ) , { return canvas . clientHeight ; } ) ;
// 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 = GetCanvasWidth ( ) ;
int height = GetCanvasHeight ( ) ;
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 ;
}
2021-07-28 15:38:31 -04:00
// 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
2021-12-31 17:46:31 +01:00
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
2021-07-28 15:38:31 -04:00
}
2016-12-25 20:42:22 +01:00
// Register touch input events
2017-04-08 00:16:03 +02:00
static EM_BOOL EmscriptenTouchCallback ( int eventType , const EmscriptenTouchEvent * touchEvent , void * userData )
2016-05-02 14:11:57 +02:00
{
2021-09-10 15:19:12 +02:00
// Register touch points count
CORE . Input . Touch . pointCount = touchEvent - > numTouches ;
2021-10-03 12:09:59 +02:00
2021-09-10 15:19:12 +02:00
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 ) ;
2021-10-03 12:09:59 +02:00
2021-09-10 15:19:12 +02:00
for ( int i = 0 ; ( i < CORE . Input . Touch . pointCount ) & & ( i < MAX_TOUCH_POINTS ) ; i + + )
2020-03-03 14:58:54 +01:00
{
2021-09-10 15:19:12 +02:00
// 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 ) ;
2021-10-03 12:09:59 +02:00
2020-03-03 14:58:54 +01:00
if ( eventType = = EMSCRIPTEN_EVENT_TOUCHSTART ) CORE . Input . Touch . currentTouchState [ i ] = 1 ;
else if ( eventType = = EMSCRIPTEN_EVENT_TOUCHEND ) CORE . Input . Touch . currentTouchState [ i ] = 0 ;
}
2020-02-29 22:10:23 +01:00
2021-09-10 15:19:12 +02:00
# if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_WEB
2020-02-12 13:16:18 +01:00
GestureEvent gestureEvent = { 0 } ;
2021-10-03 12:09:59 +02:00
2021-09-10 15:19:12 +02:00
gestureEvent . pointCount = CORE . Input . Touch . pointCount ;
2014-09-16 22:51:31 +02:00
2016-05-02 14:11:57 +02:00
// Register touch actions
2021-09-21 15:06:06 +02:00
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 ;
2016-08-16 11:09:55 +02:00
2021-09-10 15:19:12 +02:00
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 ] ;
}
2016-02-18 14:05:48 +01:00
2016-05-02 14:11:57 +02:00
// Gesture data is sent to gestures system for processing
2016-06-03 18:51:19 +02:00
ProcessGestureEvent ( gestureEvent ) ;
2019-03-25 12:30:20 +01:00
# endif
2016-02-18 14:05:48 +01:00
2021-12-31 17:46:31 +01:00
return 1 ; // The event was consumed by the callback handler
2016-12-25 20:42:22 +01:00
}
2016-05-02 14:11:57 +02:00
# endif
2016-02-18 14:05:48 +01:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2016-02-18 14:05:48 +01:00
// Initialize Keyboard system (using standard input)
static void InitKeyboard ( void )
{
2021-07-06 18:25:00 +02:00
// NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor,
// Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE
2016-02-18 14:05:48 +01:00
2021-07-06 18:25:00 +02:00
// Save terminal keyboard settings
tcgetattr ( STDIN_FILENO , & CORE . Input . Keyboard . defaultSettings ) ;
2021-07-16 16:10:53 +02:00
2021-07-06 18:25:00 +02:00
// Reconfigure terminal with new settings
2021-07-03 21:25:30 +02:00
struct termios keyboardNewSettings = { 0 } ;
2020-02-03 18:31:30 +01:00
keyboardNewSettings = CORE . Input . Keyboard . defaultSettings ;
2016-02-18 14:05:48 +01:00
// New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
// NOTE: ISIG controls if ^C and ^Z generate break signals or not
keyboardNewSettings . c_lflag & = ~ ( ICANON | ECHO | ISIG ) ;
//keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
keyboardNewSettings . c_cc [ VMIN ] = 1 ;
keyboardNewSettings . c_cc [ VTIME ] = 0 ;
// Set new keyboard settings (change occurs immediately)
tcsetattr ( STDIN_FILENO , TCSANOW , & keyboardNewSettings ) ;
// Save old keyboard mode to restore it at the end
2021-07-17 15:27:48 -03:00
CORE . Input . Keyboard . defaultFileFlags = fcntl ( STDIN_FILENO , F_GETFL , 0 ) ; // F_GETFL: Get the file access mode and the file status flags
fcntl ( STDIN_FILENO , F_SETFL , CORE . Input . Keyboard . defaultFileFlags | O_NONBLOCK ) ; // F_SETFL: Set the file status flags to the value specified
2021-07-06 18:25:00 +02:00
// NOTE: If ioctl() returns -1, it means the call failed for some reason (error code set in errno)
int result = ioctl ( STDIN_FILENO , KDGKBMODE , & CORE . Input . Keyboard . defaultMode ) ;
2021-07-16 16:10:53 +02:00
2021-07-06 18:25:00 +02:00
// In case of failure, it could mean a remote keyboard is used (SSH)
if ( result < 0 ) TRACELOG ( LOG_WARNING , " RPI: Failed to change keyboard mode, an SSH keyboard is probably used " ) ;
2016-02-18 14:05:48 +01:00
else
{
2021-07-06 18:25:00 +02:00
// Reconfigure keyboard mode to get:
2016-08-16 11:09:55 +02:00
// - scancodes (K_RAW)
2016-02-18 14:05:48 +01:00
// - keycodes (K_MEDIUMRAW)
// - ASCII chars (K_XLATE)
// - UNICODE chars (K_UNICODE)
2021-07-06 18:25:00 +02:00
ioctl ( STDIN_FILENO , KDSKBMODE , K_XLATE ) ; // ASCII chars
2016-02-18 14:05:48 +01:00
}
// Register keyboard restore when program finishes
atexit ( RestoreKeyboard ) ;
}
2021-07-06 18:25:00 +02:00
// Restore default keyboard input
static void RestoreKeyboard ( void )
{
// Reset to default keyboard settings
tcsetattr ( STDIN_FILENO , TCSANOW , & CORE . Input . Keyboard . defaultSettings ) ;
// Reconfigure keyboard to default mode
2021-07-17 15:27:48 -03:00
fcntl ( STDIN_FILENO , F_SETFL , CORE . Input . Keyboard . defaultFileFlags ) ;
2021-07-06 18:25:00 +02:00
ioctl ( STDIN_FILENO , KDSKBMODE , CORE . Input . Keyboard . defaultMode ) ;
}
# if defined(SUPPORT_SSH_KEYBOARD_RPI)
2016-02-19 19:57:25 +01:00
// Process keyboard inputs
2016-02-18 14:05:48 +01:00
static void ProcessKeyboard ( void )
{
2016-02-19 19:57:25 +01:00
# define MAX_KEYBUFFER_SIZE 32 // Max size in bytes to read
2016-08-16 11:09:55 +02:00
2014-09-16 22:51:31 +02:00
// Keyboard input polling (fill keys[256] array with status)
2021-11-09 11:49:03 +01:00
int bufferByteCount = 0 ; // Bytes available on the buffer
char keysBuffer [ MAX_KEYBUFFER_SIZE ] = { 0 } ; // Max keys to be read at a time
2014-09-16 22:51:31 +02:00
// Read availables keycodes from stdin
2016-02-19 19:57:25 +01:00
bufferByteCount = read ( STDIN_FILENO , keysBuffer , MAX_KEYBUFFER_SIZE ) ; // POSIX system call
2019-01-23 20:07:47 -05:00
2018-12-19 15:31:20 +01:00
// Reset pressed keys array (it will be filled below)
2021-07-17 15:27:48 -03:00
for ( int i = 0 ; i < MAX_KEYBOARD_KEYS ; i + + ) CORE . Input . Keyboard . currentKeyState [ i ] = 0 ;
2019-03-28 19:46:39 +01:00
2016-02-19 19:57:25 +01:00
// Fill all read bytes (looking for keys)
for ( int i = 0 ; i < bufferByteCount ; i + + )
2014-09-16 22:51:31 +02:00
{
2016-02-19 19:57:25 +01:00
// NOTE: If (key == 0x1b), depending on next key, it could be a special keymap code!
// Up -> 1b 5b 41 / Left -> 1b 5b 44 / Right -> 1b 5b 43 / Down -> 1b 5b 42
if ( keysBuffer [ i ] = = 0x1b )
2014-09-16 22:51:31 +02:00
{
2021-06-10 17:49:55 +02:00
// Check if ESCAPE key has been pressed to stop program
2020-03-09 13:01:10 +01:00
if ( bufferByteCount = = 1 ) CORE . Input . Keyboard . currentKeyState [ CORE . Input . Keyboard . exitKey ] = 1 ;
2016-02-19 19:57:25 +01:00
else
2014-09-16 22:51:31 +02:00
{
2016-02-19 19:57:25 +01:00
if ( keysBuffer [ i + 1 ] = = 0x5b ) // Special function key
2014-09-16 22:51:31 +02:00
{
2016-02-19 19:57:25 +01:00
if ( ( keysBuffer [ i + 2 ] = = 0x5b ) | | ( keysBuffer [ i + 2 ] = = 0x31 ) | | ( keysBuffer [ i + 2 ] = = 0x32 ) )
2014-09-16 22:51:31 +02:00
{
2016-02-19 19:57:25 +01:00
// Process special function keys (F1 - F12)
switch ( keysBuffer [ i + 3 ] )
{
2020-02-03 18:31:30 +01:00
case 0x41 : CORE . Input . Keyboard . currentKeyState [ 290 ] = 1 ; break ; // raylib KEY_F1
case 0x42 : CORE . Input . Keyboard . currentKeyState [ 291 ] = 1 ; break ; // raylib KEY_F2
case 0x43 : CORE . Input . Keyboard . currentKeyState [ 292 ] = 1 ; break ; // raylib KEY_F3
case 0x44 : CORE . Input . Keyboard . currentKeyState [ 293 ] = 1 ; break ; // raylib KEY_F4
case 0x45 : CORE . Input . Keyboard . currentKeyState [ 294 ] = 1 ; break ; // raylib KEY_F5
case 0x37 : CORE . Input . Keyboard . currentKeyState [ 295 ] = 1 ; break ; // raylib KEY_F6
case 0x38 : CORE . Input . Keyboard . currentKeyState [ 296 ] = 1 ; break ; // raylib KEY_F7
case 0x39 : CORE . Input . Keyboard . currentKeyState [ 297 ] = 1 ; break ; // raylib KEY_F8
case 0x30 : CORE . Input . Keyboard . currentKeyState [ 298 ] = 1 ; break ; // raylib KEY_F9
case 0x31 : CORE . Input . Keyboard . currentKeyState [ 299 ] = 1 ; break ; // raylib KEY_F10
case 0x33 : CORE . Input . Keyboard . currentKeyState [ 300 ] = 1 ; break ; // raylib KEY_F11
case 0x34 : CORE . Input . Keyboard . currentKeyState [ 301 ] = 1 ; break ; // raylib KEY_F12
2016-02-19 19:57:25 +01:00
default : break ;
}
2016-08-16 11:09:55 +02:00
2016-02-19 19:57:25 +01:00
if ( keysBuffer [ i + 2 ] = = 0x5b ) i + = 4 ;
else if ( ( keysBuffer [ i + 2 ] = = 0x31 ) | | ( keysBuffer [ i + 2 ] = = 0x32 ) ) i + = 5 ;
2014-09-16 22:51:31 +02:00
}
2016-02-19 19:57:25 +01:00
else
{
switch ( keysBuffer [ i + 2 ] )
{
2020-02-03 18:31:30 +01:00
case 0x41 : CORE . Input . Keyboard . currentKeyState [ 265 ] = 1 ; break ; // raylib KEY_UP
case 0x42 : CORE . Input . Keyboard . currentKeyState [ 264 ] = 1 ; break ; // raylib KEY_DOWN
case 0x43 : CORE . Input . Keyboard . currentKeyState [ 262 ] = 1 ; break ; // raylib KEY_RIGHT
case 0x44 : CORE . Input . Keyboard . currentKeyState [ 263 ] = 1 ; break ; // raylib KEY_LEFT
2016-02-19 19:57:25 +01:00
default : break ;
}
2014-09-16 22:51:31 +02:00
2016-02-19 19:57:25 +01:00
i + = 3 ; // Jump to next key
}
2016-08-16 11:09:55 +02:00
2016-02-19 19:57:25 +01:00
// NOTE: Some keys are not directly keymapped (CTRL, ALT, SHIFT)
2014-09-16 22:51:31 +02:00
}
}
}
2019-11-24 13:39:45 +01:00
else if ( keysBuffer [ i ] = = 0x0a ) // raylib KEY_ENTER (don't mix with <linux/input.h> KEY_*)
{
2020-02-03 19:26:28 +01:00
CORE . Input . Keyboard . currentKeyState [ 257 ] = 1 ;
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = 257 ; // Add keys pressed into queue
CORE . Input . Keyboard . keyPressedQueueCount + + ;
2019-11-24 13:39:45 +01:00
}
else if ( keysBuffer [ i ] = = 0x7f ) // raylib KEY_BACKSPACE
2020-02-03 19:26:28 +01:00
{
CORE . Input . Keyboard . currentKeyState [ 259 ] = 1 ;
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = 257 ; // Add keys pressed into queue
CORE . Input . Keyboard . keyPressedQueueCount + + ;
2019-11-24 13:39:45 +01:00
}
2016-02-19 19:57:25 +01:00
else
2014-09-16 22:51:31 +02:00
{
2016-02-19 19:57:25 +01:00
// Translate lowercase a-z letters to A-Z
if ( ( keysBuffer [ i ] > = 97 ) & & ( keysBuffer [ i ] < = 122 ) )
{
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . currentKeyState [ ( int ) keysBuffer [ i ] - 32 ] = 1 ;
2016-02-19 19:57:25 +01:00
}
2020-02-03 18:31:30 +01:00
else CORE . Input . Keyboard . currentKeyState [ ( int ) keysBuffer [ i ] ] = 1 ;
2019-01-23 20:07:47 -05:00
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = keysBuffer [ i ] ; // Add keys pressed into queue
CORE . Input . Keyboard . keyPressedQueueCount + + ;
2014-09-16 22:51:31 +02:00
}
}
2016-08-16 11:09:55 +02:00
2016-02-19 19:57:25 +01:00
// Check exit key (same functionality as GLFW3 KeyCallback())
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Keyboard . currentKeyState [ CORE . Input . Keyboard . exitKey ] = = 1 ) CORE . Window . shouldClose = true ;
2016-08-16 11:09:55 +02:00
2018-04-29 11:37:39 +02:00
# if defined(SUPPORT_SCREEN_CAPTURE)
2017-05-11 16:24:40 +02:00
// Check screen capture key (raylib key: KEY_F12)
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Keyboard . currentKeyState [ 301 ] = = 1 )
2017-05-11 16:24:40 +02:00
{
2020-08-16 11:28:15 +02:00
TakeScreenshot ( TextFormat ( " screenshot%03i.png " , screenshotCounter ) ) ;
2017-05-11 16:24:40 +02:00
screenshotCounter + + ;
}
2018-04-29 11:37:39 +02:00
# endif
2016-02-18 14:05:48 +01:00
}
2021-04-18 23:50:32 +02:00
# endif // SUPPORT_SSH_KEYBOARD_RPI
2014-07-23 00:06:24 +02:00
2019-03-28 19:46:39 +01:00
// Initialise user input from evdev(/dev/input/event<N>) this means mouse, keyboard or gamepad devices
static void InitEvdevInput ( void )
2014-07-23 00:06:24 +02:00
{
2021-07-03 21:25:30 +02:00
char path [ MAX_FILEPATH_LENGTH ] = { 0 } ;
DIR * directory = NULL ;
struct dirent * entity = NULL ;
2021-03-19 19:43:44 +01:00
2021-01-06 19:46:12 +00:00
// Initialise keyboard file descriptor
CORE . Input . Keyboard . fd = - 1 ;
2018-10-21 00:09:17 +01:00
// Reset variables
for ( int i = 0 ; i < MAX_TOUCH_POINTS ; + + i )
{
2020-02-03 18:31:30 +01:00
CORE . Input . Touch . position [ i ] . x = - 1 ;
CORE . Input . Touch . position [ i ] . y = - 1 ;
2018-10-21 00:09:17 +01:00
}
2020-02-18 18:03:28 +01:00
2019-03-28 19:46:39 +01:00
// Reset keyboard key state
2021-07-17 15:27:48 -03:00
for ( int i = 0 ; i < MAX_KEYBOARD_KEYS ; i + + ) CORE . Input . Keyboard . currentKeyState [ i ] = 0 ;
2018-10-21 00:09:17 +01:00
// Open the linux directory of "/dev/input"
2018-10-22 11:48:16 +02:00
directory = opendir ( DEFAULT_EVDEV_PATH ) ;
2019-05-08 18:33:09 +02:00
2018-11-06 15:10:50 +01:00
if ( directory )
2014-12-31 18:03:32 +01:00
{
2018-11-06 15:10:50 +01:00
while ( ( entity = readdir ( directory ) ) ! = NULL )
2018-10-21 00:09:17 +01:00
{
2022-04-26 09:30:20 +02:00
if ( ( strncmp ( " event " , entity - > d_name , strlen ( " event " ) ) = = 0 ) | | // Search for devices named "event*"
( strncmp ( " mouse " , entity - > d_name , strlen ( " mouse " ) ) = = 0 ) ) // Search for devices named "mouse*"
2018-10-21 00:09:17 +01:00
{
2018-12-18 19:11:12 +01:00
sprintf ( path , " %s%s " , DEFAULT_EVDEV_PATH , entity - > d_name ) ;
2021-01-06 19:46:12 +00:00
ConfigureEvdevDevice ( path ) ; // Configure the device if appropriate
2018-10-21 00:09:17 +01:00
}
}
2018-11-06 15:10:50 +01:00
2018-10-22 11:48:16 +02:00
closedir ( directory ) ;
2014-12-31 18:03:32 +01:00
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " RPI: Failed to open linux event directory: %s " , DEFAULT_EVDEV_PATH ) ;
2014-09-16 22:51:31 +02:00
}
2021-01-06 19:46:12 +00:00
// Identifies a input device and configures it for use if appropriate
static void ConfigureEvdevDevice ( char * device )
2018-10-21 00:09:17 +01:00
{
2020-05-23 19:23:40 +02:00
# define BITS_PER_LONG (8*sizeof(long))
2018-10-22 11:48:16 +02:00
# define NBITS(x) ((((x) - 1) / BITS_PER_LONG) + 1)
# define OFF(x) ((x)%BITS_PER_LONG)
# define BIT(x) (1UL<<OFF(x))
# define LONG(x) ((x) / BITS_PER_LONG)
2018-10-21 00:09:17 +01:00
# define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
2018-11-06 15:10:50 +01:00
2021-07-03 21:25:30 +02:00
struct input_absinfo absinfo = { 0 } ;
unsigned long evBits [ NBITS ( EV_MAX ) ] = { 0 } ;
unsigned long absBits [ NBITS ( ABS_MAX ) ] = { 0 } ;
unsigned long relBits [ NBITS ( REL_MAX ) ] = { 0 } ;
unsigned long keyBits [ NBITS ( KEY_MAX ) ] = { 0 } ;
2018-10-21 00:09:17 +01:00
bool hasAbs = false ;
bool hasRel = false ;
bool hasAbsMulti = false ;
2018-10-22 11:48:16 +02:00
int freeWorkerId = - 1 ;
2018-10-21 00:09:17 +01:00
int fd = - 1 ;
2018-11-06 15:10:50 +01:00
2021-07-03 21:25:30 +02:00
InputEventWorker * worker = NULL ;
2018-10-21 00:09:17 +01:00
2018-12-18 19:11:12 +01:00
// Open the device and allocate worker
//-------------------------------------------------------------------------------------------------------
2018-10-21 00:09:17 +01:00
// Find a free spot in the workers array
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < sizeof ( CORE . Input . eventWorker ) / sizeof ( InputEventWorker ) ; + + i )
2018-10-21 00:09:17 +01:00
{
2020-02-03 18:31:30 +01:00
if ( CORE . Input . eventWorker [ i ] . threadId = = 0 )
2018-10-21 00:09:17 +01:00
{
2018-10-22 11:48:16 +02:00
freeWorkerId = i ;
2018-10-21 00:09:17 +01:00
break ;
}
}
2016-08-16 11:09:55 +02:00
2018-10-21 00:09:17 +01:00
// Select the free worker from array
2018-10-22 11:48:16 +02:00
if ( freeWorkerId > = 0 )
2018-10-21 00:09:17 +01:00
{
2020-02-03 18:31:30 +01:00
worker = & ( CORE . Input . eventWorker [ freeWorkerId ] ) ; // Grab a pointer to the worker
2018-10-22 11:48:16 +02:00
memset ( worker , 0 , sizeof ( InputEventWorker ) ) ; // Clear the worker
2018-10-21 00:09:17 +01:00
}
else
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " RPI: Failed to create input device thread for %s, out of worker slots " , device ) ;
2018-10-21 00:09:17 +01:00
return ;
}
2014-09-16 22:51:31 +02:00
2018-10-21 00:09:17 +01:00
// Open the device
fd = open ( device , O_RDONLY | O_NONBLOCK ) ;
2018-10-22 11:48:16 +02:00
if ( fd < 0 )
2014-09-16 22:51:31 +02:00
{
2022-06-05 11:34:23 +02:00
TRACELOG ( LOG_WARNING , " RPI: Failed to open input device: %s " , device ) ;
2018-10-21 00:09:17 +01:00
return ;
}
2018-10-22 11:48:16 +02:00
worker - > fd = fd ;
2016-08-16 11:09:55 +02:00
2018-12-18 19:11:12 +01:00
// Grab number on the end of the devices name "event<N>"
2018-10-22 11:48:16 +02:00
int devNum = 0 ;
char * ptrDevName = strrchr ( device , ' t ' ) ;
worker - > eventNum = - 1 ;
2018-11-06 15:10:50 +01:00
2018-10-22 11:48:16 +02:00
if ( ptrDevName ! = NULL )
2018-10-21 15:06:40 +01:00
{
2021-07-03 21:31:52 +02:00
if ( sscanf ( ptrDevName , " t%d " , & devNum ) = = 1 ) worker - > eventNum = devNum ;
2018-10-21 15:06:40 +01:00
}
2022-06-12 11:32:10 +02:00
else worker - > eventNum = 0 ; // TODO: HACK: Grab number for mouse0 device!
2018-10-21 15:06:40 +01:00
2018-12-18 19:11:12 +01:00
// At this point we have a connection to the device, but we don't yet know what the device is.
// It could be many things, even as simple as a power button...
//-------------------------------------------------------------------------------------------------------
2014-09-16 22:51:31 +02:00
2018-12-18 19:11:12 +01:00
// Identify the device
//-------------------------------------------------------------------------------------------------------
2021-01-06 19:46:12 +00:00
ioctl ( fd , EVIOCGBIT ( 0 , sizeof ( evBits ) ) , evBits ) ; // Read a bitfield of the available device properties
2018-10-21 00:09:17 +01:00
// Check for absolute input devices
2018-11-06 15:10:50 +01:00
if ( TEST_BIT ( evBits , EV_ABS ) )
2018-10-21 00:09:17 +01:00
{
2018-10-22 11:48:16 +02:00
ioctl ( fd , EVIOCGBIT ( EV_ABS , sizeof ( absBits ) ) , absBits ) ;
2016-08-16 11:09:55 +02:00
2018-10-21 00:09:17 +01:00
// Check for absolute movement support (usualy touchscreens, but also joysticks)
2018-11-06 15:10:50 +01:00
if ( TEST_BIT ( absBits , ABS_X ) & & TEST_BIT ( absBits , ABS_Y ) )
2018-10-21 00:09:17 +01:00
{
hasAbs = true ;
2018-11-06 15:10:50 +01:00
2018-10-21 00:09:17 +01:00
// Get the scaling values
ioctl ( fd , EVIOCGABS ( ABS_X ) , & absinfo ) ;
2018-10-22 11:48:16 +02:00
worker - > absRange . x = absinfo . minimum ;
worker - > absRange . width = absinfo . maximum - absinfo . minimum ;
2018-10-21 00:09:17 +01:00
ioctl ( fd , EVIOCGABS ( ABS_Y ) , & absinfo ) ;
2018-10-22 11:48:16 +02:00
worker - > absRange . y = absinfo . minimum ;
worker - > absRange . height = absinfo . maximum - absinfo . minimum ;
2018-10-21 00:09:17 +01:00
}
2018-11-06 15:10:50 +01:00
2018-10-21 00:09:17 +01:00
// Check for multiple absolute movement support (usualy multitouch touchscreens)
2018-11-06 15:10:50 +01:00
if ( TEST_BIT ( absBits , ABS_MT_POSITION_X ) & & TEST_BIT ( absBits , ABS_MT_POSITION_Y ) )
2018-10-21 00:09:17 +01:00
{
hasAbsMulti = true ;
2018-11-06 15:10:50 +01:00
2018-10-21 00:09:17 +01:00
// Get the scaling values
ioctl ( fd , EVIOCGABS ( ABS_X ) , & absinfo ) ;
2018-10-22 11:48:16 +02:00
worker - > absRange . x = absinfo . minimum ;
worker - > absRange . width = absinfo . maximum - absinfo . minimum ;
2018-10-21 00:09:17 +01:00
ioctl ( fd , EVIOCGABS ( ABS_Y ) , & absinfo ) ;
2018-10-22 11:48:16 +02:00
worker - > absRange . y = absinfo . minimum ;
worker - > absRange . height = absinfo . maximum - absinfo . minimum ;
2018-10-21 00:09:17 +01:00
}
}
2016-08-16 11:09:55 +02:00
2018-10-21 00:09:17 +01:00
// Check for relative movement support (usualy mouse)
2018-11-06 15:10:50 +01:00
if ( TEST_BIT ( evBits , EV_REL ) )
2018-10-21 00:09:17 +01:00
{
2018-10-22 11:48:16 +02:00
ioctl ( fd , EVIOCGBIT ( EV_REL , sizeof ( relBits ) ) , relBits ) ;
2018-11-06 15:10:50 +01:00
2018-10-22 11:48:16 +02:00
if ( TEST_BIT ( relBits , REL_X ) & & TEST_BIT ( relBits , REL_Y ) ) hasRel = true ;
2018-10-21 00:09:17 +01:00
}
2016-08-16 11:09:55 +02:00
2018-10-21 00:09:17 +01:00
// Check for button support to determine the device type(usualy on all input devices)
2018-11-06 15:10:50 +01:00
if ( TEST_BIT ( evBits , EV_KEY ) )
2018-10-21 00:09:17 +01:00
{
2018-10-22 11:48:16 +02:00
ioctl ( fd , EVIOCGBIT ( EV_KEY , sizeof ( keyBits ) ) , keyBits ) ;
2016-02-19 19:57:25 +01:00
2018-10-22 11:48:16 +02:00
if ( hasAbs | | hasAbsMulti )
2018-10-21 00:09:17 +01:00
{
2018-10-22 11:48:16 +02:00
if ( TEST_BIT ( keyBits , BTN_TOUCH ) ) worker - > isTouch = true ; // This is a touchscreen
if ( TEST_BIT ( keyBits , BTN_TOOL_FINGER ) ) worker - > isTouch = true ; // This is a drawing tablet
if ( TEST_BIT ( keyBits , BTN_TOOL_PEN ) ) worker - > isTouch = true ; // This is a drawing tablet
if ( TEST_BIT ( keyBits , BTN_STYLUS ) ) worker - > isTouch = true ; // This is a drawing tablet
if ( worker - > isTouch | | hasAbsMulti ) worker - > isMultitouch = true ; // This is a multitouch capable device
2018-10-21 00:09:17 +01:00
}
2016-08-16 11:09:55 +02:00
2018-10-22 11:48:16 +02:00
if ( hasRel )
2018-10-21 00:09:17 +01:00
{
2018-10-22 11:48:16 +02:00
if ( TEST_BIT ( keyBits , BTN_LEFT ) ) worker - > isMouse = true ; // This is a mouse
if ( TEST_BIT ( keyBits , BTN_RIGHT ) ) worker - > isMouse = true ; // This is a mouse
2018-10-21 00:09:17 +01:00
}
2016-08-16 11:09:55 +02:00
2018-10-22 11:48:16 +02:00
if ( TEST_BIT ( keyBits , BTN_A ) ) worker - > isGamepad = true ; // This is a gamepad
if ( TEST_BIT ( keyBits , BTN_TRIGGER ) ) worker - > isGamepad = true ; // This is a gamepad
if ( TEST_BIT ( keyBits , BTN_START ) ) worker - > isGamepad = true ; // This is a gamepad
if ( TEST_BIT ( keyBits , BTN_TL ) ) worker - > isGamepad = true ; // This is a gamepad
if ( TEST_BIT ( keyBits , BTN_TL ) ) worker - > isGamepad = true ; // This is a gamepad
if ( TEST_BIT ( keyBits , KEY_SPACE ) ) worker - > isKeyboard = true ; // This is a keyboard
2014-09-16 22:51:31 +02:00
}
2018-12-18 19:11:12 +01:00
//-------------------------------------------------------------------------------------------------------
2014-09-16 22:51:31 +02:00
2018-12-18 19:11:12 +01:00
// Decide what to do with the device
//-------------------------------------------------------------------------------------------------------
2022-04-28 17:38:52 +02:00
if ( worker - > isKeyboard & & ( CORE . Input . Keyboard . fd = = - 1 ) )
2021-01-06 19:46:12 +00:00
{
// Use the first keyboard encountered. This assumes that a device that says it's a keyboard is just a
// keyboard. The keyboard is polled synchronously, whereas other input devices are polled in separate
// threads so that they don't drop events when the frame rate is slow.
TRACELOG ( LOG_INFO , " RPI: Opening keyboard device: %s " , device ) ;
CORE . Input . Keyboard . fd = worker - > fd ;
}
else if ( worker - > isTouch | | worker - > isMouse )
2017-01-05 21:36:40 +00:00
{
2020-03-27 18:06:09 +01:00
// Looks like an interesting device
2021-01-06 19:46:12 +00:00
TRACELOG ( LOG_INFO , " RPI: Opening input device: %s (%s%s%s%s) " , device ,
2019-02-22 13:13:11 +01:00
worker - > isMouse ? " mouse " : " " ,
worker - > isMultitouch ? " multitouch " : " " ,
worker - > isTouch ? " touchscreen " : " " ,
2021-01-06 19:46:12 +00:00
worker - > isGamepad ? " gamepad " : " " ) ;
2018-10-21 15:06:40 +01:00
2018-10-21 00:09:17 +01:00
// Create a thread for this device
2018-10-22 11:48:16 +02:00
int error = pthread_create ( & worker - > threadId , NULL , & EventThread , ( void * ) worker ) ;
if ( error ! = 0 )
2018-10-21 00:09:17 +01:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " RPI: Failed to create input device thread: %s (error: %d) " , device , error ) ;
2018-10-22 11:48:16 +02:00
worker - > threadId = 0 ;
2018-10-21 00:09:17 +01:00
close ( fd ) ;
}
2018-10-21 15:06:40 +01:00
2018-10-22 11:48:16 +02:00
# if defined(USE_LAST_TOUCH_DEVICE)
// Find touchscreen with the highest index
int maxTouchNumber = - 1 ;
2018-11-06 15:10:50 +01:00
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < sizeof ( CORE . Input . eventWorker ) / sizeof ( InputEventWorker ) ; + + i )
2018-10-21 15:06:40 +01:00
{
2020-02-03 18:31:30 +01:00
if ( CORE . Input . eventWorker [ i ] . isTouch & & ( CORE . Input . eventWorker [ i ] . eventNum > maxTouchNumber ) ) maxTouchNumber = CORE . Input . eventWorker [ i ] . eventNum ;
2018-10-22 11:48:16 +02:00
}
2018-11-06 15:10:50 +01:00
2021-01-06 19:46:12 +00:00
// Find touchscreens with lower indexes
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < sizeof ( CORE . Input . eventWorker ) / sizeof ( InputEventWorker ) ; + + i )
2018-10-22 11:48:16 +02:00
{
2020-02-03 18:31:30 +01:00
if ( CORE . Input . eventWorker [ i ] . isTouch & & ( CORE . Input . eventWorker [ i ] . eventNum < maxTouchNumber ) )
2018-10-21 15:06:40 +01:00
{
2020-02-03 18:31:30 +01:00
if ( CORE . Input . eventWorker [ i ] . threadId ! = 0 )
2018-10-21 15:06:40 +01:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " RPI: Found duplicate touchscreen, killing touchscreen on event: %d " , i ) ;
2020-02-03 18:31:30 +01:00
pthread_cancel ( CORE . Input . eventWorker [ i ] . threadId ) ;
close ( CORE . Input . eventWorker [ i ] . fd ) ;
2018-10-21 15:06:40 +01:00
}
}
}
2018-10-22 11:48:16 +02:00
# endif
2017-01-05 21:36:40 +00:00
}
2018-10-22 11:48:16 +02:00
else close ( fd ) ; // We are not interested in this device
2018-12-18 19:11:12 +01:00
//-------------------------------------------------------------------------------------------------------
2017-01-05 21:36:40 +00:00
}
2021-01-06 19:46:12 +00:00
static void PollKeyboardEvents ( void )
2017-01-05 21:36:40 +00:00
{
2019-03-28 19:46:39 +01:00
// Scancode to keycode mapping for US keyboards
2021-10-13 23:45:57 +02:00
// TODO: Replace this with a keymap from the X11 to get the correct regional map for the keyboard:
2019-04-28 16:45:23 +02:00
// Currently non US keyboards will have the wrong mapping for some keys
2021-07-05 18:45:17 +02:00
static const int keymapUS [ ] = {
2021-07-16 16:10:53 +02:00
0 , 256 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , 48 , 45 , 61 , 259 , 258 , 81 , 87 , 69 , 82 , 84 ,
89 , 85 , 73 , 79 , 80 , 91 , 93 , 257 , 341 , 65 , 83 , 68 , 70 , 71 , 72 , 74 , 75 , 76 , 59 , 39 , 96 ,
340 , 92 , 90 , 88 , 67 , 86 , 66 , 78 , 77 , 44 , 46 , 47 , 344 , 332 , 342 , 32 , 280 , 290 , 291 ,
292 , 293 , 294 , 295 , 296 , 297 , 298 , 299 , 282 , 281 , 327 , 328 , 329 , 333 , 324 , 325 ,
326 , 334 , 321 , 322 , 323 , 320 , 330 , 0 , 85 , 86 , 300 , 301 , 89 , 90 , 91 , 92 , 93 , 94 , 95 ,
335 , 345 , 331 , 283 , 346 , 101 , 268 , 265 , 266 , 263 , 262 , 269 , 264 , 267 , 260 , 261 ,
112 , 113 , 114 , 115 , 116 , 117 , 118 , 119 , 120 , 121 , 122 , 123 , 124 , 125 , 347 , 127 ,
128 , 129 , 130 , 131 , 132 , 133 , 134 , 135 , 136 , 137 , 138 , 139 , 140 , 141 , 142 , 143 ,
144 , 145 , 146 , 147 , 148 , 149 , 150 , 151 , 152 , 153 , 154 , 155 , 156 , 157 , 158 , 159 ,
160 , 161 , 162 , 163 , 164 , 165 , 166 , 167 , 168 , 169 , 170 , 171 , 172 , 173 , 174 , 175 ,
176 , 177 , 178 , 179 , 180 , 181 , 182 , 183 , 184 , 185 , 186 , 187 , 188 , 189 , 190 , 191 ,
192 , 193 , 194 , 0 , 0 , 0 , 0 , 0 , 200 , 201 , 202 , 203 , 204 , 205 , 206 , 207 , 208 , 209 , 210 ,
211 , 212 , 213 , 214 , 215 , 216 , 217 , 218 , 219 , 220 , 221 , 222 , 223 , 224 , 225 , 226 ,
227 , 228 , 229 , 230 , 231 , 232 , 233 , 234 , 235 , 236 , 237 , 238 , 239 , 240 , 241 , 242 ,
2021-07-05 18:45:17 +02:00
243 , 244 , 245 , 246 , 247 , 248 , 0 , 0 , 0 , 0 , 0 , 0 , 0
} ;
2019-03-28 19:46:39 +01:00
2021-01-06 19:46:12 +00:00
int fd = CORE . Input . Keyboard . fd ;
if ( fd = = - 1 ) return ;
2021-07-03 21:25:30 +02:00
struct input_event event = { 0 } ;
int keycode = - 1 ;
2021-03-19 19:43:44 +01:00
2021-01-06 19:46:12 +00:00
// Try to read data from the keyboard and only continue if successful
while ( read ( fd , & event , sizeof ( event ) ) = = ( int ) sizeof ( event ) )
{
// Button parsing
if ( event . type = = EV_KEY )
{
2021-07-17 15:27:48 -03:00
# if defined(SUPPORT_SSH_KEYBOARD_RPI)
// Change keyboard mode to events
CORE . Input . Keyboard . evtMode = true ;
# endif
2021-01-06 19:46:12 +00:00
// Keyboard button parsing
if ( ( event . code > = 1 ) & & ( event . code < = 255 ) ) //Keyboard keys appear for codes 1 to 255
{
2021-07-03 21:31:52 +02:00
keycode = keymapUS [ event . code & 0xFF ] ; // The code we get is a scancode so we look up the apropriate keycode
2021-01-06 19:46:12 +00:00
// Make sure we got a valid keycode
if ( ( keycode > 0 ) & & ( keycode < sizeof ( CORE . Input . Keyboard . currentKeyState ) ) )
{
// WARNING: https://www.kernel.org/doc/Documentation/input/input.txt
// Event interface: 'value' is the value the event carries. Either a relative change for EV_REL,
// absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat
CORE . Input . Keyboard . currentKeyState [ keycode ] = ( event . value > = 1 ) ? 1 : 0 ;
if ( event . value > = 1 )
{
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = keycode ; // Register last key pressed
CORE . Input . Keyboard . keyPressedQueueCount + + ;
}
2021-07-03 21:31:52 +02:00
# if defined(SUPPORT_SCREEN_CAPTURE)
// Check screen capture key (raylib key: KEY_F12)
if ( CORE . Input . Keyboard . currentKeyState [ 301 ] = = 1 )
{
TakeScreenshot ( TextFormat ( " screenshot%03i.png " , screenshotCounter ) ) ;
screenshotCounter + + ;
}
# endif
2021-01-06 19:46:12 +00:00
if ( CORE . Input . Keyboard . currentKeyState [ CORE . Input . Keyboard . exitKey ] = = 1 ) CORE . Window . shouldClose = true ;
TRACELOGD ( " RPI: KEY_%s ScanCode: %4i KeyCode: %4i " , event . value = = 0 ? " UP " : " DOWN " , event . code , keycode ) ;
}
}
}
}
}
// Input device events reading thread
static void * EventThread ( void * arg )
{
2021-07-03 21:25:30 +02:00
struct input_event event = { 0 } ;
2018-10-22 11:48:16 +02:00
InputEventWorker * worker = ( InputEventWorker * ) arg ;
2019-04-04 13:50:52 +02:00
2021-09-21 15:06:06 +02:00
int touchAction = - 1 ; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
2021-09-10 15:19:12 +02:00
bool gestureUpdate = false ; // Flag to note gestures require to update
2017-01-05 21:36:40 +00:00
2020-02-03 18:31:30 +01:00
while ( ! CORE . Window . shouldClose )
2017-01-05 21:36:40 +00:00
{
2019-03-28 19:46:39 +01:00
// Try to read data from the device and only continue if successful
2020-11-03 23:47:33 +01:00
while ( read ( worker - > fd , & event , sizeof ( event ) ) = = ( int ) sizeof ( event ) )
2017-01-05 21:36:40 +00:00
{
2018-12-18 19:11:12 +01:00
// Relative movement parsing
2018-10-22 11:48:16 +02:00
if ( event . type = = EV_REL )
2017-01-14 16:18:06 +00:00
{
2018-10-22 11:48:16 +02:00
if ( event . code = = REL_X )
2018-10-21 00:09:17 +01:00
{
2021-06-10 18:03:25 +02:00
CORE . Input . Mouse . currentPosition . x + = event . value ;
CORE . Input . Touch . position [ 0 ] . x = CORE . Input . Mouse . currentPosition . x ;
2019-03-28 20:38:13 +01:00
2021-09-21 15:06:06 +02:00
touchAction = 2 ; // TOUCH_ACTION_MOVE
2021-07-05 18:45:17 +02:00
gestureUpdate = true ;
2018-10-21 00:09:17 +01:00
}
2018-10-22 11:48:16 +02:00
if ( event . code = = REL_Y )
2018-10-21 00:09:17 +01:00
{
2021-06-10 18:03:25 +02:00
CORE . Input . Mouse . currentPosition . y + = event . value ;
CORE . Input . Touch . position [ 0 ] . y = CORE . Input . Mouse . currentPosition . y ;
2019-03-28 20:38:13 +01:00
2021-09-21 15:06:06 +02:00
touchAction = 2 ; // TOUCH_ACTION_MOVE
2021-07-05 18:45:17 +02:00
gestureUpdate = true ;
2018-10-21 00:09:17 +01:00
}
2022-06-12 11:30:07 -04:00
if ( event . code = = REL_WHEEL ) CORE . Input . Mouse . currentWheelMove . y + = event . value ;
2017-01-28 23:02:30 +01:00
}
2018-10-21 00:09:17 +01:00
2018-12-18 19:11:12 +01:00
// Absolute movement parsing
2018-10-22 11:48:16 +02:00
if ( event . type = = EV_ABS )
2017-01-14 16:18:06 +00:00
{
2018-10-21 00:09:17 +01:00
// Basic movement
2018-10-22 11:48:16 +02:00
if ( event . code = = ABS_X )
2018-10-21 00:09:17 +01:00
{
2021-07-01 21:43:13 +02:00
CORE . Input . Mouse . currentPosition . x = ( event . value - worker - > absRange . x ) * CORE . Window . screen . width / worker - > absRange . width ; // Scale acording to absRange
CORE . Input . Touch . position [ 0 ] . x = ( event . value - worker - > absRange . x ) * CORE . Window . screen . width / worker - > absRange . width ; // Scale acording to absRange
2021-03-19 19:43:44 +01:00
2021-09-21 15:06:06 +02:00
touchAction = 2 ; // TOUCH_ACTION_MOVE
2021-07-01 21:43:13 +02:00
gestureUpdate = true ;
2018-10-21 00:09:17 +01:00
}
2018-10-22 11:48:16 +02:00
if ( event . code = = ABS_Y )
2018-10-21 00:09:17 +01:00
{
2021-07-01 21:43:13 +02:00
CORE . Input . Mouse . currentPosition . y = ( event . value - worker - > absRange . y ) * CORE . Window . screen . height / worker - > absRange . height ; // Scale acording to absRange
CORE . Input . Touch . position [ 0 ] . y = ( event . value - worker - > absRange . y ) * CORE . Window . screen . height / worker - > absRange . height ; // Scale acording to absRange
2019-03-28 20:38:13 +01:00
2021-09-21 15:06:06 +02:00
touchAction = 2 ; // TOUCH_ACTION_MOVE
2021-07-01 21:43:13 +02:00
gestureUpdate = true ;
2018-10-21 00:09:17 +01:00
}
2018-10-22 11:48:16 +02:00
// Multitouch movement
2021-02-14 10:36:24 -06:00
if ( event . code = = ABS_MT_SLOT ) worker - > touchSlot = event . value ; // Remember the slot number for the folowing events
2018-10-21 00:09:17 +01:00
2018-10-22 11:48:16 +02:00
if ( event . code = = ABS_MT_POSITION_X )
2018-10-21 00:09:17 +01:00
{
2020-02-03 18:31:30 +01:00
if ( worker - > touchSlot < MAX_TOUCH_POINTS ) CORE . Input . Touch . position [ worker - > touchSlot ] . x = ( event . value - worker - > absRange . x ) * CORE . Window . screen . width / worker - > absRange . width ; // Scale acording to absRange
2018-10-21 00:09:17 +01:00
}
2018-10-22 11:48:16 +02:00
if ( event . code = = ABS_MT_POSITION_Y )
2018-10-21 00:09:17 +01:00
{
2020-02-03 18:31:30 +01:00
if ( worker - > touchSlot < MAX_TOUCH_POINTS ) CORE . Input . Touch . position [ worker - > touchSlot ] . y = ( event . value - worker - > absRange . y ) * CORE . Window . screen . height / worker - > absRange . height ; // Scale acording to absRange
2018-10-21 00:09:17 +01:00
}
2018-10-22 11:48:16 +02:00
if ( event . code = = ABS_MT_TRACKING_ID )
2018-10-21 00:09:17 +01:00
{
2019-04-28 16:45:23 +02:00
if ( ( event . value < 0 ) & & ( worker - > touchSlot < MAX_TOUCH_POINTS ) )
2018-10-21 00:09:17 +01:00
{
2018-10-22 11:48:16 +02:00
// Touch has ended for this point
2020-02-03 18:31:30 +01:00
CORE . Input . Touch . position [ worker - > touchSlot ] . x = - 1 ;
CORE . Input . Touch . position [ worker - > touchSlot ] . y = - 1 ;
2018-10-21 00:09:17 +01:00
}
}
2021-02-14 10:36:24 -06:00
// Touchscreen tap
2021-03-31 17:55:46 +02:00
if ( event . code = = ABS_PRESSURE )
2021-02-14 10:36:24 -06:00
{
2021-05-08 09:26:24 -07:00
int previousMouseLeftButtonState = CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_LEFT ] ;
2021-03-19 19:43:44 +01:00
2021-03-31 17:55:46 +02:00
if ( ! event . value & & previousMouseLeftButtonState )
2021-02-14 10:36:24 -06:00
{
2021-05-08 09:26:24 -07:00
CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_LEFT ] = 0 ;
2021-02-14 10:36:24 -06:00
2021-09-21 15:06:06 +02:00
touchAction = 0 ; // TOUCH_ACTION_UP
2021-07-01 21:43:13 +02:00
gestureUpdate = true ;
2021-02-14 10:36:24 -06:00
}
2021-03-19 19:43:44 +01:00
2021-03-31 17:55:46 +02:00
if ( event . value & & ! previousMouseLeftButtonState )
2021-02-14 10:36:24 -06:00
{
2021-05-08 09:26:24 -07:00
CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_LEFT ] = 1 ;
2021-02-14 10:36:24 -06:00
2021-09-21 15:06:06 +02:00
touchAction = 1 ; // TOUCH_ACTION_DOWN
2021-07-01 21:43:13 +02:00
gestureUpdate = true ;
2021-02-14 10:36:24 -06:00
}
}
2017-01-28 23:02:30 +01:00
}
2018-10-21 00:09:17 +01:00
2018-12-18 19:11:12 +01:00
// Button parsing
2018-10-22 11:48:16 +02:00
if ( event . type = = EV_KEY )
2017-01-14 16:18:06 +00:00
{
2019-03-28 19:46:39 +01:00
// Mouse button parsing
2019-02-28 23:06:37 +01:00
if ( ( event . code = = BTN_TOUCH ) | | ( event . code = = BTN_LEFT ) )
2018-10-21 00:09:17 +01:00
{
2021-05-08 09:26:24 -07:00
CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_LEFT ] = event . value ;
2019-04-04 13:50:52 +02:00
2021-09-21 15:06:06 +02:00
if ( event . value > 0 ) touchAction = 1 ; // TOUCH_ACTION_DOWN
else touchAction = 0 ; // TOUCH_ACTION_UP
2021-07-01 21:43:13 +02:00
gestureUpdate = true ;
2018-10-21 00:09:17 +01:00
}
2021-05-08 09:26:24 -07:00
if ( event . code = = BTN_RIGHT ) CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_RIGHT ] = event . value ;
if ( event . code = = BTN_MIDDLE ) CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_MIDDLE ] = event . value ;
if ( event . code = = BTN_SIDE ) CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_SIDE ] = event . value ;
if ( event . code = = BTN_EXTRA ) CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_EXTRA ] = event . value ;
if ( event . code = = BTN_FORWARD ) CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_FORWARD ] = event . value ;
if ( event . code = = BTN_BACK ) CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_BUTTON_BACK ] = event . value ;
2017-01-14 16:18:06 +00:00
}
2018-10-21 00:09:17 +01:00
2018-12-18 19:11:12 +01:00
// Screen confinement
2020-10-13 22:26:40 +02:00
if ( ! CORE . Input . Mouse . cursorHidden )
{
2021-06-10 18:03:25 +02:00
if ( CORE . Input . Mouse . currentPosition . x < 0 ) CORE . Input . Mouse . currentPosition . x = 0 ;
if ( CORE . Input . Mouse . currentPosition . x > CORE . Window . screen . width / CORE . Input . Mouse . scale . x ) CORE . Input . Mouse . currentPosition . x = CORE . Window . screen . width / CORE . Input . Mouse . scale . x ;
2018-10-21 00:09:17 +01:00
2021-06-10 18:03:25 +02:00
if ( CORE . Input . Mouse . currentPosition . y < 0 ) CORE . Input . Mouse . currentPosition . y = 0 ;
if ( CORE . Input . Mouse . currentPosition . y > CORE . Window . screen . height / CORE . Input . Mouse . scale . y ) CORE . Input . Mouse . currentPosition . y = CORE . Window . screen . height / CORE . Input . Mouse . scale . y ;
2020-10-13 22:26:40 +02:00
}
2018-10-21 00:09:17 +01:00
2021-09-10 15:19:12 +02:00
# if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_RPI, PLATFORM_DRM
2019-03-25 12:30:20 +01:00
if ( gestureUpdate )
2017-01-14 16:18:06 +00:00
{
2019-03-25 12:30:20 +01:00
GestureEvent gestureEvent = { 0 } ;
2018-10-21 00:09:17 +01:00
gestureEvent . pointCount = 0 ;
2019-03-25 12:30:20 +01:00
gestureEvent . touchAction = touchAction ;
2019-04-04 13:50:52 +02:00
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Touch . position [ 0 ] . x > = 0 ) gestureEvent . pointCount + + ;
if ( CORE . Input . Touch . position [ 1 ] . x > = 0 ) gestureEvent . pointCount + + ;
if ( CORE . Input . Touch . position [ 2 ] . x > = 0 ) gestureEvent . pointCount + + ;
if ( CORE . Input . Touch . position [ 3 ] . x > = 0 ) gestureEvent . pointCount + + ;
2019-04-04 13:50:52 +02:00
2021-09-10 15:19:12 +02:00
gestureEvent . pointId [ 0 ] = 0 ;
gestureEvent . pointId [ 1 ] = 1 ;
gestureEvent . pointId [ 2 ] = 2 ;
gestureEvent . pointId [ 3 ] = 3 ;
2019-04-04 13:50:52 +02:00
2020-02-03 18:31:30 +01:00
gestureEvent . position [ 0 ] = CORE . Input . Touch . position [ 0 ] ;
gestureEvent . position [ 1 ] = CORE . Input . Touch . position [ 1 ] ;
gestureEvent . position [ 2 ] = CORE . Input . Touch . position [ 2 ] ;
gestureEvent . position [ 3 ] = CORE . Input . Touch . position [ 3 ] ;
2019-04-04 13:50:52 +02:00
2017-01-14 16:18:06 +00:00
ProcessGestureEvent ( gestureEvent ) ;
}
2021-07-01 21:43:13 +02:00
# endif
2018-10-21 00:09:17 +01:00
}
2021-06-17 11:47:05 +02:00
2022-06-06 20:18:37 +02:00
WaitTime ( 0.005 ) ; // Sleep for 5ms to avoid hogging CPU time
2017-01-05 21:36:40 +00:00
}
2018-11-06 15:10:50 +01:00
2018-10-22 11:48:16 +02:00
close ( worker - > fd ) ;
2018-11-06 15:10:50 +01:00
2017-01-05 21:36:40 +00:00
return NULL ;
}
2021-06-24 18:13:25 +02:00
// Initialize gamepad system
2016-02-18 14:05:48 +01:00
static void InitGamepad ( void )
2014-09-16 22:51:31 +02:00
{
2021-07-03 21:25:30 +02:00
char gamepadDev [ 128 ] = { 0 } ;
2016-08-16 11:09:55 +02:00
2016-03-17 12:54:36 +01:00
for ( int i = 0 ; i < MAX_GAMEPADS ; i + + )
2014-09-16 22:51:31 +02:00
{
2016-03-17 12:54:36 +01:00
sprintf ( gamepadDev , " %s%i " , DEFAULT_GAMEPAD_DEV , i ) ;
2016-08-16 11:09:55 +02:00
2022-04-25 19:35:19 +02:00
if ( ( CORE . Input . Gamepad . streamId [ i ] = open ( gamepadDev , O_RDONLY | O_NONBLOCK ) ) < 0 )
2016-03-17 12:54:36 +01:00
{
// NOTE: Only show message for first gamepad
2020-03-27 18:06:09 +01:00
if ( i = = 0 ) TRACELOG ( LOG_WARNING , " RPI: Failed to open Gamepad device, no gamepad available " ) ;
2016-03-17 12:54:36 +01:00
}
else
{
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . ready [ i ] = true ;
2014-09-16 22:51:31 +02:00
2016-03-17 12:54:36 +01:00
// NOTE: Only create one thread
if ( i = = 0 )
{
2020-02-03 18:31:30 +01:00
int error = pthread_create ( & CORE . Input . Gamepad . threadId , NULL , & GamepadThread , NULL ) ;
2014-09-16 22:51:31 +02:00
2020-03-27 18:06:09 +01:00
if ( error ! = 0 ) TRACELOG ( LOG_WARNING , " RPI: Failed to create gamepad input event thread " ) ;
else TRACELOG ( LOG_INFO , " RPI: Gamepad device initialized successfully " ) ;
2016-03-17 12:54:36 +01:00
}
}
2016-08-16 11:09:55 +02:00
}
2014-09-16 22:51:31 +02:00
}
2016-02-18 14:05:48 +01:00
// Process Gamepad (/dev/input/js0)
static void * GamepadThread ( void * arg )
2014-09-16 22:51:31 +02:00
{
2016-02-18 14:05:48 +01:00
# define JS_EVENT_BUTTON 0x01 // Button pressed/released
# define JS_EVENT_AXIS 0x02 // Joystick axis moved
# define JS_EVENT_INIT 0x80 // Initial state of device
struct js_event {
unsigned int time ; // event timestamp in milliseconds
short value ; // event value
unsigned char type ; // event type
unsigned char number ; // event axis/button number
} ;
// Read gamepad event
2021-07-03 21:25:30 +02:00
struct js_event gamepadEvent = { 0 } ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
while ( ! CORE . Window . shouldClose )
2016-02-18 14:05:48 +01:00
{
2016-03-17 12:54:36 +01:00
for ( int i = 0 ; i < MAX_GAMEPADS ; i + + )
2016-02-18 14:05:48 +01:00
{
2020-02-03 18:31:30 +01:00
if ( read ( CORE . Input . Gamepad . streamId [ i ] , & gamepadEvent , sizeof ( struct js_event ) ) = = ( int ) sizeof ( struct js_event ) )
2016-02-18 14:05:48 +01:00
{
2016-03-17 12:54:36 +01:00
gamepadEvent . type & = ~ JS_EVENT_INIT ; // Ignore synthetic events
2016-08-16 11:09:55 +02:00
2016-03-17 12:54:36 +01:00
// Process gamepad events by type
2016-08-16 11:09:55 +02:00
if ( gamepadEvent . type = = JS_EVENT_BUTTON )
2016-02-18 14:05:48 +01:00
{
2021-01-31 03:07:26 +01:00
//TRACELOG(LOG_WARNING, "RPI: Gamepad button: %i, value: %i", gamepadEvent.number, gamepadEvent.value);
2016-08-16 11:09:55 +02:00
if ( gamepadEvent . number < MAX_GAMEPAD_BUTTONS )
2016-03-17 12:54:36 +01:00
{
// 1 - button pressed, 0 - button released
2021-06-10 17:11:31 +02:00
CORE . Input . Gamepad . currentButtonState [ i ] [ gamepadEvent . number ] = ( int ) gamepadEvent . value ;
2017-01-28 23:02:30 +01:00
2020-02-03 18:31:30 +01:00
if ( ( int ) gamepadEvent . value = = 1 ) CORE . Input . Gamepad . lastButtonPressed = gamepadEvent . number ;
else CORE . Input . Gamepad . lastButtonPressed = - 1 ;
2016-03-17 12:54:36 +01:00
}
2016-02-18 14:05:48 +01:00
}
2016-08-16 11:09:55 +02:00
else if ( gamepadEvent . type = = JS_EVENT_AXIS )
2016-02-18 14:05:48 +01:00
{
2021-01-31 03:07:26 +01:00
//TRACELOG(LOG_WARNING, "RPI: Gamepad axis: %i, value: %i", gamepadEvent.number, gamepadEvent.value);
2016-08-16 11:09:55 +02:00
2016-03-17 12:54:36 +01:00
if ( gamepadEvent . number < MAX_GAMEPAD_AXIS )
{
// NOTE: Scaling of gamepadEvent.value to get values between -1..1
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . axisState [ i ] [ gamepadEvent . number ] = ( float ) gamepadEvent . value / 32768 ;
2016-03-17 12:54:36 +01:00
}
2016-02-18 14:05:48 +01:00
}
}
2022-06-06 20:18:37 +02:00
else WaitTime ( 0.001 ) ; // Sleep for 1 ms to avoid hogging CPU time
2016-02-18 14:05:48 +01:00
}
2016-05-31 19:12:37 +02:00
}
2016-02-19 19:57:25 +01:00
return NULL ;
2014-09-16 22:51:31 +02:00
}
2021-04-18 23:50:32 +02:00
# endif // PLATFORM_RPI || PLATFORM_DRM
2020-04-30 18:48:39 +01:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
2020-10-24 10:37:15 +02:00
// Search matching DRM mode in connector's mode list
2020-09-27 10:18:43 +02:00
static int FindMatchingConnectorMode ( const drmModeConnector * connector , const drmModeModeInfo * mode )
{
if ( NULL = = connector ) return - 1 ;
if ( NULL = = mode ) return - 1 ;
// safe bitwise comparison of two modes
# define BINCMP(a, b) memcmp((a), (b), (sizeof(a) < sizeof(b)) ? sizeof(a) : sizeof(b))
for ( size_t i = 0 ; i < connector - > count_modes ; i + + )
{
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: DRM mode: %d %ux%u@%u %s " , i , connector - > modes [ i ] . hdisplay , connector - > modes [ i ] . vdisplay ,
2020-09-27 10:18:43 +02:00
connector - > modes [ i ] . vrefresh , ( connector - > modes [ i ] . flags & DRM_MODE_FLAG_INTERLACE ) ? " interlaced " : " progressive " ) ;
2020-12-24 19:09:05 +01:00
if ( 0 = = BINCMP ( & CORE . Window . crtc - > mode , & CORE . Window . connector - > modes [ i ] ) ) return i ;
2020-09-27 10:18:43 +02:00
}
return - 1 ;
# undef BINCMP
}
2020-10-24 10:37:15 +02:00
// Search exactly matching DRM connector mode in connector's list
2020-11-15 13:17:11 +01:00
static int FindExactConnectorMode ( const drmModeConnector * connector , uint width , uint height , uint fps , bool allowInterlaced )
{
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: Searching exact connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s " , width , height , fps , allowInterlaced ? " yes " : " no " ) ;
2020-09-27 10:18:43 +02:00
if ( NULL = = connector ) return - 1 ;
for ( int i = 0 ; i < CORE . Window . connector - > count_modes ; i + + )
{
const drmModeModeInfo * const mode = & CORE . Window . connector - > modes [ i ] ;
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: DRM Mode %d %ux%u@%u %s " , i , mode - > hdisplay , mode - > vdisplay , mode - > vrefresh , ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) ? " interlaced " : " progressive " ) ;
2020-09-27 10:18:43 +02:00
2020-12-24 19:09:05 +01:00
if ( ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) & & ( ! allowInterlaced ) ) continue ;
2020-09-27 10:18:43 +02:00
2020-12-24 19:09:05 +01:00
if ( ( mode - > hdisplay = = width ) & & ( mode - > vdisplay = = height ) & & ( mode - > vrefresh = = fps ) ) return i ;
2020-09-27 10:18:43 +02:00
}
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: No DRM exact matching mode found " ) ;
2020-09-27 10:18:43 +02:00
return - 1 ;
}
2020-10-24 10:37:15 +02:00
// Search the nearest matching DRM connector mode in connector's list
2020-11-15 13:17:11 +01:00
static int FindNearestConnectorMode ( const drmModeConnector * connector , uint width , uint height , uint fps , bool allowInterlaced )
{
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: Searching nearest connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s " , width , height , fps , allowInterlaced ? " yes " : " no " ) ;
2020-09-27 10:18:43 +02:00
if ( NULL = = connector ) return - 1 ;
int nearestIndex = - 1 ;
for ( int i = 0 ; i < CORE . Window . connector - > count_modes ; i + + )
{
const drmModeModeInfo * const mode = & CORE . Window . connector - > modes [ i ] ;
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: DRM mode: %d %ux%u@%u %s " , i , mode - > hdisplay , mode - > vdisplay , mode - > vrefresh ,
2020-09-27 10:18:43 +02:00
( mode - > flags & DRM_MODE_FLAG_INTERLACE ) ? " interlaced " : " progressive " ) ;
2022-05-09 17:12:38 +02:00
if ( ( mode - > hdisplay < width ) | | ( mode - > vdisplay < height ) )
2020-09-27 10:18:43 +02:00
{
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: DRM mode is too small " ) ;
2020-09-27 10:18:43 +02:00
continue ;
}
if ( ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) & & ( ! allowInterlaced ) )
{
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_TRACE , " DISPLAY: DRM shouldn't choose an interlaced mode " ) ;
2020-09-27 10:18:43 +02:00
continue ;
}
2022-05-09 17:12:38 +02:00
if ( nearestIndex < 0 )
2020-09-27 10:18:43 +02:00
{
2022-05-09 17:12:38 +02:00
nearestIndex = i ;
continue ;
}
2020-09-27 10:18:43 +02:00
2022-05-09 17:12:38 +02:00
const int widthDiff = abs ( mode - > hdisplay - width ) ;
const int heightDiff = abs ( mode - > vdisplay - height ) ;
const int fpsDiff = abs ( mode - > vrefresh - fps ) ;
2020-09-27 10:18:43 +02:00
2022-05-09 17:12:38 +02:00
const int nearestWidthDiff = abs ( CORE . Window . connector - > modes [ nearestIndex ] . hdisplay - width ) ;
const int nearestHeightDiff = abs ( CORE . Window . connector - > modes [ nearestIndex ] . vdisplay - height ) ;
const int nearestFpsDiff = abs ( CORE . Window . connector - > modes [ nearestIndex ] . vrefresh - fps ) ;
2020-09-27 10:18:43 +02:00
2022-05-09 17:12:38 +02:00
if ( ( widthDiff < nearestWidthDiff ) | | ( heightDiff < nearestHeightDiff ) | | ( fpsDiff < nearestFpsDiff ) ) {
nearestIndex = i ;
2020-09-27 10:18:43 +02:00
}
}
return nearestIndex ;
}
# endif
2021-06-11 12:27:46 +02:00
# if defined(SUPPORT_EVENTS_AUTOMATION)
// NOTE: Loading happens over AutomationEvent *events
2022-03-22 18:45:41 +01:00
// TODO: This system should probably be redesigned
2021-06-11 12:27:46 +02:00
static void LoadAutomationEvents ( const char * fileName )
{
//unsigned char fileId[4] = { 0 };
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// Load binary
/*
FILE * repFile = fopen ( fileName , " rb " ) ;
fread ( fileId , 4 , 1 , repFile ) ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
if ( ( fileId [ 0 ] = = ' r ' ) & & ( fileId [ 1 ] = = ' E ' ) & & ( fileId [ 2 ] = = ' P ' ) & & ( fileId [ 1 ] = = ' ' ) )
{
fread ( & eventCount , sizeof ( int ) , 1 , repFile ) ;
TraceLog ( LOG_WARNING , " Events loaded: %i \n " , eventCount ) ;
fread ( events , sizeof ( AutomationEvent ) , eventCount , repFile ) ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
fclose ( repFile ) ;
*/
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// Load events (text file)
FILE * repFile = fopen ( fileName , " rt " ) ;
if ( repFile ! = NULL )
{
unsigned int count = 0 ;
char buffer [ 256 ] = { 0 } ;
fgets ( buffer , 256 , repFile ) ;
while ( ! feof ( repFile ) )
{
if ( buffer [ 0 ] = = ' c ' ) sscanf ( buffer , " c %i " , & eventCount ) ;
else if ( buffer [ 0 ] = = ' e ' )
{
2021-06-13 17:08:30 +02:00
sscanf ( buffer , " e %d %d %d %d %d " , & events [ count ] . frame , & events [ count ] . type ,
2021-06-11 12:27:46 +02:00
& events [ count ] . params [ 0 ] , & events [ count ] . params [ 1 ] , & events [ count ] . params [ 2 ] ) ;
2021-06-22 20:14:44 +02:00
2021-06-11 12:27:46 +02:00
count + + ;
}
fgets ( buffer , 256 , repFile ) ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
if ( count ! = eventCount ) TRACELOG ( LOG_WARNING , " Events count provided is different than count " ) ;
fclose ( repFile ) ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
TRACELOG ( LOG_WARNING , " Events loaded: %i " , eventCount ) ;
}
// Export recorded events into a file
static void ExportAutomationEvents ( const char * fileName )
{
unsigned char fileId [ 4 ] = " rEP " ;
// Save as binary
/*
FILE * repFile = fopen ( fileName , " wb " ) ;
fwrite ( fileId , 4 , 1 , repFile ) ;
fwrite ( & eventCount , sizeof ( int ) , 1 , repFile ) ;
fwrite ( events , sizeof ( AutomationEvent ) , eventCount , repFile ) ;
fclose ( repFile ) ;
*/
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// Export events as text
FILE * repFile = fopen ( fileName , " wt " ) ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
if ( repFile ! = NULL )
{
fprintf ( repFile , " # Automation events list \n " ) ;
fprintf ( repFile , " # c <events_count> \n " ) ;
fprintf ( repFile , " # e <frame> <event_type> <param0> <param1> <param2> // <event_type_name> \n " ) ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
fprintf ( repFile , " c %i \n " , eventCount ) ;
for ( int i = 0 ; i < eventCount ; i + + )
{
2021-06-13 17:08:30 +02:00
fprintf ( repFile , " e %i %i %i %i %i // %s \n " , events [ i ] . frame , events [ i ] . type ,
2021-06-11 12:27:46 +02:00
events [ i ] . params [ 0 ] , events [ i ] . params [ 1 ] , events [ i ] . params [ 2 ] , autoEventTypeName [ events [ i ] . type ] ) ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
fclose ( repFile ) ;
}
}
// EndDrawing() -> After PollInputEvents()
// Check event in current frame and save into the events[i] array
static void RecordAutomationEvent ( unsigned int frame )
{
2021-07-17 15:27:48 -03:00
for ( int key = 0 ; key < MAX_KEYBOARD_KEYS ; key + + )
2021-06-11 12:27:46 +02:00
{
// INPUT_KEY_UP (only saved once)
if ( CORE . Input . Keyboard . previousKeyState [ key ] & & ! CORE . Input . Keyboard . currentKeyState [ key ] )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_KEY_UP ;
events [ eventCount ] . params [ 0 ] = key ;
events [ eventCount ] . params [ 1 ] = 0 ;
events [ eventCount ] . params [ 2 ] = 0 ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
TRACELOG ( LOG_INFO , " [%i] INPUT_KEY_UP: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_KEY_DOWN
if ( CORE . Input . Keyboard . currentKeyState [ key ] )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_KEY_DOWN ;
events [ eventCount ] . params [ 0 ] = key ;
events [ eventCount ] . params [ 1 ] = 0 ;
events [ eventCount ] . params [ 2 ] = 0 ;
TRACELOG ( LOG_INFO , " [%i] INPUT_KEY_DOWN: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
}
for ( int button = 0 ; button < MAX_MOUSE_BUTTONS ; button + + )
{
// INPUT_MOUSE_BUTTON_UP
if ( CORE . Input . Mouse . previousButtonState [ button ] & & ! CORE . Input . Mouse . currentButtonState [ button ] )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_MOUSE_BUTTON_UP ;
events [ eventCount ] . params [ 0 ] = button ;
events [ eventCount ] . params [ 1 ] = 0 ;
events [ eventCount ] . params [ 2 ] = 0 ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
TRACELOG ( LOG_INFO , " [%i] INPUT_MOUSE_BUTTON_UP: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_MOUSE_BUTTON_DOWN
if ( CORE . Input . Mouse . currentButtonState [ button ] )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_MOUSE_BUTTON_DOWN ;
events [ eventCount ] . params [ 0 ] = button ;
events [ eventCount ] . params [ 1 ] = 0 ;
events [ eventCount ] . params [ 2 ] = 0 ;
TRACELOG ( LOG_INFO , " [%i] INPUT_MOUSE_BUTTON_DOWN: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_MOUSE_POSITION (only saved if changed)
if ( ( ( int ) CORE . Input . Mouse . currentPosition . x ! = ( int ) CORE . Input . Mouse . previousPosition . x ) | |
( ( int ) CORE . Input . Mouse . currentPosition . y ! = ( int ) CORE . Input . Mouse . previousPosition . y ) )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_MOUSE_POSITION ;
events [ eventCount ] . params [ 0 ] = ( int ) CORE . Input . Mouse . currentPosition . x ;
events [ eventCount ] . params [ 1 ] = ( int ) CORE . Input . Mouse . currentPosition . y ;
events [ eventCount ] . params [ 2 ] = 0 ;
TRACELOG ( LOG_INFO , " [%i] INPUT_MOUSE_POSITION: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_MOUSE_WHEEL_MOTION
2022-06-12 11:30:07 -04:00
if ( ( ( int ) CORE . Input . Mouse . currentWheelMove . x ! = ( int ) CORE . Input . Mouse . previousWheelMove . x ) | |
( ( int ) CORE . Input . Mouse . currentWheelMove . y ! = ( int ) CORE . Input . Mouse . previousWheelMove . y ) )
2021-06-11 12:27:46 +02:00
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_MOUSE_WHEEL_MOTION ;
2022-06-12 11:30:07 -04:00
events [ eventCount ] . params [ 0 ] = ( int ) CORE . Input . Mouse . currentWheelMove . x ;
events [ eventCount ] . params [ 1 ] = ( int ) CORE . Input . Mouse . currentWheelMove . y ; ;
2021-06-11 12:27:46 +02:00
events [ eventCount ] . params [ 2 ] = 0 ;
TRACELOG ( LOG_INFO , " [%i] INPUT_MOUSE_WHEEL_MOTION: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
for ( int id = 0 ; id < MAX_TOUCH_POINTS ; id + + )
{
// INPUT_TOUCH_UP
if ( CORE . Input . Touch . previousTouchState [ id ] & & ! CORE . Input . Touch . currentTouchState [ id ] )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_TOUCH_UP ;
events [ eventCount ] . params [ 0 ] = id ;
events [ eventCount ] . params [ 1 ] = 0 ;
events [ eventCount ] . params [ 2 ] = 0 ;
TRACELOG ( LOG_INFO , " [%i] INPUT_TOUCH_UP: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_TOUCH_DOWN
if ( CORE . Input . Touch . currentTouchState [ id ] )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_TOUCH_DOWN ;
events [ eventCount ] . params [ 0 ] = id ;
events [ eventCount ] . params [ 1 ] = 0 ;
events [ eventCount ] . params [ 2 ] = 0 ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
TRACELOG ( LOG_INFO , " [%i] INPUT_TOUCH_DOWN: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_TOUCH_POSITION
// TODO: It requires the id!
/*
if ( ( ( int ) CORE . Input . Touch . currentPosition [ id ] . x ! = ( int ) CORE . Input . Touch . previousPosition [ id ] . x ) | |
( ( int ) CORE . Input . Touch . currentPosition [ id ] . y ! = ( int ) CORE . Input . Touch . previousPosition [ id ] . y ) )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_TOUCH_POSITION ;
events [ eventCount ] . params [ 0 ] = id ;
events [ eventCount ] . params [ 1 ] = ( int ) CORE . Input . Touch . currentPosition [ id ] . x ;
events [ eventCount ] . params [ 2 ] = ( int ) CORE . Input . Touch . currentPosition [ id ] . y ;
TRACELOG ( LOG_INFO , " [%i] INPUT_TOUCH_POSITION: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
*/
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
for ( int gamepad = 0 ; gamepad < MAX_GAMEPADS ; gamepad + + )
{
// INPUT_GAMEPAD_CONNECT
/*
if ( ( CORE . Input . Gamepad . currentState [ gamepad ] ! = CORE . Input . Gamepad . previousState [ gamepad ] ) & &
( CORE . Input . Gamepad . currentState [ gamepad ] = = true ) ) // Check if changed to ready
{
// TODO: Save gamepad connect event
}
*/
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_GAMEPAD_DISCONNECT
/*
if ( ( CORE . Input . Gamepad . currentState [ gamepad ] ! = CORE . Input . Gamepad . previousState [ gamepad ] ) & &
( CORE . Input . Gamepad . currentState [ gamepad ] = = false ) ) // Check if changed to not-ready
{
// TODO: Save gamepad disconnect event
}
*/
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
for ( int button = 0 ; button < MAX_GAMEPAD_BUTTONS ; button + + )
{
// INPUT_GAMEPAD_BUTTON_UP
if ( CORE . Input . Gamepad . previousButtonState [ gamepad ] [ button ] & & ! CORE . Input . Gamepad . currentButtonState [ gamepad ] [ button ] )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_GAMEPAD_BUTTON_UP ;
events [ eventCount ] . params [ 0 ] = gamepad ;
events [ eventCount ] . params [ 1 ] = button ;
events [ eventCount ] . params [ 2 ] = 0 ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
TRACELOG ( LOG_INFO , " [%i] INPUT_GAMEPAD_BUTTON_UP: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_GAMEPAD_BUTTON_DOWN
if ( CORE . Input . Gamepad . currentButtonState [ gamepad ] [ button ] )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_GAMEPAD_BUTTON_DOWN ;
events [ eventCount ] . params [ 0 ] = gamepad ;
events [ eventCount ] . params [ 1 ] = button ;
events [ eventCount ] . params [ 2 ] = 0 ;
TRACELOG ( LOG_INFO , " [%i] INPUT_GAMEPAD_BUTTON_DOWN: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
for ( int axis = 0 ; axis < MAX_GAMEPAD_AXIS ; axis + + )
{
// INPUT_GAMEPAD_AXIS_MOTION
if ( CORE . Input . Gamepad . axisState [ gamepad ] [ axis ] > 0.1f )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_GAMEPAD_AXIS_MOTION ;
events [ eventCount ] . params [ 0 ] = gamepad ;
events [ eventCount ] . params [ 1 ] = axis ;
events [ eventCount ] . params [ 2 ] = ( int ) ( CORE . Input . Gamepad . axisState [ gamepad ] [ axis ] * 32768.0f ) ;
TRACELOG ( LOG_INFO , " [%i] INPUT_GAMEPAD_AXIS_MOTION: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
}
}
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// INPUT_GESTURE
if ( GESTURES . current ! = GESTURE_NONE )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_GESTURE ;
events [ eventCount ] . params [ 0 ] = GESTURES . current ;
events [ eventCount ] . params [ 1 ] = 0 ;
events [ eventCount ] . params [ 2 ] = 0 ;
TRACELOG ( LOG_INFO , " [%i] INPUT_GESTURE: %i, %i, %i " , events [ eventCount ] . frame , events [ eventCount ] . params [ 0 ] , events [ eventCount ] . params [ 1 ] , events [ eventCount ] . params [ 2 ] ) ;
eventCount + + ;
}
}
// Play automation event
static void PlayAutomationEvent ( unsigned int frame )
{
for ( unsigned int i = 0 ; i < eventCount ; i + + )
{
if ( events [ i ] . frame = = frame )
{
switch ( events [ i ] . type )
{
// Input events
case INPUT_KEY_UP : CORE . Input . Keyboard . currentKeyState [ events [ i ] . params [ 0 ] ] = false ; break ; // param[0]: key
case INPUT_KEY_DOWN : CORE . Input . Keyboard . currentKeyState [ events [ i ] . params [ 0 ] ] = true ; break ; // param[0]: key
case INPUT_MOUSE_BUTTON_UP : CORE . Input . Mouse . currentButtonState [ events [ i ] . params [ 0 ] ] = false ; break ; // param[0]: key
case INPUT_MOUSE_BUTTON_DOWN : CORE . Input . Mouse . currentButtonState [ events [ i ] . params [ 0 ] ] = true ; break ; // param[0]: key
case INPUT_MOUSE_POSITION : // param[0]: x, param[1]: y
{
CORE . Input . Mouse . currentPosition . x = ( float ) events [ i ] . params [ 0 ] ;
CORE . Input . Mouse . currentPosition . y = ( float ) events [ i ] . params [ 1 ] ;
} break ;
2022-06-12 11:30:07 -04:00
case INPUT_MOUSE_WHEEL_MOTION : // param[0]: x delta, param[1]: y delta
{
CORE . Input . Mouse . currentWheelMove . x = ( float ) events [ i ] . params [ 0 ] ; break ;
CORE . Input . Mouse . currentWheelMove . y = ( float ) events [ i ] . params [ 1 ] ; break ;
} break ;
2021-06-11 12:27:46 +02:00
case INPUT_TOUCH_UP : CORE . Input . Touch . currentTouchState [ events [ i ] . params [ 0 ] ] = false ; break ; // param[0]: id
case INPUT_TOUCH_DOWN : CORE . Input . Touch . currentTouchState [ events [ i ] . params [ 0 ] ] = true ; break ; // param[0]: id
case INPUT_TOUCH_POSITION : // param[0]: id, param[1]: x, param[2]: y
{
CORE . Input . Touch . position [ events [ i ] . params [ 0 ] ] . x = ( float ) events [ i ] . params [ 1 ] ;
CORE . Input . Touch . position [ events [ i ] . params [ 0 ] ] . y = ( float ) events [ i ] . params [ 2 ] ;
} break ;
case INPUT_GAMEPAD_CONNECT : CORE . Input . Gamepad . ready [ events [ i ] . params [ 0 ] ] = true ; break ; // param[0]: gamepad
case INPUT_GAMEPAD_DISCONNECT : CORE . Input . Gamepad . ready [ events [ i ] . params [ 0 ] ] = false ; break ; // param[0]: gamepad
case INPUT_GAMEPAD_BUTTON_UP : CORE . Input . Gamepad . currentButtonState [ events [ i ] . params [ 0 ] ] [ events [ i ] . params [ 1 ] ] = false ; break ; // param[0]: gamepad, param[1]: button
case INPUT_GAMEPAD_BUTTON_DOWN : CORE . Input . Gamepad . currentButtonState [ events [ i ] . params [ 0 ] ] [ events [ i ] . params [ 1 ] ] = true ; break ; // param[0]: gamepad, param[1]: button
case INPUT_GAMEPAD_AXIS_MOTION : // param[0]: gamepad, param[1]: axis, param[2]: delta
{
CORE . Input . Gamepad . axisState [ events [ i ] . params [ 0 ] ] [ events [ i ] . params [ 1 ] ] = ( ( float ) events [ i ] . params [ 2 ] / 32768.0f ) ;
2021-06-13 17:08:30 +02:00
} break ;
2021-09-22 00:15:06 +02:00
case INPUT_GESTURE : GESTURES . current = events [ i ] . params [ 0 ] ; break ; // param[0]: gesture (enum Gesture) -> rgestures.h: GESTURES.current
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// Window events
case WINDOW_CLOSE : CORE . Window . shouldClose = true ; break ;
case WINDOW_MAXIMIZE : MaximizeWindow ( ) ; break ;
case WINDOW_MINIMIZE : MinimizeWindow ( ) ; break ;
case WINDOW_RESIZE : SetWindowSize ( events [ i ] . params [ 0 ] , events [ i ] . params [ 1 ] ) ; break ;
2021-06-13 17:08:30 +02:00
2021-06-11 12:27:46 +02:00
// Custom events
2021-06-13 17:08:30 +02:00
case ACTION_TAKE_SCREENSHOT :
2021-06-11 12:27:46 +02:00
{
2021-06-13 17:08:30 +02:00
TakeScreenshot ( TextFormat ( " screenshot%03i.png " , screenshotCounter ) ) ;
2021-06-11 12:27:46 +02:00
screenshotCounter + + ;
} break ;
case ACTION_SETTARGETFPS : SetTargetFPS ( events [ i ] . params [ 0 ] ) ; break ;
default : break ;
}
}
}
}
# endif
2021-12-04 19:56:02 +01:00
# if !defined(SUPPORT_MODULE_RTEXT)
// Formatting of text with variables to 'embed'
// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
const char * TextFormat ( const char * text , . . . )
{
# ifndef MAX_TEXTFORMAT_BUFFERS
# define MAX_TEXTFORMAT_BUFFERS 4 // Maximum number of static buffers for text formatting
# endif
# ifndef MAX_TEXT_BUFFER_LENGTH
# define MAX_TEXT_BUFFER_LENGTH 1024 // Maximum size of static text buffer
# endif
// We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
static char buffers [ MAX_TEXTFORMAT_BUFFERS ] [ MAX_TEXT_BUFFER_LENGTH ] = { 0 } ;
static int index = 0 ;
char * currentBuffer = buffers [ index ] ;
memset ( currentBuffer , 0 , MAX_TEXT_BUFFER_LENGTH ) ; // Clear buffer before using
va_list args ;
va_start ( args , text ) ;
vsnprintf ( currentBuffer , MAX_TEXT_BUFFER_LENGTH , text , args ) ;
va_end ( args ) ;
index + = 1 ; // Move to next buffer for next function call
if ( index > = MAX_TEXTFORMAT_BUFFERS ) index = 0 ;
return currentBuffer ;
}
# endif // !SUPPORT_MODULE_RTEXT