diff --git a/examples/Makefile b/examples/Makefile index 21482851f..6ca8b6cfe 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -96,6 +96,12 @@ ifeq ($(PLATFORM),PLATFORM_RPI) PLATFORM_OS=LINUX endif endif +ifeq ($(PLATFORM),PLATFORM_DRM) + UNAMEOS=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + endif +endif # RAYLIB_PATH adjustment for different platforms. # If using GNU make, we can get the full path to the top of the tree. Windows? BSD? @@ -112,6 +118,9 @@ endif ifeq ($(PLATFORM),PLATFORM_RPI) RAYLIB_PATH ?= /home/pi/raylib endif +ifeq ($(PLATFORM),PLATFORM_DRM) + RAYLIB_PATH ?= /home/pi/raylib +endif ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables @@ -221,6 +230,9 @@ endif ifeq ($(PLATFORM),PLATFORM_RPI) CFLAGS += -std=gnu99 endif +ifeq ($(PLATFORM),PLATFORM_DRM) + CFLAGS += -std=gnu99 -DEGL_NO_X11 +endif ifeq ($(PLATFORM),PLATFORM_WEB) # -Os # size optimization # -O2 # optimization level 2, if used, also set --memory-init-file 0 @@ -259,6 +271,10 @@ ifeq ($(PLATFORM),PLATFORM_RPI) INCLUDE_PATHS += -I/opt/vc/include/interface/vmcs_host/linux INCLUDE_PATHS += -I/opt/vc/include/interface/vcos/pthreads endif +ifeq ($(PLATFORM),PLATFORM_DRM) + # DRM required libraries + INCLUDE_PATHS += -I/usr/include/libdrm +endif ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),BSD) # Consider -L$(RAYLIB_H_INSTALL_PATH) @@ -299,6 +315,10 @@ ifeq ($(PLATFORM),PLATFORM_RPI) LDFLAGS += -L/opt/vc/lib endif +ifeq ($(PLATFORM),PLATFORM_DRM) + LDFLAGS += -lGLESv2 -lEGL -ldrm -lgbm +endif + # Define any libraries required on linking # if you want to link libraries (libname.so or libname.a), use the -lname ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -351,6 +371,11 @@ ifeq ($(PLATFORM),PLATFORM_RPI) # NOTE: Required packages: libasound2-dev (ALSA) LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl endif +ifeq ($(PLATFORM),PLATFORM_DRM) + # Libraries for DRM compiling + # NOTE: Required packages: libasound2-dev (ALSA) + LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lgbm -ldrm -ldl +endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.a @@ -522,6 +547,10 @@ ifeq ($(PLATFORM),PLATFORM_RPI) find . -type f -executable -delete rm -fv *.o endif +ifeq ($(PLATFORM),PLATFORM_DRM) + find . -type f -executable -delete + rm -fv *.o +endif ifeq ($(PLATFORM),PLATFORM_WEB) del *.o *.html *.js endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 860ebb4b4..e416b4c4b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,6 +126,22 @@ elseif(${PLATFORM} MATCHES "Raspberry Pi") link_directories(/opt/vc/lib) set(LIBS_PRIVATE ${GLESV2} ${EGL} ${BCMHOST} pthread rt m dl) + elseif(${PLATFORM} MATCHES "DRM") + set(PLATFORM_CPP "PLATFORM_DRM") + set(GRAPHICS "GRAPHICS_API_OPENGL_ES2") + + add_definitions(-D_DEFAULT_SOURCE) + add_definitions(-DEGL_NO_X11) + add_definitions(-DPLATFORM_DRM) + + find_library(GLESV2 GLESv2) + find_library(EGL EGL) + find_library(DRM drm) + find_library(GBM gbm) + + include_directories(/usr/include/libdrm) + set(LIBS_PRIVATE ${GLESV2} ${EGL} ${DRM} ${GBM} pthread m dl) + endif() if (${OPENGL_VERSION}) diff --git a/src/CMakeOptions.txt b/src/CMakeOptions.txt index dbf27bd51..a0f864457 100644 --- a/src/CMakeOptions.txt +++ b/src/CMakeOptions.txt @@ -2,7 +2,7 @@ include(CMakeDependentOption) include(EnumOption) -enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi" "Platform to build for.") +enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM" "Platform to build for.") enum_option(OPENGL_VERSION "OFF;3.3;2.1;1.1;ES 2.0" "Force a specific OpenGL Version?") diff --git a/src/Makefile b/src/Makefile index 032f66c3d..ebdc06f19 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,6 +9,7 @@ # PLATFORM_DESKTOP: FreeBSD, OpenBSD, NetBSD, DragonFly # PLATFORM_ANDROID: Android (arm, i686, arm64, x86_64) # PLATFORM_RPI: Raspberry Pi (Raspbian) +# PLATFORM_DRM: Linux native mode, including Raspberry Pi 4 with V3D fkms driver # PLATFORM_WEB: HTML5 (Chrome, Firefox) # # Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline. @@ -137,6 +138,12 @@ ifeq ($(PLATFORM),PLATFORM_RPI) PLATFORM_OS = LINUX endif endif +ifeq ($(PLATFORM),PLATFORM_DRM) + UNAMEOS = $(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS = LINUX + endif +endif # RAYLIB_SRC_PATH adjustment for different platforms. # If using GNU make, we can get the full path to the top of the tree. Windows? BSD? @@ -204,6 +211,10 @@ ifeq ($(PLATFORM),PLATFORM_RPI) # On RPI OpenGL ES 2.0 must be used GRAPHICS = GRAPHICS_API_OPENGL_ES2 endif +ifeq ($(PLATFORM),PLATFORM_DRM) + # On DRM OpenGL ES 2.0 must be used + GRAPHICS = GRAPHICS_API_OPENGL_ES2 +endif ifeq ($(PLATFORM),PLATFORM_WEB) # On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0 GRAPHICS = GRAPHICS_API_OPENGL_ES2 @@ -354,6 +365,11 @@ ifeq ($(RAYLIB_LIBTYPE),SHARED) # MinGW32 just doesn't need -fPIC, it shows warnings CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED endif +ifeq ($(PLATFORM),PLATFORM_DRM) + # without EGL_NO_X11 eglplatform.h tears Xlib.h in which tears X.h in + # which contains a conflicting type Font + CFLAGS += -DEGL_NO_X11 +endif # Use Wayland display on Linux desktop ifeq ($(PLATFORM),PLATFORM_DESKTOP) @@ -390,6 +406,10 @@ ifeq ($(PLATFORM),PLATFORM_RPI) INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vcos/pthreads INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vcos/pthreads endif +ifeq ($(PLATFORM),PLATFORM_DRM) + # DRM required libraries + INCLUDE_PATHS += -I/usr/include/libdrm +endif ifeq ($(PLATFORM),PLATFORM_ANDROID) NATIVE_APP_GLUE = $(ANDROID_NDK)/sources/android/native_app_glue # Include android_native_app_glue.h @@ -510,6 +530,14 @@ else cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) lib$(RAYLIB_LIB_NAME).so endif + ifeq ($(PLATFORM),PLATFORM_DRM) + # Compile raylib shared library version $(RAYLIB_VERSION). + # WARNING: you should type "make clean" before doing this target + $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) $(OBJS) $(LDFLAGS) -Wl,-soname,lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl + @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION)) in $(RAYLIB_RELEASE_PATH)!" + cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) + cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) lib$(RAYLIB_LIB_NAME).so + endif ifeq ($(PLATFORM),PLATFORM_ANDROID) $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so $(OBJS) $(LDFLAGS) $(LDLIBS) @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so)!" diff --git a/src/core.c b/src/core.c index 72223398e..e55562bf2 100644 --- a/src/core.c +++ b/src/core.c @@ -9,6 +9,7 @@ * - PLATFORM_DESKTOP: OSX/macOS * - PLATFORM_ANDROID: Android 4.0 (ARM, ARM64) * - PLATFORM_RPI: Raspberry Pi 0,1,2,3,4 (Raspbian) +* - PLATFORM_DRM: Linux native mode, including Raspberry Pi 4 with V3D fkms driver * - PLATFORM_WEB: HTML5 with asm.js (Chrome, Firefox) * - PLATFORM_UWP: Windows 10 App, Windows Phone, Xbox One * @@ -222,7 +223,7 @@ #include // OpenGL ES 2.0 library #endif -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) #include // POSIX file control definitions - open(), creat(), fcntl() #include // POSIX standard function definitions - read(), close(), STDIN_FILENO #include // POSIX terminal control definitions - tcgetattr(), tcsetattr() @@ -234,7 +235,15 @@ #include // Linux: Keycodes constants definition (KEY_A, ...) #include // Linux: Joystick support library +#if defined(PLATFORM_RPI) #include "bcm_host.h" // Raspberry Pi VideoCore IV access functions +#endif + +#if defined(PLATFORM_DRM) + #include // Generic Buffer Management + #include // Direct Rendering Manager user-level library interface + #include // Direct Rendering Manager modesetting interface +#endif #include "EGL/egl.h" // EGL library - Native platform display device control functions #include "EGL/eglext.h" // EGL library - Extensions @@ -266,7 +275,7 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) #define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event number #define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) @@ -306,7 +315,7 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) typedef struct { pthread_t threadId; // Event reading thread id int fd; // File descriptor to the device it is assigned to @@ -336,11 +345,24 @@ typedef struct CoreData { #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) GLFWwindow *handle; // Native window handle (graphic device) #endif +#if (defined(PLATFORM_RPI) && defined(SUPPORT_MOUSE_CURSOR_RPI)) || defined(PLATFORM_DRM) + Texture2D mouseTX; // software mouse on framebuffer +#endif #if defined(PLATFORM_RPI) - // NOTE: RPI4 does not support Dispmanx anymore, system should be redesigned EGL_DISPMANX_WINDOW_T handle; // Native window handle (graphic device) #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) +#if defined(PLATFORM_DRM) + const char *card; // /dev/dri/... file name + 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 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 @@ -384,7 +406,7 @@ typedef struct CoreData { } UWP; #endif struct { -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event" #endif struct { @@ -394,7 +416,7 @@ typedef struct CoreData { int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input characters queue int keyPressedQueueCount; // Input characters queue count -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) 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) @@ -412,7 +434,7 @@ typedef struct CoreData { char previousButtonState[3]; // Registers previous mouse button state int currentWheelMove; // Registers current mouse wheel variation int previousWheelMove; // Registers previous mouse wheel variation -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) 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; @@ -424,13 +446,13 @@ typedef struct CoreData { struct { int lastButtonPressed; // Register last gamepad button pressed int axisCount; // Register number of available gamepad axis -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) 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 #endif -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) pthread_t threadId; // Gamepad reading thread id int streamId[MAX_GAMEPADS]; // Gamepad device file descriptor char name[64]; // Gamepad name holder @@ -444,7 +466,7 @@ typedef struct CoreData { 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_RPI) || defined(PLATFORM_UWP) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) unsigned long long base; // Base time measure for hi-res timer #endif } Time; @@ -519,7 +541,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData); #endif -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) #if defined(SUPPORT_SSH_KEYBOARD_RPI) static void InitKeyboard(void); // Init raw keyboard system (standard input reading) static void ProcessKeyboard(void); // Process keyboard events @@ -535,7 +557,7 @@ static void *EventThread(void *arg); // Input device events r static void InitGamepad(void); // Init raw gamepad input static void *GamepadThread(void *arg); // Mouse reading thread -#endif // PLATFORM_RPI +#endif // PLATFORM_RPI || PLATFORM_DRM #if defined(_WIN32) // NOTE: We include Sleep() function signature here to avoid windows.h inclusion @@ -566,7 +588,7 @@ struct android_app *GetAndroidApp(void) return CORE.Android.app; } #endif -#if defined(PLATFORM_RPI) && !defined(SUPPORT_SSH_KEYBOARD_RPI) +#if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && !defined(SUPPORT_SSH_KEYBOARD_RPI) // Init terminal (block echo and signal short cuts) static void InitTerminal(void) { @@ -717,7 +739,7 @@ void InitWindow(int width, int height, const char *title) SetTextureFilter(GetFontDefault().texture, FILTER_BILINEAR); #endif -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) // Init raw input system InitEvdevInput(); // Evdev inputs initialization InitGamepad(); // Gamepad init @@ -781,12 +803,59 @@ void CloseWindow(void) timeEndPeriod(1); // Restore time period #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) +#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; + } + + if(CORE.Window.crtc) + { + 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 + // Close surface, context and display if (CORE.Window.device != EGL_NO_DISPLAY) { +#if !defined(PLATFORM_DRM) eglMakeCurrent(CORE.Window.device, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - +#endif if (CORE.Window.surface != EGL_NO_SURFACE) { eglDestroySurface(CORE.Window.device, CORE.Window.surface); @@ -804,7 +873,7 @@ void CloseWindow(void) } #endif -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) // Wait for mouse and gamepad threads to finish before closing // NOTE: Those threads should already have finished at this point // because they are controlled by CORE.Window.shouldClose variable @@ -860,7 +929,7 @@ bool WindowShouldClose(void) else return true; #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) if (CORE.Window.ready) return CORE.Window.shouldClose; else return true; #endif @@ -982,7 +1051,7 @@ void ToggleFullscreen(void) } */ #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) TRACELOG(LOG_WARNING, "SYSTEM: Failed to toggle to windowed mode"); #endif @@ -1400,10 +1469,13 @@ void BeginDrawing(void) // End canvas drawing and swap buffers (double buffering) void EndDrawing(void) { -#if defined(PLATFORM_RPI) && defined(SUPPORT_MOUSE_CURSOR_RPI) - // On RPI native mode we have no system mouse cursor, so, - // we draw a small rectangle for user reference - DrawRectangle(CORE.Input.Mouse.position.x, CORE.Input.Mouse.position.y, 3, 3, MAROON); +#if defined(PLATFORM_DRM) + // On DRM mode we have no system mouse cursor, so, + // we draw a nice mouse cursor respecting cursorHidden... + //DrawRectangle(CORE.Input.Mouse.position.x, CORE.Input.Mouse.position.y, 3, 3, MAROON); + if (!CORE.Input.Mouse.cursorHidden) { + DrawTexture(CORE.Window.mouseTX,CORE.Input.Mouse.position.x, CORE.Input.Mouse.position.y,WHITE); + } #endif rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) @@ -1806,7 +1878,7 @@ double GetTime(void) return glfwGetTime(); // Elapsed time since glfwInit() #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); unsigned long long int time = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; @@ -2439,7 +2511,7 @@ const char *GetGamepadName(int gamepad) #if defined(PLATFORM_DESKTOP) if (CORE.Input.Gamepad.ready[gamepad]) return glfwGetJoystickName(gamepad); else return NULL; -#elif defined(PLATFORM_RPI) +#elif defined(PLATFORM_RPI) || defined(PLATFORM_DRM) if (CORE.Input.Gamepad.ready[gamepad]) ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGNAME(64), &CORE.Input.Gamepad.name); return CORE.Input.Gamepad.name; @@ -2451,7 +2523,7 @@ const char *GetGamepadName(int gamepad) // Return gamepad axis count int GetGamepadAxisCount(int gamepad) { -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) int axisCount = 0; if (CORE.Input.Gamepad.ready[gamepad]) ioctl(CORE.Input.Gamepad.streamId[gamepad], JSIOCGAXES, &axisCount); CORE.Input.Gamepad.axisCount = axisCount; @@ -2657,7 +2729,7 @@ int GetTouchX(void) { #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) return (int)CORE.Input.Touch.position[0].x; -#else // PLATFORM_DESKTOP, PLATFORM_RPI +#else // PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM return GetMouseX(); #endif } @@ -2667,7 +2739,7 @@ int GetTouchY(void) { #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) return (int)CORE.Input.Touch.position[0].y; -#else // PLATFORM_DESKTOP, PLATFORM_RPI +#else // PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM return GetMouseY(); #endif } @@ -2678,7 +2750,7 @@ Vector2 GetTouchPosition(int index) { Vector2 position = { -1.0f, -1.0f }; -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) if (index < MAX_TOUCH_POINTS) position = CORE.Input.Touch.position[index]; else TRACELOG(LOG_WARNING, "INPUT: Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS); @@ -2956,7 +3028,7 @@ static bool InitGraphicsDevice(int width, int height) } #endif // PLATFORM_DESKTOP || PLATFORM_WEB -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) CORE.Window.fullscreen = true; #if defined(PLATFORM_RPI) @@ -2970,6 +3042,260 @@ static bool InitGraphicsDevice(int width, int height) VC_RECT_T srcRect; #endif +#if defined(PLATFORM_DRM) + CORE.Window.card = NULL; + 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 ((NULL != CORE.Window.card) && ('\0' != CORE.Window.card[0])) + { + char *base = "/dev/dri/"; + const int len = strlen(base) + strlen(CORE.Window.card); + char *path = malloc(len); + if (!path) { + TRACELOG(LOG_WARNING, "DISPLAY: failed to get memory for path"); + return false; + } + path[0] = '\0'; + strncpy(path, base, len - 1); + strncat(path, CORE.Window.card, len - strlen(base)); + CORE.Window.fd = open(path, O_RDWR); + free(path); + } + 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) + } + } + 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"); + close(CORE.Window.fd); + 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 0 + for (int j = 0; j < con->count_modes; j++) { + TRACELOG(LOG_TRACE, "clock %i", con->modes[j].clock); + TRACELOG(LOG_TRACE, "hdisplay %i", con->modes[j].hdisplay); + TRACELOG(LOG_TRACE, "vdisplay %i", con->modes[j].vdisplay); + TRACELOG(LOG_TRACE, "vrefresh %i", con->modes[j].vrefresh); + TRACELOG(LOG_TRACE, "flags %X", con->modes[j].flags); + TRACELOG(LOG_TRACE, "type %i", con->modes[j].type); + TRACELOG(LOG_TRACE, "name %s", con->modes[j].name); + } +#endif + 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); + close(CORE.Window.fd); + return false; + } + + drmModeEncoder *enc = drmModeGetEncoder(CORE.Window.fd, CORE.Window.connector->encoder_id); + if (!enc) + { + TRACELOG(LOG_WARNING, "failed to get DRM mode encoder"); + drmModeFreeConnector(CORE.Window.connector); + drmModeFreeResources(res); + close(CORE.Window.fd); + return false; + } + +#if 0 + TRACELOG(LOG_TRACE, "Encoder id %i", enc->encoder_id); + TRACELOG(LOG_TRACE, "Encoder type %i", enc->encoder_type); + TRACELOG(LOG_TRACE, "Encoder crtc id %i", enc->crtc_id); + TRACELOG(LOG_TRACE, "Encoder possible crtcs %i", enc->possible_crtcs); + TRACELOG(LOG_TRACE, "Encoder possible clones %i", enc->possible_clones); +#endif + + 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); + drmModeFreeConnector(CORE.Window.connector); + drmModeFreeResources(res); + close(CORE.Window.fd); + return false; + } + + int findExactly = 1; +find_connector_mode: + // 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)) + { + #define BINCMP(a, b) memcmp((a), (b), sizeof(a) < sizeof(b) ? sizeof(a) : sizeof(b)) + TRACELOG(LOG_TRACE, "selecting for (res 0x0)"); + for (int i = CORE.Window.connector->count_modes - 1; i >= 0; i--) + { + TRACELOG(LOG_TRACE, "mode %i h=%i v=%i", i, CORE.Window.connector->modes[i].hdisplay, CORE.Window.connector->modes[i].vdisplay); + if (CORE.Window.connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE) + { + TRACELOG(LOG_TRACE, "interlaced mode"); + if (!(CORE.Window.flags & FLAG_INTERLACED_HINT)) + { + TRACELOG(LOG_TRACE, "but shouldn't choose an interlaced mode"); + continue; + } + } + else + { + TRACELOG(LOG_TRACE, "progressive mode"); + } + + if (0 == BINCMP(&CORE.Window.crtc->mode, &CORE.Window.connector->modes[i])) + { + TRACELOG(LOG_TRACE, "above mode selected"); + CORE.Window.screen.width = CORE.Window.connector->modes[i].hdisplay; + CORE.Window.screen.height = CORE.Window.connector->modes[i].vdisplay; + + CORE.Window.display.width = CORE.Window.connector->modes[i].hdisplay; + CORE.Window.display.height = CORE.Window.connector->modes[i].vdisplay; + CORE.Window.modeIndex = i; + break; + } + } + #undef BINCMP + } + else + { + TRACELOG(LOG_TRACE, "selecting for (res %ix%i)", CORE.Window.screen.width, CORE.Window.screen.height); + // Get closest video mode to desired CORE.Window.screen.width/CORE.Window.screen.height + for (int i = CORE.Window.connector->count_modes - 1; i >= 0; i--) + { + TRACELOG(LOG_TRACE, "mode %i h=%i v=%i", i, CORE.Window.connector->modes[i].hdisplay, CORE.Window.connector->modes[i].vdisplay); + if (CORE.Window.connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE) + { + TRACELOG(LOG_TRACE, "interlaced mode"); + if (!(CORE.Window.flags & FLAG_INTERLACED_HINT)) + { + TRACELOG(LOG_TRACE, "but shouldn't choose an interlaced mode"); + continue; + } + } + else + { + TRACELOG(LOG_TRACE, "progressive mode"); + } + + int found = 0; + if (findExactly) { + found = (CORE.Window.connector->modes[i].hdisplay == CORE.Window.screen.width) && + (CORE.Window.connector->modes[i].vdisplay == CORE.Window.screen.height); + } + else + { + found = (CORE.Window.connector->modes[i].hdisplay >= CORE.Window.screen.width) && + (CORE.Window.connector->modes[i].vdisplay >= CORE.Window.screen.height); + } + if (found) + { + TRACELOG(LOG_TRACE, "above mode selected"); + CORE.Window.display.width = CORE.Window.connector->modes[i].hdisplay; + CORE.Window.display.height = CORE.Window.connector->modes[i].vdisplay; + CORE.Window.modeIndex = i; + break; + } + } + } + if (CORE.Window.modeIndex < 0) + { + if (findExactly) + { + findExactly = 0; + goto find_connector_mode; + } + else + { + if (CORE.Window.flags & FLAG_INTERLACED_HINT) + { + CORE.Window.flags &= ~FLAG_INTERLACED_HINT; + findExactly = 1; + goto find_connector_mode; + } + } + } + if (CORE.Window.modeIndex < 0) + { + TRACELOG(LOG_WARNING, "no suitable DRM connector mode found"); + drmModeFreeEncoder(enc); + drmModeFreeConnector(CORE.Window.connector); + drmModeFreeResources(res); + close(CORE.Window.fd); + return false; + } + + // 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"); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); + 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"); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); + return false; + } +#endif + EGLint samples = 0; EGLint sampleBuffer = 0; if (CORE.Window.flags & FLAG_MSAA_4X_HINT) @@ -2982,11 +3308,15 @@ static bool InitGraphicsDevice(int width, int height) const EGLint framebufferAttribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Type of context support -> Required on RPI? - //EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android! + #if defined(PLATFORM_DRM) + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android! + #endif EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5) EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) - //EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer) + #if defined(PLATFORM_DRM) + EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer) + #endif //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI) EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!) //EGL_STENCIL_SIZE, 8, // Stencil buffer size @@ -3170,14 +3500,22 @@ static bool InitGraphicsDevice(int width, int height) #endif // PLATFORM_UWP -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) EGLint numConfigs = 0; // Get an EGL device connection +#if defined(PLATFORM_DRM) + CORE.Window.device = eglGetDisplay((EGLNativeDisplayType)CORE.Window.gbmDevice); +#else CORE.Window.device = eglGetDisplay(EGL_DEFAULT_DISPLAY); +#endif if (CORE.Window.device == EGL_NO_DISPLAY) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); return false; } @@ -3186,11 +3524,92 @@ static bool InitGraphicsDevice(int width, int height) { // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); +#if defined(PLATFORM_DRM) + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); +#endif return false; } +#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()); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); + 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"); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); + 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); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); + 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); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); + return false; + } + + 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"); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); + return false; + } +#else // Get an appropriate EGL framebuffer configuration eglChooseConfig(CORE.Window.device, framebufferAttribs, &CORE.Window.config, 1, &numConfigs); +#endif // Set rendering API eglBindAPI(EGL_OPENGL_ES_API); @@ -3200,6 +3619,10 @@ static bool InitGraphicsDevice(int width, int height) if (CORE.Window.context == EGL_NO_CONTEXT) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); return false; } #endif @@ -3271,15 +3694,51 @@ static bool InitGraphicsDevice(int width, int height) vc_dispmanx_update_submit_sync(dispmanUpdate); CORE.Window.surface = eglCreateWindowSurface(CORE.Window.device, CORE.Window.config, &CORE.Window.handle, NULL); + + 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"); + } //--------------------------------------------------------------------------------- #endif // PLATFORM_RPI +#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()); + eglDestroyContext(CORE.Window.device, CORE.Window.context); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); + return false; + } + + // At this point we need to manage render size vs screen size + // NOTE: This function use and modify global module variables: + // -> CORE.Window.screen.width/CORE.Window.screen.height + // -> CORE.Window.render.width/CORE.Window.render.height + // -> CORE.Window.screenScale + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); +#endif // PLATFORM_DRM + // There must be at least one frame displayed before the buffers are swapped //eglSwapInterval(CORE.Window.device, 1); if (eglMakeCurrent(CORE.Window.device, CORE.Window.surface, CORE.Window.surface, CORE.Window.context) == EGL_FALSE) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to attach EGL rendering context to EGL surface"); +#if defined(PLATFORM_DRM) + eglDestroySurface(CORE.Window.device, CORE.Window.surface); + eglDestroyContext(CORE.Window.device, CORE.Window.context); + gbm_surface_destroy(CORE.Window.gbmSurface); + gbm_device_destroy(CORE.Window.gbmDevice); + drmModeFreeConnector(CORE.Window.connector); + close(CORE.Window.fd); +#endif return false; } else @@ -3290,7 +3749,7 @@ static bool InitGraphicsDevice(int width, int height) TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); } -#endif // PLATFORM_ANDROID || PLATFORM_RPI || defined(PLATFORM_UWP) +#endif // PLATFORM_ANDROID || PLATFORM_RPI || PLATFORM_DRM || PLATFORM_UWP // Initialize OpenGL context (states and resources) // NOTE: CORE.Window.screen.width and CORE.Window.screen.height not used, just stored as globals in rlgl @@ -3317,6 +3776,23 @@ static bool InitGraphicsDevice(int width, int height) ClearBackground(RAYWHITE); // Default background color for raylib games :P + // suggest changing to SUPPORT_DRM_POINTER instead of SUPPORT_MOUSE_CURSOR_RPI + #if defined(PLATFORM_DRM) + // software mouse on framebuffer + + #include "drm_mouse_img.h" + + static Image mImg = { + .data = DRM_MOUSE_IMG_DATA, + .width = DRM_MOUSE_IMG_WIDTH, + .height = DRM_MOUSE_IMG_HEIGHT, + .format = DRM_MOUSE_IMG_FORMAT, + .mipmaps = 1 + }; + + CORE.Window.mouseTX = LoadTextureFromImage(mImg); +#endif + #if defined(PLATFORM_ANDROID) || defined(PLATFORM_UWP) CORE.Window.ready = true; #endif @@ -3426,7 +3902,7 @@ static void InitTimer(void) timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms) #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) struct timespec now; if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success @@ -3556,13 +4032,13 @@ static void PollInputEvents(void) // Reset key pressed registered CORE.Input.Keyboard.keyPressedQueueCount = 0; -#if !defined(PLATFORM_RPI) +#if !(defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) // Reset last gamepad button/axis registered state CORE.Input.Gamepad.lastButtonPressed = -1; CORE.Input.Gamepad.axisCount = 0; #endif -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) // Register previous keys states for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; @@ -3751,7 +4227,7 @@ static void PollInputEvents(void) } #endif -#if defined(PLATFORM_RPI) && defined(SUPPORT_SSH_KEYBOARD_RPI) +#if (defined(PLATFORM_RPI) || defined(PLATFORM_DRM)) && defined(SUPPORT_SSH_KEYBOARD_RPI) // NOTE: Keyboard reading could be done using input_event(s) reading or just read from stdin, // we now use both methods inside here. 2nd method is still used for legacy purposes (Allows for input trough SSH console) ProcessKeyboard(); @@ -3768,9 +4244,58 @@ static void SwapBuffers(void) glfwSwapBuffers(CORE.Window.handle); #endif -#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM) || defined(PLATFORM_UWP) eglSwapBuffers(CORE.Window.device, CORE.Window.surface); -#endif + +#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) } #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) @@ -4396,7 +4921,7 @@ static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const void *reserv } #endif -#if defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) || defined(PLATFORM_DRM) #if defined(SUPPORT_SSH_KEYBOARD_RPI) // Initialize Keyboard system (using standard input) @@ -5098,7 +5623,7 @@ static void *GamepadThread(void *arg) return NULL; } -#endif // PLATFORM_RPI +#endif // PLATFORM_RPI || PLATFORM_DRM #if defined(PLATFORM_UWP) // UWP function pointers @@ -5373,3 +5898,10 @@ void UWPGestureTouch(int pointer, float x, float y, bool touch) } #endif // PLATFORM_UWP + +void SetGraphicDeviceName(const char *name) +{ +#if defined(PLATFORM_DRM) + if ((name != NULL) && (name[0] != 0)) CORE.Window.card = name; +#endif +} diff --git a/src/drm_mouse_img.h b/src/drm_mouse_img.h new file mode 100644 index 000000000..4d82fbec2 --- /dev/null +++ b/src/drm_mouse_img.h @@ -0,0 +1,222 @@ +//////////////////////////////////////////////////////////////////////////////////////// +// // +// ImageAsCode exporter v1.0 - Image pixel data exported as an array of bytes // +// // +// more info and bugs-report: github.com/raysan5/raylib // +// feedback and support: ray[at]raylib.com // +// // +// Copyright (c) 2020 Ramon Santamaria (@raysan5) // +// // +//////////////////////////////////////////////////////////////////////////////////////// + +// Image data information +#define DRM_MOUSE_IMG_WIDTH 32 +#define DRM_MOUSE_IMG_HEIGHT 32 +#define DRM_MOUSE_IMG_FORMAT 7 // raylib internal pixel format + +static unsigned char DRM_MOUSE_IMG_DATA[4096] = { 0xa0, +0xa2, 0xa4, 0xeb, 0x8d, 0x8e, 0x90, 0x39, 0x64, 0x67, 0x67, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9e, 0xa0, 0xa2, 0xfc, 0x9c, 0x9e, 0x9f, 0xd5, 0x8e, 0x91, 0x93, 0x46, 0x63, +0x68, 0x67, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa1, 0xa3, 0xa5, 0xff, 0xde, +0xdf, 0xe0, 0xfd, 0xb2, 0xb3, 0xb5, 0xdf, 0x84, 0x86, 0x87, 0x68, 0x7e, 0x80, 0x81, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0xa1, 0xa3, 0xa5, 0xff, 0xf1, 0xf1, 0xf2, 0xff, 0xe7, 0xe8, 0xe9, 0xfe, 0xb4, 0xb6, 0xb7, 0xe7, 0x88, +0x89, 0x8b, 0x76, 0x82, 0x82, 0x85, 0xf, 0x32, 0x33, 0x35, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9e, 0xa0, 0xa2, 0xff, 0xe6, 0xe7, 0xe7, 0xff, 0xe0, +0xe1, 0xe2, 0xff, 0xe3, 0xe5, 0xe6, 0xff, 0xb8, 0xb9, 0xbb, 0xeb, 0x8f, 0x90, 0x92, 0x9d, 0x72, 0x74, 0x77, 0x26, 0x21, +0x25, 0x28, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9d, +0x9e, 0xa1, 0xff, 0xe0, 0xe1, 0xe1, 0xff, 0xc7, 0xc9, 0xca, 0xff, 0xd1, 0xd3, 0xd4, 0xff, 0xdf, 0xe0, 0xe1, 0xff, 0xc2, +0xc3, 0xc5, 0xfa, 0x95, 0x97, 0x9a, 0xb0, 0x66, 0x6a, 0x6c, 0x39, 0x1e, 0x1f, 0x1f, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9c, 0x9d, 0xa1, 0xff, 0xe0, 0xe1, 0xe1, 0xff, 0xc4, 0xc6, 0xc7, 0xff, 0xbd, +0xbf, 0xc0, 0xff, 0xce, 0xd0, 0xd1, 0xff, 0xdd, 0xdd, 0xdf, 0xff, 0xc3, 0xc5, 0xc6, 0xfd, 0x94, 0x97, 0x98, 0xbd, 0x6d, +0x70, 0x72, 0x4f, 0x8e, 0x8e, 0x8d, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9b, 0x9c, 0x9f, 0xff, 0xde, +0xe0, 0xe0, 0xff, 0xc7, 0xc9, 0xc9, 0xff, 0xbe, 0xc0, 0xc1, 0xff, 0xbf, 0xc1, 0xc2, 0xff, 0xcc, 0xce, 0xcf, 0xff, 0xd5, +0xd7, 0xd8, 0xff, 0xc8, 0xca, 0xcb, 0xfe, 0xab, 0xac, 0xad, 0xd2, 0x6b, 0x6d, 0x6f, 0x66, 0x70, 0x70, 0x79, 0x5, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x99, 0x9b, 0x9d, 0xff, 0xdd, 0xdf, 0xdf, 0xff, 0xc8, 0xca, 0xcb, 0xff, 0xc1, 0xc3, 0xc4, 0xff, 0xc1, +0xc4, 0xc4, 0xff, 0xc0, 0xc3, 0xc3, 0xff, 0xca, 0xcc, 0xcd, 0xff, 0xd3, 0xd4, 0xd5, 0xff, 0xca, 0xcb, 0xcd, 0xff, 0xa6, +0xa8, 0xaa, 0xd8, 0x74, 0x76, 0x78, 0x6a, 0x89, 0x8b, 0x8b, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x98, 0x9a, 0x9c, 0xff, 0xdc, 0xdd, 0xde, 0xff, 0xc9, +0xcb, 0xcc, 0xff, 0xc3, 0xc5, 0xc6, 0xff, 0xc4, 0xc5, 0xc7, 0xff, 0xc4, 0xc5, 0xc7, 0xff, 0xc3, 0xc5, 0xc6, 0xff, 0xc8, +0xca, 0xcb, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xc9, 0xcb, 0xcd, 0xff, 0xad, 0xae, 0xb0, 0xec, 0x82, 0x83, 0x85, 0x89, 0x79, +0x78, 0x7c, 0x21, 0x42, 0x3f, 0x44, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x98, +0x99, 0x9b, 0xff, 0xdb, 0xdc, 0xdd, 0xff, 0xcb, 0xcb, 0xce, 0xff, 0xc5, 0xc6, 0xc8, 0xff, 0xc6, 0xc7, 0xc9, 0xff, 0xc6, +0xc6, 0xc9, 0xff, 0xc6, 0xc7, 0xc9, 0xff, 0xc5, 0xc6, 0xc8, 0xff, 0xc6, 0xc7, 0xca, 0xff, 0xcf, 0xd0, 0xd1, 0xff, 0xcd, +0xcd, 0xcf, 0xff, 0xaa, 0xab, 0xad, 0xfa, 0x8d, 0x8e, 0x91, 0xaa, 0x7b, 0x7a, 0x7f, 0x33, 0x4b, 0x47, 0x51, 0x2, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x97, 0x97, 0x9a, 0xff, 0xda, 0xda, 0xdb, 0xff, 0xcd, 0xce, 0xcf, 0xff, 0xc7, +0xc9, 0xca, 0xff, 0xc8, 0xc9, 0xcb, 0xff, 0xc8, 0xc9, 0xcb, 0xff, 0xc8, 0xc9, 0xcb, 0xff, 0xc8, 0xc9, 0xcb, 0xff, 0xc7, +0xc9, 0xca, 0xff, 0xc8, 0xc9, 0xcb, 0xff, 0xcc, 0xcd, 0xcf, 0xff, 0xca, 0xcc, 0xcd, 0xff, 0xaf, 0xb1, 0xb3, 0xfc, 0x8e, +0x90, 0x92, 0xbf, 0x71, 0x77, 0x7a, 0x3d, 0x55, 0x60, 0x64, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x95, 0x97, 0x98, 0xff, 0xd8, +0xda, 0xdb, 0xff, 0xce, 0xd0, 0xd1, 0xff, 0xc9, 0xcb, 0xcc, 0xff, 0xc9, 0xcb, 0xcc, 0xff, 0xc9, 0xcb, 0xcc, 0xff, 0xc9, +0xcb, 0xcc, 0xff, 0xc9, 0xcb, 0xcc, 0xff, 0xc9, 0xcb, 0xcc, 0xff, 0xc9, 0xcb, 0xcc, 0xff, 0xc9, 0xcb, 0xcc, 0xff, 0xcd, +0xcf, 0xd0, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xad, 0xaf, 0xb0, 0xfd, 0x93, 0x97, 0x99, 0xd3, 0x77, 0x7b, 0x7d, 0x45, 0x62, +0x65, 0x6a, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x94, 0x96, 0x97, 0xff, 0xd8, 0xd9, 0xda, 0xff, 0xd0, 0xd1, 0xd2, 0xff, 0xcb, 0xcc, 0xce, 0xff, 0xcb, +0xcc, 0xce, 0xff, 0xcb, 0xcc, 0xce, 0xff, 0xcb, 0xcc, 0xce, 0xff, 0xcb, 0xcc, 0xce, 0xff, 0xcb, 0xcc, 0xce, 0xff, 0xcb, +0xcc, 0xce, 0xff, 0xcb, 0xcc, 0xce, 0xff, 0xcb, 0xcc, 0xce, 0xff, 0xce, 0xcf, 0xd1, 0xff, 0xd0, 0xd1, 0xd3, 0xff, 0xb6, +0xb7, 0xb9, 0xfd, 0x94, 0x96, 0x98, 0xe7, 0x73, 0x74, 0x78, 0x5b, 0x68, 0x69, 0x6d, 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x93, 0x95, 0x96, 0xff, 0xd7, 0xd8, 0xd8, 0xff, 0xd1, +0xd2, 0xd4, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xcd, +0xce, 0xd0, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xcd, 0xce, 0xd0, 0xff, 0xcd, +0xce, 0xd0, 0xff, 0xcf, 0xd0, 0xd2, 0xff, 0xd0, 0xd1, 0xd3, 0xff, 0xb7, 0xb7, 0xb9, 0xfe, 0x96, 0x97, 0x9a, 0xf1, 0x7f, +0x81, 0x84, 0x8c, 0x74, 0x75, 0x7a, 0x19, 0x4f, 0x41, 0x61, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x91, +0x93, 0x96, 0xff, 0xd5, 0xd6, 0xd7, 0xff, 0xd2, 0xd4, 0xd5, 0xff, 0xcf, 0xd1, 0xd2, 0xff, 0xcf, 0xd1, 0xd2, 0xff, 0xcf, +0xd1, 0xd2, 0xff, 0xcf, 0xd1, 0xd2, 0xff, 0xcf, 0xd1, 0xd2, 0xff, 0xcf, 0xd1, 0xd2, 0xff, 0xcf, 0xd1, 0xd2, 0xff, 0xd0, +0xd2, 0xd3, 0xff, 0xd1, 0xd3, 0xd4, 0xff, 0xd1, 0xd3, 0xd4, 0xff, 0xd1, 0xd4, 0xd4, 0xff, 0xd3, 0xd5, 0xd6, 0xff, 0xd3, +0xd5, 0xd6, 0xff, 0xc2, 0xc3, 0xc5, 0xff, 0x9a, 0x9c, 0x9e, 0xf7, 0x88, 0x88, 0x8d, 0xa4, 0x81, 0x80, 0x86, 0x23, 0x7d, +0x7e, 0x80, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90, 0x91, 0x95, 0xff, 0xd4, 0xd5, 0xd7, 0xff, 0xd4, 0xd5, 0xd7, 0xff, 0xd1, +0xd2, 0xd4, 0xff, 0xd1, 0xd2, 0xd4, 0xff, 0xd1, 0xd2, 0xd4, 0xff, 0xd1, 0xd2, 0xd4, 0xff, 0xd1, 0xd2, 0xd4, 0xff, 0xd1, +0xd2, 0xd4, 0xff, 0xd1, 0xd3, 0xd5, 0xff, 0xd1, 0xd2, 0xd4, 0xff, 0xd2, 0xd3, 0xd5, 0xff, 0xd4, 0xd5, 0xd7, 0xff, 0xd4, +0xd6, 0xd7, 0xff, 0xd5, 0xd6, 0xd8, 0xff, 0xd7, 0xd8, 0xda, 0xff, 0xd8, 0xd9, 0xdb, 0xff, 0xc5, 0xc5, 0xc7, 0xff, 0x97, +0x97, 0x9a, 0xf9, 0x88, 0x89, 0x8c, 0xb9, 0x8a, 0x8b, 0x8e, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, 0x90, 0x94, 0xff, 0xd4, +0xd5, 0xd6, 0xff, 0xd6, 0xd7, 0xd9, 0xff, 0xd4, 0xd4, 0xd6, 0xff, 0xd4, 0xd4, 0xd6, 0xff, 0xd4, 0xd4, 0xd6, 0xff, 0xd5, +0xd5, 0xd7, 0xff, 0xd4, 0xd4, 0xd6, 0xff, 0xd5, 0xd5, 0xd8, 0xff, 0xd3, 0xd4, 0xd6, 0xff, 0xb5, 0xb6, 0xb8, 0xff, 0x93, +0x94, 0x97, 0xfe, 0x98, 0x99, 0x9c, 0xf9, 0x99, 0x9a, 0x9d, 0xf7, 0x99, 0x9a, 0x9d, 0xf7, 0x9a, 0x9b, 0x9e, 0xf7, 0x9b, +0x9c, 0x9f, 0xf7, 0x98, 0x99, 0x9c, 0xf7, 0x8e, 0x8e, 0x92, 0xf7, 0x8c, 0x8d, 0x90, 0xf3, 0x8d, 0x8e, 0x91, 0x3e, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x8e, 0x8f, 0x91, 0xff, 0xd3, 0xd4, 0xd4, 0xff, 0xd8, 0xd8, 0xda, 0xff, 0xd6, 0xd6, 0xd8, 0xff, 0xd7, +0xd7, 0xd9, 0xff, 0xd8, 0xd8, 0xda, 0xff, 0xd5, 0xd5, 0xd7, 0xff, 0xd5, 0xd5, 0xd7, 0xff, 0xd7, 0xd8, 0xd9, 0xff, 0xd8, +0xd8, 0xda, 0xff, 0xca, 0xcb, 0xcd, 0xff, 0x8c, 0x8d, 0x90, 0xf1, 0x5d, 0x5e, 0x61, 0x99, 0x3f, 0x3f, 0x41, 0x69, 0x3e, +0x3e, 0x40, 0x67, 0x3e, 0x3e, 0x40, 0x67, 0x3e, 0x3f, 0x40, 0x67, 0x41, 0x42, 0x43, 0x67, 0x5b, 0x5b, 0x5e, 0x65, 0x67, +0x68, 0x6a, 0x59, 0x6a, 0x6b, 0x6d, 0x16, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8c, 0x8e, 0x90, 0xff, 0xd1, 0xd2, 0xd3, 0xff, 0xda, +0xda, 0xdc, 0xff, 0xd9, 0xd9, 0xdb, 0xff, 0xdc, 0xdc, 0xde, 0xff, 0xc6, 0xc6, 0xc8, 0xff, 0xad, 0xaf, 0xb1, 0xff, 0xc4, +0xc6, 0xc7, 0xff, 0xda, 0xd9, 0xdc, 0xff, 0xda, 0xda, 0xdc, 0xff, 0xd6, 0xd7, 0xd8, 0xff, 0xb9, 0xba, 0xbb, 0xfb, 0x71, +0x72, 0x75, 0xbc, 0x23, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x1d, 0x0, +0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x17, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8b, +0x8c, 0x8f, 0xff, 0xcf, 0xd0, 0xd2, 0xff, 0xdc, 0xdd, 0xdf, 0xff, 0xdf, 0xdf, 0xe1, 0xff, 0xd1, 0xd1, 0xd3, 0xff, 0x9b, +0x9c, 0x9f, 0xf4, 0x83, 0x85, 0x88, 0xf0, 0xac, 0xae, 0xb0, 0xfc, 0xd4, 0xd4, 0xd7, 0xff, 0xdb, 0xdb, 0xdd, 0xff, 0xdb, +0xdb, 0xdd, 0xff, 0xcd, 0xcf, 0xcf, 0xff, 0x98, 0x9a, 0x9c, 0xe9, 0x73, 0x75, 0x77, 0x68, 0x34, 0x35, 0x36, 0x9, 0x0, +0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x3, 0x0, +0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8a, 0x8b, 0x8e, 0xff, 0xcf, 0xd0, 0xd2, 0xff, 0xe2, 0xe2, 0xe4, 0xff, 0xd8, +0xd8, 0xda, 0xff, 0xab, 0xac, 0xaf, 0xfe, 0x67, 0x68, 0x6b, 0xac, 0x58, 0x58, 0x5b, 0x94, 0x85, 0x86, 0x89, 0xe2, 0xc2, +0xc3, 0xc5, 0xff, 0xdb, 0xdb, 0xdd, 0xff, 0xde, 0xdd, 0xdf, 0xff, 0xd8, 0xd8, 0xda, 0xff, 0xbb, 0xbc, 0xbf, 0xff, 0x7e, +0x7f, 0x82, 0xc8, 0x49, 0x49, 0x4b, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8b, 0x8c, 0x8f, 0xff, 0xd1, +0xd2, 0xd4, 0xff, 0xd8, 0xd9, 0xdb, 0xff, 0xad, 0xae, 0xb0, 0xfe, 0x6f, 0x70, 0x73, 0xbf, 0x2b, 0x2c, 0x2e, 0x52, 0x1e, +0x1e, 0x1f, 0x35, 0x6c, 0x6c, 0x6f, 0xac, 0xac, 0xae, 0xb1, 0xff, 0xd3, 0xd4, 0xd5, 0xff, 0xdf, 0xde, 0xe0, 0xff, 0xde, +0xde, 0xe0, 0xff, 0xcc, 0xcd, 0xcf, 0xff, 0x99, 0x9a, 0x9c, 0xee, 0x75, 0x76, 0x77, 0x77, 0x45, 0x46, 0x46, 0xa, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x8a, 0x8c, 0x8e, 0xff, 0xc6, 0xc7, 0xca, 0xff, 0xab, 0xad, 0xaf, 0xff, 0x76, 0x78, 0x79, 0xdd, 0x3e, +0x3e, 0x40, 0x5c, 0x9, 0x9, 0x9, 0x17, 0x1, 0x1, 0x1, 0x16, 0x53, 0x54, 0x55, 0x66, 0x82, 0x83, 0x86, 0xdd, 0xb9, +0xba, 0xbd, 0xff, 0xdd, 0xdd, 0xde, 0xff, 0xe2, 0xe3, 0xe4, 0xff, 0xda, 0xdb, 0xdc, 0xff, 0xbd, 0xbe, 0xc0, 0xff, 0x82, +0x83, 0x85, 0xd7, 0x5c, 0x5c, 0x5f, 0x27, 0x56, 0x56, 0x58, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x85, 0x87, 0x89, 0xff, 0x99, 0x9a, 0x9d, 0xff, 0x7d, +0x7f, 0x81, 0xe9, 0x51, 0x52, 0x54, 0x71, 0x23, 0x23, 0x24, 0x1e, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x8, 0x1d, +0x1f, 0x1f, 0x1e, 0x5d, 0x5f, 0x61, 0x98, 0xa1, 0xa2, 0xa5, 0xfc, 0xd3, 0xd4, 0xd5, 0xff, 0xe3, 0xe3, 0xe4, 0xff, 0xe3, +0xe3, 0xe5, 0xff, 0xd0, 0xd0, 0xd3, 0xff, 0x9a, 0x9b, 0x9f, 0xf3, 0x71, 0x72, 0x77, 0x8b, 0x44, 0x44, 0x49, 0xf, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x84, +0x85, 0x88, 0xff, 0x7d, 0x7d, 0x81, 0xf1, 0x63, 0x64, 0x67, 0x83, 0x25, 0x26, 0x26, 0x28, 0x0, 0x0, 0x0, 0xa, 0x0, +0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xc, 0x4d, 0x4f, 0x50, 0x5a, 0x7d, 0x7f, 0x81, 0xd7, 0xb5, +0xb6, 0xb8, 0xff, 0xdb, 0xdb, 0xde, 0xff, 0xe6, 0xe6, 0xe8, 0xff, 0xdf, 0xdf, 0xe0, 0xff, 0xbf, 0xc0, 0xc3, 0xff, 0x88, +0x89, 0x8c, 0xe2, 0x62, 0x63, 0x64, 0x34, 0x4f, 0x50, 0x50, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7c, 0x7d, 0x80, 0xba, 0x6c, 0x6d, 0x70, 0x92, 0x37, 0x36, 0x3a, 0x33, 0x0, +0x0, 0x0, 0xd, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x26, +0x26, 0x26, 0x1d, 0x57, 0x58, 0x5a, 0x8d, 0x95, 0x97, 0x9a, 0xfa, 0xce, 0xcf, 0xd1, 0xff, 0xe6, 0xe6, 0xe7, 0xff, 0xe9, +0xe9, 0xea, 0xff, 0xd6, 0xd7, 0xd9, 0xff, 0xa7, 0xa8, 0xaa, 0xfa, 0x7c, 0x7e, 0x7f, 0xab, 0x59, 0x5b, 0x5b, 0x18, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x1f, 0x20, 0x23, 0x13, +0x13, 0x14, 0x22, 0x2, 0x2, 0x2, 0x12, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x42, 0x42, 0x45, 0x44, 0x75, 0x76, 0x79, 0xc2, 0xb0, +0xb1, 0xb3, 0xfe, 0xdd, 0xde, 0xdf, 0xff, 0xea, 0xea, 0xeb, 0xff, 0xdd, 0xde, 0xdf, 0xff, 0xb9, 0xba, 0xbc, 0xff, 0x82, +0x85, 0x86, 0xe7, 0x4e, 0x50, 0x51, 0x2e, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0xa, +0xa, 0xa, 0x16, 0x4f, 0x50, 0x52, 0x7a, 0x93, 0x94, 0x97, 0xfa, 0xce, 0xcf, 0xd0, 0xff, 0xdf, 0xe0, 0xe1, 0xff, 0xc6, +0xc7, 0xca, 0xff, 0x94, 0x95, 0x98, 0xf2, 0x6f, 0x70, 0x73, 0x9d, 0x3b, 0x3b, 0x3d, 0x21, 0x0, 0x0, 0x0, 0x1, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x3f, 0x40, 0x42, 0x3e, 0x71, 0x73, 0x76, 0xbd, 0xad, +0xae, 0xb1, 0xfe, 0xc8, 0xc9, 0xcb, 0xff, 0x92, 0x93, 0x96, 0xf2, 0x65, 0x65, 0x68, 0xa2, 0x2e, 0x2e, 0x30, 0x36, 0x4, +0x3, 0x5, 0xe, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, +0x2, 0x3, 0x13, 0x53, 0x54, 0x56, 0x69, 0x82, 0x83, 0x86, 0xf1, 0x91, 0x92, 0x95, 0xef, 0x66, 0x68, 0x69, 0x9e, 0x25, +0x26, 0x27, 0x35, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x8, 0x50, 0x51, 0x52, 0x44, 0x6b, 0x6c, 0x6e, 0xb8, 0x6d, +0x6d, 0x71, 0xb7, 0x36, 0x37, 0x38, 0x3b, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; diff --git a/src/raylib.h b/src/raylib.h index e76bdb5be..e1de52de5 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -472,7 +472,8 @@ typedef enum { FLAG_WINDOW_HIDDEN = 128, // Set to create the window initially hidden FLAG_WINDOW_ALWAYS_RUN = 256, // Set to allow windows running while minimized FLAG_MSAA_4X_HINT = 32, // Set to try enabling MSAA 4X - FLAG_VSYNC_HINT = 64 // Set to try enabling V-Sync on GPU + FLAG_VSYNC_HINT = 64, // Set to try enabling V-Sync on GPU + FLAG_INTERLACED_HINT = 512 // Set to try V3D to choose an interlaced video format } ConfigFlag; // Trace log type @@ -865,6 +866,7 @@ extern "C" { // Prevents name mangling of functions //------------------------------------------------------------------------------------ // Window-related functions +RLAPI void SetGraphicDeviceName(const char *name); // Set the name of the graphic device to use RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI void CloseWindow(void); // Close window and unload OpenGL context