Check in current state
This commit is contained in:
parent
cbef73c5cb
commit
cddb0fa969
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -75,6 +75,9 @@ xcschememanagement.plist
|
|||
xcuserdata/
|
||||
DerivedData/
|
||||
|
||||
# VSCode project
|
||||
.vscode
|
||||
|
||||
# Jetbrains project
|
||||
.idea/
|
||||
cmake-build-*/
|
||||
|
|
|
|||
621
src/rcore.c
621
src/rcore.c
|
|
@ -99,6 +99,7 @@
|
|||
**********************************************************************************************/
|
||||
|
||||
#include "raylib.h" // Declares module functions
|
||||
#include "rcore.h"
|
||||
|
||||
// Check if config flags have been externally provided on compilation line
|
||||
#if !defined(EXTERNAL_CONFIG_FLAGS)
|
||||
|
|
@ -243,265 +244,12 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
//#include <android/sensor.h> // Required for: Android sensors functions (accelerometer, gyroscope, light...)
|
||||
#include <android/window.h> // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
|
||||
#include <android_native_app_glue.h> // Required for: android_app struct and activity management
|
||||
#include <jni.h> // Required for: JNIEnv and JavaVM [Used in OpenURL()]
|
||||
|
||||
#include <EGL/egl.h> // Native platform windowing system interface
|
||||
//#include <GLES2/gl2.h> // OpenGL ES 2.0 library (not required in this module, only in rlgl)
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_DRM)
|
||||
#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
|
||||
|
||||
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
|
||||
#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
|
||||
|
||||
#if defined(PLATFORM_DRM)
|
||||
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
|
||||
#include <xf86drm.h> // Direct Rendering Manager user-level library interface
|
||||
#include <xf86drmMode.h> // Direct Rendering Manager mode setting (KMS) interface
|
||||
#endif
|
||||
|
||||
#include "EGL/egl.h" // Native platform windowing system interface
|
||||
#include "EGL/eglext.h" // EGL extensions
|
||||
//#include "GLES2/gl2.h" // OpenGL ES 2.0 library (not required in this module, only in rlgl)
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
#define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL)
|
||||
//#define GLFW_INCLUDE_ES3 // GLFW3: Enable OpenGL ES 3.0 (transalted to WebGL2?)
|
||||
#include "GLFW/glfw3.h" // GLFW3: Windows, OpenGL context and Input management
|
||||
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
|
||||
|
||||
#include <emscripten/emscripten.h> // Emscripten functionality for C
|
||||
#include <emscripten/html5.h> // Emscripten HTML5 library
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#if defined(PLATFORM_DRM)
|
||||
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
#ifndef MAX_FILEPATH_CAPACITY
|
||||
#define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
|
||||
#endif
|
||||
#ifndef MAX_FILEPATH_LENGTH
|
||||
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
|
||||
#endif
|
||||
|
||||
#ifndef MAX_KEYBOARD_KEYS
|
||||
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
|
||||
#endif
|
||||
#ifndef MAX_MOUSE_BUTTONS
|
||||
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
|
||||
#endif
|
||||
#ifndef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_AXIS
|
||||
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_BUTTONS
|
||||
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
||||
#endif
|
||||
#ifndef MAX_TOUCH_POINTS
|
||||
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
|
||||
#endif
|
||||
#ifndef MAX_KEY_PRESSED_QUEUE
|
||||
#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
|
||||
#endif
|
||||
#ifndef MAX_CHAR_PRESSED_QUEUE
|
||||
#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
|
||||
#endif
|
||||
|
||||
#ifndef MAX_DECOMPRESSION_SIZE
|
||||
#define MAX_DECOMPRESSION_SIZE 64 // Maximum size allocated for decompression in MB
|
||||
#endif
|
||||
|
||||
// Flags operation macros
|
||||
#define FLAG_SET(n, f) ((n) |= (f))
|
||||
#define FLAG_CLEAR(n, f) ((n) &= ~(f))
|
||||
#define FLAG_TOGGLE(n, f) ((n) ^= (f))
|
||||
#define FLAG_CHECK(n, f) ((n) & (f))
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
#if defined(PLATFORM_DRM)
|
||||
typedef struct {
|
||||
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
|
||||
} InputEventWorker;
|
||||
#endif
|
||||
|
||||
typedef struct { int x; int y; } Point;
|
||||
typedef struct { unsigned int width; unsigned int height; } Size;
|
||||
|
||||
// Core global state context data
|
||||
typedef struct CoreData {
|
||||
struct {
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
GLFWwindow *handle; // GLFW window handle (graphic device)
|
||||
#endif
|
||||
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM)
|
||||
#if defined(PLATFORM_DRM)
|
||||
int fd; // File descriptor for /dev/dri/...
|
||||
drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector
|
||||
drmModeCrtc *crtc; // CRT Controller
|
||||
int modeIndex; // Index of the used mode of connector->modes
|
||||
struct gbm_device *gbmDevice; // GBM device
|
||||
struct gbm_surface *gbmSurface; // GBM surface
|
||||
struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping)
|
||||
uint32_t prevFB; // Previous GBM framebufer (during frame swapping)
|
||||
#endif // PLATFORM_DRM
|
||||
EGLDisplay device; // Native display device (physical screen connection)
|
||||
EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
|
||||
EGLContext context; // Graphic context, mode in which drawing can be done
|
||||
EGLConfig config; // Graphic config
|
||||
#endif
|
||||
const char *title; // Window text title const pointer
|
||||
unsigned int flags; // Configuration flags (bit based), keeps window state
|
||||
bool ready; // Check if window has been initialized successfully
|
||||
bool fullscreen; // Check if fullscreen mode is enabled
|
||||
bool shouldClose; // Check if window set for closing
|
||||
bool resizedLastFrame; // Check if window has been resized last frame
|
||||
bool eventWaiting; // Wait for events before ending frame
|
||||
|
||||
Point position; // Window position (required on fullscreen toggle)
|
||||
Point previousPosition; // Window previous position (required on borderless windowed toggle)
|
||||
Size display; // Display width and height (monitor, device-screen, LCD, ...)
|
||||
Size screen; // Screen width and height (used render area)
|
||||
Size previousScreen; // Screen previous width and height (required on borderless windowed toggle)
|
||||
Size currentFbo; // Current render width and height (depends on active fbo)
|
||||
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)
|
||||
|
||||
char **dropFilepaths; // Store dropped files paths pointers (provided by GLFW)
|
||||
unsigned int dropFileCount; // Count dropped files strings
|
||||
|
||||
} Window;
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
struct {
|
||||
bool appEnabled; // Flag to detect if app is active ** = true
|
||||
struct android_app *app; // Android activity
|
||||
struct android_poll_source *source; // Android events polling source
|
||||
bool contextRebindRequired; // Used to know context rebind required
|
||||
} Android;
|
||||
#endif
|
||||
struct {
|
||||
const char *basePath; // Base path for data storage
|
||||
} Storage;
|
||||
struct {
|
||||
#if defined(PLATFORM_DRM)
|
||||
InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event<N>"
|
||||
#endif
|
||||
struct {
|
||||
int exitKey; // Default exit key
|
||||
char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state
|
||||
char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state
|
||||
// NOTE: Since key press logic involves comparing prev vs cur key state, we need to handle key repeats specially
|
||||
char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame.
|
||||
|
||||
int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
|
||||
int keyPressedQueueCount; // Input keys queue count
|
||||
|
||||
int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode)
|
||||
int charPressedQueueCount; // Input characters queue count
|
||||
|
||||
#if defined(PLATFORM_DRM)
|
||||
int defaultMode; // Default keyboard mode
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
bool evtMode; // Keyboard in event mode
|
||||
#endif
|
||||
int defaultFileFlags; // Default IO file flags
|
||||
struct termios defaultSettings; // Default keyboard settings
|
||||
int fd; // File descriptor for the evdev keyboard
|
||||
#endif
|
||||
} Keyboard;
|
||||
struct {
|
||||
Vector2 offset; // Mouse offset
|
||||
Vector2 scale; // Mouse scaling
|
||||
Vector2 currentPosition; // Mouse position on screen
|
||||
Vector2 previousPosition; // Previous mouse position
|
||||
|
||||
int cursor; // Tracks current mouse cursor
|
||||
bool cursorHidden; // Track if cursor is hidden
|
||||
bool cursorOnScreen; // Tracks if cursor is inside client area
|
||||
|
||||
char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state
|
||||
char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state
|
||||
Vector2 currentWheelMove; // Registers current mouse wheel variation
|
||||
Vector2 previousWheelMove; // Registers previous mouse wheel variation
|
||||
#if defined(PLATFORM_DRM)
|
||||
Vector2 eventWheelMove; // Registers the event mouse wheel variation
|
||||
// NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update
|
||||
char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
|
||||
#endif
|
||||
} Mouse;
|
||||
struct {
|
||||
int pointCount; // Number of touch points active
|
||||
int pointId[MAX_TOUCH_POINTS]; // Point identifiers
|
||||
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
|
||||
} Touch;
|
||||
struct {
|
||||
int lastButtonPressed; // Register last gamepad button pressed
|
||||
int axisCount; // Register number of available gamepad axis
|
||||
bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready
|
||||
char name[MAX_GAMEPADS][64]; // Gamepad name holder
|
||||
char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state
|
||||
char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state
|
||||
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state
|
||||
#if defined(PLATFORM_DRM)
|
||||
pthread_t threadId; // Gamepad reading thread id
|
||||
int streamId[MAX_GAMEPADS]; // Gamepad device file descriptor
|
||||
#endif
|
||||
} Gamepad;
|
||||
} Input;
|
||||
struct {
|
||||
double current; // Current time measure
|
||||
double previous; // Previous time measure
|
||||
double update; // Time measure for frame update
|
||||
double draw; // Time measure for frame draw
|
||||
double frame; // Time measure for one frame
|
||||
double target; // Desired time for one frame, if 0 not applied
|
||||
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM)
|
||||
unsigned long long int base; // Base time measure for hi-res timer
|
||||
#endif
|
||||
unsigned int frameCounter; // Frame counter
|
||||
} Time;
|
||||
} CoreData;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported symbol, required for some bindings
|
||||
|
||||
static CoreData CORE = { 0 }; // Global CORE state context
|
||||
CoreData CORE = { 0 }; // Global CORE state context
|
||||
|
||||
#if defined(SUPPORT_SCREEN_CAPTURE)
|
||||
static int screenshotCounter = 0; // Screenshots counter
|
||||
|
|
@ -644,16 +392,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd);
|
|||
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
|
||||
static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
|
||||
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
||||
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
|
||||
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_DRM)
|
||||
static void InitKeyboard(void); // Initialize raw keyboard system
|
||||
static void RestoreKeyboard(void); // Restore keyboard system
|
||||
|
|
@ -731,221 +469,6 @@ struct android_app *GetAndroidApp(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Initialize window and OpenGL context
|
||||
// NOTE: data parameter could be used to pass any kind of required data to the initialization
|
||||
void InitWindow(int width, int height, const char *title)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
|
||||
|
||||
TRACELOG(LOG_INFO, "Supported raylib modules:");
|
||||
TRACELOG(LOG_INFO, " > rcore:..... loaded (mandatory)");
|
||||
TRACELOG(LOG_INFO, " > rlgl:...... loaded (mandatory)");
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
TRACELOG(LOG_INFO, " > rshapes:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rshapes:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXTURES)
|
||||
TRACELOG(LOG_INFO, " > rtextures:. loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtextures:. not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT)
|
||||
TRACELOG(LOG_INFO, " > rtext:..... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtext:..... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RMODELS)
|
||||
TRACELOG(LOG_INFO, " > rmodels:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rmodels:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RAUDIO)
|
||||
TRACELOG(LOG_INFO, " > raudio:.... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
|
||||
#endif
|
||||
|
||||
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
|
||||
|
||||
// Initialize global input state
|
||||
memset(&CORE.Input, 0, sizeof(CORE.Input));
|
||||
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
|
||||
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
|
||||
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
|
||||
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
#if defined(SUPPORT_EVENTS_WAITING)
|
||||
CORE.Window.eventWaiting = true;
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
CORE.Window.currentFbo.width = width;
|
||||
CORE.Window.currentFbo.height = height;
|
||||
|
||||
// Set desired windows flags before initializing anything
|
||||
ANativeActivity_setWindowFlags(CORE.Android.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
|
||||
|
||||
int orientation = AConfiguration_getOrientation(CORE.Android.app->config);
|
||||
|
||||
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");
|
||||
|
||||
// TODO: Automatic orientation doesn't seem to work
|
||||
if (width <= height)
|
||||
{
|
||||
AConfiguration_setOrientation(CORE.Android.app->config, ACONFIGURATION_ORIENTATION_PORT);
|
||||
TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to portrait");
|
||||
}
|
||||
else
|
||||
{
|
||||
AConfiguration_setOrientation(CORE.Android.app->config, ACONFIGURATION_ORIENTATION_LAND);
|
||||
TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to landscape");
|
||||
}
|
||||
|
||||
//AConfiguration_getDensity(CORE.Android.app->config);
|
||||
//AConfiguration_getKeyboard(CORE.Android.app->config);
|
||||
//AConfiguration_getScreenSize(CORE.Android.app->config);
|
||||
//AConfiguration_getScreenLong(CORE.Android.app->config);
|
||||
|
||||
// Initialize App command system
|
||||
// NOTE: On APP_CMD_INIT_WINDOW -> InitGraphicsDevice(), InitTimer(), LoadFontDefault()...
|
||||
CORE.Android.app->onAppCmd = AndroidCommandCallback;
|
||||
|
||||
// Initialize input events system
|
||||
CORE.Android.app->onInputEvent = AndroidInputCallback;
|
||||
|
||||
// Initialize assets manager
|
||||
InitAssetManager(CORE.Android.app->activity->assetManager, CORE.Android.app->activity->internalDataPath);
|
||||
|
||||
// Initialize base path for storage
|
||||
CORE.Storage.basePath = CORE.Android.app->activity->internalDataPath;
|
||||
|
||||
TRACELOG(LOG_INFO, "ANDROID: App initialized successfully");
|
||||
|
||||
// Android ALooper_pollAll() variables
|
||||
int pollResult = 0;
|
||||
int pollEvents = 0;
|
||||
|
||||
// Wait for window to be initialized (display and context)
|
||||
while (!CORE.Window.ready)
|
||||
{
|
||||
// Process events loop
|
||||
while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&CORE.Android.source)) >= 0)
|
||||
{
|
||||
// Process this event
|
||||
if (CORE.Android.source != NULL) CORE.Android.source->process(CORE.Android.app, CORE.Android.source);
|
||||
|
||||
// NOTE: Never close window, native activity is controlled by the system!
|
||||
//if (CORE.Android.app->destroyRequested != 0) CORE.Window.shouldClose = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) || defined(PLATFORM_DRM)
|
||||
// Initialize graphics device (display device and OpenGL context)
|
||||
// NOTE: returns true if window and graphic device has been initialized successfully
|
||||
CORE.Window.ready = InitGraphicsDevice(width, height);
|
||||
|
||||
// If graphic device is no properly initialized, we end program
|
||||
if (!CORE.Window.ready)
|
||||
{
|
||||
TRACELOG(LOG_FATAL, "Failed to initialize Graphic Device");
|
||||
return;
|
||||
}
|
||||
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
|
||||
|
||||
// Initialize hi-res timer
|
||||
InitTimer();
|
||||
|
||||
// Initialize random seed
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
// Initialize base path for storage
|
||||
CORE.Storage.basePath = GetWorkingDirectory();
|
||||
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
// Load default font
|
||||
// WARNING: External function: Module required: rtext
|
||||
LoadFontDefault();
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
// Set font white rectangle for shapes drawing, so shapes and text can be batched together
|
||||
// WARNING: rshapes module is required, if not available, default internal white rectangle is used
|
||||
Rectangle rec = GetFontDefault().recs[95];
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
{
|
||||
// NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
// Set default texture and rectangle to be used for shapes drawing
|
||||
// NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
|
||||
Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
|
||||
SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// Set default font texture filter for HighDPI (blurry)
|
||||
// RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
|
||||
rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
|
||||
rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_DRM)
|
||||
// Initialize raw input system
|
||||
InitEvdevInput(); // Evdev inputs initialization
|
||||
InitGamepad(); // Gamepad init
|
||||
InitKeyboard(); // Keyboard init (stdin)
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
// Setup callback functions for the DOM events
|
||||
emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
|
||||
|
||||
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
|
||||
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
|
||||
//emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
// Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
|
||||
//emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
// Trigger this once to get initial window sizing
|
||||
//EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
|
||||
|
||||
// Support keyboard events -> Not used, GLFW.JS takes care of that
|
||||
//emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
|
||||
//emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
|
||||
|
||||
// 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);
|
||||
|
||||
// Support gamepad events (not provided by GLFW3 on emscripten)
|
||||
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_EVENTS_AUTOMATION)
|
||||
events = (AutomationEvent *)RL_CALLOC(MAX_CODE_AUTOMATION_EVENTS, sizeof(AutomationEvent));
|
||||
CORE.Time.frameCounter = 0;
|
||||
#endif
|
||||
|
||||
#endif // PLATFORM_DESKTOP || PLATFORM_WEB || PLATFORM_DRM
|
||||
}
|
||||
|
||||
// Close window and unload OpenGL context
|
||||
void CloseWindow(void)
|
||||
{
|
||||
|
|
@ -6150,146 +5673,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
// Register fullscreen change events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
|
||||
{
|
||||
// TODO: Implement EmscriptenFullscreenChangeCallback()?
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register window resize event
|
||||
static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
{
|
||||
// TODO: Implement EmscriptenWindowResizedCallback()?
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
EM_JS(int, GetCanvasWidth, (), { return canvas.clientWidth; });
|
||||
EM_JS(int, GetCanvasHeight, (), { return canvas.clientHeight; });
|
||||
|
||||
// Register DOM element resize event
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
{
|
||||
// Don't resize non-resizeable windows
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
|
||||
|
||||
// This event is called whenever the window changes sizes,
|
||||
// so the size of the canvas object is explicitly retrieved below
|
||||
int width = GetCanvasWidth();
|
||||
int height = GetCanvasHeight();
|
||||
emscripten_set_canvas_element_size("#canvas",width,height);
|
||||
|
||||
SetupViewport(width, height); // Reset viewport and projection matrix for new size
|
||||
|
||||
CORE.Window.currentFbo.width = width;
|
||||
CORE.Window.currentFbo.height = height;
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
|
||||
if (IsWindowFullscreen()) return 1;
|
||||
|
||||
// Set current screen size
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Register mouse input events
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// This is only for registering mouse click events with emscripten and doesn't need to do anything
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register connected/disconnected gamepads events
|
||||
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
||||
{
|
||||
/*
|
||||
TRACELOGD("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"",
|
||||
eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
|
||||
gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
|
||||
|
||||
for (int i = 0; i < gamepadEvent->numAxes; ++i) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]);
|
||||
for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
|
||||
*/
|
||||
|
||||
if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS))
|
||||
{
|
||||
CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
|
||||
sprintf(CORE.Input.Gamepad.name[gamepadEvent->index],"%s",gamepadEvent->id);
|
||||
}
|
||||
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register touch input events
|
||||
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
||||
{
|
||||
// Register touch points count
|
||||
CORE.Input.Touch.pointCount = touchEvent->numTouches;
|
||||
|
||||
double canvasWidth = 0.0;
|
||||
double canvasHeight = 0.0;
|
||||
// NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
|
||||
// we are looking for actual CSS size: canvas.style.width and canvas.style.height
|
||||
//EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
|
||||
emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight);
|
||||
|
||||
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
// Register touch points id
|
||||
CORE.Input.Touch.pointId[i] = touchEvent->touches[i].identifier;
|
||||
|
||||
// Register touch points position
|
||||
CORE.Input.Touch.position[i] = (Vector2){ touchEvent->touches[i].targetX, touchEvent->touches[i].targetY };
|
||||
|
||||
// Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height
|
||||
CORE.Input.Touch.position[i].x *= ((float)GetScreenWidth()/(float)canvasWidth);
|
||||
CORE.Input.Touch.position[i].y *= ((float)GetScreenHeight()/(float)canvasHeight);
|
||||
|
||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
|
||||
}
|
||||
|
||||
#if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_WEB
|
||||
GestureEvent gestureEvent = { 0 };
|
||||
|
||||
gestureEvent.pointCount = CORE.Input.Touch.pointCount;
|
||||
|
||||
// Register touch actions
|
||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_ACTION_UP;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL;
|
||||
|
||||
for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
|
||||
gestureEvent.position[i] = CORE.Input.Touch.position[i];
|
||||
|
||||
// Normalize gestureEvent.position[i]
|
||||
gestureEvent.position[i].x /= (float)GetScreenWidth();
|
||||
gestureEvent.position[i].y /= (float)GetScreenHeight();
|
||||
}
|
||||
|
||||
// Gesture data is sent to gestures system for processing
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
|
||||
// Reset the pointCount for web, if it was the last Touch End event
|
||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHEND && CORE.Input.Touch.pointCount == 1) CORE.Input.Touch.pointCount = 0;
|
||||
#endif
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_DRM)
|
||||
// Initialize Keyboard system (using standard input)
|
||||
static void InitKeyboard(void)
|
||||
|
|
|
|||
221
src/rcore.h
Normal file
221
src/rcore.h
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
#ifndef RCORE_H
|
||||
#define RCORE_H
|
||||
|
||||
// PROVIDE A HEADER TO BE USED BY ALL THE rcore_* IMPLEMENTATIONS.
|
||||
/*
|
||||
|
||||
Status:
|
||||
InitWindow: DRM,
|
||||
|
||||
*/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#if defined(PLATFORM_DRM)
|
||||
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
#ifndef MAX_FILEPATH_CAPACITY
|
||||
#define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
|
||||
#endif
|
||||
#ifndef MAX_FILEPATH_LENGTH
|
||||
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
|
||||
#endif
|
||||
|
||||
#ifndef MAX_KEYBOARD_KEYS
|
||||
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
|
||||
#endif
|
||||
#ifndef MAX_MOUSE_BUTTONS
|
||||
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
|
||||
#endif
|
||||
#ifndef MAX_GAMEPADS
|
||||
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_AXIS
|
||||
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
|
||||
#endif
|
||||
#ifndef MAX_GAMEPAD_BUTTONS
|
||||
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
||||
#endif
|
||||
#ifndef MAX_TOUCH_POINTS
|
||||
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
|
||||
#endif
|
||||
#ifndef MAX_KEY_PRESSED_QUEUE
|
||||
#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
|
||||
#endif
|
||||
#ifndef MAX_CHAR_PRESSED_QUEUE
|
||||
#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
|
||||
#endif
|
||||
|
||||
#ifndef MAX_DECOMPRESSION_SIZE
|
||||
#define MAX_DECOMPRESSION_SIZE 64 // Maximum size allocated for decompression in MB
|
||||
#endif
|
||||
|
||||
// Flags operation macros
|
||||
#define FLAG_SET(n, f) ((n) |= (f))
|
||||
#define FLAG_CLEAR(n, f) ((n) &= ~(f))
|
||||
#define FLAG_TOGGLE(n, f) ((n) ^= (f))
|
||||
#define FLAG_CHECK(n, f) ((n) & (f))
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
typedef struct { int x; int y; } Point;
|
||||
typedef struct { unsigned int width; unsigned int height; } Size;
|
||||
|
||||
|
||||
// Core global state context data
|
||||
typedef struct CoreData {
|
||||
struct {
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
GLFWwindow *handle; // GLFW window handle (graphic device)
|
||||
#endif
|
||||
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM)
|
||||
#if defined(PLATFORM_DRM)
|
||||
int fd; // File descriptor for /dev/dri/...
|
||||
drmModeConnector *connector; // Direct Rendering Manager (DRM) mode connector
|
||||
drmModeCrtc *crtc; // CRT Controller
|
||||
int modeIndex; // Index of the used mode of connector->modes
|
||||
struct gbm_device *gbmDevice; // GBM device
|
||||
struct gbm_surface *gbmSurface; // GBM surface
|
||||
struct gbm_bo *prevBO; // Previous GBM buffer object (during frame swapping)
|
||||
uint32_t prevFB; // Previous GBM framebufer (during frame swapping)
|
||||
#endif // PLATFORM_DRM
|
||||
EGLDisplay device; // Native display device (physical screen connection)
|
||||
EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
|
||||
EGLContext context; // Graphic context, mode in which drawing can be done
|
||||
EGLConfig config; // Graphic config
|
||||
#endif
|
||||
const char *title; // Window text title const pointer
|
||||
unsigned int flags; // Configuration flags (bit based), keeps window state
|
||||
bool ready; // Check if window has been initialized successfully
|
||||
bool fullscreen; // Check if fullscreen mode is enabled
|
||||
bool shouldClose; // Check if window set for closing
|
||||
bool resizedLastFrame; // Check if window has been resized last frame
|
||||
bool eventWaiting; // Wait for events before ending frame
|
||||
|
||||
Point position; // Window position (required on fullscreen toggle)
|
||||
Point previousPosition; // Window previous position (required on borderless windowed toggle)
|
||||
Size display; // Display width and height (monitor, device-screen, LCD, ...)
|
||||
Size screen; // Screen width and height (used render area)
|
||||
Size previousScreen; // Screen previous width and height (required on borderless windowed toggle)
|
||||
Size currentFbo; // Current render width and height (depends on active fbo)
|
||||
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)
|
||||
|
||||
char **dropFilepaths; // Store dropped files paths pointers (provided by GLFW)
|
||||
unsigned int dropFileCount; // Count dropped files strings
|
||||
|
||||
} Window;
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
struct {
|
||||
bool appEnabled; // Flag to detect if app is active ** = true
|
||||
struct android_app *app; // Android activity
|
||||
struct android_poll_source *source; // Android events polling source
|
||||
bool contextRebindRequired; // Used to know context rebind required
|
||||
} Android;
|
||||
#endif
|
||||
struct {
|
||||
const char *basePath; // Base path for data storage
|
||||
} Storage;
|
||||
struct {
|
||||
#if defined(PLATFORM_DRM)
|
||||
InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event<N>"
|
||||
#endif
|
||||
struct {
|
||||
int exitKey; // Default exit key
|
||||
char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state
|
||||
char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state
|
||||
// NOTE: Since key press logic involves comparing prev vs cur key state, we need to handle key repeats specially
|
||||
char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame.
|
||||
|
||||
int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
|
||||
int keyPressedQueueCount; // Input keys queue count
|
||||
|
||||
int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode)
|
||||
int charPressedQueueCount; // Input characters queue count
|
||||
|
||||
#if defined(PLATFORM_DRM)
|
||||
int defaultMode; // Default keyboard mode
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
bool evtMode; // Keyboard in event mode
|
||||
#endif
|
||||
int defaultFileFlags; // Default IO file flags
|
||||
struct termios defaultSettings; // Default keyboard settings
|
||||
int fd; // File descriptor for the evdev keyboard
|
||||
#endif
|
||||
} Keyboard;
|
||||
struct {
|
||||
Vector2 offset; // Mouse offset
|
||||
Vector2 scale; // Mouse scaling
|
||||
Vector2 currentPosition; // Mouse position on screen
|
||||
Vector2 previousPosition; // Previous mouse position
|
||||
|
||||
int cursor; // Tracks current mouse cursor
|
||||
bool cursorHidden; // Track if cursor is hidden
|
||||
bool cursorOnScreen; // Tracks if cursor is inside client area
|
||||
|
||||
char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state
|
||||
char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state
|
||||
Vector2 currentWheelMove; // Registers current mouse wheel variation
|
||||
Vector2 previousWheelMove; // Registers previous mouse wheel variation
|
||||
#if defined(PLATFORM_DRM)
|
||||
Vector2 eventWheelMove; // Registers the event mouse wheel variation
|
||||
// NOTE: currentButtonState[] can't be written directly due to multithreading, app could miss the update
|
||||
char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
|
||||
#endif
|
||||
} Mouse;
|
||||
struct {
|
||||
int pointCount; // Number of touch points active
|
||||
int pointId[MAX_TOUCH_POINTS]; // Point identifiers
|
||||
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
|
||||
} Touch;
|
||||
struct {
|
||||
int lastButtonPressed; // Register last gamepad button pressed
|
||||
int axisCount; // Register number of available gamepad axis
|
||||
bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready
|
||||
char name[MAX_GAMEPADS][64]; // Gamepad name holder
|
||||
char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state
|
||||
char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state
|
||||
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state
|
||||
#if defined(PLATFORM_DRM)
|
||||
pthread_t threadId; // Gamepad reading thread id
|
||||
int streamId[MAX_GAMEPADS]; // Gamepad device file descriptor
|
||||
#endif
|
||||
} Gamepad;
|
||||
} Input;
|
||||
struct {
|
||||
double current; // Current time measure
|
||||
double previous; // Previous time measure
|
||||
double update; // Time measure for frame update
|
||||
double draw; // Time measure for frame draw
|
||||
double frame; // Time measure for one frame
|
||||
double target; // Desired time for one frame, if 0 not applied
|
||||
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_DRM)
|
||||
unsigned long long int base; // Base time measure for hi-res timer
|
||||
#endif
|
||||
unsigned int frameCounter; // Frame counter
|
||||
} Time;
|
||||
} CoreData;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
extern CoreData CORE;
|
||||
|
||||
#endif
|
||||
123
src/rcore_android.c
Normal file
123
src/rcore_android.c
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "raylib.h"
|
||||
#include "rcore.h"
|
||||
|
||||
//#include <android/sensor.h> // Required for: Android sensors functions (accelerometer, gyroscope, light...)
|
||||
#include <android/window.h> // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
|
||||
#include <android_native_app_glue.h> // Required for: android_app struct and activity management
|
||||
#include <jni.h> // Required for: JNIEnv and JavaVM [Used in OpenURL()]
|
||||
|
||||
#include <EGL/egl.h> // Native platform windowing system interface
|
||||
//#include <GLES2/gl2.h> // OpenGL ES 2.0 library (not required in this module, only in rlgl)
|
||||
|
||||
// Initialize window and OpenGL context
|
||||
// NOTE: data parameter could be used to pass any kind of required data to the initialization
|
||||
void InitWindow(int width, int height, const char *title)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
|
||||
|
||||
TRACELOG(LOG_INFO, "Supported raylib modules:");
|
||||
TRACELOG(LOG_INFO, " > rcore:..... loaded (mandatory)");
|
||||
TRACELOG(LOG_INFO, " > rlgl:...... loaded (mandatory)");
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
TRACELOG(LOG_INFO, " > rshapes:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rshapes:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXTURES)
|
||||
TRACELOG(LOG_INFO, " > rtextures:. loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtextures:. not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT)
|
||||
TRACELOG(LOG_INFO, " > rtext:..... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtext:..... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RMODELS)
|
||||
TRACELOG(LOG_INFO, " > rmodels:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rmodels:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RAUDIO)
|
||||
TRACELOG(LOG_INFO, " > raudio:.... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
|
||||
#endif
|
||||
|
||||
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
|
||||
|
||||
// Initialize global input state
|
||||
memset(&CORE.Input, 0, sizeof(CORE.Input));
|
||||
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
|
||||
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
|
||||
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
|
||||
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
#if defined(SUPPORT_EVENTS_WAITING)
|
||||
CORE.Window.eventWaiting = true;
|
||||
#endif
|
||||
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
CORE.Window.currentFbo.width = width;
|
||||
CORE.Window.currentFbo.height = height;
|
||||
|
||||
// Set desired windows flags before initializing anything
|
||||
ANativeActivity_setWindowFlags(CORE.Android.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER
|
||||
|
||||
int orientation = AConfiguration_getOrientation(CORE.Android.app->config);
|
||||
|
||||
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");
|
||||
|
||||
// TODO: Automatic orientation doesn't seem to work
|
||||
if (width <= height)
|
||||
{
|
||||
AConfiguration_setOrientation(CORE.Android.app->config, ACONFIGURATION_ORIENTATION_PORT);
|
||||
TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to portrait");
|
||||
}
|
||||
else
|
||||
{
|
||||
AConfiguration_setOrientation(CORE.Android.app->config, ACONFIGURATION_ORIENTATION_LAND);
|
||||
TRACELOG(LOG_WARNING, "ANDROID: Window orientation changed to landscape");
|
||||
}
|
||||
|
||||
//AConfiguration_getDensity(CORE.Android.app->config);
|
||||
//AConfiguration_getKeyboard(CORE.Android.app->config);
|
||||
//AConfiguration_getScreenSize(CORE.Android.app->config);
|
||||
//AConfiguration_getScreenLong(CORE.Android.app->config);
|
||||
|
||||
// Initialize App command system
|
||||
// NOTE: On APP_CMD_INIT_WINDOW -> InitGraphicsDevice(), InitTimer(), LoadFontDefault()...
|
||||
CORE.Android.app->onAppCmd = AndroidCommandCallback;
|
||||
|
||||
// Initialize input events system
|
||||
CORE.Android.app->onInputEvent = AndroidInputCallback;
|
||||
|
||||
// Initialize assets manager
|
||||
InitAssetManager(CORE.Android.app->activity->assetManager, CORE.Android.app->activity->internalDataPath);
|
||||
|
||||
// Initialize base path for storage
|
||||
CORE.Storage.basePath = CORE.Android.app->activity->internalDataPath;
|
||||
|
||||
TRACELOG(LOG_INFO, "ANDROID: App initialized successfully");
|
||||
|
||||
// Android ALooper_pollAll() variables
|
||||
int pollResult = 0;
|
||||
int pollEvents = 0;
|
||||
|
||||
// Wait for window to be initialized (display and context)
|
||||
while (!CORE.Window.ready)
|
||||
{
|
||||
// Process events loop
|
||||
while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void**)&CORE.Android.source)) >= 0)
|
||||
{
|
||||
// Process this event
|
||||
if (CORE.Android.source != NULL) CORE.Android.source->process(CORE.Android.app, CORE.Android.source);
|
||||
|
||||
// NOTE: Never close window, native activity is controlled by the system!
|
||||
//if (CORE.Android.app->destroyRequested != 0) CORE.Window.shouldClose = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
114
src/rcore_desktop.c
Normal file
114
src/rcore_desktop.c
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "raylib.h"
|
||||
#include "rcore.h"
|
||||
|
||||
// Initialize window and OpenGL context
|
||||
// NOTE: data parameter could be used to pass any kind of required data to the initialization
|
||||
void InitWindow(int width, int height, const char *title)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
|
||||
|
||||
TRACELOG(LOG_INFO, "Supported raylib modules:");
|
||||
TRACELOG(LOG_INFO, " > rcore:..... loaded (mandatory)");
|
||||
TRACELOG(LOG_INFO, " > rlgl:...... loaded (mandatory)");
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
TRACELOG(LOG_INFO, " > rshapes:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rshapes:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXTURES)
|
||||
TRACELOG(LOG_INFO, " > rtextures:. loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtextures:. not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT)
|
||||
TRACELOG(LOG_INFO, " > rtext:..... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtext:..... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RMODELS)
|
||||
TRACELOG(LOG_INFO, " > rmodels:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rmodels:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RAUDIO)
|
||||
TRACELOG(LOG_INFO, " > raudio:.... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
|
||||
#endif
|
||||
|
||||
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
|
||||
|
||||
// Initialize global input state
|
||||
memset(&CORE.Input, 0, sizeof(CORE.Input));
|
||||
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
|
||||
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
|
||||
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
|
||||
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
#if defined(SUPPORT_EVENTS_WAITING)
|
||||
CORE.Window.eventWaiting = true;
|
||||
#endif
|
||||
// Initialize graphics device (display device and OpenGL context)
|
||||
// NOTE: returns true if window and graphic device has been initialized successfully
|
||||
CORE.Window.ready = InitGraphicsDevice(width, height);
|
||||
|
||||
// If graphic device is no properly initialized, we end program
|
||||
if (!CORE.Window.ready)
|
||||
{
|
||||
TRACELOG(LOG_FATAL, "Failed to initialize Graphic Device");
|
||||
return;
|
||||
}
|
||||
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
|
||||
|
||||
// Initialize hi-res timer
|
||||
InitTimer();
|
||||
|
||||
// Initialize random seed
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
// Initialize base path for storage
|
||||
CORE.Storage.basePath = GetWorkingDirectory();
|
||||
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
// Load default font
|
||||
// WARNING: External function: Module required: rtext
|
||||
LoadFontDefault();
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
// Set font white rectangle for shapes drawing, so shapes and text can be batched together
|
||||
// WARNING: rshapes module is required, if not available, default internal white rectangle is used
|
||||
Rectangle rec = GetFontDefault().recs[95];
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
{
|
||||
// NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
// Set default texture and rectangle to be used for shapes drawing
|
||||
// NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
|
||||
Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
|
||||
SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// Set default font texture filter for HighDPI (blurry)
|
||||
// RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
|
||||
rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
|
||||
rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_EVENTS_AUTOMATION)
|
||||
events = (AutomationEvent *)RL_CALLOC(MAX_CODE_AUTOMATION_EVENTS, sizeof(AutomationEvent));
|
||||
CORE.Time.frameCounter = 0;
|
||||
#endif
|
||||
}
|
||||
154
src/rcore_drm.c
Normal file
154
src/rcore_drm.c
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "raylib.h"
|
||||
#include "rcore.h"
|
||||
|
||||
#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
|
||||
|
||||
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
|
||||
#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
|
||||
|
||||
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
|
||||
#include <xf86drm.h> // Direct Rendering Manager user-level library interface
|
||||
#include <xf86drmMode.h> // Direct Rendering Manager mode setting (KMS) interface
|
||||
|
||||
#include "EGL/egl.h" // Native platform windowing system interface
|
||||
#include "EGL/eglext.h" // EGL extensions
|
||||
|
||||
typedef struct
|
||||
{
|
||||
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
|
||||
} InputEventWorker;
|
||||
|
||||
// Initialize window and OpenGL context
|
||||
// NOTE: data parameter could be used to pass any kind of required data to the initialization
|
||||
void InitWindow(int width, int height, const char *title)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
|
||||
|
||||
TRACELOG(LOG_INFO, "Supported raylib modules:");
|
||||
TRACELOG(LOG_INFO, " > rcore:..... loaded (mandatory)");
|
||||
TRACELOG(LOG_INFO, " > rlgl:...... loaded (mandatory)");
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
TRACELOG(LOG_INFO, " > rshapes:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rshapes:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXTURES)
|
||||
TRACELOG(LOG_INFO, " > rtextures:. loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtextures:. not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT)
|
||||
TRACELOG(LOG_INFO, " > rtext:..... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtext:..... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RMODELS)
|
||||
TRACELOG(LOG_INFO, " > rmodels:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rmodels:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RAUDIO)
|
||||
TRACELOG(LOG_INFO, " > raudio:.... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
|
||||
#endif
|
||||
|
||||
if ((title != NULL) && (title[0] != 0))
|
||||
CORE.Window.title = title;
|
||||
|
||||
// Initialize global input state
|
||||
memset(&CORE.Input, 0, sizeof(CORE.Input));
|
||||
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
|
||||
CORE.Input.Mouse.scale = (Vector2){1.0f, 1.0f};
|
||||
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
|
||||
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
#if defined(SUPPORT_EVENTS_WAITING)
|
||||
CORE.Window.eventWaiting = true;
|
||||
#endif
|
||||
|
||||
// Initialize graphics device (display device and OpenGL context)
|
||||
// NOTE: returns true if window and graphic device has been initialized successfully
|
||||
CORE.Window.ready = InitGraphicsDevice(width, height);
|
||||
|
||||
// If graphic device is no properly initialized, we end program
|
||||
if (!CORE.Window.ready)
|
||||
{
|
||||
TRACELOG(LOG_FATAL, "Failed to initialize Graphic Device");
|
||||
return;
|
||||
}
|
||||
else
|
||||
SetWindowPosition(GetMonitorWidth(GetCurrentMonitor()) / 2 - CORE.Window.screen.width / 2, GetMonitorHeight(GetCurrentMonitor()) / 2 - CORE.Window.screen.height / 2);
|
||||
|
||||
// Initialize hi-res timer
|
||||
InitTimer();
|
||||
|
||||
// Initialize random seed
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
// Initialize base path for storage
|
||||
CORE.Storage.basePath = GetWorkingDirectory();
|
||||
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
// Load default font
|
||||
// WARNING: External function: Module required: rtext
|
||||
LoadFontDefault();
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
// Set font white rectangle for shapes drawing, so shapes and text can be batched together
|
||||
// WARNING: rshapes module is required, if not available, default internal white rectangle is used
|
||||
Rectangle rec = GetFontDefault().recs[95];
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
{
|
||||
// NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){rec.x + 2, rec.y + 2, 1, 1});
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2});
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
// Set default texture and rectangle to be used for shapes drawing
|
||||
// NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
|
||||
Texture2D texture = {rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8};
|
||||
SetShapesTexture(texture, (Rectangle){0.0f, 0.0f, 1.0f, 1.0f}); // WARNING: Module required: rshapes
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// Set default font texture filter for HighDPI (blurry)
|
||||
// RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
|
||||
rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
|
||||
rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize raw input system
|
||||
InitEvdevInput(); // Evdev inputs initialization
|
||||
InitGamepad(); // Gamepad init
|
||||
InitKeyboard(); // Keyboard init (stdin)
|
||||
|
||||
#if defined(SUPPORT_EVENTS_AUTOMATION)
|
||||
events = (AutomationEvent *)RL_CALLOC(MAX_CODE_AUTOMATION_EVENTS, sizeof(AutomationEvent));
|
||||
CORE.Time.frameCounter = 0;
|
||||
#endif
|
||||
}
|
||||
296
src/rcore_web.c
Normal file
296
src/rcore_web.c
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "raylib.h"
|
||||
#include "rcore.h"
|
||||
|
||||
#define GLFW_INCLUDE_ES2 // GLFW3: Enable OpenGL ES 2.0 (translated to WebGL)
|
||||
//#define GLFW_INCLUDE_ES3 // GLFW3: Enable OpenGL ES 3.0 (transalted to WebGL2?)
|
||||
#include "GLFW/glfw3.h" // GLFW3: Windows, OpenGL context and Input management
|
||||
#include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
|
||||
|
||||
#include <emscripten/emscripten.h> // Emscripten functionality for C
|
||||
#include <emscripten/html5.h> // Emscripten HTML5 library
|
||||
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
|
||||
static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
|
||||
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
||||
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
|
||||
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
|
||||
|
||||
// Initialize window and OpenGL context
|
||||
// NOTE: data parameter could be used to pass any kind of required data to the initialization
|
||||
void InitWindow(int width, int height, const char *title)
|
||||
{
|
||||
TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
|
||||
|
||||
TRACELOG(LOG_INFO, "Supported raylib modules:");
|
||||
TRACELOG(LOG_INFO, " > rcore:..... loaded (mandatory)");
|
||||
TRACELOG(LOG_INFO, " > rlgl:...... loaded (mandatory)");
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
TRACELOG(LOG_INFO, " > rshapes:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rshapes:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXTURES)
|
||||
TRACELOG(LOG_INFO, " > rtextures:. loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtextures:. not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT)
|
||||
TRACELOG(LOG_INFO, " > rtext:..... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rtext:..... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RMODELS)
|
||||
TRACELOG(LOG_INFO, " > rmodels:... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > rmodels:... not loaded (optional)");
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RAUDIO)
|
||||
TRACELOG(LOG_INFO, " > raudio:.... loaded (optional)");
|
||||
#else
|
||||
TRACELOG(LOG_INFO, " > raudio:.... not loaded (optional)");
|
||||
#endif
|
||||
|
||||
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
|
||||
|
||||
// Initialize global input state
|
||||
memset(&CORE.Input, 0, sizeof(CORE.Input));
|
||||
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
|
||||
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
|
||||
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
|
||||
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
#if defined(SUPPORT_EVENTS_WAITING)
|
||||
CORE.Window.eventWaiting = true;
|
||||
#endif
|
||||
// Initialize graphics device (display device and OpenGL context)
|
||||
// NOTE: returns true if window and graphic device has been initialized successfully
|
||||
CORE.Window.ready = InitGraphicsDevice(width, height);
|
||||
|
||||
// If graphic device is no properly initialized, we end program
|
||||
if (!CORE.Window.ready)
|
||||
{
|
||||
TRACELOG(LOG_FATAL, "Failed to initialize Graphic Device");
|
||||
return;
|
||||
}
|
||||
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
|
||||
|
||||
// Initialize hi-res timer
|
||||
InitTimer();
|
||||
|
||||
// Initialize random seed
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
// Initialize base path for storage
|
||||
CORE.Storage.basePath = GetWorkingDirectory();
|
||||
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
// Load default font
|
||||
// WARNING: External function: Module required: rtext
|
||||
LoadFontDefault();
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
// Set font white rectangle for shapes drawing, so shapes and text can be batched together
|
||||
// WARNING: rshapes module is required, if not available, default internal white rectangle is used
|
||||
Rectangle rec = GetFontDefault().recs[95];
|
||||
if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
|
||||
{
|
||||
// NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
// Set default texture and rectangle to be used for shapes drawing
|
||||
// NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
|
||||
Texture2D texture = { rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
|
||||
SetShapesTexture(texture, (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f }); // WARNING: Module required: rshapes
|
||||
#endif
|
||||
#endif
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// Set default font texture filter for HighDPI (blurry)
|
||||
// RL_TEXTURE_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
|
||||
rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MIN_FILTER, RL_TEXTURE_FILTER_LINEAR);
|
||||
rlTextureParameters(GetFontDefault().texture.id, RL_TEXTURE_MAG_FILTER, RL_TEXTURE_FILTER_LINEAR);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup callback functions for the DOM events
|
||||
emscripten_set_fullscreenchange_callback("#canvas", NULL, 1, EmscriptenFullscreenChangeCallback);
|
||||
|
||||
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
|
||||
// Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
|
||||
//emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
// Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
|
||||
//emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
|
||||
// Trigger this once to get initial window sizing
|
||||
//EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
|
||||
|
||||
// Support keyboard events -> Not used, GLFW.JS takes care of that
|
||||
//emscripten_set_keypress_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
|
||||
//emscripten_set_keydown_callback("#canvas", NULL, 1, EmscriptenKeyboardCallback);
|
||||
|
||||
// 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);
|
||||
|
||||
// Support gamepad events (not provided by GLFW3 on emscripten)
|
||||
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
|
||||
#if defined(SUPPORT_EVENTS_AUTOMATION)
|
||||
events = (AutomationEvent *)RL_CALLOC(MAX_CODE_AUTOMATION_EVENTS, sizeof(AutomationEvent));
|
||||
CORE.Time.frameCounter = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Register fullscreen change events
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
|
||||
{
|
||||
// TODO: Implement EmscriptenFullscreenChangeCallback()?
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register window resize event
|
||||
static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
{
|
||||
// TODO: Implement EmscriptenWindowResizedCallback()?
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
EM_JS(int, GetCanvasWidth, (), { return canvas.clientWidth; });
|
||||
EM_JS(int, GetCanvasHeight, (), { return canvas.clientHeight; });
|
||||
|
||||
// Register DOM element resize event
|
||||
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
|
||||
{
|
||||
// Don't resize non-resizeable windows
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
|
||||
|
||||
// This event is called whenever the window changes sizes,
|
||||
// so the size of the canvas object is explicitly retrieved below
|
||||
int width = GetCanvasWidth();
|
||||
int height = GetCanvasHeight();
|
||||
emscripten_set_canvas_element_size("#canvas",width,height);
|
||||
|
||||
SetupViewport(width, height); // Reset viewport and projection matrix for new size
|
||||
|
||||
CORE.Window.currentFbo.width = width;
|
||||
CORE.Window.currentFbo.height = height;
|
||||
CORE.Window.resizedLastFrame = true;
|
||||
|
||||
if (IsWindowFullscreen()) return 1;
|
||||
|
||||
// Set current screen size
|
||||
CORE.Window.screen.width = width;
|
||||
CORE.Window.screen.height = height;
|
||||
|
||||
// NOTE: Postprocessing texture is not scaled to new size
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Register mouse input events
|
||||
static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
|
||||
{
|
||||
// This is only for registering mouse click events with emscripten and doesn't need to do anything
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register connected/disconnected gamepads events
|
||||
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
||||
{
|
||||
/*
|
||||
TRACELOGD("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"",
|
||||
eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
|
||||
gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
|
||||
|
||||
for (int i = 0; i < gamepadEvent->numAxes; ++i) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]);
|
||||
for (int i = 0; i < gamepadEvent->numButtons; ++i) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
|
||||
*/
|
||||
|
||||
if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS))
|
||||
{
|
||||
CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
|
||||
sprintf(CORE.Input.Gamepad.name[gamepadEvent->index],"%s",gamepadEvent->id);
|
||||
}
|
||||
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
|
||||
// Register touch input events
|
||||
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
||||
{
|
||||
// Register touch points count
|
||||
CORE.Input.Touch.pointCount = touchEvent->numTouches;
|
||||
|
||||
double canvasWidth = 0.0;
|
||||
double canvasHeight = 0.0;
|
||||
// NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
|
||||
// we are looking for actual CSS size: canvas.style.width and canvas.style.height
|
||||
//EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
|
||||
emscripten_get_element_css_size("#canvas", &canvasWidth, &canvasHeight);
|
||||
|
||||
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
// Register touch points id
|
||||
CORE.Input.Touch.pointId[i] = touchEvent->touches[i].identifier;
|
||||
|
||||
// Register touch points position
|
||||
CORE.Input.Touch.position[i] = (Vector2){ touchEvent->touches[i].targetX, touchEvent->touches[i].targetY };
|
||||
|
||||
// Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height
|
||||
CORE.Input.Touch.position[i].x *= ((float)GetScreenWidth()/(float)canvasWidth);
|
||||
CORE.Input.Touch.position[i].y *= ((float)GetScreenHeight()/(float)canvasHeight);
|
||||
|
||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
|
||||
}
|
||||
|
||||
#if defined(SUPPORT_GESTURES_SYSTEM) // PLATFORM_WEB
|
||||
GestureEvent gestureEvent = { 0 };
|
||||
|
||||
gestureEvent.pointCount = CORE.Input.Touch.pointCount;
|
||||
|
||||
// Register touch actions
|
||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_ACTION_UP;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL;
|
||||
|
||||
for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||
{
|
||||
gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
|
||||
gestureEvent.position[i] = CORE.Input.Touch.position[i];
|
||||
|
||||
// Normalize gestureEvent.position[i]
|
||||
gestureEvent.position[i].x /= (float)GetScreenWidth();
|
||||
gestureEvent.position[i].y /= (float)GetScreenHeight();
|
||||
}
|
||||
|
||||
// Gesture data is sent to gestures system for processing
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
|
||||
// Reset the pointCount for web, if it was the last Touch End event
|
||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHEND && CORE.Input.Touch.pointCount == 1) CORE.Input.Touch.pointCount = 0;
|
||||
#endif
|
||||
|
||||
return 1; // The event was consumed by the callback handler
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user