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 .
*
2020-09-27 10:18:43 +02:00
* # define SUPPORT_MOUSE_CURSOR_NATIVE ( Raspberry Pi and DRM only )
* 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
*
2020-01-19 17:31:55 +01:00
* # define SUPPORT_HALFBUSY_WAIT_LOOP
* Use a half - busy wait loop , in this case frame sleeps for some time and runs a busy - wait - loop at the end
*
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-05-01 14:30:36 +02:00
* # define SUPPORT_HIGH_DPI
* Allow scale all the drawn content to match the high - DPI equivalent size ( only PLATFORM_DESKTOP )
2019-05-03 15:55:24 +02:00
* NOTE : This flag is forced on macOS , since most displays are high - DPI
2019-05-01 14:30:36 +02:00
*
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
* Support saving binary data automatically to a generated storage . data file . This file is managed internally .
*
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
*
2020-01-05 20:01:54 +01:00
* Copyright ( c ) 2013 - 2020 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
2019-03-12 16:00:26 +01:00
# else
2020-06-30 11:05:09 +02:00
# define RAYLIB_VERSION "3.1-dev"
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-03-17 13:40:07 +01:00
# define RGIF_MALLOC RL_MALLOC
# define RGIF_FREE RL_FREE
2020-03-25 19:41:51 +01:00
2017-10-02 13:06:04 +02:00
# define RGIF_IMPLEMENTATION
2020-05-01 17:31:44 +02:00
# include "external/rgif.h" // Support GIF recording
2016-08-26 19:40:37 +02:00
# endif
2016-08-10 12:55:54 +02:00
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()]
# include <math.h> // Required for: tan() [Used in BeginMode3D()]
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)
2017-01-28 00:56:45 +01: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
# include <GLFW/glfw3native.h> // WARNING: It requires customization to avoid windows.h inclusion!
2018-11-06 15:10:50 +01:00
2018-10-08 16:12:09 +02:00
# if !defined(SUPPORT_BUSY_WAIT_LOOP)
// NOTE: Those functions require linking with winmm library
unsigned int __stdcall timeBeginPeriod ( unsigned int uPeriod ) ;
unsigned int __stdcall timeEndPeriod ( unsigned int uPeriod ) ;
# endif
2018-10-25 16:09:38 +02:00
2018-10-08 12:29:02 +02:00
# elif defined(__linux__)
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
2020-05-01 17:31:44 +02:00
# include <GLFW/glfw3native.h> // Required for: glfwGetX11Window()
2018-10-08 16:12:09 +02:00
# elif 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
# 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
2020-05-01 17:31:44 +02:00
# include <EGL/egl.h> // EGL library - Native platform display device control functions
# include <GLES2/gl2.h> // OpenGL ES 2.0 library
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
2020-05-01 17:31:44 +02:00
# include "EGL/egl.h" // EGL library - Native platform display device control functions
# include "EGL/eglext.h" // EGL library - Extensions
# include "GLES2/gl2.h" // OpenGL ES 2.0 library
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)
2020-05-01 17:31:44 +02:00
# include "EGL/egl.h" // EGL library - Native platform display device control functions
# include "EGL/eglext.h" // EGL library - Extensions
# include "GLES2/gl2.h" // OpenGL ES 2.0 library
# 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)
# include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
# 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
2019-09-09 21:56:16 +02:00
# if defined(SUPPORT_COMPRESSION_API)
// NOTE: Those declarations require stb_image and stb_image_write definitions, included in textures module
unsigned char * stbi_zlib_compress ( unsigned char * data , int data_len , int * out_len , int quality ) ;
char * stbi_zlib_decode_malloc ( char const * buffer , int len , int * outlen ) ;
# 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
2020-06-30 11:05:09 +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
2020-05-01 17:31:44 +02:00
# ifndef MAX_GAMEPADS
# define MAX_GAMEPADS 4 // Max number of gamepads supported
# endif
# ifndef MAX_GAMEPAD_AXIS
# define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
# endif
# ifndef MAX_GAMEPAD_BUTTONS
# define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
# endif
# ifndef MAX_TOUCH_POINTS
# define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
# endif
# ifndef MAX_KEY_PRESSED_QUEUE
# define MAX_KEY_PRESSED_QUEUE 16 // Max number of characters in the key input queue
# 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
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 ;
2020-02-27 13:33:09 +01:00
typedef struct {
int contents [ 8 ] ; // Key events FIFO contents (8 positions)
char head ; // Key events FIFO head position
char tail ; // Key events FIFO tail position
2020-01-08 17:19:06 +01:00
} KeyEventFifo ;
# 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
unsigned int flags ; // Configuration flags (bit based)
const char * title ; // Window text title const pointer
bool ready ; // Flag to check if window has been initialized successfully
bool minimized ; // Flag to check if window has been minimized
2020-09-01 19:29:13 +01:00
bool maximized ; // Flag to check if window has been maximized
2020-04-27 17:41:29 +02:00
bool focused ; // Flag to check if window has been focused
2020-02-03 18:31:30 +01:00
bool resized ; // Flag to check if window has been resized
bool fullscreen ; // Flag to check if fullscreen mode required
bool alwaysRun ; // Flag to keep window update/draw running on minimized
bool shouldClose ; // Flag to set window for closing
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)
Size currentFbo ; // Current render width and height, it could change on BeginTextureMode()
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
char currentKeyState [ 512 ] ; // Registers current frame key state
char previousKeyState [ 512 ] ; // Registers previous frame key state
2016-06-03 00:53:51 +02:00
2020-05-01 17:31:44 +02:00
int keyPressedQueue [ MAX_KEY_PRESSED_QUEUE ] ; // Input characters queue
2020-02-03 18:31:30 +01:00
int keyPressedQueueCount ; // Input characters queue count
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
KeyEventFifo lastKeyPressed ; // Buffer for holding keydown events as they arrive (Needed due to multitreading of event workers)
# endif
} Keyboard ;
struct {
Vector2 position ; // Mouse position on screen
Vector2 offset ; // Mouse offset
Vector2 scale ; // Mouse scaling
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
2020-02-03 18:31:30 +01:00
char currentButtonState [ 3 ] ; // Registers current mouse button state
char previousButtonState [ 3 ] ; // 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)
2020-02-03 18:31:30 +01:00
char currentButtonStateEvdev [ 3 ] ; // 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)
# 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
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
2020-02-03 18:31:30 +01:00
bool ready [ MAX_GAMEPADS ] ; // Flag to know if gamepad is ready
float axisState [ MAX_GAMEPADS ] [ MAX_GAMEPAD_AXIS ] ; // Gamepad axis state
char currentState [ MAX_GAMEPADS ] [ MAX_GAMEPAD_BUTTONS ] ; // Current gamepad buttons state
char previousState [ MAX_GAMEPADS ] [ MAX_GAMEPAD_BUTTONS ] ; // Previous gamepad buttons state
2016-02-19 19:57:25 +01:00
# endif
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
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
2017-05-18 18:57:11 +02:00
# 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
static void SwapBuffers ( void ) ; // Copy back buffer to front buffers
2014-09-16 22:51:31 +02:00
static void InitTimer ( void ) ; // Initialize timer
2017-03-05 19:17:00 +01:00
static void Wait ( float ms ) ; // Wait for some milliseconds (stop program execution)
2018-10-08 12:29:02 +02:00
2019-04-28 18:23:21 +02:00
static int GetGamepadButton ( int button ) ; // Get gamepad button generic to all platforms
2014-09-16 22:51:31 +02:00
static void PollInputEvents ( void ) ; // Register user events
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
2014-09-16 22:51:31 +02:00
static void KeyCallback ( GLFWwindow * window , int key , int scancode , int action , int mods ) ; // GLFW3 Keyboard Callback, runs on key pressed
2014-12-31 18:03:32 +01:00
static void MouseButtonCallback ( GLFWwindow * window , int button , int action , int mods ) ; // GLFW3 Mouse Button Callback, runs on mouse button pressed
2016-02-02 16:43:42 +01:00
static void MouseCursorPosCallback ( GLFWwindow * window , double x , double y ) ; // GLFW3 Cursor Position Callback, runs on mouse move
2014-12-31 18:03:32 +01:00
static void CharCallback ( GLFWwindow * window , unsigned int key ) ; // GLFW3 Char Key Callback, runs on key pressed (get char value)
2014-09-16 22:51:31 +02:00
static void ScrollCallback ( 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
static void WindowSizeCallback ( GLFWwindow * window , int width , int height ) ; // GLFW3 WindowSize Callback, runs when window is resized
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-09-01 19:29:13 +01:00
static void WindowMaximizeCallback ( GLFWwindow * window , int maximized ) ; // GLFW3 Window Maximize Callback, runs when window is maximized
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)
2020-02-26 23:42:06 +01:00
static EM_BOOL EmscriptenFullscreenChangeCallback ( int eventType , const EmscriptenFullscreenChangeEvent * event , void * userData ) ;
2020-05-14 17:35:26 +02:00
static EM_BOOL EmscriptenWindowResizedCallback ( int eventType , const void * reserved , void * userData ) ;
2017-04-08 00:16:03 +02:00
static EM_BOOL EmscriptenKeyboardCallback ( int eventType , const EmscriptenKeyboardEvent * keyEvent , void * userData ) ;
static EM_BOOL EmscriptenMouseCallback ( int eventType , const EmscriptenMouseEvent * mouseEvent , void * userData ) ;
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
static void EventThreadSpawn ( char * device ) ; // Identifies a input device and spawns a thread to handle it if needed
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
2017-01-28 00:56:45 +01:00
# if defined(_WIN32)
// NOTE: We include Sleep() function signature here to avoid windows.h inclusion
2017-03-05 19:17:00 +01:00
void __stdcall Sleep ( unsigned long msTimeout ) ; // Required for Wait()
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 ( ) )
{
TRACELOG ( LOG_ERROR , " UWP Functions have not been set yet, please set these before initializing raylib! " ) ;
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
}
}
# else
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
2020-02-03 18:31:30 +01:00
if ( ! CORE . Window . ready ) return ;
2020-04-29 20:55:17 +02:00
else CORE . Window . focused = true ;
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
2020-02-12 13:48:50 +01:00
SetShapesTexture ( GetFontDefault ( ) . texture , ( Rectangle ) { rec . x + 1 , rec . y + 1 , rec . width - 2 , rec . height - 2 } ) ;
2016-10-09 13:09:08 +02:00
# endif
2020-01-26 18:53:34 +01:00
# if defined(PLATFORM_DESKTOP) && defined(SUPPORT_HIGH_DPI)
// Set default font texture filter for HighDPI (blurry)
SetTextureFilter ( GetFontDefault ( ) . texture , FILTER_BILINEAR ) ;
# 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)
2020-02-26 23:42:06 +01:00
// Detect fullscreen change events
2020-02-22 17:21:10 +01:00
emscripten_set_fullscreenchange_callback ( " #canvas " , NULL , 1 , EmscriptenFullscreenChangeCallback ) ;
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);
emscripten_set_keydown_callback ( " #canvas " , NULL , 1 , EmscriptenKeyboardCallback ) ;
2018-11-06 15:10:50 +01:00
2017-04-08 00:16:03 +02:00
// Support mouse events
emscripten_set_click_callback ( " #canvas " , NULL , 1 , EmscriptenMouseCallback ) ;
// 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
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . position . x = ( float ) CORE . Window . screen . width / 2.0f ;
CORE . Input . Mouse . position . y = ( float ) CORE . Window . screen . height / 2.0f ;
2019-04-28 16:45:23 +02:00
# endif // PLATFORM_ANDROID
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 )
{
2017-05-27 14:40:05 +02:00
GifEnd ( ) ;
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
2020-04-30 18:48:39 +01:00
# if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) && !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
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
}
}
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
2020-02-03 19:13:24 +01:00
TRACELOG ( LOG_INFO , " Window closed successfully " ) ;
2013-11-18 23:38:44 +01:00
}
2018-02-04 12:26:28 +01:00
// Check if window has been initialized successfully
bool IsWindowReady ( void )
{
2020-02-03 18:31:30 +01:00
return CORE . Window . ready ;
2018-02-04 12:26:28 +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-02-03 18:31:30 +01:00
while ( ! CORE . Window . alwaysRun & & CORE . Window . minimized ) 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-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-02-03 18:31:30 +01:00
return CORE . Window . minimized ;
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)
return CORE . Window . maximized ;
# 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)
return CORE . Window . focused ;
# else
return false ;
# endif
}
2019-03-04 22:58:20 +01:00
// Check if window has been resized
bool IsWindowResized ( void )
{
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP)
2020-02-03 18:31:30 +01:00
return CORE . Window . resized ;
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
}
2019-01-10 17:06:26 +01:00
// Check if window is currently hidden
bool IsWindowHidden ( void )
{
# if defined(PLATFORM_DESKTOP)
2020-04-05 17:50:37 +02:00
return ( glfwGetWindowAttrib ( CORE . Window . handle , GLFW_VISIBLE ) = = GLFW_FALSE ) ;
2019-01-10 17:06:26 +01:00
# endif
return false ;
}
2020-03-25 18:52:38 +01:00
// Check if window is currently fullscreen
bool IsWindowFullscreen ( void )
{
return CORE . Window . fullscreen ;
}
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
GLFWmonitor * monitor = glfwGetPrimaryMonitor ( ) ;
if ( ! monitor )
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " GLFW: Failed to get monitor " ) ;
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 ) ;
2019-12-01 14:46:09 +02:00
return ;
}
const GLFWvidmode * mode = glfwGetVideoMode ( monitor ) ;
2020-02-03 18:31:30 +01:00
glfwSetWindowMonitor ( CORE . Window . handle , glfwGetPrimaryMonitor ( ) , 0 , 0 , CORE . Window . screen . width , CORE . Window . screen . height , mode - > refreshRate ) ;
2020-02-03 19:26:28 +01:00
2019-12-01 13:58:29 +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 ) glfwSwapInterval ( 1 ) ;
2019-12-01 14:46:09 +02:00
}
2020-02-03 18:31:30 +01:00
else glfwSetWindowMonitor ( CORE . Window . handle , NULL , CORE . Window . position . x , CORE . Window . position . y , CORE . Window . screen . width , CORE . Window . screen . height , GLFW_DONT_CARE ) ;
2016-06-03 00:53:51 +02:00
# endif
2020-02-22 10:37:43 +01:00
# if defined(PLATFORM_WEB)
2020-05-14 17:35:26 +02:00
/*
EM_ASM (
if ( document . fullscreenElement ) document . exitFullscreen ( ) ;
else Module . requestFullscreen ( true , true ) ;
) ;
*/
2020-11-03 23:47:33 +01:00
2020-05-14 17:35:26 +02:00
//EM_ASM(Module.requestFullscreen(false, false););
/*
if ( ! CORE . Window . fullscreen )
{
//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 , //on_canvassize_changed,
. canvasResizedCallbackUserData = NULL
} ;
2020-11-03 23:47:33 +01:00
2020-05-14 17:35:26 +02:00
emscripten_request_fullscreen ( " #canvas " , false ) ;
//emscripten_request_fullscreen_strategy("#canvas", EM_FALSE, &strategy);
//emscripten_enter_soft_fullscreen("canvas", &strategy);
2020-06-02 23:07:42 +02:00
TRACELOG ( LOG_INFO , " emscripten_request_fullscreen_strategy " ) ;
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
{
2020-06-02 23:07:42 +02:00
TRACELOG ( LOG_INFO , " emscripten_exit_fullscreen " ) ;
2020-05-14 17:35:26 +02:00
emscripten_exit_fullscreen ( ) ;
}
*/
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-05-14 17:35:26 +02:00
CORE . Window . fullscreen = ! CORE . Window . fullscreen ; // Toggle fullscreen flag
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)
2019-03-16 13:00:46 +01:00
if ( image . format = = UNCOMPRESSED_R8G8B8A8 )
{
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)
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
}
2019-01-10 16:43:21 +01:00
// Show the window
2019-01-17 16:29:36 +01:00
void UnhideWindow ( void )
2019-01-10 14:55:19 +01:00
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwShowWindow ( CORE . Window . handle ) ;
2019-01-10 14:55:19 +01:00
# endif
}
2019-01-10 16:43:21 +01:00
// Hide the window
2019-01-10 17:06:26 +01:00
void HideWindow ( void )
2019-01-10 14:55:19 +01:00
{
# if defined(PLATFORM_DESKTOP)
2020-02-03 18:31:30 +01:00
glfwHideWindow ( CORE . Window . handle ) ;
2019-01-10 14:55:19 +01:00
# endif
2019-01-10 16:43:21 +01:00
}
2020-09-01 19:29:13 +01:00
// Decorate the window (only PLATFORM_DESKTOP)
void DecorateWindow ( void )
{
# if defined(PLATFORM_DESKTOP)
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_DECORATED , GLFW_TRUE ) ;
# endif
}
// // Undecorate the window (only PLATFORM_DESKTOP)
void UndecorateWindow ( void )
{
# if defined(PLATFORM_DESKTOP)
glfwSetWindowAttrib ( CORE . Window . handle , GLFW_DECORATED , GLFW_FALSE ) ;
# endif
}
// Maximize the window, 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 ) ;
}
# endif
}
// Restore the window, if resizable (only PLATFORM_DESKTOP)
void RestoreWindow ( void )
{
# if defined(PLATFORM_DESKTOP)
if ( glfwGetWindowAttrib ( CORE . Window . handle , GLFW_RESIZABLE ) = = GLFW_TRUE )
{
glfwRestoreWindow ( CORE . Window . handle ) ;
}
# endif
}
2014-09-16 22:51:31 +02:00
// Get current screen width
int GetScreenWidth ( void )
2013-11-18 23:38:44 +01:00
{
2020-02-03 18:31:30 +01:00
return CORE . Window . screen . width ;
2013-11-18 23:38:44 +01:00
}
2014-09-16 22:51:31 +02:00
// Get current screen height
int GetScreenHeight ( void )
2013-11-18 23:38:44 +01:00
{
2020-02-03 18:31:30 +01:00
return CORE . Window . screen . 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 ) ;
2018-10-08 12:29:02 +02:00
# elif defined(__linux__)
// 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 *?
# elif 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
# else
return NULL ;
# endif
}
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
}
// Get primary monitor width
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
{
const GLFWvidmode * mode = glfwGetVideoMode ( monitors [ monitor ] ) ;
return mode - > width ;
}
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
}
2018-09-30 15:20:02 +01:00
// Get primary monitor width
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
{
const GLFWvidmode * mode = glfwGetVideoMode ( monitors [ monitor ] ) ;
return mode - > height ;
}
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 montior 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
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
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
{
2020-09-27 10:18:43 +02:00
# if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && defined(SUPPORT_MOUSE_CURSOR_NATIVE)
// On native mode we have no system mouse cursor, so,
2019-08-20 20:39:22 +02:00
// we draw a small rectangle for user reference
2020-09-27 10:18:43 +02:00
if ( ! CORE . Input . Mouse . cursorHidden )
{
DrawRectangle ( CORE . Input . Mouse . position . x , CORE . Input . Mouse . position . y , 3 , 3 , MAROON ) ;
}
2019-08-20 20:39:22 +02:00
# endif
2019-10-17 17:18:03 +02:00
2016-06-14 17:16:20 +02:00
rlglDraw ( ) ; // Draw Buffers (Only OpenGL 3+ and ES2)
2016-06-03 00:53:51 +02:00
2017-05-18 18:57:11 +02:00
# if defined(SUPPORT_GIF_RECORDING)
# define GIF_RECORD_FRAMERATE 10
if ( gifRecording )
{
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)
// NOTE: This process is very slow... :(
2020-02-03 18:31:30 +01:00
unsigned char * screenData = rlReadScreenPixels ( CORE . Window . screen . width , CORE . Window . screen . height ) ;
GifWriteFrame ( screenData , CORE . Window . screen . width , CORE . Window . screen . height , 10 , 8 , false ) ;
2018-11-06 15:10:50 +01:00
2019-04-23 14:55:35 +02: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 )
{
2020-02-03 18:31:30 +01:00
DrawCircle ( 30 , CORE . Window . screen . height - 20 , 10 , RED ) ;
DrawText ( " RECORDING " , 50 , CORE . Window . screen . height - 25 , 10 , MAROON ) ;
2017-05-18 18:57:11 +02:00
}
2018-11-06 15:10:50 +01:00
2017-05-18 18:57:11 +02:00
rlglDraw ( ) ; // Draw RECORDING message
}
# endif
2018-11-06 15:10:50 +01:00
2016-06-03 00:53:51 +02:00
SwapBuffers ( ) ; // Copy back buffer to front buffer
2014-09-16 22:51:31 +02:00
PollInputEvents ( ) ; // Poll user events
2020-02-03 19:26:28 +01: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
{
2020-02-03 18:31:30 +01:00
Wait ( ( 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
2020-02-03 18:31:30 +01:00
CORE . Time . frame + = waitTime ; // Total frame time: update + draw + wait
2013-11-23 13:30:54 +01:00
}
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
{
rlglDraw ( ) ; // Draw Buffers (Only OpenGL 3+ and ES2)
2020-04-05 17:50:37 +02: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
{
rlglDraw ( ) ; // Draw Buffers (Only OpenGL 3+ and ES2)
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 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
{
2015-02-02 00:57:08 +01:00
rlglDraw ( ) ; // Draw Buffers (Only OpenGL 3+ and ES2)
2018-11-06 15:10:50 +01:00
2014-03-25 12:40:35 +01:00
rlMatrixMode ( RL_PROJECTION ) ; // Switch to projection matrix
rlPushMatrix ( ) ; // Save previous matrix, which contains the settings for the 2d ortho projection
2020-04-05 17:50:37 +02:00
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 ;
2018-03-27 19:59:54 +02:00
2018-11-06 15:10:50 +01:00
if ( camera . type = = CAMERA_PERSPECTIVE )
2018-03-24 23:31:06 +01:00
{
// Setup perspective projection
2020-07-14 18:36:22 +10:00
double top = RL_CULL_DISTANCE_NEAR * tan ( camera . fovy * 0.5 * DEG2RAD ) ;
2018-03-24 23:31:06 +01:00
double right = top * aspect ;
2020-05-01 17:31:44 +02:00
rlFrustum ( - right , right , - top , top , RL_CULL_DISTANCE_NEAR , RL_CULL_DISTANCE_FAR ) ;
2018-03-24 23:31:06 +01:00
}
2018-04-19 20:19:53 +02:00
else if ( camera . type = = CAMERA_ORTHOGRAPHIC )
2018-03-24 23:31:06 +01:00
{
// Setup orthographic projection
double top = camera . fovy / 2.0 ;
double right = top * aspect ;
2020-05-01 17:31:44 +02:00
rlOrtho ( - right , right , - top , top , RL_CULL_DISTANCE_NEAR , RL_CULL_DISTANCE_FAR ) ;
2018-03-24 23:31:06 +01:00
}
2013-11-23 13:30:54 +01:00
2015-08-27 16:10:15 +02:00
// NOTE: zNear and zFar values are important when computing depth buffer values
2014-09-03 16:51:28 +02:00
2014-03-25 12:40:35 +01:00
rlMatrixMode ( RL_MODELVIEW ) ; // Switch back to modelview matrix
2020-04-05 17:50:37 +02:00
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
2016-03-17 13:51:48 +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
{
2016-06-21 13:49:13 +02:00
rlglDraw ( ) ; // Process internal buffers (update + draw)
2016-08-16 11:09:55 +02:00
2014-03-25 12:40:35 +01:00
rlMatrixMode ( RL_PROJECTION ) ; // Switch to projection matrix
2020-04-05 17:50:37 +02:00
rlPopMatrix ( ) ; // Restore previous matrix (projection) from matrix stack
2014-09-03 16:51:28 +02:00
2020-04-05 17:50:37 +02: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
2016-03-17 13:51:48 +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 )
{
rlglDraw ( ) ; // Draw Buffers (Only OpenGL 3+ and ES2)
2020-10-29 19:29:59 +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 ) ;
2020-04-05 17:50:37 +02: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
2020-04-05 17:50:37 +02:00
rlMatrixMode ( RL_MODELVIEW ) ; // Switch back to modelview matrix
rlLoadIdentity ( ) ; // Reset current matrix (modelview)
2016-05-29 11:49:13 +02: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 )
{
2020-09-18 02:11:49 +02:00
rlglDraw ( ) ; // Draw Buffers (Only OpenGL 3+ and ES2)
2016-03-30 20:09:16 +02:00
2020-09-18 02:11:49 +02: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
2019-05-01 16:15:33 +02:00
// Reset current screen size
2020-02-03 18:31:30 +01:00
CORE . Window . currentFbo . width = GetScreenWidth ( ) ;
CORE . Window . currentFbo . height = GetScreenHeight ( ) ;
2016-03-30 20:09:16 +02:00
}
2019-08-26 21:09:03 +02:00
// 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 )
{
rlglDraw ( ) ; // Force drawing elements
rlEnableScissorTest ( ) ;
2020-06-08 16:32:23 +08:00
rlScissor ( x , CORE . Window . currentFbo . height - ( y + height ) , width , height ) ;
2019-08-26 21:09:03 +02:00
}
// End scissor mode
void EndScissorMode ( void )
{
rlglDraw ( ) ; // Force drawing elements
rlDisableScissorTest ( ) ;
}
2017-05-09 22:03:46 +02:00
// Returns 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
{
Ray ray ;
// 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
2018-11-06 15:10:50 +01:00
if ( camera . type = = 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
}
2018-04-19 20:19:53 +02:00
else if ( camera . type = = 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
2018-04-19 20:19:53 +02:00
if ( camera . type = = CAMERA_PERSPECTIVE ) ray . position = camera . position ;
else if ( camera . type = = 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 ) ;
}
// Returns 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 ;
}
2017-05-09 22:03:46 +02:00
// Returns the screen space position from a 3d world space position
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
2020-01-24 18:54:53 +01:00
// Returns size position for a 3d world space position (useful for texture drawing)
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
2020-02-03 18:31:30 +01:00
if ( camera . type = = CAMERA_PERSPECTIVE )
{
// Calculate projection matrix from perspective
2020-05-01 17:31:44 +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
}
else if ( camera . type = = CAMERA_ORTHOGRAPHIC )
{
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
}
2019-08-27 13:15:56 +02:00
// Returns 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
}
2019-08-27 13:15:56 +02:00
// Returns 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
}
// Returns 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
}
2017-05-09 22:03:46 +02:00
// Returns time in seconds for last frame drawn
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)
2019-06-14 17:18:33 +02:00
void SetConfigFlags ( unsigned int flags )
2014-10-17 21:11:58 +02:00
{
2020-02-03 18:31:30 +01:00
CORE . Window . flags = flags ;
2014-10-17 21:11:58 +02:00
2020-02-03 18:31:30 +01:00
if ( CORE . Window . flags & FLAG_FULLSCREEN_MODE ) CORE . Window . fullscreen = true ;
if ( CORE . Window . flags & FLAG_WINDOW_ALWAYS_RUN ) CORE . Window . alwaysRun = true ;
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 ) ;
Image image = { imgData , CORE . Window . render . width , CORE . Window . render . height , 1 , 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
}
2020-06-15 12:02:50 +02:00
// Returns a random value between min and max (both included)
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
{
2020-01-09 10:43:21 +01:00
if ( TextIsEqual ( fileExtLower , TextToLower ( checkExts [ i ] + 1 ) ) )
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 ;
}
2018-01-02 02:26:05 +01:00
// Get pointer to extension for a filename string
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
2017-09-08 09:35:54 +02:00
return ( dot + 1 ) ;
}
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
2019-09-08 01:11:53 +02:00
if ( ! fileName | | ( fileName = = filePath ) ) 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
2020-02-11 19:12:49 +01:00
// In case provided path does not contains a root drive letter (C:\, D:\),
// we add the current directory path to dirPath
if ( filePath [ 1 ] ! = ' : ' )
{
// 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 )
{
// NOTE: Be careful, strncpy() is not safe, it does not care about '\0'
2020-06-07 11:50:03 +02:00
memcpy ( dirPath + ( ( filePath [ 1 ] ! = ' : ' ) ? 2 : 0 ) , filePath , strlen ( filePath ) - ( strlen ( lastSlash ) - 1 ) ) ;
2020-02-11 19:12:49 +01:00
dirPath [ strlen ( filePath ) - strlen ( lastSlash ) + ( ( filePath [ 1 ] ! = ' : ' ) ? 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
2019-04-23 14:55:35 +02:00
dirFilesPath = ( char * * ) RL_MALLOC ( sizeof ( char * ) * MAX_DIRECTORY_FILES ) ;
for ( int i = 0 ; i < MAX_DIRECTORY_FILES ; i + + ) dirFilesPath [ i ] = ( char * ) RL_MALLOC ( sizeof ( char ) * MAX_FILEPATH_LENGTH ) ;
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)
compData = stbi_zlib_compress ( data , dataLength , compDataLength , COMPRESSION_QUALITY_DEFLATE ) ;
# 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
{
char * data = NULL ;
2019-10-17 17:18:03 +02:00
2019-09-09 21:56:16 +02:00
# if defined(SUPPORT_COMPRESSION_API)
2019-09-15 11:15:33 +02:00
data = stbi_zlib_decode_malloc ( ( char * ) compData , compDataLength , dataLength ) ;
2019-09-09 21:56:16 +02:00
# endif
2019-09-15 11:15:33 +02:00
return ( unsigned char * ) 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-03-30 13:51:36 +02:00
void SaveStorageValue ( unsigned int position , int value )
2016-01-04 15:12:34 +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-03-30 13:51:36 +02:00
SaveFileData ( path , newFileData , newDataSize ) ;
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-02-27 13:18:15 +01:00
SaveFileData ( path , fileData , dataSize ) ;
RL_FREE ( fileData ) ;
}
# endif
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 ;
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
2020-02-27 13:18:15 +01:00
RL_FREE ( 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.
// CHECK: 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 ) ;
2020-02-21 01:13:41 +01:00
# elif defined(__linux__)
2018-11-12 14:59:31 +01:00
sprintf ( cmd , " xdg-open '%s' " , url ) ; // Alternatives: firefox, x-www-browser
2020-02-21 01:13:41 +01:00
# elif 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
//----------------------------------------------------------------------------------
2013-11-28 19:59:56 +01:00
// Detect 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
}
// Detect if a key is being pressed (key held down)
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
}
2013-11-28 19:59:56 +01:00
// Detect 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
}
// Detect if a key is NOT being pressed (key not held down)
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-02-03 18:31:30 +01:00
for ( int i = 0 ; i < ( CORE . Input . Keyboard . keyPressedQueueCount - 1 ) ; i + + ) 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
}
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)
2013-11-18 23:38:44 +01:00
// Detect if a gamepad is available
bool IsGamepadAvailable ( int gamepad )
{
2016-02-18 14:05:48 +01:00
bool result = false ;
2017-01-28 23:02:30 +01:00
2016-10-31 13:56:57 +01:00
# if !defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] ) result = true ;
2016-10-31 13:56:57 +01:00
# endif
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 ;
2016-11-17 13:50:56 +01:00
# if !defined(PLATFORM_ANDROID)
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
# endif
2016-11-01 14:39:57 +01:00
return result ;
}
2016-10-14 00:47:43 +02:00
// Return gamepad internal name id
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 ;
2020-09-27 10:18:43 +02:00
# elif 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 ) ;
2016-11-02 13:39:48 +01:00
2020-02-03 18:31:30 +01:00
return CORE . Input . Gamepad . name ;
2016-10-14 00:47:43 +02:00
# else
return NULL ;
# endif
}
2016-11-01 14:39:57 +01:00
// Return gamepad axis count
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
2020-02-03 18:31:30 +01:00
return CORE . Input . Gamepad . axisCount ;
2016-11-01 14:39:57 +01:00
}
2013-11-18 23:38:44 +01:00
// Return 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
2016-10-31 13:56:57 +01:00
# if !defined(PLATFORM_ANDROID)
2020-05-09 12:39:41 +02:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( axis < MAX_GAMEPAD_AXIS ) & &
2020-05-09 13:05:54 +02:00
( ( axis = = GAMEPAD_AXIS_LEFT_TRIGGER ) | | ( axis = = GAMEPAD_AXIS_RIGHT_TRIGGER ) | |
( fabsf ( CORE . Input . Gamepad . axisState [ gamepad ] [ axis ] ) > = 0.2f ) ) ) value = CORE . Input . Gamepad . axisState [ gamepad ] [ axis ] ;
2016-10-31 13:56:57 +01:00
# endif
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
}
2014-09-16 22:51:31 +02:00
// Detect 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
# if !defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( button < MAX_GAMEPAD_BUTTONS ) & &
( CORE . Input . Gamepad . currentState [ gamepad ] [ button ] ! = CORE . Input . Gamepad . previousState [ gamepad ] [ button ] ) & &
( CORE . Input . Gamepad . currentState [ gamepad ] [ button ] = = 1 ) ) pressed = true ;
2016-10-31 13:56:57 +01:00
# endif
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
}
2014-09-16 22:51:31 +02:00
// Detect 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
2016-10-31 13:56:57 +01:00
# if !defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( button < MAX_GAMEPAD_BUTTONS ) & &
( CORE . Input . Gamepad . currentState [ gamepad ] [ button ] = = 1 ) ) result = true ;
2016-10-31 13:56:57 +01:00
# endif
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
}
2014-09-16 22:51:31 +02:00
// Detect 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
2016-10-31 13:56:57 +01:00
# if !defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( button < MAX_GAMEPAD_BUTTONS ) & &
( CORE . Input . Gamepad . currentState [ gamepad ] [ button ] ! = CORE . Input . Gamepad . previousState [ gamepad ] [ button ] ) & &
( CORE . Input . Gamepad . currentState [ gamepad ] [ button ] = = 0 ) ) released = true ;
2016-10-31 13:56:57 +01:00
# endif
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
}
2014-09-16 22:51:31 +02:00
// Detect if a mouse 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
2016-10-31 13:56:57 +01:00
# if !defined(PLATFORM_ANDROID)
2020-02-03 18:31:30 +01:00
if ( ( gamepad < MAX_GAMEPADS ) & & CORE . Input . Gamepad . ready [ gamepad ] & & ( button < MAX_GAMEPAD_BUTTONS ) & &
( CORE . Input . Gamepad . currentState [ gamepad ] [ button ] = = 0 ) ) result = true ;
2016-10-31 13:56:57 +01:00
# endif
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
}
2016-04-17 11:19:32 +02:00
// Detect if a mouse button has been pressed once
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 ;
}
// Detect if a mouse button is being pressed
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 ;
}
// Detect if a mouse button has been released once
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 ;
}
// Detect if a mouse button is NOT being pressed
bool IsMouseButtonUp ( int button )
{
2020-03-24 23:23:34 +11:00
return ! IsMouseButtonDown ( button ) ;
2016-04-17 11:19:32 +02:00
}
// Returns mouse position X
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
2020-02-03 18:31:30 +01:00
return ( int ) ( ( CORE . Input . Mouse . position . x + CORE . Input . Mouse . offset . x ) * CORE . Input . Mouse . scale . x ) ;
2016-04-17 11:19:32 +02:00
# endif
}
// Returns mouse position Y
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
2020-02-03 18:31:30 +01:00
return ( int ) ( ( CORE . Input . Mouse . position . y + CORE . Input . Mouse . offset . y ) * CORE . Input . Mouse . scale . y ) ;
2016-04-17 11:19:32 +02:00
# endif
}
// Returns mouse position XY
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
2020-02-29 22:10:23 +01:00
position . x = ( CORE . Input . Mouse . position . x + CORE . Input . Mouse . offset . x ) * CORE . Input . Mouse . scale . x ;
position . y = ( CORE . Input . Mouse . position . 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
}
// 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
{
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . position = ( Vector2 ) { ( float ) x , ( float ) y } ;
2016-04-17 11:19:32 +02:00
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// NOTE: emscripten not implemented
2020-02-03 18:31:30 +01:00
glfwSetCursorPos ( CORE . Window . handle , CORE . Input . Mouse . position . x , CORE . Input . Mouse . position . 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
}
2016-04-17 11:19:32 +02:00
// Returns 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 ;
2016-04-17 11:19:32 +02:00
# elif 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
# else
2020-02-03 18:31:30 +01:00
return CORE . Input . Mouse . previousWheelMove ;
2016-04-17 11:19:32 +02:00
# endif
}
2020-10-21 03:55:52 -05:00
// Returns mouse cursor
2020-10-21 11:08:37 +02:00
int GetMouseCursor ( void )
2020-10-21 03:55:52 -05:00
{
return CORE . Input . Mouse . cursor ;
}
// 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
}
2017-05-09 22:03:46 +02:00
// Returns 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
}
2017-05-09 22:03:46 +02:00
// Returns 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
}
2017-05-09 22:03:46 +02:00
// Returns 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
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
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-01-27 12:09:31 +01:00
# if defined(PLATFORM_ANDROID)
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
}
2020-01-27 12:09:31 +01:00
# endif
2020-03-24 13:26:34 +01:00
2020-03-24 23:23:34 +11:00
# elif defined(PLATFORM_DESKTOP)
2019-12-16 18:06:48 +01:00
// TODO: GLFW is not supporting 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
2016-02-10 10:31:06 +01:00
if ( index = = 0 ) position = GetMousePosition ( ) ;
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
2014-09-16 22:51:31 +02:00
2020-02-03 18:31:30 +01:00
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
// Screen size security check
2020-02-03 18:31:30 +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
2019-04-12 13:31:05 +02: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
2019-05-01 14:30:36 +02:00
# if defined(PLATFORM_DESKTOP) && defined(SUPPORT_HIGH_DPI)
2020-01-29 11:42:55 +01:00
// Resize window content area based on the monitor content scale.
2020-02-03 19:26:28 +01:00
// NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11.
2020-01-29 11:42:55 +01:00
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size.
2019-04-25 11:39:45 +02:00
glfwWindowHint ( GLFW_SCALE_TO_MONITOR , GLFW_TRUE ) ; // Scale content area based on the monitor content scale where window is placed on
2019-04-12 13:44:16 +02:00
# endif
2014-09-16 22:51:31 +02:00
2017-03-05 10:55:29 +01:00
// Check some Window creation flags
2020-04-05 17:50:37 +02:00
if ( CORE . Window . flags & FLAG_WINDOW_HIDDEN ) glfwWindowHint ( GLFW_VISIBLE , GLFW_FALSE ) ; // Visible window
else glfwWindowHint ( GLFW_VISIBLE , GLFW_TRUE ) ; // Window initially hidden
2019-01-10 14:54:55 +01:00
2020-04-05 17:50:37 +02:00
if ( CORE . Window . flags & FLAG_WINDOW_RESIZABLE ) glfwWindowHint ( GLFW_RESIZABLE , GLFW_TRUE ) ; // Resizable window
else glfwWindowHint ( GLFW_RESIZABLE , GLFW_FALSE ) ; // Avoid window being resizable
2017-03-05 10:55:29 +01:00
2020-04-05 17:50:37 +02:00
if ( CORE . Window . flags & FLAG_WINDOW_UNDECORATED ) glfwWindowHint ( GLFW_DECORATED , GLFW_FALSE ) ; // Border and buttons on Window
2018-12-24 17:09:46 +01:00
else glfwWindowHint ( GLFW_DECORATED , GLFW_TRUE ) ; // Decorated window
2018-07-29 07:51:17 +02:00
// FLAG_WINDOW_TRANSPARENT not supported on HTML5 and not included in any released GLFW version yet
# if defined(GLFW_TRANSPARENT_FRAMEBUFFER)
2020-02-03 18:31:30 +01:00
if ( CORE . Window . flags & FLAG_WINDOW_TRANSPARENT ) 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
2018-06-12 13:21:36 +02:00
# endif
2017-01-28 23:02:30 +01:00
2020-02-03 18:31:30 +01:00
if ( CORE . Window . flags & FLAG_MSAA_4X_HINT ) 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
}
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-02-03 18:31:30 +01:00
glfwSetWindowSizeCallback ( CORE . Window . handle , WindowSizeCallback ) ; // NOTE: Resizing not allowed by default!
glfwSetCursorEnterCallback ( CORE . Window . handle , CursorEnterCallback ) ;
glfwSetKeyCallback ( CORE . Window . handle , KeyCallback ) ;
glfwSetMouseButtonCallback ( CORE . Window . handle , MouseButtonCallback ) ;
glfwSetCursorPosCallback ( CORE . Window . handle , MouseCursorPosCallback ) ; // Track mouse position changes
glfwSetCharCallback ( CORE . Window . handle , CharCallback ) ;
glfwSetScrollCallback ( CORE . Window . handle , ScrollCallback ) ;
glfwSetWindowIconifyCallback ( CORE . Window . handle , WindowIconifyCallback ) ;
2020-04-27 17:41:29 +02:00
glfwSetWindowFocusCallback ( CORE . Window . handle , WindowFocusCallback ) ;
2020-02-03 18:31:30 +01:00
glfwSetDropCallback ( CORE . Window . handle , WindowDropCallback ) ;
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
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
2016-02-07 11:35:36 +01:00
# if defined(PLATFORM_DESKTOP)
2016-06-14 15:42:04 +02:00
// Load OpenGL 3.3 extensions
// NOTE: GLFW loader function is passed as parameter
2017-07-19 10:09:34 +02:00
rlLoadExtensions ( glfwGetProcAddress ) ;
2016-02-07 11:35:36 +01:00
# endif
2016-08-16 11:09:55 +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
}
2019-04-28 16:45:23 +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 ;
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
TRACELOG ( LOG_INFO , " DISPLAY: no graphic card set, trying card1 " ) ;
CORE . Window . fd = open ( " /dev/dri/card1 " , O_RDWR ) ; // VideoCore VI (Raspberry Pi 4)
if ( - 1 = = CORE . Window . fd )
{
TRACELOG ( LOG_INFO , " DISPLAY: failed to open graphic card1, trying card0 " ) ;
CORE . Window . fd = open ( " /dev/dri/card0 " , O_RDWR ) ; // VideoCore IV (Raspberry Pi 1-3)
}
# endif
if ( - 1 = = CORE . Window . fd )
{
TRACELOG ( LOG_WARNING , " DISPLAY: failed to open graphic card " ) ;
return false ;
}
drmModeRes * res = drmModeGetResources ( CORE . Window . fd ) ;
if ( ! res )
{
TRACELOG ( LOG_WARNING , " DISPLAY: failed get DRM resources " ) ;
return false ;
}
TRACELOG ( LOG_TRACE , " DISPLAY: %i connectors found " , res - > count_connectors ) ;
for ( size_t i = 0 ; i < res - > count_connectors ; i + + )
{
TRACELOG ( LOG_TRACE , " DISPLAY: connector index %i " , i ) ;
drmModeConnector * con = drmModeGetConnector ( CORE . Window . fd , res - > connectors [ i ] ) ;
TRACELOG ( LOG_TRACE , " DISPLAY: there are %i connector modes " , con - > count_modes ) ;
if ( ( con - > connection = = DRM_MODE_CONNECTED ) & & ( con - > encoder_id ) )
{
TRACELOG ( LOG_TRACE , " DRM mode connected " ) ;
CORE . Window . connector = con ;
break ;
}
else
{
TRACELOG ( LOG_TRACE , " DRM mode NOT connected (deleting) " ) ;
drmModeFreeConnector ( con ) ;
}
}
if ( ! CORE . Window . connector )
{
TRACELOG ( LOG_WARNING , " no suitable DRM connector found " ) ;
drmModeFreeResources ( res ) ;
return false ;
}
drmModeEncoder * enc = drmModeGetEncoder ( CORE . Window . fd , CORE . Window . connector - > encoder_id ) ;
if ( ! enc )
{
TRACELOG ( LOG_WARNING , " failed to get DRM mode encoder " ) ;
drmModeFreeResources ( res ) ;
return false ;
}
CORE . Window . crtc = drmModeGetCrtc ( CORE . Window . fd , enc - > crtc_id ) ;
if ( ! CORE . Window . crtc )
{
TRACELOG ( LOG_WARNING , " failed to get DRM mode crtc " ) ;
drmModeFreeEncoder ( enc ) ;
drmModeFreeResources ( res ) ;
return false ;
}
// If InitWindow should use the current mode find it in the connector's mode list
if ( ( CORE . Window . screen . width < = 0 ) | | ( CORE . Window . screen . height < = 0 ) )
{
TRACELOG ( LOG_TRACE , " selecting DRM connector mode for current used mode " ) ;
CORE . Window . modeIndex = FindMatchingConnectorMode ( CORE . Window . connector , & CORE . Window . crtc - > mode ) ;
if ( CORE . Window . modeIndex < 0 )
{
TRACELOG ( LOG_WARNING , " no matching DRM connector mode found " ) ;
drmModeFreeEncoder ( enc ) ;
drmModeFreeResources ( res ) ;
return false ;
}
CORE . Window . screen . width = CORE . Window . display . width ;
CORE . Window . screen . height = CORE . Window . display . height ;
}
const bool allowInterlaced = CORE . Window . flags & FLAG_INTERLACED_HINT ;
const int fps = ( CORE . Time . target > 0 ) ? ( 1.0 / CORE . Time . target ) : 60 ;
// try to find an exact matching mode
CORE . Window . modeIndex = FindExactConnectorMode ( CORE . Window . connector , CORE . Window . screen . width , CORE . Window . screen . height , fps , allowInterlaced ) ;
// if nothing found, try to find a nearly matching mode
if ( CORE . Window . modeIndex < 0 )
CORE . Window . modeIndex = FindNearestConnectorMode ( CORE . Window . connector , CORE . Window . screen . width , CORE . Window . screen . height , fps , allowInterlaced ) ;
// if nothing found, try to find an exactly matching mode including interlaced
if ( CORE . Window . modeIndex < 0 )
CORE . Window . modeIndex = FindExactConnectorMode ( CORE . Window . connector , CORE . Window . screen . width , CORE . Window . screen . height , fps , true ) ;
// if nothing found, try to find a nearly matching mode including interlaced
if ( CORE . Window . modeIndex < 0 )
CORE . Window . modeIndex = FindNearestConnectorMode ( CORE . Window . connector , CORE . Window . screen . width , CORE . Window . screen . height , fps , true ) ;
// if nothing found, there is no suitable mode
if ( CORE . Window . modeIndex < 0 )
{
TRACELOG ( LOG_WARNING , " no suitable DRM connector mode found " ) ;
drmModeFreeEncoder ( enc ) ;
drmModeFreeResources ( res ) ;
return false ;
}
CORE . Window . display . width = CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . hdisplay ;
CORE . Window . display . height = CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . vdisplay ;
TRACELOG ( LOG_INFO , " DRM: choosen mode %s (%ux%u%c@%u) " , CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . name ,
CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . hdisplay , CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . vdisplay ,
( CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . flags & DRM_MODE_FLAG_INTERLACE ) ? ' i ' : ' p ' ,
CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . vrefresh ) ;
// Use the width and height of the surface for render
CORE . Window . render . width = CORE . Window . screen . width ;
CORE . Window . render . height = CORE . Window . screen . height ;
drmModeFreeEncoder ( enc ) ;
enc = NULL ;
drmModeFreeResources ( res ) ;
res = NULL ;
CORE . Window . gbmDevice = gbm_create_device ( CORE . Window . fd ) ;
if ( ! CORE . Window . gbmDevice )
{
TRACELOG ( LOG_WARNING , " failed to create GBM device " ) ;
return false ;
}
CORE . Window . gbmSurface = gbm_surface_create ( CORE . Window . gbmDevice , CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . hdisplay ,
CORE . Window . connector - > modes [ CORE . Window . modeIndex ] . vdisplay , GBM_FORMAT_ARGB8888 , GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING ) ;
if ( ! CORE . Window . gbmSurface )
{
TRACELOG ( LOG_WARNING , " failed to create GBM surface " ) ;
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-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get function 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)
if ( ! eglGetConfigs ( CORE . Window . device , NULL , 0 , & numConfigs ) )
{
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get EGL config count: 0x%x " , eglGetError ( ) ) ;
return false ;
}
TRACELOG ( LOG_TRACE , " DISPLAY: %d EGL configs available " , numConfigs ) ;
EGLConfig * configs = calloc ( numConfigs , sizeof ( * configs ) ) ;
if ( ! configs ) {
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get memory for EGL configs " ) ;
return false ;
}
EGLint matchingNumConfigs = 0 ;
if ( ! eglGetConfigs ( CORE . Window . device , configs , numConfigs , & matchingNumConfigs ) ) {
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get EGL configs: 0x%x " , eglGetError ( ) ) ;
free ( configs ) ;
return false ;
}
TRACELOG ( LOG_TRACE , " DISPLAY: %d matching EGL configs available " , matchingNumConfigs ) ;
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 ;
}
// find the EGL config that matches the previously setup GBM format
int found = 0 ;
for ( EGLint i = 0 ; i < matchingNumConfigs ; + + i ) {
EGLint id = 0 ;
if ( ! eglGetConfigAttrib ( CORE . Window . device , configs [ i ] , EGL_NATIVE_VISUAL_ID , & id ) ) {
TRACELOG ( LOG_WARNING , " DISPLAY: Failed to get EGL config attribute: 0x%x " , eglGetError ( ) ) ;
continue ;
}
if ( GBM_FORMAT_ARGB8888 = = id ) {
TRACELOG ( LOG_TRACE , " DISPLAY: using EGL config %d " , i ) ;
CORE . Window . config = configs [ i ] ;
found = 1 ;
break ;
}
}
free ( configs ) ;
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
// NOTE: RPI dispmanx windowing system takes care of srcRec scaling to dstRec by hardware (no cost)
// 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 ) ;
if ( renderer ) {
TRACELOG ( LOG_INFO , " Renderer is: %s \n " , renderer ) ;
} else {
TRACELOG ( LOG_WARNING , " failed to get renderer \n " ) ;
}
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
}
2020-09-27 10:18:43 +02:00
# endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP
2014-09-16 22:51:31 +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
2019-05-01 14:30:36 +02:00
# if defined(PLATFORM_DESKTOP) && defined(SUPPORT_HIGH_DPI)
2020-02-03 18:31:30 +01:00
glfwGetFramebufferSize ( CORE . Window . handle , & fbWidth , & fbHeight ) ;
2019-05-01 14:30:36 +02:00
// Screen scaling matrix is required in case desired screen area is different than display area
2020-02-03 18:31:30 +01:00
CORE . Window . screenScale = MatrixScale ( ( float ) fbWidth / CORE . Window . screen . width , ( float ) fbHeight / CORE . Window . screen . height , 1.0f ) ;
2019-12-04 18:09:56 +01:00
# if !defined(__APPLE__)
2020-02-03 18:31:30 +01:00
SetMouseScale ( ( float ) CORE . Window . screen . width / fbWidth , ( float ) CORE . Window . screen . height / fbHeight ) ;
2020-02-03 19:26:28 +01:00
# endif
2019-05-01 14:30:36 +02:00
# endif // PLATFORM_DESKTOP && SUPPORT_HIGH_DPI
// 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
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
2019-05-01 14:30:36 +02:00
// Set viewport width and height
// NOTE: We consider render size 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)
2020-02-03 18:31:30 +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 ) ;
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 ) ;
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
static void InitTimer ( void )
2014-12-31 18:03:32 +01:00
{
2018-08-05 00:34:35 +02:00
srand ( ( unsigned int ) time ( NULL ) ) ; // Initialize random seed
2018-11-06 15:10:50 +01:00
2020-04-30 18:48:39 +01:00
# if !defined(SUPPORT_BUSY_WAIT_LOOP) && defined(_WIN32) && !defined(PLATFORM_UWP)
2017-05-08 02:37:37 +02:00
timeBeginPeriod ( 1 ) ; // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
# 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)
2016-05-02 14:11:57 +02:00
struct timespec now ;
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
2020-02-03 18:31:30 +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!
2017-03-05 19:17:00 +01:00
static void Wait ( float ms )
{
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
2020-01-19 17:31:55 +01:00
# if defined(SUPPORT_HALFBUSY_WAIT_LOOP)
# define MAX_HALFBUSY_WAIT_TIME 4
double destTime = GetTime ( ) + ms / 1000 ;
if ( ms > MAX_HALFBUSY_WAIT_TIME ) ms - = MAX_HALFBUSY_WAIT_TIME ;
# endif
2017-05-08 02:37:37 +02:00
# if defined(_WIN32)
2017-03-28 19:15:27 +02:00
Sleep ( ( unsigned int ) ms ) ;
2017-05-08 02:37:37 +02:00
# elif defined(__linux__) || defined(PLATFORM_WEB)
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 ;
2017-05-08 02:37:37 +02:00
# elif defined(__APPLE__)
2017-03-05 19:17:00 +01:00
usleep ( ms * 1000.0f ) ;
# endif
2020-02-03 19:26:28 +01:00
2020-05-09 13:05:54 +02:00
# if defined(SUPPORT_HALFBUSY_WAIT_LOOP)
2020-01-19 17:31:55 +01:00
while ( GetTime ( ) < destTime ) { }
# endif
2017-01-28 00:56:45 +01:00
# endif
}
2019-04-28 18:23:21 +02:00
// Get gamepad button generic to all platforms
static int GetGamepadButton ( int button )
2019-04-27 20:49:33 +01:00
{
2019-04-28 18:23:21 +02:00
int btn = GAMEPAD_BUTTON_UNKNOWN ;
2019-04-27 20:49:33 +01:00
# if defined(PLATFORM_DESKTOP)
switch ( button )
{
2019-04-28 18:23:21 +02:00
case GLFW_GAMEPAD_BUTTON_Y : btn = GAMEPAD_BUTTON_RIGHT_FACE_UP ; break ;
case GLFW_GAMEPAD_BUTTON_B : btn = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT ; break ;
case GLFW_GAMEPAD_BUTTON_A : btn = GAMEPAD_BUTTON_RIGHT_FACE_DOWN ; break ;
case GLFW_GAMEPAD_BUTTON_X : btn = GAMEPAD_BUTTON_RIGHT_FACE_LEFT ; break ;
2019-04-27 21:36:57 +01:00
2019-04-28 18:23:21 +02:00
case GLFW_GAMEPAD_BUTTON_LEFT_BUMPER : btn = GAMEPAD_BUTTON_LEFT_TRIGGER_1 ; break ;
case GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER : btn = GAMEPAD_BUTTON_RIGHT_TRIGGER_1 ; break ;
2019-04-27 21:36:57 +01:00
2019-04-28 18:23:21 +02:00
case GLFW_GAMEPAD_BUTTON_BACK : btn = GAMEPAD_BUTTON_MIDDLE_LEFT ; break ;
case GLFW_GAMEPAD_BUTTON_GUIDE : btn = GAMEPAD_BUTTON_MIDDLE ; break ;
case GLFW_GAMEPAD_BUTTON_START : btn = GAMEPAD_BUTTON_MIDDLE_RIGHT ; break ;
2019-04-27 21:36:57 +01:00
2019-04-28 18:23:21 +02:00
case GLFW_GAMEPAD_BUTTON_DPAD_UP : btn = GAMEPAD_BUTTON_LEFT_FACE_UP ; break ;
case GLFW_GAMEPAD_BUTTON_DPAD_RIGHT : btn = GAMEPAD_BUTTON_LEFT_FACE_RIGHT ; break ;
case GLFW_GAMEPAD_BUTTON_DPAD_DOWN : btn = GAMEPAD_BUTTON_LEFT_FACE_DOWN ; break ;
case GLFW_GAMEPAD_BUTTON_DPAD_LEFT : btn = GAMEPAD_BUTTON_LEFT_FACE_LEFT ; break ;
2019-04-27 21:36:57 +01:00
2019-04-28 18:23:21 +02:00
case GLFW_GAMEPAD_BUTTON_LEFT_THUMB : btn = GAMEPAD_BUTTON_LEFT_THUMB ; break ;
case GLFW_GAMEPAD_BUTTON_RIGHT_THUMB : btn = GAMEPAD_BUTTON_RIGHT_THUMB ; break ;
2019-04-27 20:49:33 +01:00
}
# endif
2019-04-27 21:36:57 +01:00
# if defined(PLATFORM_UWP)
2019-04-28 18:23:21 +02:00
btn = button ; // UWP will provide the correct button
2019-04-27 21:36:57 +01:00
# endif
2019-04-27 20:49:33 +01:00
# if defined(PLATFORM_WEB)
2019-04-28 18:23:21 +02:00
// Gamepad Buttons reference: https://www.w3.org/TR/gamepad/#gamepad-interface
2019-04-27 20:49:33 +01:00
switch ( button )
{
2019-04-28 18:23:21 +02:00
case 0 : btn = GAMEPAD_BUTTON_RIGHT_FACE_DOWN ; break ;
case 1 : btn = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT ; break ;
case 2 : btn = GAMEPAD_BUTTON_RIGHT_FACE_LEFT ; break ;
case 3 : btn = GAMEPAD_BUTTON_RIGHT_FACE_UP ; break ;
case 4 : btn = GAMEPAD_BUTTON_LEFT_TRIGGER_1 ; break ;
case 5 : btn = GAMEPAD_BUTTON_RIGHT_TRIGGER_1 ; break ;
case 6 : btn = GAMEPAD_BUTTON_LEFT_TRIGGER_2 ; break ;
case 7 : btn = GAMEPAD_BUTTON_RIGHT_TRIGGER_2 ; break ;
case 8 : btn = GAMEPAD_BUTTON_MIDDLE_LEFT ; break ;
case 9 : btn = GAMEPAD_BUTTON_MIDDLE_RIGHT ; break ;
case 10 : btn = GAMEPAD_BUTTON_LEFT_THUMB ; break ;
case 11 : btn = GAMEPAD_BUTTON_RIGHT_THUMB ; break ;
case 12 : btn = GAMEPAD_BUTTON_LEFT_FACE_UP ; break ;
case 13 : btn = GAMEPAD_BUTTON_LEFT_FACE_DOWN ; break ;
case 14 : btn = GAMEPAD_BUTTON_LEFT_FACE_LEFT ; break ;
case 15 : btn = GAMEPAD_BUTTON_LEFT_FACE_RIGHT ; break ;
2019-04-27 20:49:33 +01:00
}
# endif
2019-04-28 18:23:21 +02:00
return btn ;
2019-04-27 20:49:33 +01:00
}
2016-05-02 14:11:57 +02:00
// Poll (store) all input events
static 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
2019-11-24 13:39:45 +01:00
// Reset key pressed registered
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueueCount = 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 ] ;
2019-03-28 19:46:39 +01:00
// Grab a keypress from the evdev fifo if avalable
2020-02-27 13:33:09 +01:00
if ( CORE . Input . Keyboard . lastKeyPressed . head ! = CORE . Input . Keyboard . lastKeyPressed . tail )
2019-03-28 19:46:39 +01:00
{
2020-02-27 13:33:09 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = CORE . Input . Keyboard . lastKeyPressed . contents [ CORE . Input . Keyboard . lastKeyPressed . tail ] ; // Read the key from the buffer
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueueCount + + ;
2020-02-03 19:26:28 +01:00
2020-02-27 13:33:09 +01:00
CORE . Input . Keyboard . lastKeyPressed . tail = ( CORE . Input . Keyboard . lastKeyPressed . tail + 1 ) & 0x07 ; // Increment the tail pointer forwards and binary wraparound after 7 (fifo is 8 elements long)
2019-03-28 19:46:39 +01:00
}
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
}
# 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
{
2020-02-03 18:31:30 +01:00
for ( int k = 0 ; k < MAX_GAMEPAD_BUTTONS ; k + + ) CORE . Input . Gamepad . previousState [ i ] [ k ] = CORE . Input . Gamepad . currentState [ 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 ;
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
2020-02-03 18:31:30 +01:00
for ( int k = 0 ; k < MAX_GAMEPAD_BUTTONS ; k + + ) CORE . Input . Gamepad . previousState [ i ] [ k ] = CORE . Input . Gamepad . currentState [ 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
{
2019-04-28 16:06:56 +01:00
const GamepadButton button = GetGamepadButton ( k ) ;
2019-04-27 20:49:33 +01:00
2016-10-27 13:41:43 +02:00
if ( buttons [ k ] = = GLFW_PRESS )
{
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . currentState [ i ] [ button ] = 1 ;
CORE . Input . Gamepad . lastButtonPressed = button ;
2016-10-27 13:41:43 +02:00
}
2020-02-03 18:31:30 +01:00
else CORE . Input . Gamepad . currentState [ i ] [ button ] = 0 ;
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)
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . currentState [ i ] [ GAMEPAD_BUTTON_LEFT_TRIGGER_2 ] = ( char ) ( CORE . Input . Gamepad . axisState [ i ] [ GAMEPAD_AXIS_LEFT_TRIGGER ] > 0.1 ) ;
CORE . Input . Gamepad . currentState [ 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
2020-05-09 13:05:54 +02:00
CORE . Input . Gamepad . axisCount = GLFW_GAMEPAD_AXIS_LAST ;
2016-10-14 00:47:43 +02:00
}
}
2019-04-04 13:50:52 +02:00
2020-02-03 18:31:30 +01:00
CORE . Window . resized = 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
2018-10-31 23:19:29 +01:00
# endif //defined(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
2020-02-03 18:31:30 +01:00
for ( int k = 0 ; k < MAX_GAMEPAD_BUTTONS ; k + + ) CORE . Input . Gamepad . previousState [ i ] [ k ] = CORE . Input . Gamepad . currentState [ 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 + + )
{
2019-04-28 16:06:56 +01:00
const GamepadButton button = GetGamepadButton ( j ) ;
2016-12-25 20:42:22 +01:00
if ( gamepadState . digitalButton [ j ] = = 1 )
{
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . currentState [ i ] [ button ] = 1 ;
CORE . Input . Gamepad . lastButtonPressed = button ;
2016-12-25 20:42:22 +01:00
}
2020-02-03 18:31:30 +01:00
else CORE . Input . Gamepad . currentState [ i ] [ button ] = 0 ;
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
}
// Copy back buffer to front buffers
static void SwapBuffers ( void )
{
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
2020-02-03 18:31:30 +01:00
glfwSwapBuffers ( CORE . Window . handle ) ;
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
eglSwapBuffers ( CORE . Window . device , CORE . Window . surface ) ;
2020-09-27 10:18:43 +02:00
# if defined(PLATFORM_DRM)
if ( ! CORE . Window . gbmSurface | | ( - 1 = = CORE . Window . fd ) | | ! CORE . Window . connector | | ! CORE . Window . crtc )
{
TRACELOG ( LOG_ERROR , " DRM initialization failed, can't swap " ) ;
abort ( ) ;
}
struct gbm_bo * bo = gbm_surface_lock_front_buffer ( CORE . Window . gbmSurface ) ;
if ( ! bo )
{
TRACELOG ( LOG_ERROR , " GBM failed 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 , " drmModeAddFB failed with %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 , " drmModeSetCrtc failed with %d " , result ) ;
abort ( ) ;
}
if ( CORE . Window . prevFB )
{
result = drmModeRmFB ( CORE . Window . fd , CORE . Window . prevFB ) ;
if ( 0 ! = result )
{
TRACELOG ( LOG_ERROR , " drmModeRmFB failed with %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 // defined(PLATFORM_DRM)
# endif // defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP)
2016-05-02 14:11:57 +02:00
}
# if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback ( int error , const char * description )
{
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_WARNING , " GLFW: Error: %i Description: %s " , error , description ) ;
2016-05-02 14:11:57 +02:00
}
// GLFW3 Srolling Callback, runs on mouse wheel
static void ScrollCallback ( GLFWwindow * window , double xoffset , double yoffset )
{
2020-10-06 05:16:23 +11:00
CORE . Input . Mouse . currentWheelMove = ( float ) yoffset ;
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-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!
}
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 )
{
2017-05-27 14:40:05 +02:00
GifEnd ( ) ;
2017-05-18 18:57:11 +02:00
gifRecording = false ;
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
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-02-14 00:06:05 +01:00
strcat ( path , TextFormat ( " ./screenrec%03i.gif " , screenshotCounter ) ) ;
2019-01-05 18:03:09 +01:00
# else
2019-02-14 00:06:05 +01:00
strcpy ( path , TextFormat ( " ./screenrec%03i.gif " , screenshotCounter ) ) ;
2019-01-05 18:03:09 +01:00
# endif
2018-11-06 15:10:50 +01:00
2017-05-18 18:57:11 +02:00
// NOTE: delay represents the time between frames in the gif, if we capture a gif frame every
// 10 game frames and each frame trakes 16.6ms (60fps), delay between gif frames should be ~16.6*10.
2020-02-03 18:31:30 +01:00
GifBegin ( path , CORE . Window . screen . width , CORE . Window . screen . height , ( int ) ( GetFrameTime ( ) * 10.0f ) , 8 , false ) ;
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
2019-01-05 18:03:09 +01:00
# endif // SUPPORT_GIF_RECORDING
# if defined(SUPPORT_SCREEN_CAPTURE)
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 + + ;
}
2019-01-05 18:03:09 +01:00
# endif // SUPPORT_SCREEN_CAPTURE
2017-05-11 16:24:40 +02:00
}
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 ;
}
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 )
{
2020-02-29 22:10:23 +01:00
CORE . Input . Mouse . position . x = ( float ) x ;
CORE . Input . Mouse . position . y = ( float ) y ;
CORE . Input . Touch . position [ 0 ] = CORE . Input . Mouse . position ;
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
}
2017-12-31 23:50:22 +01:00
// GLFW3 Char Key Callback, runs on key down (get unicode char value)
2016-05-02 14:11:57 +02:00
static void CharCallback ( GLFWwindow * window , unsigned int key )
2018-11-06 15:10:50 +01:00
{
2017-12-31 23:50:22 +01:00
// NOTE: Registers any key down considering OS keyboard layout but
// do not detects action events, those should be managed by user...
2019-12-01 12:55:33 +01:00
// Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
// Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char
2018-11-06 15:10:50 +01:00
2019-11-24 13:39:45 +01:00
// Check if there is space available in the queue
2020-05-01 17:31:44 +02:00
if ( CORE . Input . Keyboard . keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE )
2019-11-24 20:46:00 +09:00
{
2019-11-24 13:39:45 +01:00
// Add character to the queue
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = key ;
CORE . Input . Keyboard . keyPressedQueueCount + + ;
2019-11-24 20:46:00 +09:00
}
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
}
// GLFW3 WindowSize Callback, runs when window is resized
// NOTE: Window resizing not allowed by default
static void WindowSizeCallback ( GLFWwindow * window , int width , int height )
{
2019-05-01 14:30:36 +02:00
SetupViewport ( width , height ) ; // Reset viewport and projection matrix for new size
2016-08-16 11:09:55 +02:00
2019-05-01 16:15:33 +02:00
// Set current screen size
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 ;
2019-05-08 18:33:09 +02:00
2016-05-02 14:11:57 +02:00
// NOTE: Postprocessing texture is not scaled to new size
2019-04-04 13:50:52 +02:00
2020-02-03 18:31:30 +01:00
CORE . Window . resized = true ;
2016-05-02 14:11:57 +02:00
}
// GLFW3 WindowIconify Callback, runs when window is minimized/restored
2018-10-22 11:48:16 +02:00
static void WindowIconifyCallback ( GLFWwindow * window , int iconified )
2016-05-02 14:11:57 +02:00
{
2020-02-03 18:31:30 +01:00
if ( iconified ) CORE . Window . minimized = true ; // The window was iconified
else CORE . Window . minimized = false ; // The window was restored
2015-07-29 21:44:27 +02:00
}
2015-02-02 00:57:08 +01:00
2020-04-27 17:41:29 +02:00
// GLFW3 WindowFocus Callback, runs when window get/lose focus
static void WindowFocusCallback ( GLFWwindow * window , int focused )
{
if ( focused ) CORE . Window . focused = true ; // The window was focused
else CORE . Window . focused = false ; // The window lost focus
}
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
2020-02-03 18:31:30 +01:00
CORE . Window . dropFilesPath = ( char * * ) RL_MALLOC ( sizeof ( char * ) * count ) ;
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
{
2020-02-03 18:31:30 +01:00
CORE . Window . dropFilesPath [ i ] = ( char * ) RL_MALLOC ( sizeof ( char ) * MAX_FILEPATH_LENGTH ) ;
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
}
2020-09-01 19:29:13 +01:00
static void WindowMaximizeCallback ( GLFWwindow * window , int maximized )
{
if ( maximized ) CORE . Window . maximized = true ; // The window was maximized
else CORE . Window . maximized = false ; // The window was restored
}
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
{
2020-03-16 01:56:43 +11:00
CORE . Window . display . width = ANativeWindow_getWidth ( CORE . Android . app - > window ) ;
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
2020-02-12 13:48:50 +01: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 )
{
CORE . Input . Touch . currentTouchState [ MOUSE_LEFT_BUTTON ] = 1 ;
}
else if ( flags = = AMOTION_EVENT_ACTION_UP )
{
CORE . Input . Touch . currentTouchState [ MOUSE_LEFT_BUTTON ] = 0 ;
}
# 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 fullscreen change events
2020-02-03 18:31:30 +01:00
static EM_BOOL EmscriptenFullscreenChangeCallback ( int eventType , const EmscriptenFullscreenChangeEvent * event , void * userData )
2013-11-18 23:38:44 +01:00
{
2020-02-03 18:31:30 +01:00
//isFullscreen: int event->isFullscreen
//fullscreenEnabled: int event->fullscreenEnabled
//fs element nodeName: (char *) event->nodeName
//fs element id: (char *) event->id
//Current element size: (int) event->elementWidth, (int) event->elementHeight
//Screen size:(int) event->screenWidth, (int) event->screenHeight
2020-05-14 17:35:26 +02:00
/*
2020-02-03 18:31:30 +01:00
if ( event - > isFullscreen )
2014-09-16 22:51:31 +02:00
{
2020-02-26 23:42:06 +01:00
CORE . Window . fullscreen = true ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " WEB: Canvas scaled to fullscreen. ElementSize: (%ix%i), ScreenSize(%ix%i) " , event - > elementWidth , event - > elementHeight , event - > screenWidth , event - > screenHeight ) ;
2016-05-02 14:11:57 +02:00
}
else
{
2020-02-26 23:42:06 +01:00
CORE . Window . fullscreen = false ;
2020-03-27 18:06:09 +01:00
TRACELOG ( LOG_INFO , " WEB: Canvas scaled to windowed. ElementSize: (%ix%i), ScreenSize(%ix%i) " , event - > elementWidth , event - > elementHeight , event - > screenWidth , event - > screenHeight ) ;
2014-09-16 22:51:31 +02:00
}
2016-08-16 11:09:55 +02:00
2016-05-02 14:11:57 +02:00
// TODO: Depending on scaling factor (screen vs element), calculate factor to scale mouse/touch input
2020-05-14 17:35:26 +02:00
*/
2016-05-02 14:11:57 +02:00
return 0 ;
}
2015-02-02 00:57:08 +01:00
2017-04-08 00:16:03 +02:00
// Register keyboard input events
static EM_BOOL EmscriptenKeyboardCallback ( int eventType , const EmscriptenKeyboardEvent * keyEvent , void * userData )
{
2020-05-14 17:35:26 +02:00
if ( ( eventType = = EMSCRIPTEN_EVENT_KEYDOWN ) & & ( keyEvent - > keyCode = = 27 ) ) // ESCAPE key (strcmp(keyEvent->code, "Escape") == 0)
2017-04-08 00:16:03 +02:00
{
2020-05-14 17:35:26 +02:00
// WARNING: Not executed when pressing Esc to exit fullscreen, it seems document has priority over #canvas
2020-11-03 23:47:33 +01:00
2017-04-08 00:16:03 +02:00
emscripten_exit_pointerlock ( ) ;
2020-05-14 17:35:26 +02:00
CORE . Window . fullscreen = false ;
2020-06-02 23:07:42 +02:00
TRACELOG ( LOG_INFO , " CORE.Window.fullscreen = %s " , CORE . Window . fullscreen ? " true " : " false " ) ;
2017-04-08 00:16:03 +02:00
}
return 0 ;
}
// Register mouse input events
static EM_BOOL EmscriptenMouseCallback ( int eventType , const EmscriptenMouseEvent * mouseEvent , void * userData )
{
2017-04-28 00:29:50 +02:00
// Lock mouse pointer when click on screen
2020-07-14 12:25:21 -07:00
if ( eventType = = EMSCRIPTEN_EVENT_CLICK )
2017-04-08 00:16:03 +02:00
{
EmscriptenPointerlockChangeEvent plce ;
emscripten_get_pointerlock_status ( & plce ) ;
2020-07-14 12:25:21 -07:00
2020-07-10 18:23:17 +02:00
int result = emscripten_request_pointerlock ( " #canvas " , 1 ) ; // TODO: It does not work!
2020-07-14 12:25:21 -07:00
2020-07-10 18:23:17 +02:00
// result -> EMSCRIPTEN_RESULT_DEFERRED
2020-07-14 12:25:21 -07:00
// The requested operation cannot be completed now for web security reasons,
2020-07-10 18:23:17 +02:00
// and has been deferred for completion in the next event handler. --> but it never happens!
2017-04-08 00:16:03 +02:00
2020-07-10 18:23:17 +02:00
//if (!plce.isActive) emscripten_request_pointerlock(0, 1);
//else emscripten_exit_pointerlock();
2017-04-08 00:16:03 +02:00
}
2018-11-06 15:10:50 +01:00
2017-04-08 00:16:03 +02:00
return 0 ;
}
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 ;
}
2020-05-14 17:35:26 +02:00
static EM_BOOL EmscriptenWindowResizedCallback ( int eventType , const void * reserved , void * userData )
{
double width , height ;
emscripten_get_element_css_size ( " canvas " , & width , & height ) ;
// TODO.
return true ;
}
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)
2020-11-03 23:39:56 +01:00
if ( bufferByteCount > 0 ) for ( int i = 0 ; i < 512 ; 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)
2020-02-03 18:31:30 +01:00
//for (int i = 0; i < 512; 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
{
2016-02-19 19:57:25 +01:00
// Detect ESC 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
}
2019-05-21 20:59:13 +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 ;
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 keypress buffer
2020-02-27 13:33:09 +01:00
CORE . Input . Keyboard . lastKeyPressed . head = 0 ;
CORE . Input . Keyboard . lastKeyPressed . tail = 0 ;
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 ) ;
EventThreadSpawn ( path ) ; // Identify the device and spawn a thread for it
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
}
2018-12-18 19:11:12 +01:00
// Identifies a input device and spawns a thread to handle it if needed
2018-10-22 11:48:16 +02:00
static void EventThreadSpawn ( 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
//-------------------------------------------------------------------------------------------------------
ioctl ( fd , EVIOCGBIT ( 0 , sizeof ( evBits ) ) , evBits ) ; // Read a bitfield of the avalable 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
//-------------------------------------------------------------------------------------------------------
2019-03-28 19:46:39 +01:00
if ( worker - > isTouch | | worker - > isMouse | | worker - > isKeyboard )
2017-01-05 21:36:40 +00:00
{
2020-03-27 18:06:09 +01:00
// Looks like an interesting device
TRACELOG ( LOG_INFO , " RPI: Opening input device: %s (%s%s%s%s%s) " , device ,
2019-02-22 13:13:11 +01:00
worker - > isMouse ? " mouse " : " " ,
worker - > isMultitouch ? " multitouch " : " " ,
worker - > isTouch ? " touchscreen " : " " ,
worker - > isGamepad ? " gamepad " : " " ,
worker - > isKeyboard ? " keyboard " : " " ) ;
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
2018-10-22 11:48:16 +02:00
// Find toucnscreens 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
}
2018-12-18 19:11:12 +01:00
// Input device events reading thread
2018-10-21 00:09:17 +01:00
static void * EventThread ( void * arg )
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
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 ;
2019-03-28 19:46:39 +01:00
int keycode ;
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
{
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . position . x + = event . value ;
CORE . Input . Touch . position [ 0 ] . x = CORE . Input . Mouse . position . 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
{
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . position . y + = event . value ;
CORE . Input . Touch . position [ 0 ] . y = CORE . Input . Mouse . position . 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
{
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . position . x = ( event . value - worker - > absRange . x ) * CORE . Window . screen . width / worker - > absRange . width ; // 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
if ( event . code = = ABS_Y )
2018-10-21 00:09:17 +01:00
{
2020-02-03 18:31:30 +01:00
CORE . Input . Mouse . position . 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
2019-04-28 16:45:23 +02:00
if ( event . code = = ABS_MT_SLOT ) worker - > touchSlot = event . value ; // Remeber 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
}
}
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
{
2020-02-13 00:13:56 +01:00
CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_LEFT_BUTTON ] = 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
}
2020-02-13 00:13:56 +01:00
if ( event . code = = BTN_RIGHT ) CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_RIGHT_BUTTON ] = event . value ;
if ( event . code = = BTN_MIDDLE ) CORE . Input . Mouse . currentButtonStateEvdev [ MOUSE_MIDDLE_BUTTON ] = event . value ;
2019-03-28 19:46:39 +01:00
// Keyboard button parsing
2019-04-28 16:45:23 +02:00
if ( ( event . code > = 1 ) & & ( event . code < = 255 ) ) //Keyboard keys appear for codes 1 to 255
2019-03-28 19:46:39 +01:00
{
2019-04-04 13:50:52 +02:00
keycode = keymap_US [ event . code & 0xFF ] ; // The code we get is a scancode so we look up the apropriate keycode
2019-05-08 18:33:09 +02:00
2019-03-28 19:46:39 +01:00
// Make sure we got a valid keycode
2020-02-03 18:31:30 +01:00
if ( ( keycode > 0 ) & & ( keycode < sizeof ( CORE . Input . Keyboard . currentKeyState ) ) )
2019-03-28 19:46:39 +01:00
{
2020-04-26 13:23:03 +02:00
// 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 )
2019-11-24 13:39:45 +01:00
{
2020-02-03 18:31:30 +01:00
CORE . Input . Keyboard . keyPressedQueue [ CORE . Input . Keyboard . keyPressedQueueCount ] = keycode ; // Register last key pressed
CORE . Input . Keyboard . keyPressedQueueCount + + ;
2019-11-24 13:39:45 +01:00
}
2019-06-10 17:09:53 -04:00
# if defined(SUPPORT_SCREEN_CAPTURE)
// Check screen capture key (raylib key: KEY_F12)
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Keyboard . currentKeyState [ 301 ] = = 1 )
2019-06-10 17:09:53 -04:00
{
2020-08-16 11:28:15 +02:00
TakeScreenshot ( TextFormat ( " screenshot%03i.png " , screenshotCounter ) ) ;
2019-06-10 17:09:53 -04:00
screenshotCounter + + ;
}
# endif
2020-02-03 18:31:30 +01:00
if ( CORE . Input . Keyboard . currentKeyState [ CORE . Input . Keyboard . exitKey ] = = 1 ) CORE . Window . shouldClose = true ;
2019-10-17 17:18:03 +02:00
2020-03-27 18:06:09 +01:00
TRACELOGD ( " RPI: KEY_%s ScanCode: %4i KeyCode: %4i " , event . value = = 0 ? " UP " : " DOWN " , event . code , keycode ) ;
2019-03-28 19:46:39 +01:00
}
}
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 )
{
if ( CORE . Input . Mouse . position . x < 0 ) CORE . Input . Mouse . position . x = 0 ;
if ( CORE . Input . Mouse . position . x > CORE . Window . screen . width / CORE . Input . Mouse . scale . x ) CORE . Input . Mouse . position . x = CORE . Window . screen . width / CORE . Input . Mouse . scale . x ;
2018-10-21 00:09:17 +01:00
2020-10-13 22:26:40 +02:00
if ( CORE . Input . Mouse . position . y < 0 ) CORE . Input . Mouse . position . y = 0 ;
if ( CORE . Input . Mouse . position . y > CORE . Window . screen . height / CORE . Input . Mouse . scale . y ) CORE . Input . Mouse . position . y = CORE . Window . screen . height / CORE . Input . Mouse . scale . y ;
}
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
}
2020-11-03 23:39:56 +01:00
Wait ( 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
{
2020-03-27 18:06:09 +01:00
TRACELOGD ( " 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
2020-02-03 18:31:30 +01:00
CORE . Input . Gamepad . currentState [ 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
{
2020-03-27 18:06:09 +01:00
TRACELOGD ( " 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
}
}
2020-05-06 11:33:08 +02:00
else Wait ( 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
}
2020-09-27 10:18:43 +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 ;
2020-04-30 21:00:09 +02:00
if ( uwpQueryTimeFunc = = NULL ) { TRACELOG ( LOG_ERROR , " UWP: UWPSetQueryTimeFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpSleepFunc = = NULL ) { TRACELOG ( LOG_ERROR , " UWP: UWPSetSleepFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpDisplaySizeFunc = = NULL ) { TRACELOG ( LOG_ERROR , " UWP: UWPSetDisplaySizeFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseLockFunc = = NULL ) { TRACELOG ( LOG_ERROR , " UWP: UWPSetMouseLockFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseUnlockFunc = = NULL ) { TRACELOG ( LOG_ERROR , " UWP: UWPSetMouseUnlockFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseShowFunc = = NULL ) { TRACELOG ( LOG_ERROR , " UWP: UWPSetMouseShowFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseHideFunc = = NULL ) { TRACELOG ( LOG_ERROR , " UWP: UWPSetMouseHideFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpMouseSetPosFunc = = NULL ) { TRACELOG ( LOG_ERROR , " UWP: UWPSetMouseSetPosFunc() must be called with a valid function before InitWindow() " ) ; pass = false ; }
if ( uwpCoreWindow = = NULL ) { TRACELOG ( LOG_ERROR , " 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
void UWPSetDataPath ( const char * path ) { CORE . UWP . internalDataPath = path ; }
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 ;
}
else if ( key = = KEY_F12 & & down )
{
# if defined(SUPPORT_GIF_RECORDING)
if ( controlKey )
{
if ( gifRecording )
{
GifEnd ( ) ;
gifRecording = false ;
# 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 ;
char path [ 512 ] = { 0 } ;
strcpy ( path , CORE . UWP . internalDataPath ) ;
strcat ( path , TextFormat ( " ./screenrec%03i.gif " , screenshotCounter ) ) ;
// NOTE: delay represents the time between frames in the gif, if we capture a gif frame every
// 10 game frames and each frame trakes 16.6ms (60fps), delay between gif frames should be ~16.6*10.
GifBegin ( path , CORE . Window . screen . width , CORE . Window . screen . height , ( int ) ( GetFrameTime ( ) * 10.0f ) , 8 , false ) ;
screenshotCounter + + ;
TRACELOG ( LOG_INFO , " SYSTEM: Start animated GIF recording: %s " , TextFormat ( " screenrec%03i.gif " , screenshotCounter ) ) ;
}
}
else
# endif // SUPPORT_GIF_RECORDING
# if defined(SUPPORT_SCREEN_CAPTURE)
{
TakeScreenshot ( TextFormat ( " screenshot%03i.png " , screenshotCounter ) ) ;
screenshotCounter + + ;
}
# endif // SUPPORT_SCREEN_CAPTURE
}
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 )
{
CORE . Input . Mouse . position . x = ( float ) x ;
CORE . Input . Mouse . position . y = ( float ) y ;
CORE . Input . Touch . position [ 0 ] = CORE . Input . Mouse . position ;
# 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
gestureEvent . position [ 0 ] = CORE . Input . Mouse . position ;
// 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
CORE . Window . resized = true ;
}
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 )
{
2020-04-30 18:48:39 +01:00
CORE . Input . Gamepad . currentState [ gamepad ] [ button ] = down ;
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
}
# 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 + + )
{
TRACELOG ( LOG_TRACE , " mode %d %ux%u@%u %s " , i , connector - > modes [ i ] . hdisplay , connector - > modes [ i ] . vdisplay ,
connector - > modes [ i ] . vrefresh , ( connector - > modes [ i ] . flags & DRM_MODE_FLAG_INTERLACE ) ? " interlaced " : " progressive " ) ;
if ( 0 = = BINCMP ( & CORE . Window . crtc - > mode , & CORE . Window . connector - > modes [ i ] ) )
{
TRACELOG ( LOG_TRACE , " above mode selected " ) ;
return i ;
}
}
return - 1 ;
# undef BINCMP
}
2020-10-24 10:37:15 +02:00
// Search exactly matching DRM connector mode in connector's list
2020-09-27 10:18:43 +02:00
static int FindExactConnectorMode ( const drmModeConnector * connector , uint width , uint height , uint fps , bool allowInterlaced ) {
TRACELOG ( LOG_TRACE , " searching exact connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s " , width , height , fps , allowInterlaced ? " yes " : " no " ) ;
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 ] ;
TRACELOG ( LOG_TRACE , " mode %d %ux%u@%u %s " , i , mode - > hdisplay , mode - > vdisplay , mode - > vrefresh , ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) ? " interlaced " : " progressive " ) ;
if ( ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) & & ( ! allowInterlaced ) )
{
TRACELOG ( LOG_TRACE , " but shouldn't choose an interlaced mode " ) ;
continue ;
}
if ( ( mode - > hdisplay = = width ) & & ( mode - > vdisplay = = height ) & & ( mode - > vrefresh = = fps ) )
{
TRACELOG ( LOG_TRACE , " mode selected " ) ;
return i ;
}
}
TRACELOG ( LOG_TRACE , " no exact matching mode found " ) ;
return - 1 ;
}
2020-10-24 10:37:15 +02:00
// Search the nearest matching DRM connector mode in connector's list
2020-09-27 10:18:43 +02:00
static int FindNearestConnectorMode ( const drmModeConnector * connector , uint width , uint height , uint fps , bool allowInterlaced ) {
TRACELOG ( LOG_TRACE , " searching nearest connector mode for %ux%u@%u, selecting an interlaced mode is allowed: %s " , width , height , fps , allowInterlaced ? " yes " : " no " ) ;
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 ] ;
TRACELOG ( LOG_TRACE , " mode %d %ux%u@%u %s " , i , mode - > hdisplay , mode - > vdisplay , mode - > vrefresh ,
( mode - > flags & DRM_MODE_FLAG_INTERLACE ) ? " interlaced " : " progressive " ) ;
if ( ( mode - > hdisplay < width ) | | ( mode - > vdisplay < height ) | ( mode - > vrefresh < fps ) )
{
TRACELOG ( LOG_TRACE , " mode is too small " ) ;
continue ;
}
if ( ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) & & ( ! allowInterlaced ) )
{
TRACELOG ( LOG_TRACE , " shouldn't choose an interlaced mode " ) ;
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 )
{
TRACELOG ( LOG_TRACE , " first suitable mode " ) ;
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 ;
if ( ( widthDiff < nearestWidthDiff ) | | ( heightDiff < nearestHeightDiff ) | | ( fpsDiff < nearestFpsDiff ) )
{
TRACELOG ( LOG_TRACE , " mode is nearer than the previous one " ) ;
nearestIndex = i ;
}
else
{
TRACELOG ( LOG_TRACE , " mode is not nearer " ) ;
}
}
}
TRACELOG ( LOG_TRACE , " returning nearest mode: %d " , nearestIndex ) ;
return nearestIndex ;
}
# endif