2014-09-16 22:51:31 +02:00
/**********************************************************************************************
2013-11-18 23:38:44 +01:00
*
2017-02-16 00:50:02 +01:00
* raylib . core - 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
2018-11-06 15:10:50 +01:00
* - PLATFORM_ANDROID : Android 4.0 ( ARM , ARM64 )
2019-08-07 00:26:33 +02:00
* - PLATFORM_RPI : Raspberry Pi 0 , 1 , 2 , 3 , 4 ( Raspbian )
2020-09-27 10:18:43 +02:00
* - PLATFORM_DRM : Linux native mode , including Raspberry Pi 4 with V3D fkms driver
2017-11-10 12:37:53 +01:00
* - PLATFORM_WEB : HTML5 with asm . js ( Chrome , Firefox )
* - PLATFORM_UWP : Windows 10 App , Windows Phone , Xbox One
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
*
* # define PLATFORM_RPI
2018-11-06 15:10:50 +01:00
* Windowing and input system configured for Raspberry Pi i native mode ( no X . org required , tested on Raspbian ) ,
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-11-10 12:37:53 +01:00
* # define PLATFORM_UWP
* Universal Windows Platform support , using OpenGL ES 2.0 through ANGLE on multiple Windows platforms ,
* including Windows 10 App , Windows Phone and Xbox One platforms .
*
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
* Camera module is included ( camera . 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
* Gestures module is included ( gestures . 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
* blocking the device is not restored properly . Use with care .
*
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
*
2020-02-27 13:18:15 +01:00
* # define SUPPORT_DATA_STORAGE
2021-03-20 18:36:25 +01:00
* Support saving binary data automatically to a generated storage . data file . This file is managed internally
*
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-01-02 18:15:13 +01:00
* Copyright ( c ) 2013 - 2021 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
2020-05-01 17:31:44 +02:00
# include "utils.h" // Required for: TRACELOG macros
2020-02-03 19:13:24 +01:00
2017-12-10 21:11:04 +01:00
# if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L
2017-11-22 22:47:57 +01:00
# undef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
# endif
2020-05-01 17:31:44 +02:00
# define RAYMATH_IMPLEMENTATION // Define external out-of-line implementation of raymath here
# include "raymath.h" // Required for: Vector3 and Matrix functions
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
2018-07-16 17:53:47 +02:00
# define RLGL_IMPLEMENTATION
2020-05-01 17:31:44 +02:00
# include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
2018-07-16 17:53:47 +02:00
2017-03-21 13:22:59 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM)
# define GESTURES_IMPLEMENTATION
2020-05-01 17:31:44 +02:00
# include "gestures.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
2020-05-01 17:31:44 +02:00
# include "camera.h" // Camera system functionality
2017-05-18 18:57:11 +02:00
# endif
# if defined(SUPPORT_GIF_RECORDING)
2020-11-20 00:34:18 +01:00
//#define MSF_GIF_MALLOC RL_MALLOC
//#define MSF_GIF_FREE RL_FREE
2020-03-25 19:41:51 +01:00
2020-11-20 00:34:18 +01:00
# define MSF_GIF_IMPL
# include "external/msf_gif.h" // Support GIF recording
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
# include "external/sinfl.h"
2021-03-19 19:43:44 +01:00
2021-01-12 21:15:11 +01:00
# define SDEFL_IMPLEMENTATION
# include "external/sdefl.h"
# endif
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()]
# include <string.h> // Required for: strrchr(), strcmp(), strlen()
# 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
2020-05-01 17:31:44 +02:00
# include <sys/stat.h> // Required for: stat() [Used in GetFileModTime()]
2018-10-08 16:25:47 +02:00
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(PLATFORM_UWP)) && 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
2018-10-08 18:38:39 +02:00
# include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()]
2018-10-08 16:25:47 +02:00
# else
# include <dirent.h> // Required for: DIR, opendir(), closedir() [Used in GetDirectoryFiles()]
# 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
2018-10-14 14:14:04 +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
# if defined(__linux__) || defined(__FreeBSD__)
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)
2016-10-18 00:15:23 +02:00
//#include <android/sensor.h> // Android sensors functions (accelerometer, gyroscope, light...)
2014-09-16 22:51:31 +02:00
# include <android/window.h> // Defines AWINDOW_FLAG_FULLSCREEN and others
2016-01-03 13:01:21 +01:00
# include <android_native_app_glue.h> // Defines basic app state struct and manages activity
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-04-28 23:57:46 +02:00
//#include <GLES2/gl2.h> // OpenGL ES 2.0 library (not required in this module)
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
2020-05-01 17:31:44 +02:00
# include <sys/ioctl.h> // UNIX System call for device-specific input/output operations - ioctl()
# 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)
# include <gbm.h> // Generic Buffer Management
# include <xf86drm.h> // Direct Rendering Manager user-level library interface
# include <xf86drmMode.h> // Direct Rendering Manager modesetting interface
# 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-04-28 23:57:46 +02:00
//#include "GLES2/gl2.h" // OpenGL ES 2.0 library (not required in this module)
2014-09-16 22:51:31 +02:00
# endif
2013-11-18 23:38:44 +01:00
2017-11-10 12:37:53 +01:00
# if defined(PLATFORM_UWP)
2021-04-27 11:05:05 +02:00
# include "EGL/egl.h" // Native platform windowing system interface
# include "EGL/eglext.h" // EGL extensions
2021-04-28 23:57:46 +02:00
//#include "GLES2/gl2.h" // OpenGL ES 2.0 library (not required in this module)
2020-05-01 17:31:44 +02:00
# include "uwp_events.h" // UWP bootstrapping functions
2017-11-10 12:37:53 +01:00
# endif
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-01-30 13:22:14 -08:00
# include "GLFW/glfw3.h" // GLFW3 library: 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
2018-10-08 16:12:09 +02:00
# include <emscripten/emscripten.h> // Emscripten library - LLVM to JavaScript compiler
# 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
2020-05-01 17:31:44 +02:00
# ifndef MAX_FILEPATH_LENGTH
# if defined(__linux__)
# define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
# else
# define MAX_FILEPATH_LENGTH 512 // Maximum length supported for filepaths
# endif
# 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
# define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
# 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
2020-02-27 13:18:15 +01:00
# if defined(SUPPORT_DATA_STORAGE)
2020-05-01 17:31:44 +02:00
# ifndef STORAGE_DATA_FILE
# define STORAGE_DATA_FILE "storage.data" // Automatic storage filename
# endif
2020-02-27 13:18:15 +01:00
# endif
2016-10-09 13:09:08 +02: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)
2020-02-03 18:31:30 +01:00
GLFWwindow * handle ; // Native 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
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
# if defined(PLATFORM_DRM)
int fd ; // /dev/dri/... file descriptor
drmModeConnector * connector ; // Direct Rendering Manager (DRM) mode connector
int modeIndex ; // index of the used mode of connector->modes
drmModeCrtc * crtc ; // crt controller
struct gbm_device * gbmDevice ; // device of Generic Buffer Management (GBM, native platform for EGL on DRM)
struct gbm_surface * gbmSurface ; // surface of GBM
struct gbm_bo * prevBO ; // previous used GBM buffer object (during frame swapping)
uint32_t prevFB ; // previous used GBM framebufer (during frame swapping)
# endif
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
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
2020-02-03 18:31:30 +01:00
char * * dropFilesPath ; // Store dropped files paths as strings
int dropFilesCount ; // 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
const char * internalDataPath ; // Android internal data path to write data (/data/data/<package>/files)
bool contextRebindRequired ; // Used to know context rebind required
} Android ;
2020-04-30 18:48:39 +01:00
# endif
# if defined(PLATFORM_UWP)
struct {
2020-06-27 14:11:21 +02:00
const char * internalDataPath ; // UWP App data path
2020-04-30 18:48:39 +01:00
} UWP ;
2020-02-03 18:31:30 +01:00
# endif
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
2020-12-18 18:58:02 +01:00
int charPressedQueue [ MAX_CHAR_PRESSED_QUEUE ] ; // Input characters queue
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
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
2020-10-06 05:16:23 +11:00
float currentWheelMove ; // Registers current mouse wheel variation
float previousWheelMove ; // Registers previous mouse wheel variation
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2021-06-10 17:11:31 +02:00
char currentButtonStateEvdev [ MAX_MOUSE_BUTTONS ] ; // Holds the new mouse state for the next polling event to grab (Can't be written directly due to multithreading, app could miss the update)
2020-02-03 18:31:30 +01:00
# endif
} Mouse ;
struct {
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-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
2020-09-27 10:18:43 +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
char name [ 64 ] ; // Gamepad name holder
# 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
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
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
//----------------------------------------------------------------------------------
2020-03-23 20:24:09 +01:00
static CoreData CORE = { 0 } ; // Global CORE state context
2018-11-26 17:15:00 +01:00
2020-03-03 16:10:31 +01:00
static char * * dirFilesPath = NULL ; // Store directory files paths as strings
2018-10-08 12:29:02 +02:00
static int dirFilesCount = 0 ; // Count directory files strings
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)
2018-04-29 11:49:10 +02:00
static int gifFramesCounter = 0 ; // GIF frames counter
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
INPUT_MOUSE_WHEEL_MOTION , // param[0]: delta
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)
//----------------------------------------------------------------------------------
2017-03-21 13:22:59 +01:00
# if 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
//----------------------------------------------------------------------------------
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
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)
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)
2019-05-21 20:59:13 +02:00
# if defined(SUPPORT_SSH_KEYBOARD_RPI)
static void InitKeyboard ( void ) ; // Init raw keyboard system (standard input reading)
static void ProcessKeyboard ( void ) ; // Process keyboard events
static void RestoreKeyboard ( void ) ; // Restore keyboard system
2019-06-10 17:09:53 -04:00
# else
static void InitTerminal ( void ) ; // Init terminal (block echo and signal short cuts)
static void RestoreTerminal ( void ) ; // Restore terminal
2019-05-21 20:59:13 +02:00
# endif
2019-04-28 16:45:23 +02:00
static void InitEvdevInput ( void ) ; // Evdev inputs initialization
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
2016-05-02 14:11:57 +02:00
static void InitGamepad ( void ) ; // Init raw gamepad input
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)
static void LoadAutomationEvents ( const char * fileName ) ;
static void ExportAutomationEvents ( const char * fileName ) ;
static void RecordAutomationEvent ( unsigned int frame ) ;
static void PlayAutomationEvent ( unsigned int frame ) ;
# endif
2017-01-28 00:56:45 +01:00
# if defined(_WIN32)
2021-03-12 17:18:48 +01:00
// NOTE: We include Sleep() function signature here to avoid windows.h inclusion (kernel32 lib)
2021-06-17 11:47:05 +02:00
void __stdcall Sleep ( unsigned long msTimeout ) ; // Required for WaitTime()
2017-01-28 00:56:45 +01:00
# endif
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
// TODO: Should we maybe report != 0 return codes somewhere?
2018-10-18 16:00:11 +02:00
( void ) main ( 1 , ( char * [ ] ) { arg0 , NULL } ) ;
2018-04-02 14:49:01 +02:00
}
// TODO: Add this to header (if apps really need it)
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
2020-09-27 10:18:43 +02:00
# if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && !defined(SUPPORT_SSH_KEYBOARD_RPI)
2019-06-10 17:09:53 -04:00
// Init terminal (block echo and signal short cuts)
static void InitTerminal ( void )
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " RPI: Reconfiguring terminal... " ) ;
2019-06-10 17:09:53 -04:00
// Save terminal keyboard settings and reconfigure terminal with new settings
struct termios keyboardNewSettings ;
2020-02-03 18:31:30 +01:00
tcgetattr ( STDIN_FILENO , & CORE . Input . Keyboard . defaultSettings ) ; // Get current keyboard settings
keyboardNewSettings = CORE . Input . Keyboard . defaultSettings ;
2019-06-10 17:09:53 -04:00
// New terminal settings for keyboard: turn off buffering (non-canonical mode), echo
// NOTE: ISIG controls if ^C and ^Z generate break signals or not
keyboardNewSettings . c_lflag & = ~ ( ICANON | ECHO | ISIG ) ;
keyboardNewSettings . c_cc [ VMIN ] = 1 ;
keyboardNewSettings . c_cc [ VTIME ] = 0 ;
// Set new keyboard settings (change occurs immediately)
tcsetattr ( STDIN_FILENO , TCSANOW , & keyboardNewSettings ) ;
2018-04-02 14:49:01 +02:00
2019-06-10 17:09:53 -04:00
// Save old keyboard mode to restore it at the end
2020-02-03 18:31:30 +01:00
if ( ioctl ( STDIN_FILENO , KDGKBMODE , & CORE . Input . Keyboard . defaultMode ) < 0 )
2019-06-10 17:09:53 -04:00
{
// NOTE: It could mean we are using a remote keyboard through ssh or from the desktop
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " RPI: Failed to change keyboard mode (not a local terminal) " ) ;
2019-06-10 17:09:53 -04:00
}
2020-03-27 18:06:09 +01:00
else ioctl ( STDIN_FILENO , KDSKBMODE , K_XLATE ) ;
2019-06-10 17:09:53 -04:00
// Register terminal restore when program finishes
atexit ( RestoreTerminal ) ;
}
// Restore terminal
static void RestoreTerminal ( void )
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " RPI: Restoring terminal... " ) ;
2019-10-17 17:18:03 +02:00
2019-06-10 17:09:53 -04:00
// Reset to default keyboard settings
2020-02-03 18:31:30 +01:00
tcsetattr ( STDIN_FILENO , TCSANOW , & CORE . Input . Keyboard . defaultSettings ) ;
2019-06-10 17:09:53 -04:00
// Reconfigure keyboard to default mode
2020-02-03 18:31:30 +01:00
ioctl ( STDIN_FILENO , KDSKBMODE , CORE . Input . Keyboard . defaultMode ) ;
2019-06-10 17:09:53 -04:00
}
# endif
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-04-30 18:48:39 +01:00
# if defined(PLATFORM_UWP)
if ( ! UWPIsConfigured ( ) )
{
2021-05-30 18:02:06 +02:00
TRACELOG ( LOG_FATAL , " UWP Functions have not been set yet, please set these before initializing raylib! " ) ;
2020-04-30 18:48:39 +01:00
return ;
}
# endif
2020-02-03 19:13:24 +01:00
TRACELOG ( LOG_INFO , " Initializing raylib %s " , RAYLIB_VERSION ) ;
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 ;
2020-02-03 19:26:28 +01:00
2020-02-03 18:31:30 +01:00
// Initialize required global values different than 0
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 ;
2020-11-03 23:47:33 +01:00
2020-04-30 18:48:39 +01:00
# if defined(PLATFORM_UWP)
// The axis count is 6 (2 thumbsticks and left and right trigger)
CORE . Input . Gamepad . axisCount = 6 ;
# endif
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
// Input data is android app pointer
2020-02-03 18:31:30 +01:00
CORE . Android . internalDataPath = CORE . Android . app - > activity - > internalDataPath ;
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
2020-02-03 18:31:30 +01:00
CORE . Android . app - > onAppCmd = AndroidCommandCallback ;
CORE . Android . app - > onInputEvent = AndroidInputCallback ;
2018-04-02 14:49:01 +02:00
2020-03-05 18:12:41 +01:00
InitAssetManager ( CORE . Android . app - > activity - > assetManager , 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
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) || defined(PLATFORM_DRM)
2016-06-25 21:28:50 +02:00
// Init 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
2018-03-31 12:22:44 +02:00
// Init hi-res timer
InitTimer ( ) ;
2017-03-21 13:22:59 +01:00
# if defined(SUPPORT_DEFAULT_FONT)
2016-10-09 13:09:08 +02:00
// Load default font
2020-02-03 18:31:30 +01:00
// NOTE: External functions (defined in module: text)
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-04-04 14:59:17 +02:00
SetShapesTexture ( GetFontDefault ( ) . texture , ( Rectangle ) { rec . x + 1 , rec . y + 1 , rec . width - 2 , rec . height - 2 } ) ;
# else
// Set default internal texture (1px white) and rectangle to be used for shapes drawing
SetShapesTexture ( rlGetTextureDefault ( ) , ( Rectangle ) { 0.0f , 0.0f , 1.0f , 1.0f } ) ;
2016-10-09 13:09:08 +02:00
# endif
2020-11-23 00:49:27 +01:00
# if defined(PLATFORM_DESKTOP)
if ( ( CORE . Window . flags & FLAG_WINDOW_HIGHDPI ) > 0 )
{
// Set default font texture filter for HighDPI (blurry)
2021-03-03 19:47:37 +01:00
SetTextureFilter ( GetFontDefault ( ) . texture , TEXTURE_FILTER_BILINEAR ) ;
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)
2014-09-16 22:51:31 +02:00
// Init 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
2019-05-21 20:59:13 +02:00
# if defined(SUPPORT_SSH_KEYBOARD_RPI)
InitKeyboard ( ) ; // Keyboard init
2019-06-10 17:09:53 -04:00
# else
InitTerminal ( ) ; // Terminal init
2019-05-21 20:59:13 +02:00
# endif
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-06-10 17:49:55 +02:00
// Check fullscreen change events
2021-04-02 13:46:56 +02:00
//emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
//emscripten_set_resize_callback("#canvas", NULL, 1, EmscriptenResizeCallback);
2018-11-06 15:10:50 +01:00
2017-04-08 00:16:03 +02:00
// Support keyboard events
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
// 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
2021-06-11 12:27:46 +02:00
# endif // PLATFORM_DESKTOP || PLATFORM_WEB || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP
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
2017-03-21 13:22:59 +01:00
# if defined(SUPPORT_DEFAULT_FONT)
2019-06-16 23:42:51 +02:00
UnloadFontDefault ( ) ;
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
2021-03-12 17:18:48 +01:00
# if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) && !defined(PLATFORM_UWP)
2017-05-08 02:37:37 +02:00
timeEndPeriod ( 1 ) ; // Restore time period
# endif
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
# 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 ;
}
# endif
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-09-27 10:18:43 +02:00
# if !defined(PLATFORM_DRM)
2020-02-03 18:31:30 +01:00
eglMakeCurrent ( CORE . Window . device , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
2020-09-27 10:18:43 +02:00
# endif
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
2019-10-17 17:18:03 +02: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
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
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 )
{
2017-11-10 12:37:53 +01:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
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 )
{
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
2020-11-23 00:49:27 +01:00
return ( ( CORE . Window . flags & FLAG_WINDOW_UNFOCUSED ) = = 0 ) ; // TODO!
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 )
{
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
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)
2016-06-26 01:36:06 +02:00
// NOTE: glfwSetWindowMonitor() doesn't work properly (bugs)
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 ;
2021-03-22 20:45:04 +01:00
GLFWmonitor * * monitors = glfwGetMonitors ( & monitorCount ) ;
2021-03-08 09:08:37 -08:00
int monitorIndex = GetCurrentMonitor ( ) ;
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
2021-03-08 09:08:37 -08:00
GLFWmonitor * monitor = monitorIndex < monitorCount ? monitors [ monitorIndex ] : NULL ;
2019-12-01 14:46:09 +02:00
if ( ! monitor )
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " GLFW: Failed to get monitor " ) ;
2021-03-19 19:43:44 +01:00
2021-03-08 23:51:10 +02:00
CORE . Window . fullscreen = false ; // Toggle fullscreen flag
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
return ;
}
2021-03-19 19:43:44 +01:00
2021-03-08 23:51:10 +02:00
CORE . Window . fullscreen = true ; // Toggle fullscreen flag
CORE . Window . flags | = FLAG_FULLSCREEN_MODE ;
2021-03-19 19:43:44 +01:00
2021-02-14 16:47:19 +01: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
{
2021-03-08 23:51:10 +02:00
CORE . Window . fullscreen = false ; // Toggle fullscreen flag
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-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-04-02 13:46:56 +02:00
else Module . requestFullscreen ( false , true ) ;
2020-05-14 17:35:26 +02:00
) ;
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
// This option does not seem to work at all
//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 ) ;
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();
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 ) ;
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
2021-02-14 16:47:19 +01:00
CORE . Window . flags ^ = FLAG_FULLSCREEN_MODE ;
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 " ) ;
}
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
}
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
2019-05-07 09:50:40 +02:00
// TODO: Issues on HighDPI scaling
2018-03-09 11:43:53 +01:00
void SetWindowSize ( int width , int height )
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwSetWindowSize ( CORE . Window . handle , width , height ) ;
2018-03-09 11:43:53 +01:00
# endif
2020-02-24 12:35:53 +01:00
# if defined(PLATFORM_WEB)
2020-12-18 19:32:52 +01:00
//emscripten_set_canvas_size(width, height); // DEPRECATED!
2020-02-26 23:42:06 +01:00
2020-02-24 12:35:53 +01:00
// TODO: Below functions should be used to replace previous one but
// they do not seem to work properly
//emscripten_set_canvas_element_size("canvas", width, height);
//emscripten_set_element_css_size("canvas", width, height);
# endif
2018-03-09 11:43:53 +01:00
}
2014-09-16 22:51:31 +02:00
// Get current screen width
int GetScreenWidth ( void )
2013-11-18 23:38:44 +01:00
{
2021-03-01 23:51:32 +01:00
return CORE . Window . currentFbo . 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-03-01 23:51:32 +01:00
return CORE . Window . currentFbo . 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
}
2020-12-05 12:51:20 -08:00
// Get selected monitor width
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 } ;
}
2021-02-07 20:47:40 +01:00
// Get selected monitor width (max available 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
{
2021-02-07 21:44:38 +02:00
int count = 0 ;
const GLFWvidmode * modes = glfwGetVideoModes ( monitors [ monitor ] , & count ) ;
2021-03-19 19:43:44 +01:00
2021-02-07 20:47:40 +01:00
// We return the maximum resolution available, the last one in the modes array
if ( count > 0 ) return modes [ count - 1 ] . width ;
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
}
2021-02-07 20:47:40 +01:00
// Get selected monitor width (max available 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
{
2021-02-07 21:44:38 +02:00
int count = 0 ;
const GLFWvidmode * modes = glfwGetVideoModes ( monitors [ monitor ] , & count ) ;
2021-03-19 19:43:44 +01:00
2021-02-07 20:47:40 +01:00
// We return the maximum resolution available, the last one in the modes array
if ( count > 0 ) return modes [ count - 1 ] . height ;
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
}
2019-02-11 18:03:06 +01:00
// Get clipboard text content
// NOTE: returned string is allocated and freed by GLFW
const char * GetClipboardText ( void )
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
return glfwGetClipboardString ( CORE . Window . handle ) ;
2019-02-28 22:25:27 +01:00
# else
return NULL ;
2019-02-11 18:03:06 +01:00
# endif
}
// Set clipboard text content
void SetClipboardText ( const char * text )
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwSetClipboardString ( CORE . Window . handle , text ) ;
2019-02-11 18:03:06 +01:00
# endif
}
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
# if defined(PLATFORM_UWP)
2020-04-30 18:48:39 +01:00
UWPGetMouseShowFunc ( ) ( ) ;
2016-10-17 18:18:13 +02:00
# endif
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
# if defined(PLATFORM_UWP)
2020-04-30 18:48:39 +01:00
UWPGetMouseHideFunc ( ) ( ) ;
2016-10-17 18:18:13 +02:00
# endif
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
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_UWP)
2020-04-30 18:48:39 +01:00
UWPGetMouseUnlockFunc ( ) ( ) ;
2016-10-17 18:18:13 +02:00
# endif
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
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_UWP)
2020-04-30 18:48:39 +01:00
UWPGetMouseLockFunc ( ) ( ) ;
2016-10-17 18:18:13 +02:00
# endif
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
{
2020-02-03 18:31:30 +01:00
CORE . Time . current = GetTime ( ) ; // Number of elapsed seconds since InitTimer()
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
# if defined(SUPPORT_MOUSE_CURSOR_POINT)
// Draw a small rectangle on mouse position for user reference
2020-09-27 10:18:43 +02:00
if ( ! CORE . Input . Mouse . cursorHidden )
{
2021-06-10 18:03:25 +02:00
DrawRectangle ( CORE . Input . Mouse . currentPosition . x , CORE . Input . Mouse . currentPosition . y , 3 , 3 , MAROON ) ;
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
2017-05-18 18:57:11 +02:00
gifFramesCounter + + ;
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
if ( ( gifFramesCounter % GIF_RECORD_FRAMERATE ) = = 0 )
{
// Get image data for the current frame (from backbuffer)
2020-11-20 00:34:18 +01:00
// NOTE: This process is quite slow... :(
2020-02-03 18:31:30 +01:00
unsigned char * screenData = rlReadScreenPixels ( CORE . Window . screen . width , CORE . Window . screen . height ) ;
2020-11-20 00:34:18 +01:00
msf_gif_frame ( & gifState , screenData , 10 , 16 , CORE . Window . screen . width * 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
2017-05-18 18:57:11 +02:00
if ( ( ( gifFramesCounter / 15 ) % 2 ) = = 1 )
{
2021-06-11 12:27:46 +02:00
DrawCircle ( 30 , CORE . Window . screen . height - 20 , 10 , MAROON ) ;
DrawText ( " GIF RECORDING " , 50 , CORE . Window . screen . height - 25 , 10 , RED ) ;
}
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 )
{
gifFramesCounter + + ;
if ( ( ( gifFramesCounter / 15 ) % 2 ) = = 1 )
{
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 )
{
gifFramesCounter + + ;
if ( ( ( gifFramesCounter / 15 ) % 2 ) = = 1 )
{
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-17 11:17:39 +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
{
2021-06-17 11:47:05 +02:00
WaitTime ( ( float ) ( CORE . Time . target - CORE . Time . frame ) * 1000.0f ) ;
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
PollInputEvents ( ) ; // Poll user events
2021-06-17 12:17:50 +02:00
# endif
2021-06-17 11:17:39 +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
2016-05-29 11:49:13 +02:00
// Set viewport to framebuffer size
2016-08-16 11:09:55 +02:00
rlViewport ( 0 , 0 , target . texture . width , target . texture . height ) ;
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
CORE . Window . currentFbo . width = CORE . Window . screen . width ;
CORE . Window . currentFbo . height = CORE . Window . screen . 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 )
{
rlSetShader ( shader ) ;
}
// End custom shader mode (returns to default shader)
void EndShaderMode ( void )
{
rlSetShader ( rlGetShaderDefault ( ) ) ;
}
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 ( ) ;
rlScissor ( x , CORE . Window . currentFbo . height - ( y + height ) , width , height ) ;
}
// 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
rlSetMatrixProjectionStereo ( config . projection [ 0 ] , config . projection [ 1 ] ) ;
rlSetMatrixViewOffsetStereo ( config . viewOffset [ 0 ] , config . viewOffset [ 1 ] ) ;
}
// 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-04-06 22:49:41 +02:00
# if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// 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)
//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 ) ;
// 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 ) ;
2021-04-18 23:50:32 +02:00
2021-04-06 22:49:41 +02:00
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 " ) ;
# endif
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 } ;
shader . locs = ( int * ) RL_CALLOC ( MAX_SHADER_LOCATIONS , sizeof ( int ) ) ;
// NOTE: All locations must be reseted to -1 (no location)
for ( int i = 0 ; i < MAX_SHADER_LOCATIONS ; i + + ) shader . locs [ i ] = - 1 ;
char * vShaderStr = NULL ;
char * fShaderStr = NULL ;
if ( vsFileName ! = NULL ) vShaderStr = LoadFileText ( vsFileName ) ;
if ( fsFileName ! = NULL ) fShaderStr = LoadFileText ( fsFileName ) ;
shader . id = rlLoadShaderCode ( vShaderStr , fShaderStr ) ;
2021-05-22 16:54:04 +02:00
if ( vShaderStr ! = NULL ) UnloadFileText ( vShaderStr ) ;
if ( fShaderStr ! = NULL ) UnloadFileText ( fShaderStr ) ;
2021-04-01 20:24:33 +02:00
2021-03-21 01:29:31 +01:00
// After shader loading, we TRY to set default location names
2021-03-22 20:45:04 +01:00
if ( shader . id > 0 )
2021-03-28 20:12:48 +02:00
{
// Default shader attrib locations have been fixed before linking:
// 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-28 20:12:48 +02:00
// NOTE: If any location is not found, loc point becomes -1
// Get handles to GLSL input attibute locations
shader . locs [ SHADER_LOC_VERTEX_POSITION ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_POSITION ) ;
shader . locs [ SHADER_LOC_VERTEX_TEXCOORD01 ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD ) ;
shader . locs [ SHADER_LOC_VERTEX_TEXCOORD02 ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 ) ;
shader . locs [ SHADER_LOC_VERTEX_NORMAL ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_NORMAL ) ;
shader . locs [ SHADER_LOC_VERTEX_TANGENT ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_TANGENT ) ;
shader . locs [ SHADER_LOC_VERTEX_COLOR ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_COLOR ) ;
// Get handles to GLSL uniform locations (vertex shader)
2021-03-31 20:44:16 +02:00
shader . locs [ SHADER_LOC_MATRIX_MVP ] = rlGetLocationUniform ( shader . id , " mvp " ) ;
shader . locs [ SHADER_LOC_MATRIX_VIEW ] = rlGetLocationUniform ( shader . id , " view " ) ;
shader . locs [ SHADER_LOC_MATRIX_PROJECTION ] = rlGetLocationUniform ( shader . id , " projection " ) ;
shader . locs [ SHADER_LOC_MATRIX_NORMAL ] = rlGetLocationUniform ( shader . id , " matNormal " ) ;
2021-03-28 20:12:48 +02:00
// Get handles to GLSL uniform locations (fragment shader)
shader . locs [ SHADER_LOC_COLOR_DIFFUSE ] = rlGetLocationUniform ( shader . id , " colDiffuse " ) ;
shader . locs [ SHADER_LOC_MAP_DIFFUSE ] = rlGetLocationUniform ( shader . id , " texture0 " ) ;
shader . locs [ SHADER_LOC_MAP_SPECULAR ] = rlGetLocationUniform ( shader . id , " texture1 " ) ;
shader . locs [ SHADER_LOC_MAP_NORMAL ] = rlGetLocationUniform ( shader . id , " texture2 " ) ;
}
return shader ;
}
// Load shader from code strings and bind default locations
RLAPI Shader LoadShaderFromMemory ( const char * vsCode , const char * fsCode )
{
Shader shader = { 0 } ;
shader . locs = ( int * ) RL_CALLOC ( MAX_SHADER_LOCATIONS , sizeof ( int ) ) ;
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
{
// Default shader attrib locations have been fixed before linking:
// 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
shader . locs [ SHADER_LOC_VERTEX_POSITION ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_POSITION ) ;
shader . locs [ SHADER_LOC_VERTEX_TEXCOORD01 ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD ) ;
shader . locs [ SHADER_LOC_VERTEX_TEXCOORD02 ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 ) ;
shader . locs [ SHADER_LOC_VERTEX_NORMAL ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_NORMAL ) ;
shader . locs [ SHADER_LOC_VERTEX_TANGENT ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_TANGENT ) ;
shader . locs [ SHADER_LOC_VERTEX_COLOR ] = rlGetLocationAttrib ( shader . id , DEFAULT_SHADER_ATTRIB_NAME_COLOR ) ;
// Get handles to GLSL uniform locations (vertex shader)
2021-06-05 12:33:05 +02:00
shader . locs [ SHADER_LOC_MATRIX_MVP ] = rlGetLocationUniform ( shader . id , " mvp " ) ;
shader . locs [ SHADER_LOC_MATRIX_PROJECTION ] = rlGetLocationUniform ( shader . id , " projection " ) ;
shader . locs [ SHADER_LOC_MATRIX_VIEW ] = rlGetLocationUniform ( shader . id , " view " ) ;
2021-03-22 20:45:04 +01:00
// Get handles to GLSL uniform locations (fragment shader)
shader . locs [ SHADER_LOC_COLOR_DIFFUSE ] = rlGetLocationUniform ( shader . id , " colDiffuse " ) ;
shader . locs [ SHADER_LOC_MAP_DIFFUSE ] = rlGetLocationUniform ( shader . id , " texture0 " ) ;
shader . locs [ SHADER_LOC_MAP_SPECULAR ] = rlGetLocationUniform ( shader . id , " texture1 " ) ;
shader . locs [ SHADER_LOC_MAP_NORMAL ] = rlGetLocationUniform ( shader . id , " texture2 " ) ;
}
2021-03-21 01:29:31 +01:00
return shader ;
}
// Unload shader from GPU memory (VRAM)
void UnloadShader ( Shader shader )
{
if ( shader . id ! = rlGetShaderDefault ( ) . id )
{
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 ) ;
rlSetUniformMatrix ( locIndex , mat ) ;
//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
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
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " TIMER: Target time per frame: %02.03f milliseconds " , ( float ) CORE . Time . target * 1000 ) ;
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
{
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 ] ;
}
2020-02-26 23:42:06 +01:00
2020-02-19 12:20:15 +01:00
return ( int ) roundf ( 1.0f / average ) ;
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)
return glfwGetTime ( ) ; // Elapsed time since glfwInit()
# endif
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
2017-12-19 14:06:54 +01:00
struct timespec ts ;
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
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_UWP)
2020-04-30 18:48:39 +01:00
return UWPGetQueryTimeFunc ( ) ( ) ;
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
2017-12-19 14:06:54 +01:00
}
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)
2019-01-05 18:03:09 +01:00
// NOTE: This function could work in any platform but some platforms: PLATFORM_ANDROID and PLATFORM_WEB
// have their own internal file-systems, to dowload image to user file-system some additional mechanism is required
2017-05-11 16:24:40 +02:00
void TakeScreenshot ( const char * fileName )
2017-04-16 13:47:49 +02:00
{
2020-02-03 18:31:30 +01:00
unsigned char * imgData = rlReadScreenPixels ( CORE . Window . render . width , CORE . Window . render . height ) ;
2021-03-14 11:05:51 +01:00
Image image = { imgData , CORE . Window . render . width , CORE . Window . render . height , 1 , PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 } ;
2019-01-23 20:07:47 -05:00
2019-01-05 18:03:09 +01:00
char path [ 512 ] = { 0 } ;
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
strcpy ( path , CORE . Android . internalDataPath ) ;
2019-01-05 18:03:09 +01:00
strcat ( path , " / " ) ;
strcat ( path , fileName ) ;
2020-04-30 18:48:39 +01:00
# elif defined(PLATFORM_UWP)
strcpy ( path , CORE . UWP . internalDataPath ) ;
strcat ( path , " / " ) ;
strcat ( path , fileName ) ;
2019-01-05 18:03:09 +01:00
# else
strcpy ( path , fileName ) ;
# endif
2019-01-23 20:07:47 -05:00
2019-01-05 18:03:09 +01:00
ExportImage ( image , path ) ;
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
// TODO: Verification required for log
TRACELOG ( LOG_INFO , " SYSTEM: [%s] Screenshot taken successfully " , path ) ;
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 ) ;
}
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
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
{
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
{
2020-05-09 13:05:54 +02:00
# if defined(SUPPORT_TEXT_MANIPULATION)
2019-10-21 17:37:43 +02:00
int extCount = 0 ;
const char * * checkExts = TextSplit ( ext , ' ; ' , & extCount ) ;
2020-02-03 19:26:28 +01:00
2020-01-12 13:56:03 +01:00
char fileExtLower [ 16 ] = { 0 } ;
strcpy ( fileExtLower , TextToLower ( fileExt ) ) ;
2019-10-21 17:37:43 +02:00
for ( int i = 0 ; i < extCount ; i + + )
2018-03-16 13:09:49 +01:00
{
2021-03-03 16:41:15 +02:00
if ( TextIsEqual ( fileExtLower , TextToLower ( checkExts [ i ] ) ) )
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 ;
}
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 )
{
2019-08-21 18:59:15 +02:00
# define MAX_FILENAMEWITHOUTEXT_LENGTH 128
2019-04-04 13:50:52 +02:00
2019-03-13 10:07:01 +01:00
static char fileName [ MAX_FILENAMEWITHOUTEXT_LENGTH ] ;
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
2020-05-06 19:12:09 +02:00
int len = ( int ) strlen ( fileName ) ;
2019-04-04 13:50:52 +02:00
2019-03-13 10:07:01 +01:00
for ( int i = 0 ; ( i < len ) & & ( 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 ;
2019-08-11 12:04:54 +02:00
static char dirPath [ MAX_FILEPATH_LENGTH ] ;
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
{
2019-08-11 12:04:54 +02:00
static char prevDirPath [ MAX_FILEPATH_LENGTH ] ;
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 )
{
2018-10-25 16:09:38 +02:00
static char currentDir [ MAX_FILEPATH_LENGTH ] ;
memset ( currentDir , 0 , MAX_FILEPATH_LENGTH ) ;
2018-11-06 15:10:50 +01:00
2020-09-16 11:44:48 +02:00
char * ptr = GETCWD ( currentDir , MAX_FILEPATH_LENGTH - 1 ) ;
2018-11-06 15:10:50 +01:00
2020-09-16 11:44:48 +02:00
return ptr ;
2017-05-11 16:24:40 +02:00
}
2018-10-25 16:18:44 +02:00
// Get filenames in a directory path (max 512 files)
2018-10-08 12:29:02 +02:00
// NOTE: Files count is returned by parameters pointer
char * * GetDirectoryFiles ( const char * dirPath , int * fileCount )
{
# define MAX_DIRECTORY_FILES 512
2018-11-06 15:10:50 +01:00
2018-10-08 12:29:02 +02:00
ClearDirectoryFiles ( ) ;
// Memory allocation for MAX_DIRECTORY_FILES
2021-05-22 16:54:04 +02:00
dirFilesPath = ( char * * ) RL_MALLOC ( MAX_DIRECTORY_FILES * sizeof ( char * ) ) ;
for ( int i = 0 ; i < MAX_DIRECTORY_FILES ; i + + ) dirFilesPath [ 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
int counter = 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
2018-10-08 12:29:02 +02:00
if ( dir ! = NULL ) // It's a directory
{
2018-11-06 15:10:50 +01:00
// TODO: Reading could be done in two passes,
2018-10-08 12:29:02 +02:00
// first one to count files and second one to read names
// That way we can allocate required memory, instead of a limited pool
2018-11-06 15:10:50 +01:00
2020-03-09 18:45:37 +01:00
while ( ( entity = readdir ( dir ) ) ! = NULL )
2018-10-08 12:29:02 +02:00
{
2020-03-09 18:45:37 +01:00
strcpy ( dirFilesPath [ counter ] , entity - > d_name ) ;
2018-10-08 12:29:02 +02:00
counter + + ;
}
2018-11-06 15:10:50 +01:00
2018-10-08 12:29:02 +02:00
closedir ( dir ) ;
}
2020-03-27 18:06:09 +01:00
else TRACELOG ( LOG_WARNING , " FILEIO: Failed to open requested directory " ) ; // Maybe it's a file...
2018-10-08 12:29:02 +02:00
dirFilesCount = counter ;
* fileCount = dirFilesCount ;
2018-11-06 15:10:50 +01:00
2018-10-08 12:29:02 +02:00
return dirFilesPath ;
}
// Clear directory files paths buffers
void ClearDirectoryFiles ( void )
{
2019-10-25 14:29:12 +02:00
if ( dirFilesCount > 0 )
2019-10-23 00:46:41 +02:00
{
for ( int i = 0 ; i < MAX_DIRECTORY_FILES ; i + + ) RL_FREE ( dirFilesPath [ i ] ) ;
2018-10-08 12:29:02 +02:00
2019-10-23 00:46:41 +02:00
RL_FREE ( dirFilesPath ) ;
}
2020-02-03 19:26:28 +01:00
2019-10-22 23:18:42 +02:00
dirFilesCount = 0 ;
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
}
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 )
{
2020-02-03 18:31:30 +01:00
if ( CORE . Window . dropFilesCount > 0 ) return true ;
2015-07-29 21:44:27 +02:00
else return false ;
}
2017-05-09 22:03:46 +02:00
// Get dropped files names
2015-07-29 21:44:27 +02:00
char * * GetDroppedFiles ( int * count )
{
2020-02-03 18:31:30 +01:00
* count = CORE . Window . dropFilesCount ;
return CORE . Window . dropFilesPath ;
2015-07-29 21:44:27 +02:00
}
// Clear dropped files paths buffer
void ClearDroppedFiles ( void )
{
2020-02-03 18:31:30 +01:00
if ( CORE . Window . dropFilesCount > 0 )
2015-07-29 21:44:27 +02:00
{
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < CORE . Window . dropFilesCount ; i + + ) RL_FREE ( CORE . Window . dropFilesPath [ i ] ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
RL_FREE ( CORE . Window . dropFilesPath ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
CORE . Window . dropFilesCount = 0 ;
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 ;
}
2019-09-09 21:56:16 +02:00
// Compress data (DEFLATE algorythm)
unsigned char * CompressData ( unsigned char * data , int dataLength , int * compDataLength )
{
# 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 } ;
int bounds = sdefl_bound ( dataLength ) ;
compData = ( unsigned char * ) RL_CALLOC ( bounds , 1 ) ;
* compDataLength = sdeflate ( & sdefl , compData , data , dataLength , COMPRESSION_QUALITY_DEFLATE ) ; // Compression level 8, same as stbwi
2021-03-19 19:43:44 +01:00
2021-04-02 13:43:10 +02:00
TraceLog ( LOG_INFO , " SYSTEM: Compress data: Original size: %i -> Comp. size: %i " , dataLength , compDataLength ) ;
2019-09-09 21:56:16 +02:00
# endif
return compData ;
}
// Decompress data (DEFLATE algorythm)
2019-09-15 11:15:33 +02:00
unsigned char * DecompressData ( unsigned char * compData , int compDataLength , int * dataLength )
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 ) ;
2021-01-12 21:15:11 +01:00
int length = sinflate ( data , compData , compDataLength ) ;
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
2021-01-12 21:15:11 +01:00
* dataLength = length ;
2021-04-02 13:43:10 +02:00
TraceLog ( LOG_INFO , " SYSTEM: Decompress data: Comp. size: %i -> Original size: %i " , compDataLength , dataLength ) ;
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
}
2017-05-09 22:03:46 +02:00
// Save integer value to storage file (to defined position)
2016-01-04 15:12:34 +01:00
// NOTE: Storage positions is directly related to file memory layout (4 bytes each integer)
2020-11-22 00:10:16 +01:00
bool SaveStorageValue ( unsigned int position , int value )
2016-01-04 15:12:34 +01:00
{
2020-11-22 00:10:16 +01:00
bool success = false ;
2020-12-23 15:03:26 +01:00
2020-02-27 13:18:15 +01:00
# if defined(SUPPORT_DATA_STORAGE)
2019-01-05 18:03:09 +01:00
char path [ 512 ] = { 0 } ;
2016-05-31 00:01:19 +02:00
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
strcpy ( path , CORE . Android . internalDataPath ) ;
2016-05-31 00:01:19 +02:00
strcat ( path , " / " ) ;
2020-02-27 13:18:15 +01:00
strcat ( path , STORAGE_DATA_FILE ) ;
2020-04-30 18:48:39 +01:00
# elif defined(PLATFORM_UWP)
strcpy ( path , CORE . UWP . internalDataPath ) ;
strcat ( path , " / " ) ;
strcat ( path , STORAGE_DATA_FILE ) ;
2016-05-31 00:01:19 +02:00
# else
2020-02-27 13:18:15 +01:00
strcpy ( path , STORAGE_DATA_FILE ) ;
2016-05-31 00:01:19 +02:00
# endif
2016-01-04 15:12:34 +01:00
2020-03-30 13:51:36 +02:00
unsigned int dataSize = 0 ;
unsigned int newDataSize = 0 ;
2020-02-27 13:18:15 +01:00
unsigned char * fileData = LoadFileData ( path , & dataSize ) ;
2020-03-30 13:51:36 +02:00
unsigned char * newFileData = NULL ;
2020-02-27 13:33:09 +01:00
2020-02-27 13:18:15 +01:00
if ( fileData ! = NULL )
2016-01-04 15:12:34 +01:00
{
2020-02-27 13:18:15 +01:00
if ( dataSize < = ( position * sizeof ( int ) ) )
{
// Increase data size up to position and store value
2020-03-30 13:51:36 +02:00
newDataSize = ( position + 1 ) * sizeof ( int ) ;
newFileData = ( unsigned char * ) RL_REALLOC ( fileData , newDataSize ) ;
if ( newFileData ! = NULL )
{
// RL_REALLOC succeded
int * dataPtr = ( int * ) newFileData ;
2020-11-03 23:47:33 +01:00
dataPtr [ position ] = value ;
2020-03-30 13:51:36 +02:00
}
else
{
// RL_REALLOC failed
2020-11-03 23:47:33 +01:00
TRACELOG ( LOG_WARNING , " FILEIO: [%s] Failed to realloc data (%u), position in bytes (%u) bigger than actual file size " , path , dataSize , position * sizeof ( int ) ) ;
2020-03-30 14:38:16 +02:00
// We store the old size of the file
newFileData = fileData ;
newDataSize = dataSize ;
2020-03-30 13:51:36 +02:00
}
2020-02-27 13:18:15 +01:00
}
2016-01-04 15:12:34 +01:00
else
{
2020-03-30 14:38:16 +02:00
// Store the old size of the file
newFileData = fileData ;
newDataSize = dataSize ;
2020-03-30 13:51:36 +02:00
2020-02-27 13:18:15 +01:00
// Replace value on selected position
2020-03-30 13:51:36 +02:00
int * dataPtr = ( int * ) newFileData ;
2020-02-27 13:18:15 +01:00
dataPtr [ position ] = value ;
2016-01-04 15:12:34 +01:00
}
2020-02-27 13:33:09 +01:00
2020-11-22 00:10:16 +01:00
success = SaveFileData ( path , newFileData , newDataSize ) ;
2020-03-30 13:51:36 +02:00
RL_FREE ( newFileData ) ;
2016-01-04 15:12:34 +01:00
}
2020-02-27 13:18:15 +01:00
else
{
2020-03-30 14:38:16 +02:00
TRACELOG ( LOG_INFO , " FILEIO: [%s] File not found, creating it " , path ) ;
2020-02-27 13:18:15 +01:00
dataSize = ( position + 1 ) * sizeof ( int ) ;
fileData = ( unsigned char * ) RL_MALLOC ( dataSize ) ;
int * dataPtr = ( int * ) fileData ;
dataPtr [ position ] = value ;
2020-02-27 13:33:09 +01:00
2020-11-22 00:10:16 +01:00
success = SaveFileData ( path , fileData , dataSize ) ;
2021-03-14 14:14:31 +01:00
UnloadFileData ( fileData ) ;
2020-02-27 13:18:15 +01:00
}
# endif
2020-11-22 00:10:16 +01:00
return success ;
2016-01-04 15:12:34 +01:00
}
2017-05-09 22:03:46 +02:00
// Load integer value from storage file (from defined position)
2016-01-04 15:12:34 +01:00
// NOTE: If requested position could not be found, value 0 is returned
2020-03-30 13:51:36 +02:00
int LoadStorageValue ( unsigned int position )
2016-01-04 15:12:34 +01:00
{
int value = 0 ;
2021-03-02 12:45:23 +01:00
2020-02-27 13:18:15 +01:00
# if defined(SUPPORT_DATA_STORAGE)
2019-01-05 18:03:09 +01:00
char path [ 512 ] = { 0 } ;
2016-05-31 00:01:19 +02:00
# if defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
strcpy ( path , CORE . Android . internalDataPath ) ;
2016-05-31 00:01:19 +02:00
strcat ( path , " / " ) ;
2020-02-27 13:18:15 +01:00
strcat ( path , STORAGE_DATA_FILE ) ;
2020-04-30 18:48:39 +01:00
# elif defined(PLATFORM_UWP)
strcpy ( path , CORE . UWP . internalDataPath ) ;
strcat ( path , " / " ) ;
strcat ( path , STORAGE_DATA_FILE ) ;
2016-05-31 00:01:19 +02:00
# else
2020-02-27 13:18:15 +01:00
strcpy ( path , STORAGE_DATA_FILE ) ;
2016-05-31 00:01:19 +02:00
# endif
2016-08-16 11:09:55 +02:00
2020-03-30 13:51:36 +02:00
unsigned int dataSize = 0 ;
2020-02-27 13:18:15 +01:00
unsigned char * fileData = LoadFileData ( path , & dataSize ) ;
2020-02-27 13:33:09 +01:00
2020-02-27 13:18:15 +01:00
if ( fileData ! = NULL )
2016-01-04 15:12:34 +01:00
{
2020-03-27 18:06:09 +01:00
if ( dataSize < ( position * 4 ) ) TRACELOG ( LOG_WARNING , " SYSTEM: Failed to find storage position " ) ;
2016-01-04 15:12:34 +01:00
else
{
2020-02-27 13:18:15 +01:00
int * dataPtr = ( int * ) fileData ;
value = dataPtr [ position ] ;
2016-01-04 15:12:34 +01:00
}
2020-02-27 13:33:09 +01:00
2021-03-14 14:14:31 +01:00
UnloadFileData ( fileData ) ;
2016-01-04 15:12:34 +01:00
}
2020-02-27 13:18:15 +01:00
# endif
2016-01-04 15:12:34 +01:00
return value ;
}
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)
2019-02-21 11:28:10 +01:00
sprintf ( cmd , " explorer %s " , url ) ;
2021-03-02 12:45:23 +01:00
# endif
# if defined(__linux__) || defined(__FreeBSD__)
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
2018-11-12 14:59:31 +01:00
system ( cmd ) ;
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 ) ) ;
# 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-04-09 20:25:26 +02:00
else pressed = false ;
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-04-09 20:25:26 +02:00
else released = false ;
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
}
2016-11-01 14:39:57 +01:00
// Check gamepad name (if available)
bool IsGamepadName ( int gamepad , const char * name )
{
bool result = false ;
2020-02-03 18:31:30 +01:00
const char * currentName = NULL ;
2016-11-18 13:39:57 +01:00
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Gamepad . ready [ gamepad ] ) currentName = GetGamepadName ( gamepad ) ;
if ( ( name ! = NULL ) & & ( currentName ! = NULL ) ) result = ( strcmp ( name , currentName ) = = 0 ) ;
2016-11-17 13:50:56 +01:00
2016-11-01 14:39:57 +01:00
return result ;
}
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)
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Gamepad . ready [ gamepad ] ) ioctl ( CORE . Input . Gamepad . streamId [ gamepad ] , JSIOCGNAME ( 64 ) , & CORE . Input . Gamepad . name ) ;
return CORE . Input . Gamepad . name ;
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 ;
2021-01-31 03:07:26 +01:00
else pressed = false ;
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 ;
2021-01-31 03:07:26 +01:00
else released = false ;
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
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_UWP)
2020-04-30 18:48:39 +01:00
UWPGetMouseSetPosFunc ( ) ( x , y ) ;
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
2016-04-17 11:19:32 +02:00
}
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
{
# if defined(PLATFORM_ANDROID)
2020-10-05 20:19:18 +02:00
return 0.0f ;
2021-03-02 12:45:23 +01:00
# endif
# if defined(PLATFORM_WEB)
2020-10-05 20:19:18 +02:00
return CORE . Input . Mouse . previousWheelMove / 100.0f ;
2016-04-17 11:19:32 +02:00
# endif
2021-03-02 12:45:23 +01:00
return CORE . Input . Mouse . previousWheelMove ;
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 )
{
2020-04-30 18:48:39 +01:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
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 )
{
2020-04-30 18:48:39 +01:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
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
# if defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
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) ;
2021-03-19 19:43:44 +01:00
2021-03-02 12:45:23 +01:00
// TODO: Touch position scaling required?
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
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 ) ;
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 ) ;
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
}
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-02-07 20:52:11 +01:00
// Forcing this initialization here avoids doing it on `PollInputEvents` called by `EndDrawing` after first frame has been just drawn.
// The initialization will still happen and possible delays still occur, but before the window is shown, which is a nicer experience.
// REF: https://github.com/raysan5/raylib/issues/1554
if ( MAX_GAMEPADS > 0 ) glfwSetJoystickCallback ( NULL ) ;
# endif
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
}
else
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " DISPLAY: Device initialized successfully " ) ;
2014-12-15 01:08:30 +01:00
# if defined(PLATFORM_DESKTOP)
2020-03-27 18:49:21 +01:00
TRACELOG ( LOG_INFO , " > Display size: %i x %i " , CORE . Window . display . width , CORE . Window . display . height ) ;
2014-12-15 01:08:30 +01:00
# endif
2020-03-27 18:49:21 +01:00
TRACELOG ( LOG_INFO , " > Render size: %i x %i " , CORE . Window . render . width , CORE . Window . render . height ) ;
TRACELOG ( LOG_INFO , " > Screen size: %i x %i " , CORE . Window . screen . width , CORE . Window . screen . height ) ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " > Viewport offsets: %i, %i " , CORE . Window . renderOffset . x , CORE . Window . renderOffset . y ) ;
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
}
2021-04-18 23:50:32 +02:00
# endif // PLATFORM_DESKTOP || PLATFORM_WEB
2014-09-16 22:51:31 +02:00
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
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 ( ) ;
DISPMANX_ELEMENT_HANDLE_T dispmanElement ;
DISPMANX_DISPLAY_HANDLE_T dispmanDisplay ;
DISPMANX_UPDATE_HANDLE_T dispmanUpdate ;
2014-09-30 18:22:21 +02:00
2014-09-16 22:51:31 +02:00
VC_RECT_T dstRect ;
VC_RECT_T srcRect ;
# 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
2020-12-24 17:56:08 +01:00
TRACELOG ( LOG_INFO , " DISPLAY: No graphic card set, trying card1 " ) ;
2020-09-27 10:18:43 +02:00
CORE . Window . fd = open ( " /dev/dri/card1 " , O_RDWR ) ; // VideoCore VI (Raspberry Pi 4)
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
} ;
2017-11-10 12:37:53 +01:00
# if defined(PLATFORM_UWP)
const EGLint surfaceAttributes [ ] =
{
// EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is part of the same optimization as EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER (see above).
// If you have compilation issues with it then please update your Visual Studio templates.
EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER , EGL_TRUE ,
EGL_NONE
} ;
const EGLint defaultDisplayAttributes [ ] =
{
// These are the default display attributes, used to request ANGLE's D3D11 renderer.
// eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+.
EGL_PLATFORM_ANGLE_TYPE_ANGLE , EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE ,
// EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices.
// Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it.
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER , EGL_TRUE ,
2018-11-06 15:10:50 +01:00
// EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call
// the IDXGIDevice3::Trim method on behalf of the application when it gets suspended.
2017-11-10 12:37:53 +01:00
// Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement.
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE , EGL_TRUE ,
EGL_NONE ,
} ;
2018-11-06 15:10:50 +01:00
2017-11-10 12:37:53 +01:00
const EGLint fl9_3DisplayAttributes [ ] =
{
// These can be used to request ANGLE's D3D11 renderer, with D3D11 Feature Level 9_3.
// These attributes are used if the call to eglInitialize fails with the default display attributes.
EGL_PLATFORM_ANGLE_TYPE_ANGLE , EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE ,
EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE , 9 ,
EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE , 3 ,
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER , EGL_TRUE ,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE , EGL_TRUE ,
EGL_NONE ,
} ;
const EGLint warpDisplayAttributes [ ] =
{
// These attributes can be used to request D3D11 WARP.
// They are used if eglInitialize fails with both the default display attributes and the 9_3 display attributes.
EGL_PLATFORM_ANGLE_TYPE_ANGLE , EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE ,
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE , EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE ,
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER , EGL_TRUE ,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE , EGL_TRUE ,
EGL_NONE ,
} ;
2018-11-06 15:10:50 +01:00
2017-11-10 12:37:53 +01:00
// eglGetPlatformDisplayEXT is an alternative to eglGetDisplay. It allows us to pass in display attributes, used to configure D3D11.
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = ( PFNEGLGETPLATFORMDISPLAYEXTPROC ) ( eglGetProcAddress ( " eglGetPlatformDisplayEXT " ) ) ;
2018-02-04 12:26:28 +01:00
if ( ! eglGetPlatformDisplayEXT )
{
2020-12-24 19:09:05 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get function pointer: eglGetPlatformDisplayEXT() " ) ;
2018-02-04 12:26:28 +01:00
return false ;
}
2017-11-10 12:37:53 +01:00
//
2018-11-06 15:10:50 +01:00
// To initialize the display, we make three sets of calls to eglGetPlatformDisplayEXT and eglInitialize, with varying
2017-11-10 12:37:53 +01:00
// parameters passed to eglGetPlatformDisplayEXT:
// 1) The first calls uses "defaultDisplayAttributes" as a parameter. This corresponds to D3D11 Feature Level 10_0+.
2018-11-06 15:10:50 +01:00
// 2) If eglInitialize fails for step 1 (e.g. because 10_0+ isn't supported by the default GPU), then we try again
2017-11-10 12:37:53 +01:00
// using "fl9_3DisplayAttributes". This corresponds to D3D11 Feature Level 9_3.
2018-11-06 15:10:50 +01:00
// 3) If eglInitialize fails for step 2 (e.g. because 9_3+ isn't supported by the default GPU), then we try again
2017-11-10 12:37:53 +01:00
// using "warpDisplayAttributes". This corresponds to D3D11 Feature Level 11_0 on WARP, a D3D11 software rasterizer.
//
2018-11-06 15:10:50 +01:00
2017-11-10 12:37:53 +01:00
// This tries to initialize EGL to D3D11 Feature Level 10_0+. See above comment for details.
2020-02-03 18:31:30 +01:00
CORE . Window . device = eglGetPlatformDisplayEXT ( EGL_PLATFORM_ANGLE_ANGLE , EGL_DEFAULT_DISPLAY , defaultDisplayAttributes ) ;
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 ;
}
2018-11-06 15:10:50 +01:00
2020-02-03 18:31:30 +01:00
if ( eglInitialize ( CORE . Window . device , NULL , NULL ) = = EGL_FALSE )
2017-11-10 12:37:53 +01:00
{
// This tries to initialize EGL to D3D11 Feature Level 9_3, if 10_0+ is unavailable (e.g. on some mobile devices).
2020-02-03 18:31:30 +01:00
CORE . Window . device = eglGetPlatformDisplayEXT ( EGL_PLATFORM_ANGLE_ANGLE , EGL_DEFAULT_DISPLAY , fl9_3DisplayAttributes ) ;
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 ;
}
2017-11-10 12:37:53 +01:00
2020-02-03 18:31:30 +01:00
if ( eglInitialize ( CORE . Window . device , NULL , NULL ) = = EGL_FALSE )
2017-11-10 12:37:53 +01:00
{
// This initializes EGL to D3D11 Feature Level 11_0 on WARP, if 9_3+ is unavailable on the default GPU.
2020-02-03 18:31:30 +01:00
CORE . Window . device = eglGetPlatformDisplayEXT ( EGL_PLATFORM_ANGLE_ANGLE , EGL_DEFAULT_DISPLAY , warpDisplayAttributes ) ;
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 ;
}
2017-11-10 12:37:53 +01:00
2020-02-03 18:31:30 +01:00
if ( eglInitialize ( CORE . Window . device , NULL , NULL ) = = EGL_FALSE )
2017-11-10 12:37:53 +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 ;
2017-11-10 12:37:53 +01:00
}
}
}
EGLint numConfigs = 0 ;
2020-02-03 18:31:30 +01:00
if ( ( eglChooseConfig ( CORE . Window . device , framebufferAttribs , & CORE . Window . config , 1 , & numConfigs ) = = EGL_FALSE ) | | ( numConfigs = = 0 ) )
2017-11-10 12:37:53 +01:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to choose first EGL configuration " ) ;
2018-02-04 12:26:28 +01:00
return false ;
2017-11-10 12:37:53 +01:00
}
// Create a PropertySet and initialize with the EGLNativeWindowType.
//PropertySet^ surfaceCreationProperties = ref new PropertySet();
//surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), window); // CoreWindow^ window
2018-11-06 15:10:50 +01:00
// You can configure the surface to render at a lower resolution and be scaled up to
2017-11-10 12:37:53 +01:00
// the full window size. The scaling is often free on mobile hardware.
//
// One way to configure the SwapChainPanel is to specify precisely which resolution it should render at.
// Size customRenderSurfaceSize = Size(800, 600);
// surfaceCreationProperties->Insert(ref new String(EGLRenderSurfaceSizeProperty), PropertyValue::CreateSize(customRenderSurfaceSize));
//
// Another way is to tell the SwapChainPanel to render at a certain scale factor compared to its size.
// e.g. if the SwapChainPanel is 1920x1280 then setting a factor of 0.5f will make the app render at 960x640
// float customResolutionScale = 0.5f;
// surfaceCreationProperties->Insert(ref new String(EGLRenderResolutionScaleProperty), PropertyValue::CreateSingle(customResolutionScale));
2018-11-06 15:10:50 +01:00
// eglCreateWindowSurface() requires a EGLNativeWindowType parameter,
2017-11-10 12:37:53 +01:00
// In Windows platform: typedef HWND EGLNativeWindowType;
2018-11-06 15:10:50 +01:00
2017-11-10 12:37:53 +01:00
// Property: EGLNativeWindowTypeProperty
// Type: IInspectable
// Description: Set this property to specify the window type to use for creating a surface.
// If this property is missing, surface creation will fail.
//
//const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty";
2018-11-06 15:10:50 +01:00
2017-11-10 12:37:53 +01:00
//https://stackoverflow.com/questions/46550182/how-to-create-eglsurface-using-c-winrt-and-angle
2018-11-06 15:10:50 +01:00
2020-02-03 18:31:30 +01:00
//CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes);
2020-04-30 18:48:39 +01:00
CORE . Window . surface = eglCreateWindowSurface ( CORE . Window . device , CORE . Window . config , ( EGLNativeWindowType ) UWPGetCoreWindowPtr ( ) , surfaceAttributes ) ;
2020-02-03 18:31:30 +01:00
if ( CORE . Window . surface = = EGL_NO_SURFACE )
2018-02-04 12:26:28 +01:00
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to create EGL fullscreen surface " ) ;
2018-02-04 12:26:28 +01:00
return false ;
}
2017-11-10 12:37:53 +01:00
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
2020-02-03 18:31:30 +01:00
// Get EGL device window size
2020-04-30 18:48:39 +01:00
eglQuerySurface ( CORE . Window . device , CORE . Window . surface , EGL_WIDTH , & CORE . Window . screen . width ) ;
eglQuerySurface ( CORE . Window . device , CORE . Window . surface , EGL_HEIGHT , & CORE . Window . screen . height ) ;
// Get display size
UWPGetDisplaySizeFunc ( ) ( & CORE . Window . display . width , & CORE . Window . display . height ) ;
2018-11-06 15:10:50 +01:00
2020-07-17 18:39:31 +02:00
// 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 ;
2020-04-09 23:50:00 +02:00
# endif // PLATFORM_UWP
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
2014-09-30 18:22:21 +02:00
VC_DISPMANX_ALPHA_T alpha ;
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
}
else
{
2020-03-27 18:06:09 +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 ) ;
2020-03-27 18:49:21 +01:00
TRACELOG ( LOG_INFO , " > Render size: %i x %i " , CORE . Window . render . width , CORE . Window . render . height ) ;
TRACELOG ( LOG_INFO , " > Screen size: %i x %i " , CORE . Window . screen . width , CORE . Window . screen . height ) ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " > Viewport offsets: %i, %i " , CORE . Window . renderOffset . x , CORE . Window . renderOffset . y ) ;
2014-09-16 22:51:31 +02:00
}
2021-04-18 23:50:32 +02:00
# endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP
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
2016-06-25 21:28:50 +02:00
// Initialize OpenGL context (states and resources)
2020-02-03 18:31:30 +01:00
// NOTE: CORE.Window.screen.width and CORE.Window.screen.height not used, just stored as globals in rlgl
rlglInit ( CORE . Window . screen . width , CORE . Window . screen . height ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
int fbWidth = CORE . Window . render . width ;
int fbHeight = CORE . Window . render . height ;
2016-06-25 23:28:50 +02:00
2020-11-23 00:49:27 +01:00
# if defined(PLATFORM_DESKTOP)
2020-12-23 15:03:26 +01:00
if ( ( CORE . Window . flags & FLAG_WINDOW_HIGHDPI ) > 0 )
2020-11-23 00:49:27 +01:00
{
2021-03-20 13:02:44 +01:00
// 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__)
2020-11-23 00:49:27 +01:00
glfwGetFramebufferSize ( CORE . Window . handle , & fbWidth , & fbHeight ) ;
2019-05-01 14:30:36 +02:00
2020-11-23 00:49:27 +01:00
// 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 ) ;
2021-04-01 20:24:33 +02:00
2021-03-20 13:02:44 +01:00
// Mouse input scaling for the new screen size
2020-11-23 00:49:27 +01:00
SetMouseScale ( ( float ) CORE . Window . screen . width / fbWidth , ( float ) CORE . Window . screen . height / fbHeight ) ;
# endif
}
2020-02-03 19:26:28 +01:00
# endif
2019-05-01 14:30:36 +02:00
// Setup default viewport
SetupViewport ( fbWidth , fbHeight ) ;
2016-06-03 00:53:51 +02:00
2020-02-03 18:31:30 +01:00
CORE . Window . currentFbo . width = CORE . Window . screen . width ;
CORE . Window . currentFbo . height = CORE . Window . screen . 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
2020-04-30 18:48:39 +01:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_UWP)
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 ) ;
rlViewport ( CORE . Window . renderOffset . x / 2 * xScale , CORE . Window . renderOffset . y / 2 * yScale , ( CORE . Window . render . width - CORE . Window . renderOffset . x ) * xScale , ( CORE . Window . render . height - CORE . Window . renderOffset . y ) * yScale ) ;
2021-04-01 20:24:33 +02:00
# else
2021-03-20 20:06:38 +01:00
rlViewport ( CORE . Window . renderOffset . x / 2 , CORE . Window . renderOffset . y / 2 , CORE . Window . render . width - CORE . Window . renderOffset . x , CORE . Window . render . height - CORE . Window . renderOffset . y ) ;
# 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-17 12:17:50 +02:00
void InitTimer ( void )
2014-12-31 18:03:32 +01:00
{
2021-03-12 17:18:48 +01:00
srand ( ( unsigned int ) time ( NULL ) ) ; // Initialize random seed
2018-11-06 15:10:50 +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.
# if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) && !defined(PLATFORM_UWP)
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
}
2017-01-28 00:56:45 +01:00
// Wait for some milliseconds (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!
2021-06-17 12:17:50 +02:00
void WaitTime ( float ms )
2017-03-05 19:17:00 +01:00
{
2020-04-30 18:48:39 +01:00
# if defined(PLATFORM_UWP)
2020-05-09 13:05:54 +02:00
UWPGetSleepFunc ( ) ( ms / 1000 ) ;
return ;
# endif
# if defined(SUPPORT_BUSY_WAIT_LOOP)
2017-01-28 00:56:45 +01:00
double prevTime = GetTime ( ) ;
double nextTime = 0.0 ;
// Busy wait loop
2017-03-05 19:17:00 +01:00
while ( ( nextTime - prevTime ) < ms / 1000.0f ) nextTime = GetTime ( ) ;
# else
2021-05-07 10:49:44 -07:00
# if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
2021-05-14 14:01:42 +02:00
# define DEFAULT_PARTIALBUSY_WAIT_TIME 4
# define PARTIALBUSY_WAIT_FACTOR 0.95
double halfWait = DEFAULT_PARTIALBUSY_WAIT_TIME ;
if ( CORE . Time . target > 0 ) halfWait = CORE . Time . target * PARTIALBUSY_WAIT_FACTOR ;
2021-05-07 10:49:44 -07:00
2020-01-19 17:31:55 +01:00
double destTime = GetTime ( ) + ms / 1000 ;
2021-05-14 14:01:42 +02:00
if ( ms > halfWait ) ms - = ( float ) halfWait ;
2020-01-19 17:31:55 +01:00
# endif
2017-05-08 02:37:37 +02:00
# if defined(_WIN32)
2017-03-28 19:15:27 +02:00
Sleep ( ( unsigned int ) ms ) ;
2021-03-02 12:44:53 +01:00
# endif
# if defined(__linux__) || defined(__FreeBSD__) || defined(__EMSCRIPTEN__)
2017-03-05 19:17:00 +01:00
struct timespec req = { 0 } ;
time_t sec = ( int ) ( ms / 1000.0f ) ;
ms - = ( sec * 1000 ) ;
req . tv_sec = sec ;
req . tv_nsec = ms * 1000000L ;
// 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__)
2017-03-05 19:17:00 +01:00
usleep ( ms * 1000.0f ) ;
# endif
2020-02-03 19:26:28 +01:00
2021-05-07 10:49:44 -07:00
# if defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
2020-01-19 17:31:55 +01:00
while ( GetTime ( ) < destTime ) { }
# 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
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
eglSwapBuffers ( CORE . Window . device , CORE . Window . surface ) ;
# if defined(PLATFORM_DRM)
if ( ! CORE . Window . gbmSurface | | ( - 1 = = CORE . Window . fd ) | | ! CORE . Window . connector | | ! CORE . Window . crtc )
{
TRACELOG ( LOG_ERROR , " DISPLAY: DRM initialization failed to swap " ) ;
abort ( ) ;
}
struct gbm_bo * bo = gbm_surface_lock_front_buffer ( CORE . Window . gbmSurface ) ;
if ( ! bo )
{
TRACELOG ( LOG_ERROR , " DISPLAY: Failed GBM to lock front buffer " ) ;
abort ( ) ;
}
uint32_t fb = 0 ;
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 ( 0 ! = result )
{
TRACELOG ( LOG_ERROR , " DISPLAY: drmModeAddFB() failed with result: %d " , result ) ;
abort ( ) ;
}
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 ( 0 ! = result )
{
TRACELOG ( LOG_ERROR , " DISPLAY: drmModeSetCrtc() failed with result: %d " , result ) ;
abort ( ) ;
}
if ( CORE . Window . prevFB )
{
result = drmModeRmFB ( CORE . Window . fd , CORE . Window . prevFB ) ;
if ( 0 ! = result )
{
TRACELOG ( LOG_ERROR , " DISPLAY: drmModeRmFB() failed with result: %d " , result ) ;
abort ( ) ;
}
}
CORE . Window . prevFB = fb ;
if ( CORE . Window . prevBO )
{
gbm_surface_release_buffer ( CORE . Window . gbmSurface , CORE . Window . prevBO ) ;
}
CORE . Window . prevBO = bo ;
# endif // PLATFORM_DRM
# endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP
}
// 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
2020-02-29 22:10:23 +01:00
for ( int i = 0 ; i < 512 ; 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 ;
2020-10-05 20:19:18 +02:00
CORE . Input . Mouse . currentWheelMove = 0.0f ;
2018-11-06 15:10:50 +01:00
for ( int i = 0 ; i < 3 ; 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 + + )
{
if ( CORE . Input . Gamepad . ready [ i ] ) // Check if gamepad is available
{
// 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
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_UWP)
// Register previous keys states
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < 512 ; i + + ) CORE . Input . Keyboard . previousKeyState [ i ] = CORE . Input . Keyboard . currentKeyState [ i ] ;
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
for ( int i = 0 ; i < MAX_GAMEPADS ; i + + )
{
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Gamepad . ready [ i ] )
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
{
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 ] ;
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
}
}
// Register previous mouse states
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . previousWheelMove = CORE . Input . Mouse . currentWheelMove ;
2020-10-05 20:19:18 +02:00
CORE . Input . Mouse . currentWheelMove = 0.0f ;
2020-03-01 01:29:34 +01:00
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < 3 ; i + + ) CORE . Input . Mouse . previousButtonState [ i ] = CORE . Input . Mouse . currentButtonState [ i ] ;
2019-04-28 16:45:23 +02:00
# endif // PLATFORM_UWP
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
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
2020-02-03 18:31:30 +01:00
for ( int i = 0 ; i < 512 ; i + + ) CORE . Input . Keyboard . previousKeyState [ i ] = CORE . Input . Keyboard . currentKeyState [ i ] ;
2016-05-02 14:11:57 +02:00
// Register previous mouse states
2020-03-03 14:58:54 +01:00
for ( int i = 0 ; i < 3 ; 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 ;
2020-10-05 20:19:18 +02:00
CORE . Input . Mouse . currentWheelMove = 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 ] ;
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)
2021-06-10 17:11:31 +02:00
CORE . Input . Gamepad . currentButtonState [ i ] [ GAMEPAD_BUTTON_LEFT_TRIGGER_2 ] = ( char ) ( CORE . Input . Gamepad . axisState [ i ] [ GAMEPAD_AXIS_LEFT_TRIGGER ] > 0.1 ) ;
CORE . Input . Gamepad . currentButtonState [ i ] [ GAMEPAD_BUTTON_RIGHT_TRIGGER_2 ] = ( char ) ( CORE . Input . Gamepad . axisState [ i ] [ GAMEPAD_AXIS_RIGHT_TRIGGER ] > 0.1 ) ;
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
2020-11-23 00:49:27 +01:00
CORE . Window . resizedLastFrame = false ;
2016-05-02 14:11:57 +02:00
2018-10-31 23:19:29 +01:00
# if defined(SUPPORT_EVENTS_WAITING)
glfwWaitEvents ( ) ;
# else
2016-10-14 00:47:43 +02:00
glfwPollEvents ( ) ; // Register keyboard/mouse events (callbacks)... and window events!
2016-06-03 00:53:51 +02:00
# endif
2021-04-18 23:50:32 +02:00
# endif // PLATFORM_DESKTOP
2016-05-02 14:11:57 +02:00
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)
2016-05-02 14:11:57 +02:00
// NOTE: Keyboard reading could be done using input_event(s) reading or just read from stdin,
2019-03-28 19:46:39 +01:00
// we now use both methods inside here. 2nd method is still used for legacy purposes (Allows for input trough SSH console)
2016-05-02 14:11:57 +02:00
ProcessKeyboard ( ) ;
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
}
# 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
}
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
{
2020-12-18 18:58:02 +01:00
SetupViewport ( width , height ) ; // Reset viewport and projection matrix for new size
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
CORE . Window . screen . width = width ;
CORE . Window . screen . height = height ;
// NOTE: Postprocessing texture is not scaled to new size
}
// GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowIconifyCallback ( GLFWwindow * window , int iconified )
{
if ( iconified ) CORE . Window . flags | = FLAG_WINDOW_MINIMIZED ; // The window was iconified
else CORE . Window . flags & = ~ FLAG_WINDOW_MINIMIZED ; // The window was restored
}
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 )
{
2020-12-18 18:58:02 +01:00
//TRACELOG(LOG_DEBUG, "Key Callback: KEY:%i(%c) - SCANCODE:%i (STATE:%i)", key, key, scancode, action);
2020-02-03 18:31:30 +01:00
if ( key = = CORE . Input . Keyboard . exitKey & & action = = GLFW_PRESS )
2016-05-02 14:11:57 +02:00
{
2020-02-03 18:31:30 +01:00
glfwSetWindowShouldClose ( CORE . Window . handle , GLFW_TRUE ) ;
2016-05-02 14:11:57 +02:00
// NOTE: Before closing window, while loop must be left!
}
2021-01-20 17:06:53 +01:00
# if defined(SUPPORT_SCREEN_CAPTURE)
2017-05-11 16:24:40 +02:00
else if ( key = = GLFW_KEY_F12 & & action = = GLFW_PRESS )
{
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
2020-11-20 00:34:18 +01:00
char path [ 512 ] = { 0 } ;
# if defined(PLATFORM_ANDROID)
strcpy ( path , CORE . Android . internalDataPath ) ;
strcat ( path , TextFormat ( " ./screenrec%03i.gif " , screenshotCounter ) ) ;
# else
strcpy ( path , TextFormat ( " ./screenrec%03i.gif " , screenshotCounter ) ) ;
# endif
2020-12-23 15:03:26 +01:00
2020-11-29 23:14:11 -08:00
SaveFileData ( path , 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 ;
gifFramesCounter = 0 ;
2019-01-23 20:07:47 -05:00
2020-11-20 00:34:18 +01:00
msf_gif_begin ( & gifState , CORE . Window . screen . width , CORE . Window . screen . height ) ;
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-06-11 12:27:46 +02:00
# if defined(SUPPORT_EVENTS_AUTOMATION)
else if ( key = = GLFW_KEY_F11 & & action = = GLFW_PRESS )
{
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 " ) ;
}
else if ( key = = GLFW_KEY_F9 & & action = = GLFW_PRESS )
{
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-03-25 19:41:51 +01:00
else
2020-03-03 16:43:15 +01: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-23 15:03:26 +01:00
2020-12-18 18:58:02 +01:00
// Check if there is space available in the key queue
2021-04-09 00:21:56 +02:00
if ( ( CORE . Input . Keyboard . keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE ) & & ( action = = GLFW_PRESS ) )
2020-12-18 18:58:02 +01:00
{
// Add character to the queue
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = key ;
CORE . Input . Keyboard . keyPressedQueueCount + + ;
}
}
}
// 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
2017-03-21 13:22:59 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
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
2020-03-03 14:58:54 +01:00
if ( ( CORE . Input . Mouse . currentButtonState [ button ] = = 1 ) & & ( CORE . Input . Mouse . previousButtonState [ button ] = = 0 ) ) gestureEvent . touchAction = TOUCH_DOWN ;
else if ( ( CORE . Input . Mouse . currentButtonState [ button ] = = 0 ) & & ( CORE . Input . Mouse . previousButtonState [ button ] = = 1 ) ) gestureEvent . touchAction = TOUCH_UP ;
2020-03-25 19:41:51 +01:00
2016-05-02 14:11:57 +02:00
// NOTE: TOUCH_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
gestureEvent . pointerId [ 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
2017-03-21 13:22:59 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
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
gestureEvent . touchAction = TOUCH_MOVE ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Assign a pointer ID
gestureEvent . pointerId [ 0 ] = 0 ;
// 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
}
2020-12-18 18:58:02 +01:00
// GLFW3 Srolling Callback, runs on mouse wheel
static void MouseScrollCallback ( GLFWwindow * window , double xoffset , double yoffset )
2018-11-06 15:10:50 +01:00
{
2020-12-18 18:58:02 +01:00
CORE . Input . Mouse . currentWheelMove = ( 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
2019-09-13 17:07:29 +02:00
// NOTE: Paths are stored in dynamic memory for further retrieval
2015-07-29 21:44:27 +02:00
// Everytime new files are dropped, old ones are discarded
static void WindowDropCallback ( GLFWwindow * window , int count , const char * * paths )
{
ClearDroppedFiles ( ) ;
2016-08-16 11:09:55 +02:00
2021-05-22 16:54:04 +02:00
CORE . Window . dropFilesPath = ( char * * ) RL_MALLOC ( count * sizeof ( char * ) ) ;
2016-08-16 11:09:55 +02:00
2015-07-29 21:44:27 +02:00
for ( int i = 0 ; i < count ; i + + )
2015-01-21 00:13:17 +01:00
{
2021-05-22 16:54:04 +02:00
CORE . Window . dropFilesPath [ i ] = ( char * ) RL_MALLOC ( MAX_FILEPATH_LENGTH * sizeof ( char ) ) ;
2020-02-03 18:31:30 +01:00
strcpy ( CORE . Window . dropFilesPath [ i ] , paths [ i ] ) ;
2015-01-21 00:13:17 +01:00
}
2015-07-29 21:44:27 +02:00
2020-02-03 18:31:30 +01:00
CORE . Window . dropFilesCount = count ;
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
EGLint displayFormat ;
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 ) ;
2016-06-25 21:28:50 +02:00
// Init 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
2017-12-19 14:06:54 +01:00
// Init hi-res timer
InitTimer ( ) ;
2016-01-03 13:01:21 +01:00
2019-01-05 18:03:09 +01:00
# if defined(SUPPORT_DEFAULT_FONT)
2016-10-09 13:09:08 +02:00
// Load default font
2016-01-03 13:01:21 +01:00
// NOTE: External function (defined in module: text)
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-04-04 14:59:17 +02:00
SetShapesTexture ( GetFontDefault ( ) . texture , ( Rectangle ) { rec . x + 1 , rec . y + 1 , rec . width - 2 , rec . height - 2 } ) ;
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 )
{
for ( int i = 0 ; i < assetsCount ; i + + )
{
// 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
}
2016-08-16 11:09:55 +02:00
2020-03-20 02:56:48 +11:00
CORE . Input . Touch . position [ 0 ] . x = AMotionEvent_getX ( event , 0 ) ;
CORE . Input . Touch . position [ 0 ] . y = AMotionEvent_getY ( event , 0 ) ;
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
2020-03-24 23:23:34 +11:00
if ( flags = = AMOTION_EVENT_ACTION_DOWN | | flags = = AMOTION_EVENT_ACTION_MOVE )
{
2021-05-08 09:26:24 -07:00
CORE . Input . Touch . currentTouchState [ MOUSE_BUTTON_LEFT ] = 1 ;
2020-03-24 23:23:34 +11:00
}
else if ( flags = = AMOTION_EVENT_ACTION_UP )
{
2021-05-08 09:26:24 -07:00
CORE . Input . Touch . currentTouchState [ MOUSE_BUTTON_LEFT ] = 0 ;
2020-03-24 23:23:34 +11:00
}
# if defined(SUPPORT_GESTURES_SYSTEM)
2020-03-20 02:56:48 +11:00
GestureEvent gestureEvent ;
2016-08-16 11:09:55 +02:00
2016-01-03 13:01:21 +01:00
// Register touch actions
if ( flags = = AMOTION_EVENT_ACTION_DOWN ) gestureEvent . touchAction = TOUCH_DOWN ;
else if ( flags = = AMOTION_EVENT_ACTION_UP ) gestureEvent . touchAction = TOUCH_UP ;
else if ( flags = = AMOTION_EVENT_ACTION_MOVE ) gestureEvent . touchAction = TOUCH_MOVE ;
2016-08-16 11:09:55 +02:00
2016-01-03 13:01:21 +01:00
// Register touch points count
2018-07-07 10:15:19 +02:00
// NOTE: Documentation says pointerCount is Always >= 1,
// but in practice it can be 0 or over a million
2016-01-03 13:01:21 +01:00
gestureEvent . pointCount = AMotionEvent_getPointerCount ( event ) ;
2016-08-16 11:09:55 +02:00
2018-07-07 10:15:19 +02:00
// Only enable gestures for 1-3 touch points
if ( ( gestureEvent . pointCount > 0 ) & & ( gestureEvent . pointCount < 4 ) )
{
// Register touch points id
// NOTE: Only two points registered
gestureEvent . pointerId [ 0 ] = AMotionEvent_getPointerId ( event , 0 ) ;
gestureEvent . pointerId [ 1 ] = AMotionEvent_getPointerId ( event , 1 ) ;
2016-08-16 11:09:55 +02:00
2018-07-07 10:15:19 +02:00
// Register touch points position
gestureEvent . position [ 0 ] = ( Vector2 ) { AMotionEvent_getX ( event , 0 ) , AMotionEvent_getY ( event , 0 ) } ;
gestureEvent . position [ 1 ] = ( Vector2 ) { AMotionEvent_getX ( event , 1 ) , AMotionEvent_getY ( event , 1 ) } ;
2016-08-16 11:09:55 +02:00
2020-03-20 02:56:48 +11:00
// Normalize gestureEvent.position[x] for screenWidth and screenHeight
2018-07-07 10:15:19 +02:00
gestureEvent . position [ 0 ] . x / = ( float ) GetScreenWidth ( ) ;
gestureEvent . position [ 0 ] . y / = ( float ) GetScreenHeight ( ) ;
2018-11-06 15:10:50 +01:00
2018-07-07 10:15:19 +02:00
gestureEvent . position [ 1 ] . x / = ( float ) GetScreenWidth ( ) ;
gestureEvent . position [ 1 ] . y / = ( float ) GetScreenHeight ( ) ;
2016-08-16 11:09:55 +02:00
2018-07-07 10:15:19 +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)
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
{
2020-03-25 19:41:51 +01:00
for ( int i = 0 ; i < touchEvent - > numTouches ; i + + )
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
2019-03-25 12:30:20 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM)
2020-02-12 13:16:18 +01:00
GestureEvent gestureEvent = { 0 } ;
2014-09-16 22:51:31 +02:00
2016-05-02 14:11:57 +02:00
// Register touch actions
if ( eventType = = EMSCRIPTEN_EVENT_TOUCHSTART ) gestureEvent . touchAction = TOUCH_DOWN ;
else if ( eventType = = EMSCRIPTEN_EVENT_TOUCHEND ) gestureEvent . touchAction = TOUCH_UP ;
else if ( eventType = = EMSCRIPTEN_EVENT_TOUCHMOVE ) gestureEvent . touchAction = TOUCH_MOVE ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Register touch points count
gestureEvent . pointCount = touchEvent - > numTouches ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Register touch points id
gestureEvent . pointerId [ 0 ] = touchEvent - > touches [ 0 ] . identifier ;
gestureEvent . pointerId [ 1 ] = touchEvent - > touches [ 1 ] . identifier ;
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// Register touch points position
// NOTE: Only two points registered
gestureEvent . position [ 0 ] = ( Vector2 ) { touchEvent - > touches [ 0 ] . targetX , touchEvent - > touches [ 0 ] . targetY } ;
gestureEvent . position [ 1 ] = ( Vector2 ) { touchEvent - > touches [ 1 ] . targetX , touchEvent - > touches [ 1 ] . targetY } ;
2014-09-16 22:51:31 +02:00
2020-01-27 12:09:31 +01:00
double canvasWidth , canvasHeight ;
2020-02-03 18:31:30 +01:00
// 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
2020-01-27 12:09:31 +01:00
//EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
emscripten_get_element_css_size ( " #canvas " , & canvasWidth , & canvasHeight ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
// Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height
2020-01-27 12:09:31 +01:00
gestureEvent . position [ 0 ] . x * = ( ( float ) GetScreenWidth ( ) / ( float ) canvasWidth ) ;
gestureEvent . position [ 0 ] . y * = ( ( float ) GetScreenHeight ( ) / ( float ) canvasHeight ) ;
gestureEvent . position [ 1 ] . x * = ( ( float ) GetScreenWidth ( ) / ( float ) canvasWidth ) ;
gestureEvent . position [ 1 ] . y * = ( ( float ) GetScreenHeight ( ) / ( float ) canvasHeight ) ;
2016-08-16 11:09:55 +02:00
2020-02-03 18:31:30 +01:00
CORE . Input . Touch . position [ 0 ] = gestureEvent . position [ 0 ] ;
CORE . Input . Touch . position [ 1 ] = gestureEvent . position [ 1 ] ;
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
# else
// Support only simple touch position
if ( eventType = = EMSCRIPTEN_EVENT_TOUCHSTART )
{
// Get first touch position
2020-02-03 18:31:30 +01:00
CORE . Input . Touch . position [ 0 ] = ( Vector2 ) { touchEvent - > touches [ 0 ] . targetX , touchEvent - > touches [ 0 ] . targetY } ;
2019-03-25 12:30:20 +01:00
2020-01-27 12:09:31 +01:00
double canvasWidth , canvasHeight ;
//EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
emscripten_get_element_css_size ( " #canvas " , & canvasWidth , & canvasHeight ) ;
// Normalize gestureEvent.position[x] for screenWidth and screenHeight
2020-02-03 18:31:30 +01:00
CORE . Input . Touch . position [ 0 ] . x * = ( ( float ) GetScreenWidth ( ) / ( float ) canvasWidth ) ;
CORE . Input . Touch . position [ 0 ] . y * = ( ( float ) GetScreenHeight ( ) / ( float ) canvasHeight ) ;
2019-03-25 12:30:20 +01:00
}
# endif
2016-02-18 14:05:48 +01:00
2016-05-02 14:11:57 +02:00
return 1 ;
2016-02-18 14:05:48 +01:00
}
2016-12-25 20:42:22 +01:00
// Register connected/disconnected gamepads events
static EM_BOOL EmscriptenGamepadCallback ( int eventType , const EmscriptenGamepadEvent * gamepadEvent , void * userData )
{
/*
2020-02-03 19:13:24 +01:00
TRACELOGD ( " %s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \" %s \" , mapping: \" %s \" " ,
2019-02-22 13:13:11 +01:00
eventType ! = 0 ? emscripten_event_type_to_string ( eventType ) : " Gamepad state " ,
2016-12-25 20:42:22 +01:00
gamepadEvent - > timestamp , gamepadEvent - > connected , gamepadEvent - > index , gamepadEvent - > numAxes , gamepadEvent - > numButtons , gamepadEvent - > id , gamepadEvent - > mapping ) ;
2017-01-28 23:02:30 +01:00
2020-02-03 19:13:24 +01:00
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 ] ) ;
2016-12-25 20:42:22 +01:00
*/
2017-01-28 23:02:30 +01:00
2020-02-03 18:31:30 +01:00
if ( ( gamepadEvent - > connected ) & & ( gamepadEvent - > index < MAX_GAMEPADS ) ) CORE . Input . Gamepad . ready [ gamepadEvent - > index ] = true ;
else CORE . Input . Gamepad . ready [ gamepadEvent - > index ] = false ;
2017-01-28 23:02:30 +01:00
2016-12-25 20:42:22 +01:00
// TODO: Test gamepadEvent->index
return 0 ;
}
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)
2019-05-21 20:59:13 +02:00
# if defined(SUPPORT_SSH_KEYBOARD_RPI)
2016-02-18 14:05:48 +01:00
// Initialize Keyboard system (using standard input)
static void InitKeyboard ( void )
{
// NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor
2014-09-16 22:51:31 +02:00
2016-02-18 14:05:48 +01:00
// Make stdin non-blocking (not enough, need to configure to non-canonical mode)
int flags = fcntl ( STDIN_FILENO , F_GETFL , 0 ) ; // F_GETFL: Get the file access mode and the file status flags
fcntl ( STDIN_FILENO , F_SETFL , flags | O_NONBLOCK ) ; // F_SETFL: Set the file status flags to the value specified
// Save terminal keyboard settings and reconfigure terminal with new settings
struct termios keyboardNewSettings ;
2020-02-03 18:31:30 +01:00
tcgetattr ( STDIN_FILENO , & CORE . Input . Keyboard . defaultSettings ) ; // Get current keyboard settings
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 ) ;
2018-12-19 15:31:20 +01:00
// NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE
2019-01-23 20:07:47 -05:00
2016-02-18 14:05:48 +01:00
// Save old keyboard mode to restore it at the end
2020-02-03 18:31:30 +01:00
if ( ioctl ( STDIN_FILENO , KDGKBMODE , & CORE . Input . Keyboard . defaultMode ) < 0 )
2016-02-18 14:05:48 +01:00
{
// NOTE: It could mean we are using a remote keyboard through ssh!
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " RPI: Failed to change keyboard mode (SSH keyboard?) " ) ;
2016-02-18 14:05:48 +01:00
}
else
{
// We 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)
ioctl ( STDIN_FILENO , KDSKBMODE , K_XLATE ) ;
}
// Register keyboard restore when program finishes
atexit ( RestoreKeyboard ) ;
}
2016-02-19 19:57:25 +01:00
// Process keyboard inputs
// TODO: Most probably input reading and processing should be in a separate thread
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)
2016-02-19 19:57:25 +01:00
int bufferByteCount = 0 ; // Bytes available on the buffer
char keysBuffer [ MAX_KEYBUFFER_SIZE ] ; // 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-06-10 17:11:31 +02:00
if ( bufferByteCount > 0 ) for ( int i = 0 ; i < MAX_KEYBOARD_KEYS ; i + + ) CORE . Input . Keyboard . currentKeyState [ i ] = 0 ;
2020-03-25 19:41:51 +01:00
2019-03-28 19:46:39 +01:00
// Check keys from event input workers (This is the new keyboard reading method)
2021-06-10 17:11:31 +02:00
//for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) CORE.Input.Keyboard.currentKeyState[i] = CORE.Input.Keyboard.currentKeyStateEvdev[i];
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
}
2014-09-16 22:51:31 +02:00
2016-02-18 14:05:48 +01:00
// Restore default keyboard input
static void RestoreKeyboard ( void )
{
// Reset to default keyboard settings
2020-02-03 18:31:30 +01:00
tcsetattr ( STDIN_FILENO , TCSANOW , & CORE . Input . Keyboard . defaultSettings ) ;
2016-08-16 11:09:55 +02:00
2016-02-18 14:05:48 +01:00
// Reconfigure keyboard to default mode
2020-02-03 18:31:30 +01:00
ioctl ( STDIN_FILENO , KDSKBMODE , CORE . Input . Keyboard . defaultMode ) ;
2014-09-16 22:51:31 +02: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
{
2018-12-18 19:11:12 +01:00
char path [ MAX_FILEPATH_LENGTH ] ;
2018-10-22 11:48:16 +02:00
DIR * directory ;
struct dirent * entity ;
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
2020-02-13 00:13:56 +01:00
for ( int i = 0 ; i < 512 ; 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
{
2018-10-22 11:48:16 +02:00
if ( strncmp ( " event " , entity - > d_name , strlen ( " event " ) ) = = 0 ) // Search for devices named "event*"
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
2018-10-21 00:09:17 +01:00
struct input_absinfo absinfo ;
2018-10-22 11:48:16 +02:00
unsigned long evBits [ NBITS ( EV_MAX ) ] ;
unsigned long absBits [ NBITS ( ABS_MAX ) ] ;
unsigned long relBits [ NBITS ( REL_MAX ) ] ;
unsigned long keyBits [ NBITS ( KEY_MAX ) ] ;
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
2018-10-22 11:48:16 +02:00
InputEventWorker * worker ;
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
{
2020-09-18 08:52:52 +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
{
2018-10-22 11:48:16 +02:00
if ( sscanf ( ptrDevName , " t%d " , & devNum ) = = 1 )
worker - > eventNum = devNum ;
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
//-------------------------------------------------------------------------------------------------------
2021-01-06 19:46:12 +00:00
if ( worker - > isKeyboard & & CORE . Input . Keyboard . fd = = - 1 )
{
// 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
2019-04-28 16:45:23 +02:00
// TODO: Probably replace this with a keymap from the X11 to get the correct regional map for the keyboard:
// Currently non US keyboards will have the wrong mapping for some keys
2019-04-04 13:50:52 +02:00
static const int keymap_US [ ] =
2019-04-28 16:45:23 +02:00
{ 0 , 256 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , 48 , 45 , 61 , 259 , 258 , 81 , 87 , 69 , 82 , 84 ,
2019-03-28 19:46:39 +01:00
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 ,
2019-04-28 16:45:23 +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 ;
struct input_event event ;
int keycode ;
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 )
{
// Keyboard button parsing
if ( ( event . code > = 1 ) & & ( event . code < = 255 ) ) //Keyboard keys appear for codes 1 to 255
{
keycode = keymap_US [ event . code & 0xFF ] ; // The code we get is a scancode so we look up the apropriate keycode
// 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 + + ;
}
# 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
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 )
{
2018-10-22 11:48:16 +02:00
struct input_event event ;
InputEventWorker * worker = ( InputEventWorker * ) arg ;
2019-04-04 13:50:52 +02:00
2019-03-25 12:30:20 +01:00
int touchAction = - 1 ;
bool gestureUpdate = false ;
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
# if defined(SUPPORT_GESTURES_SYSTEM)
touchAction = TOUCH_MOVE ;
gestureUpdate = true ;
# endif
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
# if defined(SUPPORT_GESTURES_SYSTEM)
touchAction = TOUCH_MOVE ;
gestureUpdate = true ;
# endif
2018-10-21 00:09:17 +01:00
}
2020-02-03 18:31:30 +01:00
if ( event . code = = REL_WHEEL ) CORE . Input . Mouse . currentWheelMove + = 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-06-10 18:03:25 +02:00
CORE . Input . Mouse . currentPosition . x = ( event . value - worker - > absRange . x ) * CORE . Window . screen . width / worker - > absRange . width ; // Scale acording to absRange
2021-02-14 10:36:24 -06:00
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
2019-03-28 20:38:13 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM)
touchAction = TOUCH_MOVE ;
gestureUpdate = true ;
# endif
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-06-10 18:03:25 +02:00
CORE . Input . Mouse . currentPosition . y = ( event . value - worker - > absRange . y ) * CORE . Window . screen . height / worker - > absRange . height ; // Scale acording to absRange
2021-02-14 10:36:24 -06:00
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
# if defined(SUPPORT_GESTURES_SYSTEM)
touchAction = TOUCH_MOVE ;
gestureUpdate = true ;
# endif
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
# if defined(SUPPORT_GESTURES_SYSTEM)
touchAction = TOUCH_UP ;
gestureUpdate = true ;
# endif
}
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
# if defined(SUPPORT_GESTURES_SYSTEM)
touchAction = TOUCH_DOWN ;
gestureUpdate = true ;
# endif
}
}
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
2019-03-28 20:38:13 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM)
if ( event . value > 0 ) touchAction = TOUCH_DOWN ;
else touchAction = TOUCH_UP ;
gestureUpdate = true ;
# endif
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
2018-12-18 19:11:12 +01:00
// Gesture update
2019-03-25 12:30:20 +01:00
if ( gestureUpdate )
2017-01-14 16:18:06 +00:00
{
2019-05-21 20:59:13 +02:00
# if defined(SUPPORT_GESTURES_SYSTEM)
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
2017-01-14 16:18:06 +00:00
gestureEvent . pointerId [ 0 ] = 0 ;
gestureEvent . pointerId [ 1 ] = 1 ;
2018-10-21 00:09:17 +01:00
gestureEvent . pointerId [ 2 ] = 2 ;
gestureEvent . pointerId [ 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 ) ;
2019-05-21 20:59:13 +02:00
# endif
2017-01-14 16:18:06 +00:00
}
2018-10-21 00:09:17 +01:00
}
2021-06-17 11:47:05 +02:00
WaitTime ( 5 ) ; // 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 ;
}
2016-02-18 14:05:48 +01:00
// Init gamepad system
static void InitGamepad ( void )
2014-09-16 22:51:31 +02:00
{
2016-03-17 12:54:36 +01:00
char gamepadDev [ 128 ] = " " ;
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
2020-02-03 18:31:30 +01: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
2016-05-31 19:12:37 +02:00
struct js_event gamepadEvent ;
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
}
}
2021-06-17 11:47:05 +02:00
else WaitTime ( 1 ) ; // 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
# if defined(PLATFORM_UWP)
2020-04-30 21:00:09 +02:00
// UWP function pointers
// NOTE: Those pointers are set by UWP App
2020-04-30 18:48:39 +01:00
static UWPQueryTimeFunc uwpQueryTimeFunc = NULL ;
static UWPSleepFunc uwpSleepFunc = NULL ;
static UWPDisplaySizeFunc uwpDisplaySizeFunc = NULL ;
static UWPMouseFunc uwpMouseLockFunc = NULL ;
static UWPMouseFunc uwpMouseUnlockFunc = NULL ;
static UWPMouseFunc uwpMouseShowFunc = NULL ;
static UWPMouseFunc uwpMouseHideFunc = NULL ;
static UWPMouseSetPosFunc uwpMouseSetPosFunc = NULL ;
2020-04-30 21:00:09 +02:00
static void * uwpCoreWindow = NULL ;
2020-04-30 18:48:39 +01:00
2020-04-30 21:00:09 +02:00
// Check all required UWP function pointers have been set
2020-04-30 18:48:39 +01:00
bool UWPIsConfigured ( )
{
bool pass = true ;
2021-05-30 18:02:06 +02:00
if ( uwpQueryTimeFunc = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: UWPSetQueryTimeFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpSleepFunc = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: UWPSetSleepFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpDisplaySizeFunc = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: UWPSetDisplaySizeFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseLockFunc = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: UWPSetMouseLockFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseUnlockFunc = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: UWPSetMouseUnlockFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseShowFunc = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: UWPSetMouseShowFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseHideFunc = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: UWPSetMouseHideFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseSetPosFunc = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: UWPSetMouseSetPosFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpCoreWindow = = NULL ) { TRACELOG ( LOG_WARNING , " UWP: A pointer to the UWP core window must be set before InitWindow() " ) ; pass = false ; }
2020-04-30 18:48:39 +01:00
return pass ;
}
2020-04-30 21:00:09 +02:00
// UWP function handlers get/set
2021-06-10 18:00:44 +02:00
void UWPSetDataPath ( const char * path ) { CORE . UWP . internalDataPath = path ; }
2020-04-30 21:00:09 +02:00
UWPQueryTimeFunc UWPGetQueryTimeFunc ( void ) { return uwpQueryTimeFunc ; }
void UWPSetQueryTimeFunc ( UWPQueryTimeFunc func ) { uwpQueryTimeFunc = func ; }
UWPSleepFunc UWPGetSleepFunc ( void ) { return uwpSleepFunc ; }
void UWPSetSleepFunc ( UWPSleepFunc func ) { uwpSleepFunc = func ; }
UWPDisplaySizeFunc UWPGetDisplaySizeFunc ( void ) { return uwpDisplaySizeFunc ; }
void UWPSetDisplaySizeFunc ( UWPDisplaySizeFunc func ) { uwpDisplaySizeFunc = func ; }
UWPMouseFunc UWPGetMouseLockFunc ( ) { return uwpMouseLockFunc ; }
void UWPSetMouseLockFunc ( UWPMouseFunc func ) { uwpMouseLockFunc = func ; }
UWPMouseFunc UWPGetMouseUnlockFunc ( ) { return uwpMouseUnlockFunc ; }
void UWPSetMouseUnlockFunc ( UWPMouseFunc func ) { uwpMouseUnlockFunc = func ; }
UWPMouseFunc UWPGetMouseShowFunc ( ) { return uwpMouseShowFunc ; }
void UWPSetMouseShowFunc ( UWPMouseFunc func ) { uwpMouseShowFunc = func ; }
UWPMouseFunc UWPGetMouseHideFunc ( ) { return uwpMouseHideFunc ; }
void UWPSetMouseHideFunc ( UWPMouseFunc func ) { uwpMouseHideFunc = func ; }
UWPMouseSetPosFunc UWPGetMouseSetPosFunc ( ) { return uwpMouseSetPosFunc ; }
void UWPSetMouseSetPosFunc ( UWPMouseSetPosFunc func ) { uwpMouseSetPosFunc = func ; }
void * UWPGetCoreWindowPtr ( ) { return uwpCoreWindow ; }
void UWPSetCoreWindowPtr ( void * ptr ) { uwpCoreWindow = ptr ; }
2020-10-06 05:16:23 +11:00
void UWPMouseWheelEvent ( int deltaY ) { CORE . Input . Mouse . currentWheelMove = ( float ) deltaY ; }
2020-04-30 18:48:39 +01:00
void UWPKeyDownEvent ( int key , bool down , bool controlKey )
{
if ( key = = CORE . Input . Keyboard . exitKey & & down )
{
// Time to close the window.
CORE . Window . shouldClose = true ;
}
2021-01-20 17:06:53 +01:00
# if defined(SUPPORT_SCREEN_CAPTURE)
2020-04-30 18:48:39 +01:00
else if ( key = = KEY_F12 & & down )
{
# if defined(SUPPORT_GIF_RECORDING)
if ( controlKey )
{
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 ) ;
SaveFileData ( TextFormat ( " %s/screenrec%03i.gif " , CORE . UWP . internalDataPath , screenshotCounter ) , result . data , result . dataSize ) ;
msf_gif_free ( result ) ;
2020-04-30 18:48:39 +01:00
# if defined(PLATFORM_WEB)
// Download file from MEMFS (emscripten memory filesystem)
// saveFileFromMEMFSToDisk() function is defined in raylib/templates/web_shel/shell.html
emscripten_run_script ( TextFormat ( " saveFileFromMEMFSToDisk('%s','%s') " , TextFormat ( " screenrec%03i.gif " , screenshotCounter - 1 ) , TextFormat ( " screenrec%03i.gif " , screenshotCounter - 1 ) ) ) ;
# endif
TRACELOG ( LOG_INFO , " SYSTEM: Finish animated GIF recording " ) ;
}
else
{
gifRecording = true ;
gifFramesCounter = 0 ;
2020-11-20 00:34:18 +01:00
msf_gif_begin ( & gifState , CORE . Window . screen . width , CORE . Window . screen . height ) ;
2020-04-30 18:48:39 +01:00
screenshotCounter + + ;
TRACELOG ( LOG_INFO , " SYSTEM: Start animated GIF recording: %s " , TextFormat ( " screenrec%03i.gif " , screenshotCounter ) ) ;
}
}
else
2021-03-19 19:43:44 +01:00
# endif // SUPPORT_GIF_RECORDING
2020-04-30 18:48:39 +01:00
{
TakeScreenshot ( TextFormat ( " screenshot%03i.png " , screenshotCounter ) ) ;
screenshotCounter + + ;
}
}
2021-01-20 17:06:53 +01:00
# endif // SUPPORT_SCREEN_CAPTURE
2020-04-30 18:48:39 +01:00
else
{
CORE . Input . Keyboard . currentKeyState [ key ] = down ;
}
}
void UWPKeyCharEvent ( int key )
{
2020-05-01 17:31:44 +02:00
if ( CORE . Input . Keyboard . keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE )
2020-04-30 18:48:39 +01:00
{
// Add character to the queue
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = key ;
CORE . Input . Keyboard . keyPressedQueueCount + + ;
}
}
void UWPMouseButtonEvent ( int button , bool down )
{
CORE . Input . Mouse . currentButtonState [ button ] = down ;
# if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
// Process mouse events as touches to be able to use mouse-gestures
GestureEvent gestureEvent = { 0 } ;
// Register touch actions
if ( ( CORE . Input . Mouse . currentButtonState [ button ] = = 1 ) & & ( CORE . Input . Mouse . previousButtonState [ button ] = = 0 ) ) gestureEvent . touchAction = TOUCH_DOWN ;
else if ( ( CORE . Input . Mouse . currentButtonState [ button ] = = 0 ) & & ( CORE . Input . Mouse . previousButtonState [ button ] = = 1 ) ) gestureEvent . touchAction = TOUCH_UP ;
// NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback()
// Assign a pointer ID
gestureEvent . pointerId [ 0 ] = 0 ;
// Register touch points count
gestureEvent . pointCount = 1 ;
// Register touch points position, only one point registered
gestureEvent . position [ 0 ] = GetMousePosition ( ) ;
// Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
gestureEvent . position [ 0 ] . x / = ( float ) GetScreenWidth ( ) ;
gestureEvent . position [ 0 ] . y / = ( float ) GetScreenHeight ( ) ;
// Gesture data is sent to gestures system for processing
ProcessGestureEvent ( gestureEvent ) ;
# endif
}
void UWPMousePosEvent ( 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-04-30 18:48:39 +01:00
# if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
// Process mouse events as touches to be able to use mouse-gestures
GestureEvent gestureEvent = { 0 } ;
gestureEvent . touchAction = TOUCH_MOVE ;
// Assign a pointer ID
gestureEvent . pointerId [ 0 ] = 0 ;
// Register touch points count
gestureEvent . pointCount = 1 ;
// Register touch points position, only one point registered
2021-06-10 18:03:25 +02:00
gestureEvent . position [ 0 ] = CORE . Input . Mouse . currentPosition ;
2020-04-30 18:48:39 +01:00
// Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
gestureEvent . position [ 0 ] . x / = ( float ) GetScreenWidth ( ) ;
gestureEvent . position [ 0 ] . y / = ( float ) GetScreenHeight ( ) ;
// Gesture data is sent to gestures system for processing
ProcessGestureEvent ( gestureEvent ) ;
# endif
}
void UWPResizeEvent ( int width , int height )
{
SetupViewport ( width , height ) ; // Reset viewport and projection matrix for new size
// Set current screen size
CORE . Window . screen . width = width ;
CORE . Window . screen . height = height ;
CORE . Window . currentFbo . width = width ;
CORE . Window . currentFbo . height = height ;
// NOTE: Postprocessing texture is not scaled to new size
2020-11-23 00:49:27 +01:00
CORE . Window . resizedLastFrame = true ;
2020-04-30 18:48:39 +01:00
}
void UWPActivateGamepadEvent ( int gamepad , bool active )
{
2020-04-30 21:00:09 +02:00
if ( gamepad < MAX_GAMEPADS ) CORE . Input . Gamepad . ready [ gamepad ] = active ;
2020-04-30 18:48:39 +01:00
}
void UWPRegisterGamepadButton ( int gamepad , int button , bool down )
{
2020-04-30 21:00:09 +02:00
if ( gamepad < MAX_GAMEPADS )
{
if ( button < MAX_GAMEPAD_BUTTONS )
{
2021-06-10 17:11:31 +02:00
CORE . Input . Gamepad . currentButtonState [ gamepad ] [ button ] = down ;
2020-04-30 18:48:39 +01:00
CORE . Input . Gamepad . lastButtonPressed = button ;
}
}
}
void UWPRegisterGamepadAxis ( int gamepad , int axis , float value )
{
if ( gamepad < MAX_GAMEPADS )
{
2020-04-30 21:00:09 +02:00
if ( axis < MAX_GAMEPAD_AXIS ) CORE . Input . Gamepad . axisState [ gamepad ] [ axis ] = value ;
2020-04-30 18:48:39 +01:00
}
}
void UWPGestureMove ( int pointer , float x , float y )
{
# if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent = { 0 } ;
// Assign the pointer ID and touch action
gestureEvent . pointerId [ 0 ] = pointer ;
gestureEvent . touchAction = TOUCH_MOVE ;
// Register touch points count
gestureEvent . pointCount = 1 ;
// Register touch points position, only one point registered
gestureEvent . position [ 0 ] . x = x ;
gestureEvent . position [ 0 ] . y = y ;
// Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
gestureEvent . position [ 0 ] . x / = ( float ) GetScreenWidth ( ) ;
gestureEvent . position [ 0 ] . y / = ( float ) GetScreenHeight ( ) ;
// Gesture data is sent to gestures system for processing
ProcessGestureEvent ( gestureEvent ) ;
# endif
}
void UWPGestureTouch ( int pointer , float x , float y , bool touch )
{
# if defined(SUPPORT_GESTURES_SYSTEM)
GestureEvent gestureEvent = { 0 } ;
// Assign the pointer ID and touch action
gestureEvent . pointerId [ 0 ] = pointer ;
gestureEvent . touchAction = touch ? TOUCH_DOWN : TOUCH_UP ;
// Register touch points count
gestureEvent . pointCount = 1 ;
// Register touch points position, only one point registered
gestureEvent . position [ 0 ] . x = x ;
gestureEvent . position [ 0 ] . y = y ;
// Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
gestureEvent . position [ 0 ] . x / = ( float ) GetScreenWidth ( ) ;
gestureEvent . position [ 0 ] . y / = ( float ) GetScreenHeight ( ) ;
// Gesture data is sent to gestures system for processing
ProcessGestureEvent ( gestureEvent ) ;
# endif
}
2021-04-18 23:50:32 +02:00
# endif // PLATFORM_UWP
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 " ) ;
if ( ( mode - > hdisplay < width ) | | ( mode - > vdisplay < height ) | ( mode - > vrefresh < fps ) )
{
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 ;
}
if ( ( mode - > hdisplay > = width ) & & ( mode - > vdisplay > = height ) & & ( mode - > vrefresh > = fps ) )
{
const int widthDiff = mode - > hdisplay - width ;
const int heightDiff = mode - > vdisplay - height ;
const int fpsDiff = mode - > vrefresh - fps ;
if ( nearestIndex < 0 )
{
nearestIndex = i ;
continue ;
}
const int nearestWidthDiff = CORE . Window . connector - > modes [ nearestIndex ] . hdisplay - width ;
const int nearestHeightDiff = CORE . Window . connector - > modes [ nearestIndex ] . vdisplay - height ;
const int nearestFpsDiff = CORE . Window . connector - > modes [ nearestIndex ] . vrefresh - fps ;
2020-12-24 19:09:05 +01: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
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-13 17:08:30 +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 )
{
// TODO: eventCount is required -> header? -> rAEL
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 )
{
for ( int key = 0 ; key < 512 ; key + + )
{
// 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
if ( ( int ) CORE . Input . Mouse . currentWheelMove ! = ( int ) CORE . Input . Mouse . previousWheelMove )
{
events [ eventCount ] . frame = frame ;
events [ eventCount ] . type = INPUT_MOUSE_WHEEL_MOTION ;
events [ eventCount ] . params [ 0 ] = ( int ) CORE . Input . Mouse . currentWheelMove ;
events [ eventCount ] . params [ 1 ] = 0 ;
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 ;
case INPUT_MOUSE_WHEEL_MOTION : CORE . Input . Mouse . currentWheelMove = ( float ) events [ i ] . params [ 0 ] ; break ; // param[0]: delta
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-06-11 12:27:46 +02:00
case INPUT_GESTURE : GESTURES . current = events [ i ] . params [ 0 ] ; break ; // param[0]: gesture (enum Gesture) -> gestures.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