From c333e8049778de79c6f4e0c2698b49c16af19577 Mon Sep 17 00:00:00 2001 From: Colleague Riley Date: Wed, 25 Dec 2024 12:19:51 -0800 Subject: [PATCH 01/33] Update RGFW (#4637) * add PLATFORM_WEB_RGFW * fix some bugs * fix web_rgfw gamepad * send fake screensize * fix gamepad bugs (linux) | add L3 + R3 (gamepad) * fix? * update RGFW (again) * update raylib (merge) * fix xinput stuff * delete makefile added by mistake * update RGFW * update RGFW (rename joystick to gamepad to avoid misunderstandings * update RGFW (fix X11 bug) * update RGFW * use RL_MALLOC for RGFW * update RGFW (fixes xdnd bug) * fix some formating * Update RGFW * update RGFW * undo change * undo change * undo change * undo change * have .scroll be 0 by default --- src/external/RGFW.h | 922 ++++++++++++++++++----------- src/platforms/rcore_desktop_rgfw.c | 68 +-- 2 files changed, 585 insertions(+), 405 deletions(-) diff --git a/src/external/RGFW.h b/src/external/RGFW.h index 2a10eda2c..317d00c7a 100644 --- a/src/external/RGFW.h +++ b/src/external/RGFW.h @@ -30,6 +30,7 @@ /* #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included #define RGFW_PRINT_ERRORS - (optional) makes it so RGFW prints errors when they're found + #define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl) #define RGFW_BUFFER - (optional) just draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format) #define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api) @@ -65,7 +66,7 @@ /* Example to get you started : -linux : gcc main.c -lX11 -lXrandr -lGL +linux : gcc main.c -lX11 -lXrandr -lGL -lm windows : gcc main.c -lopengl32 -lwinmm -lshell32 -lgdi32 macos : gcc main.c -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo @@ -207,11 +208,7 @@ int main() { #endif #ifndef RGFWDEF - #ifdef __clang__ - #define RGFWDEF static inline - #else - #define RGFWDEF inline - #endif + #define RGFWDEF inline #endif #ifndef RGFW_ENUM @@ -391,7 +388,7 @@ typedef RGFW_ENUM(u8, RGFW_event_types) { RGFW_keyReleased, /*!< a key has been released*/ /*! key event note the code of the key pressed is stored in - RGFW_Event.keyCode + RGFW_Event.key !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! while a string version is stored in @@ -546,8 +543,9 @@ typedef struct RGFW_Event { u32 type; /*!< which event has been sent?*/ RGFW_point point; /*!< mouse x, y of event (or drop point) */ - u8 keyCode; /*!< keycode of event !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */ - + u8 key; /*!< the physical key of the event, refers to where key is physically !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */ + u8 keyChar; /*!< mapped key char of the event*/ + b8 repeat; /*!< key press event repeated (the key is being held) */ b8 inFocus; /*!< if the window is in focus or not (this is always true for MacOS windows due to the api being weird) */ @@ -871,14 +869,6 @@ RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); /*error handling*/ RGFWDEF b8 RGFW_Error(void); /*!< returns true if an error has occurred (doesn't print errors itself) */ -/*! returns true if the key should be shifted */ -RGFWDEF b8 RGFW_shouldShift(u32 keycode, u8 lockState); - -/*! get char from RGFW keycode (using a LUT), uses shift'd version if shift = true */ -RGFWDEF char RGFW_keyCodeToChar(u32 keycode, b8 shift); -/*! get char from RGFW keycode (using a LUT), uses lockState for shouldShift) */ -RGFWDEF char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState); - /*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus.*/ RGFWDEF b8 RGFW_isPressed(RGFW_window* win, u8 key); /*!< if key is pressed (key code)*/ @@ -935,8 +925,8 @@ typedef void (* RGFW_mouseposfunc)(RGFW_window* win, RGFW_point point); typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point); /*! RGFW_windowRefresh, the window that needs to be refreshed */ typedef void (* RGFW_windowrefreshfunc)(RGFW_window* win); -/*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the keycode, the string version, the state of mod keys, if it was a press (else it's a release) */ -typedef void (* RGFW_keyfunc)(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed); +/*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of mod keys, if it was a press (else it's a release) */ +typedef void (* RGFW_keyfunc)(RGFW_window* win, u32 key, u32 mappedKey, char keyName[16], u8 lockState, b8 pressed); /*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ typedef void (* RGFW_mousebuttonfunc)(RGFW_window* win, u8 button, double scroll, b8 pressed); /*!gp /gp, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ @@ -1085,7 +1075,64 @@ RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */ typedef RGFW_ENUM(u8, RGFW_Key) { RGFW_KEY_NULL = 0, - RGFW_Escape, + RGFW_Escape = '\033', + RGFW_Backtick = '`', + RGFW_0 = '0', + RGFW_1 = '1', + RGFW_2 = '2', + RGFW_3 = '3', + RGFW_4 = '4', + RGFW_5 = '5', + RGFW_6 = '6', + RGFW_7 = '7', + RGFW_8 = '8', + RGFW_9 = '9', + + RGFW_Minus = '-', + RGFW_Equals = '=', + RGFW_BackSpace = '\b', + RGFW_Tab = '\t', + RGFW_Space = ' ', + + RGFW_a = 'a', + RGFW_b = 'b', + RGFW_c = 'c', + RGFW_d = 'd', + RGFW_e = 'e', + RGFW_f = 'f', + RGFW_g = 'g', + RGFW_h = 'h', + RGFW_i = 'i', + RGFW_j = 'j', + RGFW_k = 'k', + RGFW_l = 'l', + RGFW_m = 'm', + RGFW_n = 'n', + RGFW_o = 'o', + RGFW_p = 'p', + RGFW_q = 'q', + RGFW_r = 'r', + RGFW_s = 's', + RGFW_t = 't', + RGFW_u = 'u', + RGFW_v = 'v', + RGFW_w = 'w', + RGFW_x = 'x', + RGFW_y = 'y', + RGFW_z = 'z', + + RGFW_Period = '.', + RGFW_Comma = ',', + RGFW_Slash = '/', + RGFW_Bracket = '{', + RGFW_CloseBracket = '}', + RGFW_Semicolon = ';', + RGFW_Apostrophe = '\'', + RGFW_BackSlash = '\\', + RGFW_Return = '\n', + + RGFW_Delete = '\177', /* 127 */ + RGFW_F1, RGFW_F2, RGFW_F3, @@ -1099,23 +1146,6 @@ typedef RGFW_ENUM(u8, RGFW_Key) { RGFW_F11, RGFW_F12, - RGFW_Backtick, - - RGFW_0, - RGFW_1, - RGFW_2, - RGFW_3, - RGFW_4, - RGFW_5, - RGFW_6, - RGFW_7, - RGFW_8, - RGFW_9, - - RGFW_Minus, - RGFW_Equals, - RGFW_BackSpace, - RGFW_Tab, RGFW_CapsLock, RGFW_ShiftL, RGFW_ControlL, @@ -1125,51 +1155,11 @@ typedef RGFW_ENUM(u8, RGFW_Key) { RGFW_ControlR, RGFW_AltR, RGFW_SuperR, - RGFW_Space, - - RGFW_a, - RGFW_b, - RGFW_c, - RGFW_d, - RGFW_e, - RGFW_f, - RGFW_g, - RGFW_h, - RGFW_i, - RGFW_j, - RGFW_k, - RGFW_l, - RGFW_m, - RGFW_n, - RGFW_o, - RGFW_p, - RGFW_q, - RGFW_r, - RGFW_s, - RGFW_t, - RGFW_u, - RGFW_v, - RGFW_w, - RGFW_x, - RGFW_y, - RGFW_z, - - RGFW_Period, - RGFW_Comma, - RGFW_Slash, - RGFW_Bracket, - RGFW_CloseBracket, - RGFW_Semicolon, - RGFW_Return, - RGFW_Quote, - RGFW_BackSlash, - RGFW_Up, RGFW_Down, RGFW_Left, RGFW_Right, - RGFW_Delete, RGFW_Insert, RGFW_End, RGFW_Home, @@ -1180,10 +1170,10 @@ typedef RGFW_ENUM(u8, RGFW_Key) { RGFW_KP_Slash, RGFW_Multiply, RGFW_KP_Minus, - RGFW_KP_1, - RGFW_KP_2, - RGFW_KP_3, - RGFW_KP_4, + RGFW_KP_1, + RGFW_KP_2, + RGFW_KP_3, + RGFW_KP_4, RGFW_KP_5, RGFW_KP_6, RGFW_KP_7, @@ -1193,7 +1183,7 @@ typedef RGFW_ENUM(u8, RGFW_Key) { RGFW_KP_Period, RGFW_KP_Return, - final_key, + final_key }; @@ -1263,121 +1253,121 @@ This is the start of keycode data #include #endif -u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(136, 337, 128, DOM_VK_WIN_OEM_CLEAR + 1, 130)] = { +u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(136, 0x15C + 1, 128, DOM_VK_WIN_OEM_CLEAR + 1, 130)] = { #ifdef __cplusplus 0 }; void RGFW_init_keys(void) { #endif - RGFW_MAP [RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE)] = RGFW_Backtick RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE)] = RGFW_Backtick RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x30, 29, DOM_VK_0, KEY_0)] = RGFW_0 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x31, 18, DOM_VK_1, KEY_1)] = RGFW_1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x32, 19, DOM_VK_2, KEY_2)] = RGFW_2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x33, 20, DOM_VK_3, KEY_3)] = RGFW_3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x34, 21, DOM_VK_4, KEY_4)] = RGFW_4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x35, 23, DOM_VK_5, KEY_5)] = RGFW_5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x36, 22, DOM_VK_6, KEY_6)] = RGFW_6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x37, 26, DOM_VK_7, KEY_7)] = RGFW_7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x38, 28, DOM_VK_8, KEY_8)] = RGFW_8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x39, 25, DOM_VK_9, KEY_9)] = RGFW_9, + RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x00B, 29, DOM_VK_0, KEY_0)] = RGFW_0 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x002, 18, DOM_VK_1, KEY_1)] = RGFW_1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x003, 19, DOM_VK_2, KEY_2)] = RGFW_2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x004, 20, DOM_VK_3, KEY_3)] = RGFW_3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x005, 21, DOM_VK_4, KEY_4)] = RGFW_4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x006, 23, DOM_VK_5, KEY_5)] = RGFW_5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x007, 22, DOM_VK_6, KEY_6)] = RGFW_6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x008, 26, DOM_VK_7, KEY_7)] = RGFW_7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x009, 28, DOM_VK_8, KEY_8)] = RGFW_8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x00A, 25, DOM_VK_9, KEY_9)] = RGFW_9, - RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x20, 49, DOM_VK_SPACE, KEY_SPACE)] = RGFW_Space, + RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x039, 49, DOM_VK_SPACE, KEY_SPACE)] = RGFW_Space, - RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x41, 0, DOM_VK_A, KEY_A)] = RGFW_a RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x42, 11, DOM_VK_B, KEY_B)] = RGFW_b RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x43, 8, DOM_VK_C, KEY_C)] = RGFW_c RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x44, 2, DOM_VK_D, KEY_D)] = RGFW_d RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x45, 14, DOM_VK_E, KEY_E)] = RGFW_e RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x46, 3, DOM_VK_F, KEY_F)] = RGFW_f RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x47, 5, DOM_VK_G, KEY_G)] = RGFW_g RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x48, 4, DOM_VK_H, KEY_H)] = RGFW_h RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x49, 34, DOM_VK_I, KEY_I)] = RGFW_i RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x4A, 38, DOM_VK_J, KEY_J)] = RGFW_j RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x4B, 40, DOM_VK_K, KEY_K)] = RGFW_k RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x4C, 37, DOM_VK_L, KEY_L)] = RGFW_l RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x4D, 46, DOM_VK_M, KEY_M)] = RGFW_m RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x4E, 45, DOM_VK_N, KEY_N)] = RGFW_n RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x4F, 31, DOM_VK_O, KEY_O)] = RGFW_o RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x50, 35, DOM_VK_P, KEY_P)] = RGFW_p RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x51, 12, DOM_VK_Q, KEY_Q)] = RGFW_q RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x52, 15, DOM_VK_R, KEY_R)] = RGFW_r RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x53, 1, DOM_VK_S, KEY_S)] = RGFW_s RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x54, 17, DOM_VK_T, KEY_T)] = RGFW_t RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x55, 32, DOM_VK_U, KEY_U)] = RGFW_u RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x56, 9, DOM_VK_V, KEY_V)] = RGFW_v RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x57, 13, DOM_VK_W, KEY_W)] = RGFW_w RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x58, 7, DOM_VK_X, KEY_X)] = RGFW_x RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x59, 16, DOM_VK_Y, KEY_Y)] = RGFW_y RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x5A, 6, DOM_VK_Z, KEY_Z)] = RGFW_z, + RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x01E, 0, DOM_VK_A, KEY_A)] = RGFW_a RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x030, 11, DOM_VK_B, KEY_B)] = RGFW_b RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x02E, 8, DOM_VK_C, KEY_C)] = RGFW_c RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x020, 2, DOM_VK_D, KEY_D)] = RGFW_d RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x012, 14, DOM_VK_E, KEY_E)] = RGFW_e RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x021, 3, DOM_VK_F, KEY_F)] = RGFW_f RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x022, 5, DOM_VK_G, KEY_G)] = RGFW_g RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x023, 4, DOM_VK_H, KEY_H)] = RGFW_h RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x017, 34, DOM_VK_I, KEY_I)] = RGFW_i RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x024, 38, DOM_VK_J, KEY_J)] = RGFW_j RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x025, 40, DOM_VK_K, KEY_K)] = RGFW_k RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x026, 37, DOM_VK_L, KEY_L)] = RGFW_l RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x032, 46, DOM_VK_M, KEY_M)] = RGFW_m RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x031, 45, DOM_VK_N, KEY_N)] = RGFW_n RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x018, 31, DOM_VK_O, KEY_O)] = RGFW_o RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x019, 35, DOM_VK_P, KEY_P)] = RGFW_p RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x010, 12, DOM_VK_Q, KEY_Q)] = RGFW_q RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x013, 15, DOM_VK_R, KEY_R)] = RGFW_r RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x01F, 1, DOM_VK_S, KEY_S)] = RGFW_s RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x014, 17, DOM_VK_T, KEY_T)] = RGFW_t RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x016, 32, DOM_VK_U, KEY_U)] = RGFW_u RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x02F, 9, DOM_VK_V, KEY_V)] = RGFW_v RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x011, 13, DOM_VK_W, KEY_W)] = RGFW_w RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x02D, 7, DOM_VK_X, KEY_X)] = RGFW_x RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x015, 16, DOM_VK_Y, KEY_Y)] = RGFW_y RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x02C, 6, DOM_VK_Z, KEY_Z)] = RGFW_z, - RGFW_MAP [RGFW_OS_BASED_VALUE(60, 190, 47, DOM_VK_PERIOD, KEY_DOT)] = RGFW_Period RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(59, 188, 43, DOM_VK_COMMA, KEY_COMMA)] = RGFW_Comma RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(61, 191, 44, DOM_VK_SLASH, KEY_SLASH)] = RGFW_Slash RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(34, 219, 33, DOM_VK_OPEN_BRACKET, KEY_LEFTBRACE)] = RGFW_Bracket RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(35, 221, 30, DOM_VK_CLOSE_BRACKET, KEY_RIGHTBRACE)] = RGFW_CloseBracket RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(47, 186, 41, DOM_VK_SEMICOLON, KEY_SEMICOLON)] = RGFW_Semicolon RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(48, 222, 39, DOM_VK_QUOTE, KEY_APOSTROPHE)] = RGFW_Quote RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(51, 322, 42, DOM_VK_BACK_SLASH, KEY_BACKSLASH)] = RGFW_BackSlash, + RGFW_MAP [RGFW_OS_BASED_VALUE(60, 0x034, 47, DOM_VK_PERIOD, KEY_DOT)] = RGFW_Period RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(59, 0x033, 43, DOM_VK_COMMA, KEY_COMMA)] = RGFW_Comma RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(61, 0x035, 44, DOM_VK_SLASH, KEY_SLASH)] = RGFW_Slash RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(34, 0x01A, 33, DOM_VK_OPEN_BRACKET, KEY_LEFTBRACE)] = RGFW_Bracket RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(35, 0x01B, 30, DOM_VK_CLOSE_BRACKET, KEY_RIGHTBRACE)] = RGFW_CloseBracket RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(47, 0x027, 41, DOM_VK_SEMICOLON, KEY_SEMICOLON)] = RGFW_Semicolon RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(48, 0x028, 39, DOM_VK_QUOTE, KEY_APOSTROPHE)] = RGFW_Apostrophe RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(51, 0x02B, 42, DOM_VK_BACK_SLASH, KEY_BACKSLASH)] = RGFW_BackSlash, - RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x0D, 36, DOM_VK_RETURN, KEY_ENTER)] = RGFW_Return RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x2E, 118, DOM_VK_DELETE, KEY_DELETE)] = RGFW_Delete RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x90, 72, DOM_VK_NUM_LOCK, KEY_NUMLOCK)] = RGFW_Numlock RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x6F, 82, DOM_VK_DIVIDE, KEY_KPSLASH)] = RGFW_KP_Slash RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x6A, 76, DOM_VK_MULTIPLY, KEY_KPASTERISK)] = RGFW_Multiply RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x6D, 67, DOM_VK_SUBTRACT, KEY_KPMINUS)] = RGFW_KP_Minus RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x61, 84, DOM_VK_NUMPAD1, KEY_KP1)] = RGFW_KP_1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x62, 85, DOM_VK_NUMPAD2, KEY_KP2)] = RGFW_KP_2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x63, 86, DOM_VK_NUMPAD3, KEY_KP3)] = RGFW_KP_3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x64, 87, DOM_VK_NUMPAD4, KEY_KP4)] = RGFW_KP_4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x65, 88, DOM_VK_NUMPAD5, KEY_KP5)] = RGFW_KP_5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x66, 89, DOM_VK_NUMPAD6, KEY_KP6)] = RGFW_KP_6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x67, 90, DOM_VK_NUMPAD7, KEY_KP7)] = RGFW_KP_7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x68, 92, DOM_VK_NUMPAD8, KEY_KP8)] = RGFW_KP_8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x69, 93, DOM_VK_NUMPAD9, KEY_KP9)] = RGFW_KP_9 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x60, 83, DOM_VK_NUMPAD0, KEY_KP0)] = RGFW_KP_0 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x6E, 65, DOM_VK_DECIMAL, KEY_KPDOT)] = RGFW_KP_Period RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x92, 77, 0, KEY_KPENTER)] = RGFW_KP_Return, + RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x01C, 36, DOM_VK_RETURN, KEY_ENTER)] = RGFW_Return RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x153, 118, DOM_VK_DELETE, KEY_DELETE)] = RGFW_Delete RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x145, 72, DOM_VK_NUM_LOCK, KEY_NUMLOCK)] = RGFW_Numlock RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x135, 82, DOM_VK_DIVIDE, KEY_KPSLASH)] = RGFW_KP_Slash RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x037, 76, DOM_VK_MULTIPLY, KEY_KPASTERISK)] = RGFW_Multiply RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x04A, 67, DOM_VK_SUBTRACT, KEY_KPMINUS)] = RGFW_KP_Minus RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x04F, 84, DOM_VK_NUMPAD1, KEY_KP1)] = RGFW_KP_1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x050, 85, DOM_VK_NUMPAD2, KEY_KP2)] = RGFW_KP_2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x051, 86, DOM_VK_NUMPAD3, KEY_KP3)] = RGFW_KP_3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x04B, 87, DOM_VK_NUMPAD4, KEY_KP4)] = RGFW_KP_4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x04C, 88, DOM_VK_NUMPAD5, KEY_KP5)] = RGFW_KP_5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x04D, 89, DOM_VK_NUMPAD6, KEY_KP6)] = RGFW_KP_6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x047, 90, DOM_VK_NUMPAD7, KEY_KP7)] = RGFW_KP_7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x048, 92, DOM_VK_NUMPAD8, KEY_KP8)] = RGFW_KP_8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x049, 93, DOM_VK_NUMPAD9, KEY_KP9)] = RGFW_KP_9 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x052, 83, DOM_VK_NUMPAD0, KEY_KP0)] = RGFW_KP_0 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x053, 65, DOM_VK_DECIMAL, KEY_KPDOT)] = RGFW_KP_Period RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x11C, 77, 0, KEY_KPENTER)] = RGFW_KP_Return, - RGFW_MAP [RGFW_OS_BASED_VALUE(20, 189, 27, DOM_VK_HYPHEN_MINUS, KEY_MINUS)] = RGFW_Minus RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(21, 187, 24, DOM_VK_EQUALS, KEY_EQUAL)] = RGFW_Equals RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(22, 8, 51, DOM_VK_BACK_SPACE, KEY_BACKSPACE)] = RGFW_BackSpace RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x09, 48, DOM_VK_TAB, KEY_TAB)] = RGFW_Tab RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(66, 20, 57, DOM_VK_CAPS_LOCK, KEY_CAPSLOCK)] = RGFW_CapsLock RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x10, 56, DOM_VK_SHIFT, KEY_LEFTSHIFT)] = RGFW_ShiftL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x11, 59, DOM_VK_CONTROL, KEY_LEFTCTRL)] = RGFW_ControlL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(64,0x12, 58, DOM_VK_ALT, KEY_LEFTALT)] = RGFW_AltL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x5B, 55, DOM_VK_WIN, KEY_LEFTMETA)] = RGFW_SuperL, + RGFW_MAP [RGFW_OS_BASED_VALUE(20, 0x00C, 27, DOM_VK_HYPHEN_MINUS, KEY_MINUS)] = RGFW_Minus RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(21, 0x00D, 24, DOM_VK_EQUALS, KEY_EQUAL)] = RGFW_Equals RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(22, 0x00E, 51, DOM_VK_BACK_SPACE, KEY_BACKSPACE)] = RGFW_BackSpace RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x00F, 48, DOM_VK_TAB, KEY_TAB)] = RGFW_Tab RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(66, 0x03A, 57, DOM_VK_CAPS_LOCK, KEY_CAPSLOCK)] = RGFW_CapsLock RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x02A, 56, DOM_VK_SHIFT, KEY_LEFTSHIFT)] = RGFW_ShiftL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL, KEY_LEFTCTRL)] = RGFW_ControlL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT, KEY_LEFTALT)] = RGFW_AltL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN, KEY_LEFTMETA)] = RGFW_SuperL, - #if !defined(RGFW_WINDOWS) && !defined(RGFW_MACOS) && !defined(RGFW_WEBASM) - RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11, 59, 0, KEY_RIGHTCTRL)] = RGFW_ControlR RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(135, 0xA4, 55, 0, KEY_RIGHTMETA)] = RGFW_SuperR, - RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x5C, 56, 0, KEY_RIGHTSHIFT)] = RGFW_ShiftR RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(108, 165, 58, 0, KEY_RIGHTALT)] = RGFW_AltR, + #if !defined(RGFW_MACOS) && !defined(RGFW_WEBASM) + RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0, KEY_RIGHTCTRL)] = RGFW_ControlR RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(135, 0x15C, 55, 0, KEY_RIGHTMETA)] = RGFW_SuperR, + RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0, KEY_RIGHTSHIFT)] = RGFW_ShiftR RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(108, 0x138, 58, 0, KEY_RIGHTALT)] = RGFW_AltR, #endif - RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x70, 127, DOM_VK_F1, KEY_F1)] = RGFW_F1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x71, 121, DOM_VK_F2, KEY_F2)] = RGFW_F2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x72, 100, DOM_VK_F3, KEY_F3)] = RGFW_F3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x73, 119, DOM_VK_F4, KEY_F4)] = RGFW_F4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x74, 97, DOM_VK_F5, KEY_F5)] = RGFW_F5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x75, 98, DOM_VK_F6, KEY_F6)] = RGFW_F6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x76, 99, DOM_VK_F7, KEY_F7)] = RGFW_F7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x77, 101, DOM_VK_F8, KEY_F8)] = RGFW_F8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x78, 102, DOM_VK_F9, KEY_F9)] = RGFW_F9 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x79, 110, DOM_VK_F10, KEY_F10)] = RGFW_F10 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x7A, 104, DOM_VK_F11, KEY_F11)] = RGFW_F11 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x7B, 112, DOM_VK_F12, KEY_F12)] = RGFW_F12 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x26, 126, DOM_VK_UP, KEY_UP)] = RGFW_Up RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x28, 125, DOM_VK_DOWN, KEY_DOWN)] = RGFW_Down RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x25, 123, DOM_VK_LEFT, KEY_LEFT)] = RGFW_Left RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x27, 124, DOM_VK_RIGHT, KEY_RIGHT)] = RGFW_Right RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x2D, 115, DOM_VK_INSERT, KEY_INSERT)] = RGFW_Insert RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x23, 120, DOM_VK_END, KEY_END)] = RGFW_End RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(112, 336, 117, DOM_VK_PAGE_UP, KEY_PAGEUP)] = RGFW_PageUp RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(117, 325, 122, DOM_VK_PAGE_DOWN, KEY_PAGEDOWN)] = RGFW_PageDown RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x1B, 53, DOM_VK_ESCAPE, KEY_ESC)] = RGFW_Escape RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x24, 116, DOM_VK_HOME, KEY_HOME)] = RGFW_Home RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x03B, 127, DOM_VK_F1, KEY_F1)] = RGFW_F1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x03C, 121, DOM_VK_F2, KEY_F2)] = RGFW_F2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x03D, 100, DOM_VK_F3, KEY_F3)] = RGFW_F3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x03E, 119, DOM_VK_F4, KEY_F4)] = RGFW_F4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x03F, 97, DOM_VK_F5, KEY_F5)] = RGFW_F5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x040, 98, DOM_VK_F6, KEY_F6)] = RGFW_F6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x041, 99, DOM_VK_F7, KEY_F7)] = RGFW_F7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x042, 101, DOM_VK_F8, KEY_F8)] = RGFW_F8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x043, 102, DOM_VK_F9, KEY_F9)] = RGFW_F9 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x044, 110, DOM_VK_F10, KEY_F10)] = RGFW_F10 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x057, 104, DOM_VK_F11, KEY_F11)] = RGFW_F11 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x058, 112, DOM_VK_F12, KEY_F12)] = RGFW_F12 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x148, 126, DOM_VK_UP, KEY_UP)] = RGFW_Up RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x150, 125, DOM_VK_DOWN, KEY_DOWN)] = RGFW_Down RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x14B, 123, DOM_VK_LEFT, KEY_LEFT)] = RGFW_Left RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x14D, 124, DOM_VK_RIGHT, KEY_RIGHT)] = RGFW_Right RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x152, 115, DOM_VK_INSERT, KEY_INSERT)] = RGFW_Insert RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x14F, 120, DOM_VK_END, KEY_END)] = RGFW_End RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(112, 0x149, 117, DOM_VK_PAGE_UP, KEY_PAGEUP)] = RGFW_PageUp RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN, KEY_PAGEDOWN)] = RGFW_PageDown RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE, KEY_ESC)] = RGFW_Escape RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME, KEY_HOME)] = RGFW_Home RGFW_NEXT #ifndef __cplusplus }; #else @@ -1394,9 +1384,9 @@ typedef struct { RGFW_keyState RGFW_keyboard[final_key] = { {0, 0} }; -RGFWDEF u32 RGFW_apiKeyCodeToRGFW(u32 keycode); +RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode); -u32 RGFW_apiKeyCodeToRGFW(u32 keycode) { +u32 RGFW_apiKeyToRGFW(u32 keycode) { #ifdef __cplusplus if (RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE) != RGFW_Backtick) { RGFW_init_keys(); @@ -1419,38 +1409,6 @@ void RGFW_resetKey(void) { RGFW_keyboard[i].prev = 0; } -b8 RGFW_shouldShift(u32 keycode, u8 lockState) { - #define RGFW_xor(x, y) (( (x) && (!(y)) ) || ((y) && (!(x)) )) - b8 caps4caps = (lockState & RGFW_CAPSLOCK) && ((keycode >= RGFW_a) && (keycode <= RGFW_z)); - b8 shouldShift = RGFW_xor((RGFW_isPressed(NULL, RGFW_ShiftL) || RGFW_isPressed(NULL, RGFW_ShiftR)), caps4caps); - #undef RGFW_xor - - return shouldShift; -} - -char RGFW_keyCodeToChar(u32 keycode, b8 shift) { - static const char map[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '`', '0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', '-', '=', 0, '\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '.', ',', '/', '[', ']', ';', '\n', '\'', '\\', - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', '*', '-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\n' - }; - - static const char mapCaps[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '~', ')', '!', '@', '#', '$', '%', '^', '&', '*', - '(', '_', '+', 0, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '>', '<', '?', '{', '}', ':', '\n', '"', '|', - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '?', '*', '-', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - if (shift == RGFW_FALSE) - return map[keycode]; - return mapCaps[keycode]; -} - -char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState) { return RGFW_keyCodeToChar(keycode, RGFW_shouldShift(keycode, lockState)); } - /* this is the end of keycode data */ @@ -1479,7 +1437,7 @@ void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, b8 status) {R void RGFW_mouseposfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} void RGFW_windowrefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); } -void RGFW_keyfuncEMPTY(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(keycode); RGFW_UNUSED(keyName); RGFW_UNUSED(lockState); RGFW_UNUSED(pressed);} +void RGFW_keyfuncEMPTY(RGFW_window* win, u32 key, u32 mappedKey, char keyName[16], u8 lockState, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(mappedKey); RGFW_UNUSED(keyName); RGFW_UNUSED(lockState); RGFW_UNUSED(pressed);} void RGFW_mousebuttonfuncEMPTY(RGFW_window* win, u8 button, double scroll, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);} void RGFW_gpButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, b8 pressed){RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); } void RGFW_gpAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount){RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); } @@ -1959,7 +1917,7 @@ void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) { MacOS and Windows do this using a structure called a "pixel format" X11 calls it a "Visual" This function returns the attributes for the format we want */ - static u32* RGFW_initFormatAttribs(u32 useSoftware) { + u32* RGFW_initFormatAttribs(u32 useSoftware) { RGFW_UNUSED(useSoftware); static u32 attribs[] = { #if defined(RGFW_X11) || defined(RGFW_WINDOWS) @@ -2422,6 +2380,10 @@ Start of Linux / Unix defines win->buffer = (u8*)RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); + #ifdef RGFW_DEBUG + printf("RGFW INFO: createing a 4 channel %i by %i buffer\n", RGFW_bufferSize.w, RGFW_bufferSize.h); + #endif + #ifdef RGFW_OSMESA win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); @@ -2489,7 +2451,6 @@ Start of Linux / Unix defines XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2))); } @@ -2739,6 +2700,10 @@ Start of Linux / Unix defines RGFW_windowsOpen++; + #ifdef RGFW_DEBUG + printf("RGFW INFO: a window with a rect of {%i, %i, %i, %i} \n", win->r.x, win->r.y, win->r.w, win->r.h); + #endif + return win; /*return newly created window*/ } @@ -2831,8 +2796,10 @@ Start of Linux / Unix defines } /* set event key data */ + win->event.key = RGFW_apiKeyToRGFW(E.xkey.keycode); + KeySym sym = (KeySym)XkbKeycodeToKeysym((Display*) win->src.display, E.xkey.keycode, 0, E.xkey.state & ShiftMask ? 1 : 0); - win->event.keyCode = RGFW_apiKeyCodeToRGFW(E.xkey.keycode); + win->event.keyChar = (u8)sym; char* str = (char*)XKeysymToString(sym); if (str != NULL) @@ -2840,7 +2807,7 @@ Start of Linux / Unix defines win->event.keyName[15] = '\0'; - RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); + RGFW_keyboard[win->event.key].prev = RGFW_isPressed(win, win->event.key); /* get keystate data */ win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased; @@ -2849,14 +2816,15 @@ Start of Linux / Unix defines XGetKeyboardControl((Display*) win->src.display, &keystate); RGFW_updateLockState(win, (keystate.led_mask & 1), (keystate.led_mask & 2)); - RGFW_keyboard[win->event.keyCode].current = (E.type == KeyPress); - RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, (E.type == KeyPress)); + RGFW_keyboard[win->event.key].current = (E.type == KeyPress); + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyName, win->event.lockState, (E.type == KeyPress)); break; } case ButtonPress: case ButtonRelease: win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); // the events match + win->event.button = E.xbutton.button; switch(win->event.button) { case RGFW_mouseScrollUp: win->event.scroll = 1; @@ -2866,12 +2834,11 @@ Start of Linux / Unix defines break; default: break; } - - win->event.button = E.xbutton.button; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; if (win->event.repeat == RGFW_FALSE) - win->event.repeat = RGFW_isPressed(win, win->event.keyCode); + win->event.repeat = RGFW_isPressed(win, win->event.key); RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress); RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress)); @@ -2884,8 +2851,8 @@ Start of Linux / Unix defines if ((win->_winArgs & RGFW_HOLD_MOUSE)) { win->event.point.y = E.xmotion.y; - win->event.point.x = win->_lastMousePoint.x - abs(win->event.point.x); - win->event.point.y = win->_lastMousePoint.y - abs(win->event.point.y); + win->event.point.x = win->event.point.x - win->_lastMousePoint.x; + win->event.point.y = win->event.point.y - win->_lastMousePoint.y; } win->_lastMousePoint = RGFW_POINT(E.xmotion.x, E.xmotion.y); @@ -3217,9 +3184,9 @@ Start of Linux / Unix defines break; } - default: { - break; - } + default: + XFlush((Display*) win->src.display); + return RGFW_window_checkEvent(win); } XFlush((Display*) win->src.display); @@ -3432,7 +3399,7 @@ Start of Linux / Unix defines #endif } - void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { + void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { assert(win != NULL); XEvent event; @@ -3442,10 +3409,11 @@ Start of Linux / Unix defines &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); - if (event.xbutton.x == v.x && event.xbutton.y == v.y) + win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y); + if (event.xbutton.x == p.x && event.xbutton.y == p.y) return; - XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) v.x - win->r.x, (int) v.y - win->r.y); + XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) p.x - win->r.x, (int) p.y - win->r.y); } RGFWDEF void RGFW_window_disableMouse(RGFW_window* win) { @@ -3783,6 +3751,10 @@ Start of Linux / Unix defines monitor.scaleY = (float) (dpi_height) / (float) 96; XRRFreeScreenResources(sr); XCloseDisplay(display); + + #ifdef RGFW_DEBUG + printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n", monitor.name, monitor.rect.x, monitor.rect.y, monitor.rect.w, monitor.rect.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY); + #endif return monitor; } @@ -3812,6 +3784,10 @@ Start of Linux / Unix defines XCloseDisplay(display); + #ifdef RGFW_DEBUG + printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n", monitor.name, monitor.rect.x, monitor.rect.y, monitor.rect.w, monitor.rect.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY); + #endif + return monitor; } @@ -4421,19 +4397,20 @@ static void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t ser char name[16]; xkb_keysym_get_name(keysym, name, 16); - u32 RGFW_key = RGFW_apiKeyCodeToRGFW(key); + u32 RGFW_key = RGFW_apiKeyToRGFW(key); RGFW_keyboard[RGFW_key].prev = RGFW_keyboard[RGFW_key].current; RGFW_keyboard[RGFW_key].current = state; RGFW_Event ev; ev.type = RGFW_keyPressed + state; - ev.keyCode = RGFW_key; + ev.key = RGFW_key; + ev.keyChar = (u8)keysym; strcpy(ev.keyName, name); ev.repeat = RGFW_isHeld(RGFW_key_win, RGFW_key); RGFW_eventPipe_push(RGFW_key_win, ev); RGFW_updateLockState(RGFW_key_win, xkb_keymap_mod_get_index(keymap, "Lock"), xkb_keymap_mod_get_index(keymap, "Mod2")); - RGFW_keyCallback(RGFW_key_win, RGFW_key, name, RGFW_key_win->event.lockState, state); + RGFW_keyCallback(RGFW_key_win, RGFW_key, (u8)keysym, name, RGFW_key_win->event.lockState, state); } static void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); @@ -4563,6 +4540,8 @@ int create_shm_file(off_t size) { } static void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { + RGFW_UNUSED(data); RGFW_UNUSED(cb); RGFW_UNUSED(time); + #ifdef RGFW_BUFFER RGFW_window* win = (RGFW_window*)data; if ((win->_winArgs & RGFW_NO_CPU_RENDER)) @@ -4608,11 +4587,13 @@ static const struct wl_callback_listener wl_surface_frame_listener = { void RGFW_releaseCursor(RGFW_window* win) { RGFW_UNUSED(win); + + /* TODO wayland */ } void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); - + /* TODO wayland */ } @@ -4764,6 +4745,10 @@ static const struct wl_callback_listener wl_surface_frame_listener = { win->src.eventIndex = 0; win->src.eventLen = 0; + + #ifdef RGFW_DEBUG + printf("RGFW INFO: a window with a rect of {%i, %i, %i, %i} \n", win->r.x, win->r.y, win->r.w, win->r.h); + #endif return win; } @@ -4812,8 +4797,20 @@ static const struct wl_callback_listener wl_surface_frame_listener = { void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); - + /* TODO wayland */ + assert(win != NULL); + struct wl_pointer *pointer = wl_seat_get_pointer(win->seat); + if (!pointer) { + return; + } + + // Initiate the move operation + wl_shell_surface_move(win->shell_surface, pointer, win->serial); + win->r.x = v.x; + win->r.y = v.y; + + wl_display_flush(win->display); } void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) { @@ -4821,9 +4818,11 @@ static const struct wl_callback_listener wl_surface_frame_listener = { /* TODO wayland */ } - void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { - RGFW_UNUSED(win); RGFW_UNUSED(v); - + void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { + win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y); + #ifdef RGFW_DEBUG + printf("Wayland: The platform does not support moving the mouse\n"); + #endif /* TODO wayland */ } @@ -5206,7 +5205,7 @@ static HMODULE wglinstance = NULL; return DefWindowProcA(hWnd, message, wParam, lParam); } } - + #ifndef RGFW_NO_DPI static HMODULE RGFW_Shcore_dll = NULL; typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); @@ -5363,9 +5362,9 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ Class.hCursor = LoadCursor(NULL, IDC_ARROW); Class.lpfnWndProc = WndProc; - Class.hIcon = LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); if (Class.hIcon == NULL) { - Class.hIcon = LoadImageA(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + Class.hIcon = (HICON)LoadImageA(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); } RegisterClassA(&Class); @@ -5606,6 +5605,10 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ wglShareLists(RGFW_root->src.ctx, win->src.ctx); #endif + #ifdef RGFW_DEBUG + printf("RGFW INFO: a window with a rect of {%i, %i, %i, %i} \n", win->r.x, win->r.y, win->r.w, win->r.h); + #endif + return win; } @@ -5848,9 +5851,19 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ return &win->event; static BYTE keyboardState[256]; + GetKeyboardState(keyboardState); - if (PeekMessageA(&msg, win->src.window, 0u, 0u, PM_REMOVE)) { - switch (msg.message) { + + if (!IsWindow(win->src.window)) { + win->event.type = RGFW_quit; + RGFW_windowQuitCallback(win); + return &win->event; + } + + if (PeekMessageA(&msg, win->src.window, 0u, 0u, PM_REMOVE) == 0) + return NULL; + + switch (msg.message) { case WM_CLOSE: case WM_QUIT: RGFW_windowQuitCallback(win); @@ -5883,15 +5896,36 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ break; case WM_KEYUP: { - win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam); - - RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); + i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); + if (scancode == 0) + scancode = MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC); + + switch (scancode) { + case 0x54: scancode = 0x137; break; /* Alt+PrtS */ + case 0x146: scancode = 0x45; break; /* Ctrl+Pause */ + case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */ + default: break; + } + + win->event.key = RGFW_apiKeyToRGFW((u32) scancode); + + if (msg.wParam == VK_CONTROL) { + if (HIWORD(msg.lParam) & KF_EXTENDED) + win->event.key = RGFW_ControlR; + else win->event.key = RGFW_ControlL; + } + + wchar_t charBuffer; + ToUnicodeEx(msg.wParam, scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL); + + win->event.keyChar = (u8)charBuffer; + + RGFW_keyboard[win->event.key].prev = RGFW_isPressed(win, win->event.key); static char keyName[16]; { GetKeyNameTextA((LONG) msg.lParam, keyName, 16); - if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) || ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) { CharLowerBuffA(keyName, 16); @@ -5908,14 +5942,35 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ } win->event.type = RGFW_keyReleased; - RGFW_keyboard[win->event.keyCode].current = 0; - RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0); + RGFW_keyboard[win->event.key].current = 0; + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyName, win->event.lockState, 0); break; } case WM_KEYDOWN: { - win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam); + i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); + if (scancode == 0) + scancode = MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC); - RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); + switch (scancode) { + case 0x54: scancode = 0x137; break; /* Alt+PrtS */ + case 0x146: scancode = 0x45; break; /* Ctrl+Pause */ + case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */ + default: break; + } + + win->event.key = RGFW_apiKeyToRGFW((u32) scancode); + + if (msg.wParam == VK_CONTROL) { + if (HIWORD(msg.lParam) & KF_EXTENDED) + win->event.key = RGFW_ControlR; + else win->event.key = RGFW_ControlL; + } + + wchar_t charBuffer; + ToUnicodeEx(msg.wParam, scancode, keyboardState, &charBuffer, 1, 0, NULL); + win->event.keyChar = (u8)charBuffer; + + RGFW_keyboard[win->event.key].prev = RGFW_isPressed(win, win->event.key); static char keyName[16]; @@ -5938,20 +5993,20 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ } win->event.type = RGFW_keyPressed; - win->event.repeat = RGFW_isPressed(win, win->event.keyCode); - RGFW_keyboard[win->event.keyCode].current = 1; - RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1); + win->event.repeat = RGFW_isPressed(win, win->event.key); + RGFW_keyboard[win->event.key].current = 1; + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyName, win->event.lockState, 1); break; } - case WM_MOUSEMOVE: + case WM_MOUSEMOVE: { if ((win->_winArgs & RGFW_HOLD_MOUSE)) break; win->event.type = RGFW_mousePosChanged; - win->event.point.x = GET_X_LPARAM(msg.lParam); - win->event.point.y = GET_Y_LPARAM(msg.lParam); + i32 x = GET_X_LPARAM(msg.lParam); + i32 y = GET_Y_LPARAM(msg.lParam); RGFW_mousePosCallback(win, win->event.point); @@ -5961,22 +6016,64 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ RGFW_mouseNotifyCallBack(win, win->event.point, 1); } - break; + /*if ((win->_winArgs & RGFW_HOLD_MOUSE)) { + RGFW_point p = RGFW_getGlobalMousePoint(); + //p = RGFW_POINT(p.x + win->r.x, p.y + win->r.y); + win->event.point.x = x - win->_lastMousePoint.x; + win->event.point.y = y - win->_lastMousePoint.y; + + win->_lastMousePoint = RGFW_POINT(x, y); + break; + }*/ + + win->event.point.x = x; + win->event.point.y = y; + win->_lastMousePoint = RGFW_POINT(x, y); + + break; + } case WM_INPUT: { if (!(win->_winArgs & RGFW_HOLD_MOUSE)) break; unsigned size = sizeof(RAWINPUT); - static RAWINPUT raw[sizeof(RAWINPUT)]; - GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); + static RAWINPUT raw = {}; - if (raw->header.dwType != RIM_TYPEMOUSE || (raw->data.mouse.lLastX == 0 && raw->data.mouse.lLastY == 0) ) + GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER)); + + if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) ) break; - + + if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) { + POINT pos = {0}; + int width, height; + + if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) { + pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN); + pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN); + width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + } + else { + width = GetSystemMetrics(SM_CXSCREEN); + height = GetSystemMetrics(SM_CYSCREEN); + } + + pos.x += (int) ((raw.data.mouse.lLastX / 65535.f) * width); + pos.y += (int) ((raw.data.mouse.lLastY / 65535.f) * height); + ScreenToClient(win->src.window, &pos); + + win->event.point.x = pos.x - win->_lastMousePoint.x; + win->event.point.y = pos.y - win->_lastMousePoint.y; + } else { + win->event.point.x = raw.data.mouse.lLastX; + win->event.point.y = raw.data.mouse.lLastY; + } + win->event.type = RGFW_mousePosChanged; - win->event.point.x = raw->data.mouse.lLastX; - win->event.point.y = raw->data.mouse.lLastY; + win->_lastMousePoint.x += win->event.point.x; + win->_lastMousePoint.y += win->event.point.y; break; } @@ -6074,26 +6171,18 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ return 0; } default: - win->event.type = 0; + TranslateMessage(&msg); + DispatchMessageA(&msg); + + return RGFW_window_checkEvent(win); break; } TranslateMessage(&msg); DispatchMessageA(&msg); - } - else - win->event.type = 0; - if (!IsWindow(win->src.window)) { - win->event.type = RGFW_quit; - RGFW_windowQuitCallback(win); - } - - if (win->event.type) - return &win->event; - else - return NULL; + return &win->event; } u8 RGFW_window_isFullscreen(RGFW_window* win) { @@ -6208,6 +6297,10 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX; monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY; + #ifdef RGFW_DEBUG + printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n", monitor.name, monitor.rect.x, monitor.rect.y, monitor.rect.w, monitor.rect.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY); + #endif + return monitor; } #endif /* RGFW_NO_MONITOR */ @@ -6576,7 +6669,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { assert(win != NULL); - + win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y); SetCursorPos(p.x, p.y); } @@ -6738,7 +6831,6 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ typedef void NSDraggingInfo; typedef void NSWindow; typedef void NSApplication; - typedef void NSScreen; typedef void NSEvent; typedef void NSString; typedef void NSOpenGLContext; @@ -7210,7 +7302,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ return false; } - static void NSMoveToResourceDir(void) { + void NSMoveToResourceDir(void) { /* sourced from glfw */ char resourcesPath[255]; @@ -7497,6 +7589,10 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ NSRetain(win->src.window); NSRetain(NSApp); + #ifdef RGFW_DEBUG + printf("RGFW INFO: a window with a rect of {%i, %i, %i, %i} \n", win->r.x, win->r.y, win->r.w, win->r.h); + #endif + return win; } @@ -7663,7 +7759,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ if (e) { - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + ((void (*)(id, SEL, id, bool))objc_msgSend) + (NSApp, sel_registerName("postEvent:atStart:"), e, 1); } objc_msgSend_bool_void(eventPool, sel_registerName("drain")); @@ -7687,8 +7784,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ if (eventFunc == NULL) eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); - if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.keyCode != 120) { - win->event.keyCode = 120; + if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.key != 120) { + win->event.key = 120; objc_msgSend_bool_void(eventPool, sel_registerName("drain")); return &win->event; } @@ -7723,7 +7820,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ switch (objc_msgSend_uint(e, sel_registerName("type"))) { case NSEventTypeMouseEntered: { win->event.type = RGFW_mouseEnter; - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); + NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y)); RGFW_mouseNotifyCallBack(win, win->event.point, 1); @@ -7737,31 +7834,40 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ case NSEventTypeKeyDown: { u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); - win->event.keyCode = RGFW_apiKeyCodeToRGFW(key); - RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current; + + u32 mappedKey = *((u32*)((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers"))))); + + win->event.keyChar = (u8)mappedKey; + + win->event.key = RGFW_apiKeyToRGFW(key); + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; win->event.type = RGFW_keyPressed; char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters"))); strncpy(win->event.keyName, str, 16); - win->event.repeat = RGFW_isPressed(win, win->event.keyCode); - RGFW_keyboard[win->event.keyCode].current = 1; + win->event.repeat = RGFW_isPressed(win, win->event.key); + RGFW_keyboard[win->event.key].current = 1; - RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1); + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyName, win->event.lockState, 1); break; } case NSEventTypeKeyUp: { - u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); - win->event.keyCode = RGFW_apiKeyCodeToRGFW(key);; - - RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current; + u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); + + u32 mappedKey = *((u32*)((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers"))))); + win->event.keyChar = (u8)mappedKey; + + win->event.key = RGFW_apiKeyToRGFW(key); + + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; win->event.type = RGFW_keyReleased; char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters"))); strncpy(win->event.keyName, str, 16); - RGFW_keyboard[win->event.keyCode].current = 0; - RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0); + RGFW_keyboard[win->event.key].current = 0; + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyName, win->event.lockState, 0); break; } @@ -7784,7 +7890,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ RGFW_keyboard[key+ 4].current = 1; win->event.type = RGFW_keyPressed; - win->event.keyCode = key; + win->event.key = key; break; } @@ -7795,12 +7901,12 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ RGFW_keyboard[key + 4].current = 0; win->event.type = RGFW_keyReleased; - win->event.keyCode = key; + win->event.key = key; break; } } - RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, win->event.type == RGFW_keyPressed); + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyName, win->event.lockState, win->event.type == RGFW_keyPressed); break; } @@ -7890,8 +7996,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ break; } - default: - break; + default: return RGFW_window_checkEvent(win); } objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); @@ -8057,7 +8162,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); - + + win->_lastMousePoint = RGFW_POINT(v.x - win->r.x, v.y - win->r.y); CGWarpMouseCursorPosition(CGPointMake(v.x, v.y)); } @@ -8097,7 +8203,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ return objc_msgSend_bool(win->src.window, sel_registerName("isZoomed")); } - static RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display) { + RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display) { RGFW_monitor monitor; CGRect bounds = CGDisplayBounds(display); @@ -8111,7 +8217,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ float dpi_height = round((double)monitor.rect.h/(double)monitor.physH); monitor.scaleX = (float) (dpi_width) / (float) 96; - monitor.scaleY = (float) (dpi_height) / (float) 96; + monitor.scaleY = (float) (dpi_height) / (float) 96; if (isinf(monitor.scaleX) || (monitor.scaleX > 1 && monitor.scaleX < 1.1)) monitor.scaleX = 1; @@ -8119,11 +8225,15 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ if (isinf(monitor.scaleY) || (monitor.scaleY > 1 && monitor.scaleY < 1.1)) monitor.scaleY = 1; + #ifdef RGFW_DEBUG + printf("RGFW INFO: monitor found: scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n", monitor.name, monitor.rect.x, monitor.rect.y, monitor.rect.w, monitor.rect.h, monitor.physW, monitor.physH, monitor.scaleX, monitor.scaleY); + #endif + return monitor; } - static RGFW_monitor RGFW_monitors[7]; + RGFW_monitor RGFW_monitors[7]; RGFW_monitor* RGFW_getMonitors(void) { static CGDirectDisplayID displays[7]; @@ -8334,39 +8444,6 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ RGFW_Event RGFW_events[20]; size_t RGFW_eventLen = 0; -EM_BOOL Emscripten_on_keydown(int eventType, const EmscriptenKeyboardEvent* e, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - RGFW_events[RGFW_eventLen].type = RGFW_keyPressed; - memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16); - RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode); - RGFW_events[RGFW_eventLen].lockState = 0; - RGFW_eventLen++; - - RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current; - RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 1; - RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 1); - - return EM_TRUE; -} - -EM_BOOL Emscripten_on_keyup(int eventType, const EmscriptenKeyboardEvent* e, void* userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - RGFW_events[RGFW_eventLen].type = RGFW_keyReleased; - memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16); - RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode); - RGFW_events[RGFW_eventLen].lockState = 0; - RGFW_eventLen++; - - RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current; - RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 0; - - RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 0); - - return EM_TRUE; -} - EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* e, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); @@ -8395,7 +8472,7 @@ EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreen RGFW_root->r = RGFW_RECT(0, 0, e->screenWidth, e->screenHeight); EM_ASM("Module.canvas.focus();"); - + if (fullscreen == RGFW_FALSE) { RGFW_root->r = RGFW_RECT(0, 0, ogRect.w, ogRect.h); // emscripten_request_fullscreen("#canvas", 0); @@ -8576,6 +8653,141 @@ EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamep return 1; // The event was consumed by the callback handler } + +u32 RGFW_webasmPhysicalToRGFW(u32 hash) { + switch(hash) { /* 0x0000 */ + case 0x67243A2DU /* Escape */: return RGFW_Escape; /* 0x0001 */ + case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */ + case 0x67251059U /* Digit1 */: return RGFW_1; /* 0x0003 */ + case 0x6725105AU /* Digit2 */: return RGFW_2; /* 0x0004 */ + case 0x6725105BU /* Digit3 */: return RGFW_3; /* 0x0005 */ + case 0x6725105CU /* Digit4 */: return RGFW_4; /* 0x0006 */ + case 0x6725105DU /* Digit5 */: return RGFW_5; /* 0x0007 */ + case 0x6725105EU /* Digit6 */: return RGFW_6; /* 0x0008 */ + case 0x6725105FU /* Digit7 */: return RGFW_7; /* 0x0009 */ + case 0x67251050U /* Digit8 */: return RGFW_8; /* 0x000A */ + case 0x67251051U /* Digit9 */: return RGFW_9; /* 0x000B */ + case 0x92E14DD3U /* Minus */: return RGFW_Minus; /* 0x000C */ + case 0x92E1FBACU /* Equal */: return RGFW_Equals; /* 0x000D */ + case 0x36BF1CB5U /* Backspace */: return RGFW_BackSpace; /* 0x000E */ + case 0x7B8E51E2U /* Tab */: return RGFW_Tab; /* 0x000F */ + case 0x2C595B51U /* KeyQ */: return RGFW_q; /* 0x0010 */ + case 0x2C595B57U /* KeyW */: return RGFW_w; /* 0x0011 */ + case 0x2C595B45U /* KeyE */: return RGFW_e; /* 0x0012 */ + case 0x2C595B52U /* KeyR */: return RGFW_r; /* 0x0013 */ + case 0x2C595B54U /* KeyT */: return RGFW_t; /* 0x0014 */ + case 0x2C595B59U /* KeyY */: return RGFW_y; /* 0x0015 */ + case 0x2C595B55U /* KeyU */: return RGFW_u; /* 0x0016 */ + case 0x2C595B4FU /* KeyO */: return RGFW_o; /* 0x0018 */ + case 0x2C595B50U /* KeyP */: return RGFW_p; /* 0x0019 */ + case 0x45D8158CU /* BracketLeft */: return RGFW_CloseBracket; /* 0x001A */ + case 0xDEEABF7CU /* BracketRight */: return RGFW_Bracket; /* 0x001B */ + case 0x92E1C5D2U /* Enter */: return RGFW_Return; /* 0x001C */ + case 0xE058958CU /* ControlLeft */: return RGFW_ControlL; /* 0x001D */ + case 0x2C595B41U /* KeyA */: return RGFW_a; /* 0x001E */ + case 0x2C595B53U /* KeyS */: return RGFW_s; /* 0x001F */ + case 0x2C595B44U /* KeyD */: return RGFW_d; /* 0x0020 */ + case 0x2C595B46U /* KeyF */: return RGFW_f; /* 0x0021 */ + case 0x2C595B47U /* KeyG */: return RGFW_g; /* 0x0022 */ + case 0x2C595B48U /* KeyH */: return RGFW_h; /* 0x0023 */ + case 0x2C595B4AU /* KeyJ */: return RGFW_j; /* 0x0024 */ + case 0x2C595B4BU /* KeyK */: return RGFW_k; /* 0x0025 */ + case 0x2C595B4CU /* KeyL */: return RGFW_l; /* 0x0026 */ + case 0x2707219EU /* Semicolon */: return RGFW_Semicolon; /* 0x0027 */ + case 0x92E0B58DU /* Quote */: return RGFW_Apostrophe; /* 0x0028 */ + case 0x36BF358DU /* Backquote */: return RGFW_Backtick; /* 0x0029 */ + case 0x26B1958CU /* ShiftLeft */: return RGFW_ShiftL; /* 0x002A */ + case 0x36BF2438U /* Backslash */: return RGFW_BackSlash; /* 0x002B */ + case 0x2C595B5AU /* KeyZ */: return RGFW_z; /* 0x002C */ + case 0x2C595B58U /* KeyX */: return RGFW_x; /* 0x002D */ + case 0x2C595B43U /* KeyC */: return RGFW_c; /* 0x002E */ + case 0x2C595B56U /* KeyV */: return RGFW_v; /* 0x002F */ + case 0x2C595B42U /* KeyB */: return RGFW_b; /* 0x0030 */ + case 0x2C595B4EU /* KeyN */: return RGFW_n; /* 0x0031 */ + case 0x2C595B4DU /* KeyM */: return RGFW_m; /* 0x0032 */ + case 0x92E1A1C1U /* Comma */: return RGFW_Comma; /* 0x0033 */ + case 0x672FFAD4U /* Period */: return RGFW_Period; /* 0x0034 */ + case 0x92E0A438U /* Slash */: return RGFW_Slash; /* 0x0035 */ + case 0xC5A6BF7CU /* ShiftRight */: return RGFW_ShiftR; + case 0x5D64DA91U /* NumpadMultiply */: return RGFW_Multiply; + case 0xC914958CU /* AltLeft */: return RGFW_AltL; /* 0x0038 */ + case 0x92E09CB5U /* Space */: return RGFW_Space; /* 0x0039 */ + case 0xB8FAE73BU /* CapsLock */: return RGFW_CapsLock; /* 0x003A */ + case 0x7174B789U /* F1 */: return RGFW_F1; /* 0x003B */ + case 0x7174B78AU /* F2 */: return RGFW_F2; /* 0x003C */ + case 0x7174B78BU /* F3 */: return RGFW_F3; /* 0x003D */ + case 0x7174B78CU /* F4 */: return RGFW_F4; /* 0x003E */ + case 0x7174B78DU /* F5 */: return RGFW_F5; /* 0x003F */ + case 0x7174B78EU /* F6 */: return RGFW_F6; /* 0x0040 */ + case 0x7174B78FU /* F7 */: return RGFW_F7; /* 0x0041 */ + case 0x7174B780U /* F8 */: return RGFW_F8; /* 0x0042 */ + case 0x7174B781U /* F9 */: return RGFW_F9; /* 0x0043 */ + case 0x7B8E57B0U /* F10 */: return RGFW_F10; /* 0x0044 */ + case 0xC925FCDFU /* Numpad7 */: return RGFW_Multiply; /* 0x0047 */ + case 0xC925FCD0U /* Numpad8 */: return RGFW_KP_8; /* 0x0048 */ + case 0xC925FCD1U /* Numpad9 */: return RGFW_KP_9; /* 0x0049 */ + case 0x5EA3E8A4U /* NumpadSubtract */: return RGFW_Minus; /* 0x004A */ + case 0xC925FCDCU /* Numpad4 */: return RGFW_KP_4; /* 0x004B */ + case 0xC925FCDDU /* Numpad5 */: return RGFW_KP_5; /* 0x004C */ + case 0xC925FCDEU /* Numpad6 */: return RGFW_KP_6; /* 0x004D */ + case 0xC925FCD9U /* Numpad1 */: return RGFW_KP_1; /* 0x004F */ + case 0xC925FCDAU /* Numpad2 */: return RGFW_KP_2; /* 0x0050 */ + case 0xC925FCDBU /* Numpad3 */: return RGFW_KP_3; /* 0x0051 */ + case 0xC925FCD8U /* Numpad0 */: return RGFW_KP_0; /* 0x0052 */ + case 0x95852DACU /* NumpadDecimal */: return RGFW_KP_Period; /* 0x0053 */ + case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */ + case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */ + case 0x7393FBACU /* NumpadEqual */: return RGFW_KP_Return; + case 0xB88EBF7CU /* AltRight */: return RGFW_AltR; /* 0xE038 */ + case 0xC925873BU /* NumLock */: return RGFW_Numlock; /* 0xE045 */ + case 0x2C595F45U /* Home */: return RGFW_Home; /* 0xE047 */ + case 0xC91BB690U /* ArrowUp */: return RGFW_Up; /* 0xE048 */ + case 0x672F9210U /* PageUp */: return RGFW_PageUp; /* 0xE049 */ + case 0x3799258CU /* ArrowLeft */: return RGFW_Left; /* 0xE04B */ + case 0x4CE33F7CU /* ArrowRight */: return RGFW_Right; /* 0xE04D */ + case 0x7B8E55DCU /* End */: return RGFW_End; /* 0xE04F */ + case 0x3799379EU /* ArrowDown */: return RGFW_Down; /* 0xE050 */ + case 0xBA90179EU /* PageDown */: return RGFW_PageDown; /* 0xE051 */ + case 0x6723CB2CU /* Insert */: return RGFW_Insert; /* 0xE052 */ + case 0x6725C50DU /* Delete */: return RGFW_Delete; /* 0xE053 */ + case 0x6723658CU /* OSLeft */: return RGFW_SuperL; /* 0xE05B */ + case 0x39643F7CU /* MetaRight */: return RGFW_SuperR; /* 0xE05C */ + } + + return 0; +} + +void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, b8 press) { + const char* iCode = code; + + u32 hash = 0; + while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++; + + u32 physicalKey = RGFW_webasmPhysicalToRGFW(hash); + + u8 mappedKey = (u8)(*((u32*)key)); + + if (*((u16*)key) != mappedKey) { + mappedKey = 0; + if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_Tab; + } + + RGFW_events[RGFW_eventLen].type = press ? RGFW_keyPressed : RGFW_keyReleased; + memcpy(RGFW_events[RGFW_eventLen].keyName, key, 16); + RGFW_events[RGFW_eventLen].key = physicalKey; + RGFW_events[RGFW_eventLen].keyChar = mappedKey; + RGFW_events[RGFW_eventLen].lockState = 0; + RGFW_eventLen++; + + RGFW_keyboard[physicalKey].prev = RGFW_keyboard[physicalKey].current; + RGFW_keyboard[physicalKey].current = 0; + + RGFW_keyCallback(RGFW_root, physicalKey, mappedKey, RGFW_events[RGFW_eventLen].keyName, 0, press); + + free(key); + free(code); +} + void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { if (!(RGFW_root->_winArgs & RGFW_ALLOW_DND)) return; @@ -8694,8 +8906,6 @@ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { emscripten_set_window_title(name); /* load callbacks */ - emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keydown); - emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keyup); emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize); emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange); emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove); @@ -8715,6 +8925,22 @@ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { win->_winArgs |= RGFW_ALLOW_DND; } + EM_ASM({ + window.addEventListener("keydown", + (event) => { + Module._RGFW_handleKeyEvent(stringToNewUTF8(event.key), stringToNewUTF8(event.code), 1); + }, true, + ); + }); + + EM_ASM({ + window.addEventListener("keyup", + (event) => { + Module._RGFW_handleKeyEvent(stringToNewUTF8(event.key), stringToNewUTF8(event.code), 0); + }, true, + ); + }); + EM_ASM({ var canvas = document.getElementById('canvas'); canvas.addEventListener('drop', function(e) { @@ -8778,6 +9004,10 @@ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { RGFW_window_resize(win, RGFW_getScreenSize()); } + #ifdef RGFW_DEBUG + printf("RGFW INFO: a window with a rect of {%i, %i, %i, %i} \n", win->r.x, win->r.y, win->r.w, win->r.h); + #endif + return win; } @@ -9099,6 +9329,8 @@ RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win) return void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); } #ifdef __linux__ void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); } +#else + void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { RGFW_UNUSED(thread); RGFW_UNUSED(priority); } #endif #endif diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index a74af2074..ca756361a 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -129,7 +129,8 @@ static bool RGFW_disableCursor = false; static const unsigned short keyMappingRGFW[] = { [RGFW_KEY_NULL] = KEY_NULL, [RGFW_Return] = KEY_ENTER, - [RGFW_Quote] = KEY_APOSTROPHE, + [RGFW_Return] = KEY_ENTER, + [RGFW_Apostrophe] = KEY_APOSTROPHE, [RGFW_Comma] = KEY_COMMA, [RGFW_Minus] = KEY_MINUS, [RGFW_Period] = KEY_PERIOD, @@ -817,59 +818,6 @@ const char *GetKeyName(int key) static KeyboardKey ConvertScancodeToKey(u32 keycode); -// TODO: Review function to avoid duplicate with RSGL -char RSGL_keystrToChar(const char *str) -{ - if (str[1] == 0) return str[0]; - - static const char *map[] = { - "asciitilde", "`", - "grave", "~", - "exclam", "!", - "at", "@", - "numbersign", "#", - "dollar", "$", - "percent", "%%", - "asciicircum", "^", - "ampersand", "&", - "asterisk", "*", - "parenleft", "(", - "parenright", ")", - "underscore", "_", - "minus", "-", - "plus", "+", - "equal", "=", - "braceleft", "{", - "bracketleft", "[", - "bracketright", "]", - "braceright", "}", - "colon", ":", - "semicolon", ";", - "quotedbl", "\"", - "apostrophe", "'", - "bar", "|", - "backslash", "\'", - "less", "<", - "comma", ",", - "greater", ">", - "period", ".", - "question", "?", - "slash", "/", - "space", " ", - "Return", "\n", - "Enter", "\n", - "enter", "\n", - }; - - for (unsigned char i = 0; i < (sizeof(map)/sizeof(char *)); i += 2) - { - if (strcmp(map[i], str) == 0) return *map[i + 1]; - } - - return '\0'; -} - -// Gamepad buttons conversion table int RGFW_gpConvTable[18] = { [RGFW_GP_Y] = GAMEPAD_BUTTON_RIGHT_FACE_UP, [RGFW_GP_B] = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, @@ -1025,7 +973,7 @@ void PollInputEvents(void) // Keyboard events case RGFW_keyPressed: { - KeyboardKey key = ConvertScancodeToKey(event->keyCode); + KeyboardKey key = ConvertScancodeToKey(event->key); if (key != KEY_NULL) { // If key was up, add it to the key pressed queue @@ -1049,13 +997,13 @@ void PollInputEvents(void) if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) { // Add character (codepoint) to the queue - CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = RSGL_keystrToChar(event->keyName); + CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = event->keyChar; CORE.Input.Keyboard.charPressedQueueCount++; } } break; case RGFW_keyReleased: { - KeyboardKey key = ConvertScancodeToKey(event->keyCode); + KeyboardKey key = ConvertScancodeToKey(event->key); if (key != KEY_NULL) CORE.Input.Keyboard.currentKeyState[key] = 0; } break; @@ -1066,7 +1014,7 @@ void PollInputEvents(void) { CORE.Input.Mouse.currentWheelMove.y = event->scroll; break; - } + } else CORE.Input.Mouse.currentWheelMove.y = 0; int btn = event->button; if (btn == RGFW_mouseLeft) btn = 1; @@ -1084,7 +1032,7 @@ void PollInputEvents(void) { CORE.Input.Mouse.currentWheelMove.y = event->scroll; break; - } + } else CORE.Input.Mouse.currentWheelMove.y = 0; int btn = event->button; if (btn == RGFW_mouseLeft) btn = 1; @@ -1303,7 +1251,7 @@ int InitPlatform(void) #ifdef RGFW_X11 for (int i = 0; (i < 4) && (i < MAX_GAMEPADS); i++) { - RGFW_registergamepad(platform.window, i); + RGFW_registerGamepad(platform.window, i); } #endif From b07967993f6b13d5edb02c596cde652a3db139a1 Mon Sep 17 00:00:00 2001 From: Antonis Geralis <43617260+planetis-m@users.noreply.github.com> Date: Wed, 25 Dec 2024 23:08:42 +0200 Subject: [PATCH 02/33] Update version number for the nim wrapper (#4638) --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 5e93a076a..8f5c86f96 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -50,7 +50,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [raylib-matte](https://github.com/jcorks/raylib-matte) | 4.6-dev | [Matte](https://github.com/jcorks/matte) | **???** | | [Raylib.nelua](https://github.com/AuzFox/Raylib.nelua) | **5.0** | [nelua](https://nelua.io) | Zlib | | [raylib-bindings](https://github.com/vaiorabbit/raylib-bindings) | 5.6-dev | [Ruby](https://www.ruby-lang.org/en) | Zlib | -| [naylib](https://github.com/planetis-m/naylib) | **5.1-dev** | [Nim](https://nim-lang.org) | MIT | +| [naylib](https://github.com/planetis-m/naylib) | **5.6-dev** | [Nim](https://nim-lang.org) | MIT | | [node-raylib](https://github.com/RobLoach/node-raylib) | 4.5 | [Node.js](https://nodejs.org/en) | Zlib | | [raylib-odin](https://github.com/odin-lang/Odin/tree/master/vendor/raylib) | **5.5** | [Odin](https://odin-lang.org) | BSD-3Clause | | [raylib_odin_bindings](https://github.com/Deathbat2190/raylib_odin_bindings) | 4.0-dev | [Odin](https://odin-lang.org) | MIT | From 51b9a0acfc8fe16f7487ee058f1fa9ee4b99bd26 Mon Sep 17 00:00:00 2001 From: Bot Randomness <114881271+BotRandomness@users.noreply.github.com> Date: Thu, 26 Dec 2024 12:55:38 -0500 Subject: [PATCH 03/33] Updated BINDINGS.md for Ruby (#4639) Added a Ruby binding known as raylib-ruby on 4.5. (https://github.com/wilsonsilva/raylib-ruby) --- BINDINGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BINDINGS.md b/BINDINGS.md index 8f5c86f96..3bc235b76 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -69,6 +69,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [raylibr](https://github.com/jeroenjanssens/raylibr) | 4.0 | [R](https://www.r-project.org) | MIT | | [raylib-ffi](https://github.com/ewpratten/raylib-ffi) | 5.5 | [Rust](https://www.rust-lang.org) | GPLv3 | | [raylib-rs](https://github.com/raylib-rs/raylib-rs) | **5.5** | [Rust](https://www.rust-lang.org) | Zlib | +| [raylib-ruby](https://github.com/wilsonsilva/raylib-ruby) | 4.5 | [Ruby](https://www.ruby-lang.org) | Zlib | | [Relib](https://github.com/RedCubeDev-ByteSpace/Relib) | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | **???** | | [racket-raylib](https://github.com/eutro/racket-raylib) | 4.0 | [Racket](https://racket-lang.org) | MIT/Apache-2.0 | | [raylib-swift](https://github.com/STREGAsGate/Raylib) | 4.0 | [Swift](https://swift.org) | MIT | From 47588678156e6533eed5f1ca1d2d7779666819f0 Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Thu, 26 Dec 2024 15:02:57 -0300 Subject: [PATCH 04/33] [rcore] [SDL2] Add implementation for `FLAG_WINDOW_ALWAYS_RUN` (#4598) * Enable FLAG_WINDOW_ALWAYS_RUN by default on PLATFORM_DESKTOP_GLFW * Revert enabling FLAG_WINDOW_ALWAYS_RUN by default on PLATFORM_DESKTOP_GLFW * Add implementation for FLAG_WINDOW_ALWAYS_RUN on PLATFORM_DESKTOP_SDL * Add reset for GetFrameTime() --- src/platforms/rcore_desktop_glfw.c | 7 ++++++- src/platforms/rcore_desktop_sdl.c | 8 ++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index cb61f7d81..ac419ea7b 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1739,7 +1739,12 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s static void WindowIconifyCallback(GLFWwindow *window, int iconified) { if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified - else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored + else + { + CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored + + if ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0) CORE.Time.previous = GetTime(); + } } // GLFW3 WindowMaximize Callback, runs when window is maximized/restored diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 3d1ac0bf3..5d316df50 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -571,7 +571,7 @@ void SetWindowState(unsigned int flags) } if (flags & FLAG_WINDOW_ALWAYS_RUN) { - TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_SDL"); + CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN; } if (flags & FLAG_WINDOW_TRANSPARENT) { @@ -658,7 +658,7 @@ void ClearWindowState(unsigned int flags) } if (flags & FLAG_WINDOW_ALWAYS_RUN) { - TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_ALWAYS_RUN is not supported on PLATFORM_DESKTOP_SDL"); + CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN; } if (flags & FLAG_WINDOW_TRANSPARENT) { @@ -1378,6 +1378,8 @@ void PollInputEvents(void) CORE.Window.resizedLastFrame = false; + if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0)) SDL_WaitEvent(NULL); + SDL_Event event = { 0 }; while (SDL_PollEvent(&event) != 0) { @@ -1497,6 +1499,8 @@ void PollInputEvents(void) if ((CORE.Window.flags & SDL_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~SDL_WINDOW_MAXIMIZED; } #endif + + if ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0) CORE.Time.previous = GetTime(); } break; case SDL_WINDOWEVENT_HIDDEN: From 7ecc47d12e5f4c322af3d16615a08ba9bc47c4c2 Mon Sep 17 00:00:00 2001 From: Mario Nachbaur Date: Thu, 26 Dec 2024 20:12:53 +0100 Subject: [PATCH 05/33] Fix `IsWindowFocused()` on web. (#4640) --- src/platforms/rcore_web.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index d28ed55c2..996e7daf5 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -133,6 +133,7 @@ static void CursorEnterCallback(GLFWwindow *window, int enter); 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 EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData); // Emscripten input callback events static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData); @@ -1369,6 +1370,10 @@ int InitPlatform(void) // Support gamepad events (not provided by GLFW3 on emscripten) emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback); emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback); + + // Support focus events + emscripten_set_blur_callback("#canvas", platform.handle, 1, EmscriptenFocusCallback); + emscripten_set_focus_callback("#canvas", platform.handle, 1, EmscriptenFocusCallback); //---------------------------------------------------------------------------- // Initialize timing system @@ -1732,6 +1737,18 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE return 1; // The event was consumed by the callback handler } +static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData) +{ + EM_BOOL consumed = 1; + switch (eventType) + { + case EMSCRIPTEN_EVENT_BLUR: WindowFocusCallback(userData, 0); break; + case EMSCRIPTEN_EVENT_FOCUS: WindowFocusCallback(userData, 1); break; + default: consumed = 0; break; + } + return consumed; +} + // Register touch input events static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) { From e062dc085c164c3e89eb928ec91278f08c2f4ccf Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Sat, 28 Dec 2024 06:56:04 -0800 Subject: [PATCH 06/33] Add filters and platform files so they show up in MSVC for ease of editing (#4644) --- projects/VS2022/raylib/raylib.vcxproj | 70 ++++++++++ projects/VS2022/raylib/raylib.vcxproj.filters | 120 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 projects/VS2022/raylib/raylib.vcxproj.filters diff --git a/projects/VS2022/raylib/raylib.vcxproj b/projects/VS2022/raylib/raylib.vcxproj index 0c03027a4..347ff5d11 100644 --- a/projects/VS2022/raylib/raylib.vcxproj +++ b/projects/VS2022/raylib/raylib.vcxproj @@ -302,6 +302,76 @@ + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + + + true + true + true + true + true + true + true + true + diff --git a/projects/VS2022/raylib/raylib.vcxproj.filters b/projects/VS2022/raylib/raylib.vcxproj.filters new file mode 100644 index 000000000..182358229 --- /dev/null +++ b/projects/VS2022/raylib/raylib.vcxproj.filters @@ -0,0 +1,120 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\Platform Files + + + Source Files\Platform Files + + + Source Files\Platform Files + + + Source Files\Platform Files + + + Source Files\Platform Files + + + Source Files\Platform Files + + + Source Files\Platform Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + + + {88e8d1f8-5c93-4f9e-a856-819a1f82a387} + + + {cba93591-3674-4384-9325-bc0ae2d72b9b} + + + {d18433d7-0e5c-40d7-a39d-e0f11f80d183} + + + \ No newline at end of file From 75b6b825dfc93488bc411c00845164b5c0f8fae6 Mon Sep 17 00:00:00 2001 From: Johannes <59510166+Joonsey@users.noreply.github.com> Date: Sat, 28 Dec 2024 15:57:10 +0100 Subject: [PATCH 07/33] using addCMacro instead of defineCMacro (#4620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Johannes Rønning --- build.zig | 24 ++++++++++++------------ examples/build.zig | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/build.zig b/build.zig index 66e8fab4f..0f6f29755 100644 --- a/build.zig +++ b/build.zig @@ -13,9 +13,9 @@ comptime { fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void { switch (platform) { - .glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null), - .rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null), - .sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null), + .glfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_GLFW", ""), + .rgfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_RGFW", ""), + .sdl => raylib.root_module.addCMacro("PLATFORM_DESKTOP_SDL", ""), else => {}, } } @@ -173,7 +173,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. } if (options.opengl_version != .auto) { - raylib.defineCMacro(options.opengl_version.toCMacroStr(), null); + raylib.root_module.addCMacro(options.opengl_version.toCMacroStr(), ""); } raylib.addIncludePath(b.path("src/platforms")); @@ -191,7 +191,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. try c_source_files.append("src/rglfw.c"); if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) { - raylib.defineCMacro("_GLFW_X11", null); + raylib.root_module.addCMacro("_GLFW_X11", ""); raylib.linkSystemLibrary("GLX"); raylib.linkSystemLibrary("X11"); raylib.linkSystemLibrary("Xcursor"); @@ -211,7 +211,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. , .{}); @panic("`wayland-scanner` not found"); }; - raylib.defineCMacro("_GLFW_WAYLAND", null); + raylib.root_module.addCMacro("_GLFW_WAYLAND", ""); raylib.linkSystemLibrary("EGL"); raylib.linkSystemLibrary("wayland-client"); raylib.linkSystemLibrary("xkbcommon"); @@ -230,16 +230,16 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. } else { if (options.opengl_version == .auto) { raylib.linkSystemLibrary("GLESv2"); - raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null); + raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", ""); } raylib.linkSystemLibrary("EGL"); raylib.linkSystemLibrary("gbm"); raylib.linkSystemLibrary2("libdrm", .{ .use_pkg_config = .force }); - raylib.defineCMacro("PLATFORM_DRM", null); - raylib.defineCMacro("EGL_NO_X11", null); - raylib.defineCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "2048"); + raylib.root_module.addCMacro("PLATFORM_DRM", ""); + raylib.root_module.addCMacro("EGL_NO_X11", ""); + raylib.root_module.addCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", ""); } }, .freebsd, .openbsd, .netbsd, .dragonfly => { @@ -290,9 +290,9 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.addIncludePath(dep.path("upstream/emscripten/cache/sysroot/include")); } - raylib.defineCMacro("PLATFORM_WEB", null); + raylib.root_module.addCMacro("PLATFORM_WEB", ""); if (options.opengl_version == .auto) { - raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null); + raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", ""); } }, else => { diff --git a/examples/build.zig b/examples/build.zig index df0cdf8c1..301381df3 100644 --- a/examples/build.zig +++ b/examples/build.zig @@ -46,7 +46,7 @@ fn add_module(comptime module: []const u8, b: *std.Build, target: std.Build.Reso exe.linkSystemLibrary("gdi32"); exe.linkSystemLibrary("opengl32"); - exe.defineCMacro("PLATFORM_DESKTOP", null); + exe.root_module.addCMacro("PLATFORM_DESKTOP", ""); }, .linux => { exe.linkSystemLibrary("GL"); @@ -55,7 +55,7 @@ fn add_module(comptime module: []const u8, b: *std.Build, target: std.Build.Reso exe.linkSystemLibrary("m"); exe.linkSystemLibrary("X11"); - exe.defineCMacro("PLATFORM_DESKTOP", null); + exe.root_module.addCMacro("PLATFORM_DESKTOP", ""); }, .macos => { exe.linkFramework("Foundation"); @@ -65,7 +65,7 @@ fn add_module(comptime module: []const u8, b: *std.Build, target: std.Build.Reso exe.linkFramework("CoreVideo"); exe.linkFramework("IOKit"); - exe.defineCMacro("PLATFORM_DESKTOP", null); + exe.root_module.addCMacro("PLATFORM_DESKTOP", ""); }, else => { @panic("Unsupported OS"); From 5b822585e5aa31baf1d11e572f9fe7ef1fafc2ba Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Sat, 28 Dec 2024 11:59:05 -0300 Subject: [PATCH 08/33] [rcore] [GLFW] [SDL2] Updates `CORE.Window.eventWaiting` and `FLAG_WINDOW_ALWAYS_RUN` handling (#4642) * Add implementation for CORE.Window.eventWaiting on PLATFORM_DESKTOP_SDL * Optimize GetFrameTime() reset * Optimize FLAG_WINDOW_ALWAYS_RUN and GetFrameTime() reset for PLATFORM_DESKTOP_GLFW --- src/platforms/rcore_desktop_glfw.c | 16 ++++++---------- src/platforms/rcore_desktop_sdl.c | 8 +++++--- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index ac419ea7b..c2a43be11 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1248,12 +1248,13 @@ void PollInputEvents(void) CORE.Window.resizedLastFrame = false; - if (CORE.Window.eventWaiting) glfwWaitEvents(); // Wait for in input events before continue (drawing is paused) + if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN))) + { + glfwWaitEvents(); // Wait for in input events before continue (drawing is paused) + CORE.Time.previous = GetTime(); + } else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) -> Update keys state - // While window minimized, stop loop execution - while (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)) glfwWaitEvents(); - CORE.Window.shouldClose = glfwWindowShouldClose(platform.handle); // Reset close status for next frame @@ -1739,12 +1740,7 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s static void WindowIconifyCallback(GLFWwindow *window, int iconified) { if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified - else - { - CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored - - if ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0) CORE.Time.previous = GetTime(); - } + else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored } // GLFW3 WindowMaximize Callback, runs when window is maximized/restored diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 5d316df50..c5ff97cf0 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1378,7 +1378,11 @@ void PollInputEvents(void) CORE.Window.resizedLastFrame = false; - if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0)) SDL_WaitEvent(NULL); + if ((CORE.Window.eventWaiting) || (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0))) + { + SDL_WaitEvent(NULL); + CORE.Time.previous = GetTime(); + } SDL_Event event = { 0 }; while (SDL_PollEvent(&event) != 0) @@ -1499,8 +1503,6 @@ void PollInputEvents(void) if ((CORE.Window.flags & SDL_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~SDL_WINDOW_MAXIMIZED; } #endif - - if ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0) CORE.Time.previous = GetTime(); } break; case SDL_WINDOWEVENT_HIDDEN: From c0f2067dbadecbc0130acb08f931361ebaed4d54 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 28 Dec 2024 16:35:42 +0100 Subject: [PATCH 09/33] REVIEWED: `LoadShaderFromMemory()`, use default locations for default shader #4641 --- src/rcore.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 5ba24a5b8..17634a52c 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1326,9 +1326,10 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) shader.id = rlLoadShaderCode(vsCode, fsCode); - // After shader loading, we TRY to set default location names - if (shader.id > 0) + if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault(); + else if (shader.id > 0) { + // After custom shader loading, we TRY to set default location names // Default shader attribute locations have been binded before linking: // vertex position location = 0 // vertex texcoord location = 1 From f355d6f1db7d39b983d3a3fa06f9d29447dcc382 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Sat, 28 Dec 2024 16:07:52 -0800 Subject: [PATCH 10/33] Transform the vertex normals by the animated matrix (#4646) --- .../models/resources/shaders/glsl330/skinning.vs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/models/resources/shaders/glsl330/skinning.vs b/examples/models/resources/shaders/glsl330/skinning.vs index 73ecca51e..43bbca76c 100644 --- a/examples/models/resources/shaders/glsl330/skinning.vs +++ b/examples/models/resources/shaders/glsl330/skinning.vs @@ -6,16 +6,19 @@ in vec3 vertexPosition; in vec2 vertexTexCoord; in vec4 vertexColor; +in vec3 vertexNormal; in vec4 vertexBoneIds; in vec4 vertexBoneWeights; // Input uniform values uniform mat4 mvp; +uniform mat4 matNormal; uniform mat4 boneMatrices[MAX_BONE_NUM]; // Output vertex attributes (to fragment shader) out vec2 fragTexCoord; out vec4 fragColor; +out vec3 fragNormal; void main() { @@ -29,9 +32,18 @@ void main() vertexBoneWeights.y*(boneMatrices[boneIndex1]*vec4(vertexPosition, 1.0)) + vertexBoneWeights.z*(boneMatrices[boneIndex2]*vec4(vertexPosition, 1.0)) + vertexBoneWeights.w*(boneMatrices[boneIndex3]*vec4(vertexPosition, 1.0)); - + + vec4 skinnedNormal = + vertexBoneWeights.x*(boneMatrices[boneIndex0]*vec4(vertexNormal, 0.0)) + + vertexBoneWeights.y*(boneMatrices[boneIndex1]*vec4(vertexNormal, 0.0)) + + vertexBoneWeights.z*(boneMatrices[boneIndex2]*vec4(vertexNormal, 0.0)) + + vertexBoneWeights.w*(boneMatrices[boneIndex3]*vec4(vertexNormal, 0.0)); + skinnedNormal.w = 0.0; + fragTexCoord = vertexTexCoord; fragColor = vertexColor; + fragNormal = normalize(vec3(matNormal*skinnedNormal)); + gl_Position = mvp*skinnedPosition; } \ No newline at end of file From d1315e8a0429e9b43b80b705199d5fec4ee5a83b Mon Sep 17 00:00:00 2001 From: Peter Zmanovsky <48548636+peter15914@users.noreply.github.com> Date: Mon, 30 Dec 2024 01:06:40 +0500 Subject: [PATCH 11/33] [rmodels] Fix leaks in LoadIQM() and LoadModelAnimationsIQM() (#4649) Add calls to UnloadFileData() before return in cases of invalid IQM file. --- src/rmodels.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rmodels.c b/src/rmodels.c index c62267de4..70e461ea5 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4570,12 +4570,14 @@ static Model LoadIQM(const char *fileName) if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0) { TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName); + UnloadFileData(fileData); return model; } if (iqmHeader->version != IQM_VERSION) { TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version); + UnloadFileData(fileData); return model; } @@ -4891,12 +4893,14 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou if (memcmp(iqmHeader->magic, IQM_MAGIC, sizeof(IQM_MAGIC)) != 0) { TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file is not a valid model", fileName); + UnloadFileData(fileData); return NULL; } if (iqmHeader->version != IQM_VERSION) { TRACELOG(LOG_WARNING, "MODEL: [%s] IQM file version not supported (%i)", fileName, iqmHeader->version); + UnloadFileData(fileData); return NULL; } From fa0eada61a1131a7413df9139ead6d018b169f22 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jan 2025 00:02:52 +0100 Subject: [PATCH 12/33] Update year to 2025 --- LICENSE | 2 +- examples/Makefile | 2 +- examples/Makefile.Android | 2 +- examples/Makefile.Web | 2 +- examples/examples.rc | 2 +- parser/LICENSE | 2 +- parser/README.md | 2 +- parser/raylib_parser.c | 4 ++-- projects/VSCode/main.c | 2 +- src/Makefile | 2 +- src/config.h | 2 +- src/platforms/rcore_android.c | 2 +- src/platforms/rcore_desktop_glfw.c | 2 +- src/platforms/rcore_desktop_rgfw.c | 2 +- src/platforms/rcore_desktop_sdl.c | 2 +- src/platforms/rcore_drm.c | 2 +- src/platforms/rcore_template.c | 2 +- src/platforms/rcore_web.c | 2 +- src/raudio.c | 4 ++-- src/raylib.dll.rc | 2 +- src/raylib.dll.rc.data | Bin 11318 -> 7742 bytes src/raylib.h | 2 +- src/raylib.rc | 2 +- src/raylib.rc.data | Bin 11302 -> 7726 bytes src/raymath.h | 2 +- src/rcamera.h | 2 +- src/rcore.c | 4 ++-- src/rgestures.h | 2 +- src/rglfw.c | 2 +- src/rlgl.h | 2 +- src/rmodels.c | 4 ++-- src/rshapes.c | 2 +- src/rtext.c | 4 ++-- src/rtextures.c | 4 ++-- src/utils.c | 4 ++-- src/utils.h | 2 +- 36 files changed, 41 insertions(+), 41 deletions(-) diff --git a/LICENSE b/LICENSE index d1bfe3b1a..e96f876a2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) This software is provided "as-is", without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. diff --git a/examples/Makefile b/examples/Makefile index c02cad434..12d798b50 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -30,7 +30,7 @@ # > PLATFORM_ANDROID: # - Android (ARM, ARM64) # -# Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/examples/Makefile.Android b/examples/Makefile.Android index 01d88fa49..c00da171e 100644 --- a/examples/Makefile.Android +++ b/examples/Makefile.Android @@ -2,7 +2,7 @@ # # raylib makefile for Android project (APK building) # -# Copyright (c) 2017-2024 Ramon Santamaria (@raysan5) +# Copyright (c) 2017-2025 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/examples/Makefile.Web b/examples/Makefile.Web index a4470e09f..90345f97d 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -2,7 +2,7 @@ # # raylib makefile for Web platform # -# Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/examples/examples.rc b/examples/examples.rc index 4767ad480..e5024b731 100644 --- a/examples/examples.rc +++ b/examples/examples.rc @@ -13,7 +13,7 @@ BEGIN VALUE "FileDescription", "raylib example" VALUE "FileVersion", "1.0" VALUE "InternalName", "raylib-example" - VALUE "LegalCopyright", "(c) 2024 raylib technologies (@raylibtech)" + VALUE "LegalCopyright", "(c) 2025 raylib technologies (@raylibtech)" //VALUE "OriginalFilename", "raylib_app.exe" VALUE "ProductName", "raylib-example" VALUE "ProductVersion", "1.0" diff --git a/parser/LICENSE b/parser/LICENSE index 7fc2d13b0..7ed4b8722 100644 --- a/parser/LICENSE +++ b/parser/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2021-2024 Ramon Santamaria (@raysan5) +Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) This software is provided "as-is", without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. diff --git a/parser/README.md b/parser/README.md index 6616cdc51..86cdfdd5b 100644 --- a/parser/README.md +++ b/parser/README.md @@ -19,7 +19,7 @@ Check `raylib_parser.c` for details about those structs. // // // more info and bugs-report: github.com/raysan5/raylib/parser // // // -// Copyright (c) 2021-2024 Ramon Santamaria (@raysan5) // +// Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) // // // ////////////////////////////////////////////////////////////////////////////////// diff --git a/parser/raylib_parser.c b/parser/raylib_parser.c index 94a715562..82e22f195 100644 --- a/parser/raylib_parser.c +++ b/parser/raylib_parser.c @@ -54,7 +54,7 @@ raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software: - Copyright (c) 2021-2024 Ramon Santamaria (@raysan5) + Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) **********************************************************************************************/ @@ -1084,7 +1084,7 @@ static void ShowCommandLineInfo(void) printf("// //\n"); printf("// more info and bugs-report: github.com/raysan5/raylib/parser //\n"); printf("// //\n"); - printf("// Copyright (c) 2021-2024 Ramon Santamaria (@raysan5) //\n"); + printf("// Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) //\n"); printf("// //\n"); printf("//////////////////////////////////////////////////////////////////////////////////\n\n"); diff --git a/projects/VSCode/main.c b/projects/VSCode/main.c index 5a2e342bd..cad32c2ef 100644 --- a/projects/VSCode/main.c +++ b/projects/VSCode/main.c @@ -15,7 +15,7 @@ * This example has been created using raylib 1.0 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) * ********************************************************************************************/ diff --git a/src/Makefile b/src/Makefile index b5fa2ecff..37554b2a0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,7 +33,7 @@ # Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline. # Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline. # -# Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +# Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) # # This software is provided "as-is", without any express or implied warranty. In no event # will the authors be held liable for any damages arising from the use of this software. diff --git a/src/config.h b/src/config.h index 74e0a1353..f7b015305 100644 --- a/src/config.h +++ b/src/config.h @@ -6,7 +6,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2018-2024 Ahmad Fatoum & Ramon Santamaria (@raysan5) +* Copyright (c) 2018-2025 Ahmad Fatoum & Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index faa00c98b..96ea367dc 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -27,7 +27,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index c2a43be11..bd2600c87 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -30,7 +30,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index ca756361a..800f54658 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -29,7 +29,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5), Colleague Riley and contributors +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5), Colleague Riley and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index c5ff97cf0..4b3327ee1 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -29,7 +29,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 09cb80556..36d255bc0 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -29,7 +29,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c index d7605950e..c532bf24f 100644 --- a/src/platforms/rcore_template.c +++ b/src/platforms/rcore_template.c @@ -27,7 +27,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 996e7daf5..9fd2afb5a 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -26,7 +26,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/raudio.c b/src/raudio.c index cc596ec11..a143c5ff5 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -50,7 +50,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -1125,7 +1125,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName) byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2024 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "//////////////////////////////////////////////////////////////////////////////////\n\n"); diff --git a/src/raylib.dll.rc b/src/raylib.dll.rc index 2f02b495c..7ad39c76f 100644 --- a/src/raylib.dll.rc +++ b/src/raylib.dll.rc @@ -13,7 +13,7 @@ BEGIN VALUE "FileDescription", "raylib dynamic library (www.raylib.com)" VALUE "FileVersion", "5.5.0" VALUE "InternalName", "raylib.dll" - VALUE "LegalCopyright", "(c) 2024 Ramon Santamaria (@raysan5)" + VALUE "LegalCopyright", "(c) 2025 Ramon Santamaria (@raysan5)" VALUE "OriginalFilename", "raylib.dll" VALUE "ProductName", "raylib" VALUE "ProductVersion", "5.5.0" diff --git a/src/raylib.dll.rc.data b/src/raylib.dll.rc.data index 64d2a1cd5708166afa50efa2611b82ee528088e0..db6b924a70a57a674f6ece692b44bac7e11eac6d 100644 GIT binary patch delta 6124 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 HW-|f+2sVKk literal 11318 zcmYdkV`KmU1sw(k2#bY5uc){v86*hB4cZJ0HVh05d$b_}Tnr2h4h#kk5FU(VW?*Ju zV9;P-Xy9XDV6b3hXb@mvV8~!(Xn?7J&>UcUDi|0Vm>3usCNMBGfb^|kU}#`rU|=}F zz|g?Tz`$^WfuVtofq~%z149El0|NsGBSQlR0|SEshIxz(oGc6s8z7E{SOF#>;sFHF)%O)GBEgn0vE~;kYHeVi)5dJGy{V( zC{m#E9r6qevp|srkRO7=jDMxilJ^pI^o86wl{5k8L+n;{FR`==S-w=C>J*D{G zgT0l1&7Sj~`^bDj?3h43?mTRum=1pMQ3pKoNRP(6F^ z{v%uXYnMg-ZK$ZTy!u&rS?M34Igfun?K#&!hg6~X$LCp~7iX`3PUM<{3d ztiAh>nB;wFxsWbpzp(h7nSD}J`q$|XuCA3kaJ6@xyy08t`OW4x!km15Ur>LOXMgaj z&3;3WHK%@vs~l&4qMUTA-R|;_h9`G&|8```?q_-agLAI2l|4w9-F{*5p1Q3anex9{ zDw~VTs-4P}m$BD#Zu35SFFr|X`>*K_uKwiQE0z>>T>qe@or2}!&&tbcUle~}d%nhQ z|JB+!uqlc65@vVK__okrQhvf-s7CJ(uh@@#KD~0Dyy4o%(;v*a%DiLO#jhaE$*wgH zS)g#@{LJ>e;_oqm%XVKhAM@V3{pPRgvf3BPVT*n>2wb*Wy`N?MKki3JVKZm*uRmem zEB}IBYuQj84f2otuNkdp>=cfeoQrQNw%I@D)lb38R{w3DKOO zP};EjFH87m<}@Bd+n#@&|3zv~RWyG$tFG_NoD<(vT+>jz>U#f-YahJ}`uIP@Ky*Hs zbC;>Y6ckj6dMgG;-?mn-7s9GFnS4l4cJ5T0M%ejw? zD_ucRaz=X3_N(8f&-k{mKk~#IW>7SxOa14ZT)Z9R)Ybc0tQ#y>pU)Qoxv<&XB7HkU zTrbF$8RizpUqda-|8Otuy}n`ZXZ!Yhw_m*ux3y1-Iv(Ft{7&q^YEV#aRQlJt8e*IO z0h#mpJRrl2>X@GWXsB`V`F$Z>N`Ate-LeAEcsyXa__e#w?+edU@4V%#CpU`Ey zFEi7=GC%scwiT?iul`|?+jVf_KK()XR~$6%EbSDMLCh&1+1|sn9rJ%NXZP9u8P_8J zs@`Bc6Iolg7^FmI&q2%GtRJ$VR$AH}NbY!<_*4Jjw(U3BTR^$Sq>ky?o!q)3Tl&CB zU?)`9HX&HF$s0f|W4sAYWQB|W&+GtYi8pJj>N_)K{};cIk$(Wz7a=G=Aqs3&*!=|d z0{tUjHvE~Mz+RBQ`8y~E&zt;XJ-PGtpN>q~dd_o^wRO8e*|oTUAy*ZwN#=lzeF8K^ zGjG~{^S8Ip?+eG*xO`<)Tvqx=)#7;lp(oJ1embJId94^Io($Lxj_-$s2h558o?j?i z`s%MLq=aCeV+>8ptMfNJFV}}!ws-9|aHO1ZN|P5zl6pSAJ zEB+vCb)0<(+_uls&OW~{Ebp1$U}>iy4@y8Yk4eud-pDL36M~nc$dlI_H%G{7k;J=&p0!$npc#9 zZL|OtLk!OmPK5;j9v=1&@H8^-z62-+Q~$7>`N;UQW5%(cpe$CQ3yJ6&hi9M+h^;g+ zH&z4I?vmd}Q2n-_oX#UD^& z+|zT_{06kh6E-*w3Vr^6u!0>_Zo!M5=?`E*DD$Uf+f;}H8Bc!v1GP!Lq>ulE`w^2o zQ2B4!kPS*zLUSI+?|?@1XQMwY`@}(^mU!>M-nHAn)y*kH-ZWfO*YN&Z10HRB34Q!0 zz~P>zxS8Jo6!V#XTF!yf{M@VYO|l2}Lh2lO?MKW(-FOPBbCG`;?!RSp_IdroyWrew zmJiR}L;MRS28gb5D&+z>k=>rL+%c;46{nuiDyPsDevaVMlJU&U?R85+SIm2`Xuf^@ zp1<*{K85{mekB4*@~3_@tZCZ9byYY%|YK2JcvX8=6>UR6@H`;;(1y;qc zii6h4XP7qGi%JBp`1k4e{>kbFivmPf8QxLO-)jHb9podBG`ovys zgGB+n6;%!rfh)MKO1u*Ug#^SGFoheY@^fUzGzzw6HJ<18i(GN6pdS>5Us=RCLl;Ih z3LXX}v7AQJbq6|}wlXPmg)WpjZ0i)d0v1fp-~1iic$AkFmj4qvBei_P!5)qM-Kt>w zir?2a?sQ+l6}qshsk>!Wz}f>HiAT1aI~U&+nY=J6`;WgvnsP|%s({{ya+RykR&Xwp zI&5nMDTv~Z?H8M1Dz+*-*$iwKiql)Oc)oL7H2_6&;$!~U%&5a703SU zd+PvJd){O&dkan{yqf;+R{T4`Rf*tqu)kTb{^Y;(11{VC9YP8mu-7DO89?<`rR4u8 zhiefl!V-=&EN5>Kg!mg_dnh>Mc|lDW;cGwDeXb=pR>w6-Zanaub-7MR@(!eM1jl*^ zEMmk~iArq55;4v3O_RgwIsaAF^+Ys+th4=IS9b>-;I;={!J(@EcPmKba7X4`>A%Gp zt3)L}PTy|7amBGccfYZNf)LZ%#o#(8oqNqjP;@$d)vnJs_|Ab{EyRf}sq-$}jYtNi zB~a8n_}mmM21>S|n1?w86upVyEErSifKZERZtVx}f}rP&iM_3_W~_gHyu-<~t-57Z zfat2{_s;i2Sn4}GKuPY`(*4)^t6Q=pz;(|1gd_3u>Rwc}3ASdjx{0iUDuShN8LRm) zH!{zY6L1q*1@aBp;UG0!`VXt3)LXduGVF{kNB! zzsMh&%CrrVKz4zYLXCO_&n=79TkN6}dO?P-f#xhoxw9&ux1!7eWZJcxKj%B2-*9Pu zLyFgmcdekd$mxow)4yb~#6!6LH(oLBxy-2e!^t##>sRGv?N8&IbkkKDSmIZFn^o%o z%D6s{<0s7d{#p5l)7L0)JMzsR)rz)PKLzh`e!ZWOGBw!f!8xXORx4agXfCU9f%54X9vA*i!3{{rr|5uyQJ z$9eAKd;_Ewe+9gw@O|4YaO(h6(K>Ww&e_lM9H~Ept?6wbKLJ)9K^rUPzl3tiv{%au z$UoStyMMo(LiOi=dFQ0(JZ4aFVdQ&MBb@ zv%d-+>u3P?SAAl>&7oa?m2Ee)zdHS5(qbzf*4zL8-`)LQd{eU7MnSt4=O;nWQm034 zdSci+OMhzqzrQ9~vE_5Triokc_gxTkU03b(0jp(VU-`3IPo;c87q%j z5`sJTM?bL2)BpClPp_aNtFfNx-{bpo?<}SU{&rsdZ&6xj;Lj}w_FgHycuVLmN9FFq zZb{b%ffrUe$DPO*t|+nJ@@m5LV=u(FZ@1raY=v_~>K5}2&vY&dW_;y;xcbP-J<;N8 zbzcd{{XLL(r}U}$eup@ZX%eE}xr=Ke>6+eIxEZALj`NS03$x5yHlKL4eqDE% z?59hG+$H-XvSgx4PjDBSub8A7pn8jct<{sIg;Tq=3p09mo)Rd#UfOu=<9^QFl1ufX zq8CXk<|}%Cc_F_1*vb65#yu0(a0eECFNfH}+NZYc*_zLbOrLG%O)QV$-}0+{!)*U< z%kEtu_iuk7Hd)nb_5NxO`6n;xGOjAV7n4}HF_{tX4$1#dQoaIU*gm?%)1NcGOzuoXtV3Z znt!i$Wn5LvKUk~y&SL7CUEc-lPF#d)>6fbz@v6`0Jt=i4a*=&)VaDEb=85HVX77TA zT;i1G8m{u#Ew3hsFEX>(+U&M%w1fVaaHlW-i6wPscUwzZaJ31`|u*jXMgSOxg+xz zoO&T1^Boe5%;`s0rhF~uf0%M%*M+?TpY)Uss_nrV)^LXver*r?FK|w1ZfN*Ya5@sZ z!+uU^##Q;K-#gk1#3C0hw%DR~$Jye+nqA<)$lK)d-Qo2QXA5n=r+0T{F(dTq2i#ZeK=pqifQd*{zTF5b$PG;fuhmrTI&wi z^sBDf@}(TBcknNoR9YwqN=8OZp;vZQ|8~wk^TIjesZOK2mELB7HHte$BvTaBEhiMXi9~SWJ6z!<%z2ER+p7OOVKYA7ac-8VPlD=^3xNXb) zg~#PwT8rQB zjmwU1-XOMz_agUEc~DATv#G4`%MPs-?z`oyGo92UlD|G}lDDsHY+Y_XD?RhG=!IAE zhpHdFFnm|UZhij+=d~>rV)yRv`PKwV@G{~~{r!4V|2_-&s+`^S+}Hh)`?a9y>A9ad z=Sg3<-?gZhVM2ty^wR+|L%UALAGNJEBF6tR`**Xxx>^ita6_B=b83}hfLTmucPOM;-s9|4SV|6t&vsd&iyy zr3pqi$SS-yK#ygu;n&^? z*B9*j`Oac$g+0&16S3Rbqy9Qa9IaLS{rJNDeM^=Hd~d%t?S?Rnp%r zpMVS5WiL2b>^tlht9RTxeo>(~Da_6t2WJ=s`|T$h5_ zSnAUR1_p)%aDAHl>p?zQ^{E8P_-_Gt{5LPPM8QPQP|q+~YmPSq15+HdHof5Jm+UCO z68P-j^SQP{qTN&0a7oT;_5Bw8Rix2wvi$YZ*y~@X|It6j(zi`W*y5I#&w~tY!^XvH zkBl^dZ@zziAF|)~MD_mp1Sa?2YI5o)y!XvN$kO-C_Xo?r%kDl8GVZtdKd`So!qWHc zz@Nz3@6A5@Ri6KT;`AQ#%PMLGTiAd6d$jxPp5S|*Z9f^kKWoy-Df71R?dS6+?w>6` zRlUzW?$g|D*1{IIm~TIyKXL!;_fx*t^zV6Mom&plyY2k)OtYJ3te@K6SJwaOcY7{G zbLK2xs4d?6E|;YKcVf0z+Wv8t3g%FWq%i^Os=Y0!Ir5r4qOaNVsek}gbO^_weIz%Su$UEYx@)nfHVU0%y1_mtY9W({UP|F#+?^=;#NWU8F=RdhM6;Isc5!#}v63oUesV{`KE59NqGM-f z9xE{_{LCq69CYr8%k}3;Eo*NWDWxqbxprSFE#|{6)=DSYU(4B|m6K-_*8gh>aqhVx za-`e+24@|gsgjk}+Jn>hU#@BHS)H)P?bQ!WUc=Wdb9-LT7ci8So!Hlw^V7xfP}qvV zo%~iwM{_1_x05Va)Kh#euEze;V}XOI+nmnX{wE5=Jh+>)78xJ%d)ZldCD=Q=;8`+P zli#t}2g0u;Chj(7+Pw6|G)<$8aZYDKe9w5iTvN{DEx#o8KSPtQvh(rf$rZ~_?%+CB z)h0Dl@MVU_a}F`daDBzJRb~>szgGNs)A6EbgXpos*FTKqgLP8wwC-T(x&Q9`ieqb} z5BKqR``oE;WmpV+~5EV|F_kF)%uwm@Hj=h@Dw^_t0NqqdRj2?>vo| z@*{Mpht-Z#!v|dB9}f3?=Q8iSbQSS(NOG9-mgU ziZo7`vhEVMjBe7r8XiZ!i;}&IJOx&q^g1*7+P6e91p0iIl z`yg&M(+>aMzXA4teR-FOHkR=uT&`)7SklpSxVA}ThMzXm+X#-L4nL7)XRj<{c*lJx z<=uTP=led&54e0*W;C>FHh67UzG8pV>09Hg3o|Y)?!Tq_v^(;Hx#@(n4YPi*eDq|9 zekGj1!|!;F=O+6S<{3d34+zKeC0_A3Yf&oju6EO`nxGf=wbsuLWU|O=(Ef0MDdx7_ zjgJAw4Z(+t8ICh;D6x0?e`cW_Tf^1YbN}n@-MC`Q&sz)G?83w5q?M?s^4F|8Dsxmi zzBz5pt=EzIn%c)7MCdPW($+O~YP`N(m({=fO4L-#j&FaX8*daZea5jUTy5^t?p1fs zDQ)3@_q@15?By(@j;%94AN{g%k6dmW!!>2Kh*&wZ{PPRfX4zezelzI?&*h@E|ChFN z@ISC+ymVoec!BPe4M%!)!@7{W+E%N&uZsFPaci-=8TyE*2t}XR%R>eD|tM(I}OE!ISej+e;%^v~F zBlUH%>#v(9iM;q`8uKs+BYR@2=M_LpS-|=8kHp)>w9B82(?R*u!~5!#+kHnAc$`oF z|NrjY?_(Bh!Wma5K1=PN;xy;M7o%C+Tk2GAXg6Fx5*xegI=kMry%tv+-#e~#|787R zW9Y*@>z7;JtrzoIA(QumacuVzxmC8N?3>Ncp3IrY`~1$zty|UCel?!k zda~}tp6~M_-yb^?e=#S*l>ft$$%%a5+ycJOW6m@^@QHWcyanstzs}_It1ok4&uUQb zO0%)ie#m)KslJ#bw9=2yS$-m2I0KV;>;+%5ay z%rjFfONNBrk~b#}o-+ve>b_gjEb{wIWN)@ak4V}#mc{m$F1)m7TVUC>g15x{LTZWB zgv=P_>&N0J+7(GI*nPapnnC)72tV_m^-XTg2Fv=4r6y$V|HW|kPCN6jyUG>{#SsTG zUR<=vHfLrylY3xV^NIG>tXIJk@^rqb9c?Lh52{jG>zNg=3L*YmUjNEo{FEsm=Jeld z$f*TOdr*Rbfk6VCPVz-pt*2c&VR#2hCl>y5Cpk`P3J`EE>=!@q`+mT8ul+aJ4lUQX zzbN;TXPf5S2g}aOYuG8ym0rhkXL8-gnzxqWH)hV>71T2OfarBcQH8TR;z~ZaJ!dSK z8!I|NRI-3IAcS#g2aiQ%DC_@)^W9xv*gd?o{aIs(gXn}r{yDE#H3YdtDRw)EK3K-H zgh>O$Wt+2S71I*Q_QrYh^H*(|s`W!@?FX*=cgq5ftY0v{`rxa{+3y=ZEv}WX;FfbQ z?N2RCZQWP)<y}O2Z_08v+}a-SigC)EA_vXcpF8%fYT9o( z>%s2{J%10I>}6an`@y49{b(F=@MFuTpe1Yq;P9U?F~f|8;Xefu{%iXk`3@@xFu(l2 z|MneY18se!munY`n#M(&Fx!2ep&;|s?@wID*QANrzyH;&?^IWKC*32dKQ=8rN`L+~%=^_<_5|?Fp;bIsLmd@o>7% zi|^celi0YeSk5sO)QgGaT#fzk?$%|_S6OBa0pWpGk+Cxf2tatCHDnXD&8S)s?8Qd5$8FCm>89W*C7}6L( zV-G%HH3keO3s84P(0`3yM>`3&g{nGC56#S9D#6$}~-jBtBhz@o`u_Y^Rc zFk~|1Gvr}0FNL9!ArEX@CPOlV0@NOmoka|l3`#{d$8xkHa38SGw71_lNl z1~w#n!x&N-iWrKK>@#K1V*p`Lqtc9ln}HD=CLn(lfo;w~@-3r?7MV^42BZ$+R zYzbH-5v(r}>^ldjzly=~rVJn-F)-MH-RTcj2MS?O2<5=T7Q}vu=O*=g;;0O(MU7 zibUF^3)^0Q&Q%qw+#qv!`6^%=+JpH(=m zxMP>F&!Gts3O7XBj#y>>eI(z$?BixhPL}Qrw@(%(9DVoV`<*8@Tzq}~-{FX5E+%!E zY#R=8Eiqxfkr2EngJau4C8;L;vvU)IC4v`asNY!3vCL&o0{aEtOQKDN9KG^ySuS5N zu~VPnwzaNa;f74SNlBCKnPZ;%aSr!5*sF_*Ly+Zmf{>|HldOY~ zD2w!BF24e)Favh56nrZpP*?k;NyInpXGLf9WzH6gQt$4!D@MyYW0XljR(5~-pox9Vq|&W zknphWFoVK5kv8ERFBOY}g+h*Xa}vxur2B;5FieV=lfXXVh!Lw1n@XaTB`72w91_Uk z$?!VDnO1VLUzn%qDSK09hSdKXObI2O864j%Ogb5wq^%Dwlc`rxP@fU}w(T|7L50aJ zooxxp4y;U|w7|i^c94msIf1uL*e6Nzfg$SxW~~X=SQ(mR51iyZ_V_}cg}@tzR~MSO zPqc58IdDh1V)Z+g<^*#CbqSW!>tBhSkp9T`;ED9P>kCU?Tzq|;Q*EP&0mn7QxB47m z2e@VkuW|UHFel;XQJ#8B2ZPR~4UPu9y7mHV8d%jM8aeznFbRe#M4XAUf6u}n@9@*K zyh;D8;te)wXLsif%pQxH5{ipHE@}E0uhMyu_k#67z6H`Vgx@e^8O%vw7icbMD$QVQ z^6ivp4V{zF@4Wk=#larEpSq{|g?*A-pFf|QAe2^8Hzz^XpsL>T;KO>^fX0F*(GAk? zY&fnhv|M}9ZHA#V$1|4ZgxA-vaxVMWTRHjrb{m%2MHvQj5@e&AAF>$lGLaC_@i-92 zx`267!&+_zmgWS397azEfj10V0{u=i4xPvsQT}PQ<;1xKUNF6!%H1Gb!5B&b54S6K;4`N8S@>RXYw4h zGFhBm!YHv=E5Wbej>HEC^%?w3O@|K42(@y{S{KPK{@BjJCAO6pN;xfyF zCi@<+%s%wNahH?9^3di;u7hSb7@x2dH{E_xzGd~Sa~_Z9CJ69cT0A#F%HDea(_n?* z8E>TPk6d5auD^ikUF?CUa}#7YtUWpFA<%tTka-Z`W`#ew%lOLHhgmUt`~}a68PB&in8y_p0IzHtPmZ zu4d+FGR_w;lxbRBp5eG?S{g&6W7xCh3?6G<{5fUM_m-h6gCngZ)%xX}1XicV#Z96e zUzrbbu_(*(AFP_A=~MKFS+LeO$mKTM^vVC#6ejx%3e>Z-Luu+?db1#x2+@D7ofMGV{u9PhZX3q$~Y(@o8557aCoy*AHlP8JJ#p zeZ+O+)I=7Gg92%vpK~=Pp2%S@I;}Z%zr2lH|6TnlUXkA4SLa^&9(}zu{M_mJ?4h}z6w`1?tx~f&GeIcsVEApPud}zBZ1~Q#ZeD|O z@RX*k1=qOl{k&%?uL=f`31)=Xp46S-9H?cE^xXxXmbmbH$- zvMq~e^znG^d7zxATW%QWFhh*^FPNc*GX8cTvH_4PpCT7!#wM zT7vA9MJegJR7}k$oM&M)jT%nG=({e+sZAhs;-GjUcPwmRo9l&NoQVWWS(7q zoH=jxVohyM_Ct$5{tTLB?|8#PP?)VHQ`5Ix;my`(S7H;zdbKqSpNTuj-Osym-=coci?sAedntj6IH^R&8uJdwK@9pH5 z=Zr42PW;AMt*yU2P~z;wf+o~BLQkmmV_`}n!=OJd*8MXUPNwJwSlxYxJ&w{_j`w0a!sUT>3qpUL%Q@5bWa&+OFa=w*FbvY1u9{)ziqt1BgocC7Jq*Iv70 zLrICC*n@&}_i*1kobM`cFV&Reyxg~T$@@!h;$~b`U9gI$)84xE>z*$kk6h)|+vjhg z`P5_aHBr<2z(t&DoWU$%Ir*ltx|#=Ub!>ktmhN2s|M+@SS^K|!$L`mCd3(BI>Ed+1 z8#^Yv^4g!jG2B?lZ1QVMfBbWTHE_Ctt+Cmcn-`xeoYCMr5c@zNwcU3c)5D8< zBnqu|IhY*Nda$|f9aCY{hd3YoTer^E9x~BS+wr?)@r1^!3N_K!uZioqRW>~O_;;F8 z{%&8Eh&g-jE6U!DW@cR_>SMCM;==(Jbh!{-`|*#`QYkDuk_%QR3<5L?b++M zUU_-`C|lCvEtZVO-pbc2>lTK!U8tUHASge1zJx$MBNMcUy0e?_kOBj1fX|&%|LZm1 z@agqx2u++at=L^_*U$*`}$SBR^{#gMUI=9dNaCC|EY4Y-QCQ_nDyHG_Z-1+ zH(o2I6;JuLrk~p<_;k)+kN?Ftukg-FJY3c_SMtSveLWMfL&F%f_P^%yU|{59V#zpV z!@y^8^ROaBx9FZtO}IXCixwj0;4RlW*ovU8VRVm~XCcCTR0ft9Z30#^31 zSoArYtkze%K0k!{St-Nsec>~=|6z2vG0XRh3pv@EK4qFP+2}x{xopdpl3R!0 z9$2|}YNYS-r%Xj@i~Eh5CtTJwYADRhVNldzo;mr6qDdZ)LJD_EVEW-_aq|^a99j65 zo!|;y!!m#3%7P^8F9DNmSm%bZDx|N{^fG6-$8E`W#; zt1nVaH+sNxFUKwIgVXkul=U$g6DC@ED?en_pAhGvR5ANn(ki1B-G1Hc15%gqR7{_^ zvEO8VJMBC@6OI%P z-vR09vT(1B{KBnk9o!B&t06h zpZoYDJ@diGuRk`gEB;r-x9jSHtj$K@0#>Z^?`K@S>=l+O^vLVf&a1!H&MB^GZg%ur zespW}o}FjAI_pzpZE^&ymIcdC_2e{cU*r2lVArC<|GpOWT{hnGL{%h#W&e?4MQO{` z>N{#{UtGDpIgWL0;_KfZv(4Gt{Pu3kI+VO?)wTGG1z%5`+3ufqOEmbLB}aI}u;B8))2lglP2FvFsO;j|3;nkK(iZQN|2^RSbL4qBbGdyzgP6*j^;>`26F&ukCL8fPO9Zd#(i@S8dK>OJtmaj( z@5~b0bkb$b@0Tx@oRe(VF!H!~K*VZA`K7AwKMOqUws3X={R)qD@E30Z0G9El2t$ zRZU;HXAzO!W!9$vknM3 zAJkcrrzNs+e!J!Lu+p?CTdIScueYC^cgR5Q6;J=9r@kvW3)-ITN#Qdo`=<+K&9jzVvrm}_~)SF<%_xSx3t4mYs z-CnWIz3FoAr^V}=u0`jzc4oc${H59VRmHyB4;~g>OIufW=ab*v^B5)AIJXlvShtn zXF2!N{Oy+?KNfzed1bnM;@X^*&s7tIcgikU_4BFBmMFJ<%k-Ay1&Pe_=lwCUSTEM4 zEGXth>u$FCf00w74hL`9&1AiFUqXI%)S{Kmzbn)>T~D<-QDVe@^-7k%r|fjyaIWXElv^vA+L=3?BqQd3_~UN6{Q4T7CDrHuPi!00acA1xvCJ{0%d|&1>PKn1xYOlq-njCWs6CQ3nRvstSz+xE7IdQvsT&mPo zhPSCAO8JU2*Y+thm+7ur!?(a-#@G2%Wh`4irU`_$Z{M8m`terA#PGn&(R>#@B%0$) zljo-dv0B{Zp2k_lqmW?m+SSqHw~G72jnxbJly1E?bgg$e!!9Um&3;!zEa}x-VU~3U zi;Ldz&FOuSc<7AF7l}3VrOl_`7W9rzRA88*|8tX8oVjSj;|!DT7}nG3A3iu0RGxPY z@7UJYIAeCB)YOAID>u(RA*{4NXhu1Mjt94Td`-%)#k1T3=kMb2eR@TvC4H0Mxw*~9 zI(}O4=8I09`BZSVwg2~dQ&Ng-56%VME%eu54G;KXLjp179(uXPKZ`TwREULQkzfRNi z-TTF>m>S=`(z=|!eQ`H??C0yPZ$BQK+pDI3@Jz05ZtM(Y*Z(}Fzl&=aC)W0Gyj}kG z8ftKHtE<+}hlEsZkhfTi0SEWz8-~UIo3&n_3C>wM?bIQEDUSxG2ATfX&bRW}KMOYW zGpv!2skAkT+g+V<>O@-5k6E&ub50eMToO!cHHv7Q#qCj~6l%|6(y#G(hrpGoTYP>j zJ&;*YoOY3Ub==}5Gk5-;dtt48h2ht?OVY$=-Q@rJw*F3YXK z#E_5x;eiI#nHd}$AUx2JItzn=0fbk<%)p?*%AlYC;ey7~*%%}wAUx1$Iy-}a0EBmg SVe>MLCyb1yo4d7UGXem6m4R^p literal 11302 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 YU~5a689=K>LAEfXto;QU!why806y$$!~g&Q diff --git a/src/raymath.h b/src/raymath.h index 9d712027c..bee21b4f6 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -32,7 +32,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/rcamera.h b/src/rcamera.h index ab998ae03..a598e1107 100644 --- a/src/rcamera.h +++ b/src/rcamera.h @@ -20,7 +20,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2022-2024 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5) +* Copyright (c) 2022-2025 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/rcore.c b/src/rcore.c index 17634a52c..2806235cc 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -70,7 +70,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -3000,7 +3000,7 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName) byteCount += sprintf(txtData + byteCount, "# more info and bugs-report: github.com/raysan5/raylib\n"); byteCount += sprintf(txtData + byteCount, "# feedback and support: ray[at]raylib.com\n"); byteCount += sprintf(txtData + byteCount, "#\n"); - byteCount += sprintf(txtData + byteCount, "# Copyright (c) 2023-2024 Ramon Santamaria (@raysan5)\n"); + byteCount += sprintf(txtData + byteCount, "# Copyright (c) 2023-2025 Ramon Santamaria (@raysan5)\n"); byteCount += sprintf(txtData + byteCount, "#\n\n"); // Add events data diff --git a/src/rgestures.h b/src/rgestures.h index b5624be56..1bf4e0555 100644 --- a/src/rgestures.h +++ b/src/rgestures.h @@ -21,7 +21,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/rglfw.c b/src/rglfw.c index 2282955a1..b167955bc 100644 --- a/src/rglfw.c +++ b/src/rglfw.c @@ -7,7 +7,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2017-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2017-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/rlgl.h b/src/rlgl.h index 5fd523b3c..0f3a203e7 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -88,7 +88,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/rmodels.c b/src/rmodels.c index 70e461ea5..ed0ce9136 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -21,7 +21,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -1960,7 +1960,7 @@ bool ExportMesh(Mesh mesh, const char *fileName) byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "# // feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "# // //\n"); - byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2024 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "# // //\n"); byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n"); byteCount += sprintf(txtData + byteCount, "# Vertex Count: %i\n", mesh.vertexCount); diff --git a/src/rshapes.c b/src/rshapes.c index ece5513b3..f0da73575 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -25,7 +25,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/rtext.c b/src/rtext.c index b60c8cb1d..12c25e4e6 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -34,7 +34,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -989,7 +989,7 @@ bool ExportFontAsCode(Font font, const char *fileName) byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2024 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); diff --git a/src/rtextures.c b/src/rtextures.c index e0ae5f4af..5248f1f4c 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -42,7 +42,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -761,7 +761,7 @@ bool ExportImageAsCode(Image image, const char *fileName) byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2024 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); diff --git a/src/utils.c b/src/utils.c index c5d9748d4..5c189845b 100644 --- a/src/utils.c +++ b/src/utils.c @@ -10,7 +10,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -308,7 +308,7 @@ bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileN byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); - byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2024 Ramon Santamaria (@raysan5) //\n"); + byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2025 Ramon Santamaria (@raysan5) //\n"); byteCount += sprintf(txtData + byteCount, "// //\n"); byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); diff --git a/src/utils.h b/src/utils.h index 23eca8ee9..271d0d2c7 100644 --- a/src/utils.h +++ b/src/utils.h @@ -5,7 +5,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. From 0f6e85a975f637e14b1fed3ff6022a0e0008e620 Mon Sep 17 00:00:00 2001 From: Peter0x44 Date: Wed, 1 Jan 2025 11:18:11 +0000 Subject: [PATCH 13/33] [build] CMake: Don't build examples using audio if audio is disabled (#4652) --- examples/CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 64b6d7604..f77ece4c0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -124,7 +124,21 @@ endif () # The rlgl_standalone example only targets desktop, without shared libraries. if (BUILD_SHARED_LIBS OR NOT ${PLATFORM} MATCHES "Desktop") list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/rlgl_standalone.c) +endif() +# The audio examples fail to link if raylib is built without raudio +if (NOT SUPPORT_MODULE_RAUDIO) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/audio/audio_mixed_processor.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/audio/audio_module_playing.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/audio/audio_music_stream.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/audio/audio_raw_stream.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/audio/audio_sound_loading.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/audio/audio_sound_multi.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/audio/audio_stream_effects.c) + + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/others/embedded_files_loading.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/textures/textures_sprite_button.c) + list(REMOVE_ITEM example_sources ${CMAKE_CURRENT_SOURCE_DIR}/textures/textures_sprite_explosion.c) endif() include_directories(BEFORE SYSTEM others/external/include) From 97fa3a73e82416fa7542dd50e8e96dd20a71d980 Mon Sep 17 00:00:00 2001 From: veins1 <19636663+veins1@users.noreply.github.com> Date: Fri, 3 Jan 2025 21:36:48 +0500 Subject: [PATCH 14/33] Fix: Alt-Tab not working in borderless fullscreen (#3865) (#4655) --- src/platforms/rcore_desktop_glfw.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index bd2600c87..0076ccb0d 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -223,11 +223,9 @@ void ToggleBorderlessWindowed(void) if (!wasOnFullscreen) CORE.Window.previousPosition = CORE.Window.position; CORE.Window.previousScreen = CORE.Window.screen; - // Set undecorated and topmost modes and flags + // Set undecorated flag glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE); CORE.Window.flags |= FLAG_WINDOW_UNDECORATED; - glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_TRUE); - CORE.Window.flags |= FLAG_WINDOW_TOPMOST; // Get monitor position and size int monitorPosX = 0; @@ -247,9 +245,7 @@ void ToggleBorderlessWindowed(void) } else { - // Remove topmost and undecorated modes and flags - glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_FALSE); - CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST; + // Remove undecorated flag glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE); CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED; From 05c4d8a652e8b56932ffb87dbf8914bd82c19d22 Mon Sep 17 00:00:00 2001 From: Brian E <72316548+Brian-ED@users.noreply.github.com> Date: Sun, 5 Jan 2025 12:29:31 +0100 Subject: [PATCH 15/33] [rlgl.h] Fixed typo in top comment (#4658) "renderer" to "rendered" --- src/rlgl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rlgl.h b/src/rlgl.h index 0f3a203e7..cb10fd7ab 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -10,7 +10,7 @@ * When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are * initialized on rlglInit() to accumulate vertex data * -* When an internal state change is required all the stored vertex data is renderer in batch, +* When an internal state change is required all the stored vertex data is rendered in batch, * additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch * * Some resources are also loaded for convenience, here the complete list: From 2f95e8382b7b5e93fa2c018510b917c166cb5db2 Mon Sep 17 00:00:00 2001 From: rexept <103546774+rexept@users.noreply.github.com> Date: Sun, 5 Jan 2025 04:30:06 -0700 Subject: [PATCH 16/33] typo fix (#4656) --- examples/core/core_3d_camera_split_screen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/core/core_3d_camera_split_screen.c b/examples/core/core_3d_camera_split_screen.c index 5294e8949..313b64f65 100644 --- a/examples/core/core_3d_camera_split_screen.c +++ b/examples/core/core_3d_camera_split_screen.c @@ -63,7 +63,7 @@ int main(void) // Update //---------------------------------------------------------------------------------- // If anyone moves this frame, how far will they move based on the time since the last frame - // this moves thigns at 10 world units per second, regardless of the actual FPS + // this moves things at 10 world units per second, regardless of the actual FPS float offsetThisFrame = 10.0f*GetFrameTime(); // Move Player1 forward and backwards (no turning) @@ -171,4 +171,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} From ad035edfacf18214b46a4739244e21b63db41ed1 Mon Sep 17 00:00:00 2001 From: Asdqwe Date: Sun, 5 Jan 2025 08:30:43 -0300 Subject: [PATCH 17/33] Fix camera initial position (#4657) --- src/platforms/rcore_desktop_glfw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 0076ccb0d..dba821ddd 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1017,6 +1017,9 @@ void EnableCursor(void) // Disables cursor (lock cursor) void DisableCursor(void) { + // Reset mouse position within the window area before disabling cursor + SetMousePosition(CORE.Window.screen.width, CORE.Window.screen.height); + glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // Set cursor position in the middle From fc29bc27fd1c6904143fc24fbcf5ca629ec491c6 Mon Sep 17 00:00:00 2001 From: Maicon Santana Date: Mon, 6 Jan 2025 10:29:24 +0000 Subject: [PATCH 18/33] Fix Touch pointCount reduction (#4661) --- src/platforms/rcore_web.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 9fd2afb5a..78fd46f50 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -1812,7 +1812,23 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) { - CORE.Input.Touch.pointCount--; + // Identify the EMSCRIPTEN_EVENT_TOUCHEND and remove it from the list + for (int i = 0; i < CORE.Input.Touch.pointCount; i++) + { + if (touchEvent->touches[i].isChanged) + { + // Move all touch points one position up + for (int j = i; j < CORE.Input.Touch.pointCount - 1; j++) + { + CORE.Input.Touch.pointId[j] = CORE.Input.Touch.pointId[j + 1]; + CORE.Input.Touch.position[j] = CORE.Input.Touch.position[j + 1]; + } + // Decrease touch points count to remove the last one + CORE.Input.Touch.pointCount--; + break; + } + } + // Clamp pointCount to avoid negative values if (CORE.Input.Touch.pointCount < 0) CORE.Input.Touch.pointCount = 0; } From 5d9aed5d4063158bbc3634e6889ba2dd979412b0 Mon Sep 17 00:00:00 2001 From: "K. Adam Christensen" Date: Wed, 8 Jan 2025 09:53:27 -0800 Subject: [PATCH 19/33] [rlgl] Optimize rlReadScreenPixels (#4667) This optimization works in the following ways: 1. Reduces calls to malloc to 1. Instead of needing an extra array, we can just swap the top half with the bottom half of the one array. 2. Unroll the inner for loop and remove a condition. Unrolling loops buys some performance wins, but the real goal was to remove the if check and just set the alpha channel to 255. On my hidpi arm64 laptop, I saw ~60% improvement in performance in my debug build (29 FPS vs 47 FPS). When optimized, the gains were roughly 10% (75 FPS vs 83%). Signed-off-by: K. Adam Christensen --- src/rlgl.h | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index cb10fd7ab..574b860b0 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3666,29 +3666,37 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) // Read screen pixel data (color buffer) unsigned char *rlReadScreenPixels(int width, int height) { - unsigned char *screenData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); + unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly! - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imgData); // Flip image vertically! - unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*4*sizeof(unsigned char)); - - for (int y = height - 1; y >= 0; y--) + // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it! + for (int y = height - 1; y >= height / 2; y--) { - for (int x = 0; x < (width*4); x++) + for (int x = 0; x < (width*4); x += 4) { - imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line + size_t s = ((height - 1) - y)*width*4 + x; + size_t e = y*width*4 + x; - // Set alpha component value to 255 (no trasparent image retrieval) - // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it! - if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255; + unsigned char r = imgData[s]; + unsigned char g = imgData[s+1]; + unsigned char b = imgData[s+2]; + + imgData[s] = imgData[e]; + imgData[s+1] = imgData[e+1]; + imgData[s+2] = imgData[e+2]; + imgData[s+3] = 255; // Set alpha component value to 255 (no trasparent image retrieval) + + imgData[e] = r; + imgData[e+1] = g; + imgData[e+2] = b; + imgData[e+3] = 255; // Ditto } } - RL_FREE(screenData); - return imgData; // NOTE: image data should be freed } From ddd86a33874b407f9f0cbb7a095c9e72c9ed3b47 Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Thu, 9 Jan 2025 00:07:59 +0100 Subject: [PATCH 20/33] [rshapes] Fix pixel offset issue with line drawing (#4666) * fix pixel offset issue with `DrawRectangleRoundedLinesEx` * improve fix - (pixel offset issue with `DrawRectangleRoundedLinesEx`) * revert radius tweak (`DrawRectangleRoundedLines`) --- src/rshapes.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/rshapes.c b/src/rshapes.c index f0da73575..07c685b6e 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -1160,18 +1160,29 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f P5 ================== P4 */ const Vector2 point[16] = { - {(float)rec.x + innerRadius, rec.y - lineThick}, {(float)(rec.x + rec.width) - innerRadius, rec.y - lineThick}, { rec.x + rec.width + lineThick, (float)rec.y + innerRadius }, // PO, P1, P2 - {rec.x + rec.width + lineThick, (float)(rec.y + rec.height) - innerRadius}, {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height + lineThick}, // P3, P4 - {(float)rec.x + innerRadius, rec.y + rec.height + lineThick}, { rec.x - lineThick, (float)(rec.y + rec.height) - innerRadius}, {rec.x - lineThick, (float)rec.y + innerRadius}, // P5, P6, P7 - {(float)rec.x + innerRadius, rec.y}, {(float)(rec.x + rec.width) - innerRadius, rec.y}, // P8, P9 - { rec.x + rec.width, (float)rec.y + innerRadius }, {rec.x + rec.width, (float)(rec.y + rec.height) - innerRadius}, // P10, P11 - {(float)(rec.x + rec.width) - innerRadius, rec.y + rec.height}, {(float)rec.x + innerRadius, rec.y + rec.height}, // P12, P13 - { rec.x, (float)(rec.y + rec.height) - innerRadius}, {rec.x, (float)rec.y + innerRadius} // P14, P15 + {(float)rec.x + innerRadius + 0.5f, rec.y - lineThick + 0.5f}, + {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y - lineThick + 0.5f}, + {rec.x + rec.width + lineThick - 0.5f, (float)rec.y + innerRadius + 0.5f}, // PO, P1, P2 + {rec.x + rec.width + lineThick - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, + {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height + lineThick - 0.5f}, // P3, P4 + {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height + lineThick - 0.5f}, + {rec.x - lineThick + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, + {rec.x - lineThick + 0.5f, (float)rec.y + innerRadius + 0.5f}, // P5, P6, P7 + {(float)rec.x + innerRadius + 0.5f, rec.y + 0.5f}, + {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + 0.5f}, // P8, P9 + {rec.x + rec.width - 0.5f, (float)rec.y + innerRadius + 0.5f}, + {rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, // P10, P11 + {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height - 0.5f}, + {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height - 0.5f}, // P12, P13 + {rec.x + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, + {rec.x + 0.5f, (float)rec.y + innerRadius + 0.5f} // P14, P15 }; const Vector2 centers[4] = { - {(float)rec.x + innerRadius, (float)rec.y + innerRadius}, {(float)(rec.x + rec.width) - innerRadius, (float)rec.y + innerRadius}, // P16, P17 - {(float)(rec.x + rec.width) - innerRadius, (float)(rec.y + rec.height) - innerRadius}, {(float)rec.x + innerRadius, (float)(rec.y + rec.height) - innerRadius} // P18, P19 + {(float)rec.x + innerRadius + 0.5f, (float)rec.y + innerRadius + 0.5f}, + {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)rec.y + innerRadius + 0.5f}, // P16, P17 + {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, + {(float)rec.x + innerRadius + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f} // P18, P19 }; const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f }; From bf8962dbc7233d9814b45d83d7a7b91b8335fb52 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 10 Jan 2025 13:06:28 +0100 Subject: [PATCH 21/33] REVIEWED: Remove some `const` from text buffer return values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lately got some compilation `errors` related, it seems GCC 14 interprets some `const`-missmatch as errors instead of warnings (as previous versions). But in any case, I don't see why an user won't be able to operate directly over of those returned buffers; `const` adds a restriction (for security reasons?) that in my opinion is useless. From an expert on compilers (w64devkit creator), here there are some notes I agree with: ``` No const. It serves no practical role in optimization, and I cannot recall an instance where it caught, or would have caught, a mistake. I held out for awhile as prototype documentation, but on reflection I found that good parameter names were sufficient. Dropping const has made me noticeably more productive by reducing cognitive load and eliminating visual clutter. I now believe its inclusion in C was a costly mistake. (One small exception: I still like it as a hint to place static tables in read-only memory closer to the code. I’ll cast away the const if needed. This is only of minor importance.) ``` Ref: https://nullprogram.com/blog/2023/10/08/ --- src/raylib.h | 14 +++++++------- src/rtext.c | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 451091269..f59e1c041 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1510,15 +1510,15 @@ RLAPI const char *TextFormat(const char *text, ...); RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string RLAPI char *TextReplace(const char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!) RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) -RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter -RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings +RLAPI char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter +RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor! RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string -RLAPI const char *TextToUpper(const char *text); // Get upper case version of provided string -RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string -RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string -RLAPI const char *TextToSnake(const char *text); // Get Snake case notation version of provided string -RLAPI const char *TextToCamel(const char *text); // Get Camel case notation version of provided string +RLAPI char *TextToUpper(const char *text); // Get upper case version of provided string +RLAPI char *TextToLower(const char *text); // Get lower case version of provided string +RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string +RLAPI char *TextToSnake(const char *text); // Get Snake case notation version of provided string +RLAPI char *TextToCamel(const char *text); // Get Camel case notation version of provided string RLAPI int TextToInteger(const char *text); // Get integer value from text RLAPI float TextToFloat(const char *text); // Get float value from text diff --git a/src/rtext.c b/src/rtext.c index 12c25e4e6..e22e14778 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1629,7 +1629,7 @@ char *TextInsert(const char *text, const char *insert, int position) // Join text strings with delimiter // REQUIRES: memset(), memcpy() -const char *TextJoin(const char **textList, int count, const char *delimiter) +char *TextJoin(const char **textList, int count, const char *delimiter) { static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); @@ -1663,7 +1663,7 @@ const char *TextJoin(const char **textList, int count, const char *delimiter) // Split string into multiple strings // REQUIRES: memset() -const char **TextSplit(const char *text, char delimiter, int *count) +char **TextSplit(const char *text, char delimiter, int *count) { // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, @@ -1671,7 +1671,7 @@ const char **TextSplit(const char *text, char delimiter, int *count) // 1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH - static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL }; + static char *result[MAX_TEXTSPLIT_COUNT] = { NULL }; static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); @@ -1727,7 +1727,7 @@ int TextFindIndex(const char *text, const char *find) // Get upper case version of provided string // WARNING: Limited functionality, only basic characters set // TODO: Support UTF-8 diacritics to upper-case, check codepoints -const char *TextToUpper(const char *text) +char *TextToUpper(const char *text) { static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); @@ -1746,7 +1746,7 @@ const char *TextToUpper(const char *text) // Get lower case version of provided string // WARNING: Limited functionality, only basic characters set -const char *TextToLower(const char *text) +char *TextToLower(const char *text) { static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); @@ -1765,7 +1765,7 @@ const char *TextToLower(const char *text) // Get Pascal case notation version of provided string // WARNING: Limited functionality, only basic characters set -const char *TextToPascal(const char *text) +char *TextToPascal(const char *text) { static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); @@ -1793,7 +1793,7 @@ const char *TextToPascal(const char *text) // Get snake case notation version of provided string // WARNING: Limited functionality, only basic characters set -const char *TextToSnake(const char *text) +char *TextToSnake(const char *text) { static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0}; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); @@ -1821,7 +1821,7 @@ const char *TextToSnake(const char *text) // Get Camel case notation version of provided string // WARNING: Limited functionality, only basic characters set -const char *TextToCamel(const char *text) +char *TextToCamel(const char *text) { static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0}; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); From 433cc23ea4511fbeddc0fccc597cde91f5756d59 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 10 Jan 2025 12:06:46 +0000 Subject: [PATCH 22/33] Update raylib_api.* by CI --- parser/output/raylib_api.json | 14 +++++++------- parser/output/raylib_api.lua | 14 +++++++------- parser/output/raylib_api.txt | 14 +++++++------- parser/output/raylib_api.xml | 14 +++++++------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index 853f591d4..c7ebeaf38 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -9675,7 +9675,7 @@ { "name": "TextJoin", "description": "Join text strings with delimiter", - "returnType": "const char *", + "returnType": "char *", "params": [ { "type": "const char **", @@ -9694,7 +9694,7 @@ { "name": "TextSplit", "description": "Split text into multiple strings", - "returnType": "const char **", + "returnType": "char **", "params": [ { "type": "const char *", @@ -9747,7 +9747,7 @@ { "name": "TextToUpper", "description": "Get upper case version of provided string", - "returnType": "const char *", + "returnType": "char *", "params": [ { "type": "const char *", @@ -9758,7 +9758,7 @@ { "name": "TextToLower", "description": "Get lower case version of provided string", - "returnType": "const char *", + "returnType": "char *", "params": [ { "type": "const char *", @@ -9769,7 +9769,7 @@ { "name": "TextToPascal", "description": "Get Pascal case notation version of provided string", - "returnType": "const char *", + "returnType": "char *", "params": [ { "type": "const char *", @@ -9780,7 +9780,7 @@ { "name": "TextToSnake", "description": "Get Snake case notation version of provided string", - "returnType": "const char *", + "returnType": "char *", "params": [ { "type": "const char *", @@ -9791,7 +9791,7 @@ { "name": "TextToCamel", "description": "Get Camel case notation version of provided string", - "returnType": "const char *", + "returnType": "char *", "params": [ { "type": "const char *", diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index 2983456f3..d3130a7d9 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -6891,7 +6891,7 @@ return { { name = "TextJoin", description = "Join text strings with delimiter", - returnType = "const char *", + returnType = "char *", params = { {type = "const char **", name = "textList"}, {type = "int", name = "count"}, @@ -6901,7 +6901,7 @@ return { { name = "TextSplit", description = "Split text into multiple strings", - returnType = "const char **", + returnType = "char **", params = { {type = "const char *", name = "text"}, {type = "char", name = "delimiter"}, @@ -6930,7 +6930,7 @@ return { { name = "TextToUpper", description = "Get upper case version of provided string", - returnType = "const char *", + returnType = "char *", params = { {type = "const char *", name = "text"} } @@ -6938,7 +6938,7 @@ return { { name = "TextToLower", description = "Get lower case version of provided string", - returnType = "const char *", + returnType = "char *", params = { {type = "const char *", name = "text"} } @@ -6946,7 +6946,7 @@ return { { name = "TextToPascal", description = "Get Pascal case notation version of provided string", - returnType = "const char *", + returnType = "char *", params = { {type = "const char *", name = "text"} } @@ -6954,7 +6954,7 @@ return { { name = "TextToSnake", description = "Get Snake case notation version of provided string", - returnType = "const char *", + returnType = "char *", params = { {type = "const char *", name = "text"} } @@ -6962,7 +6962,7 @@ return { { name = "TextToCamel", description = "Get Camel case notation version of provided string", - returnType = "const char *", + returnType = "char *", params = { {type = "const char *", name = "text"} } diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 038b43e17..4d2ed2c93 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -3704,14 +3704,14 @@ Function 429: TextInsert() (3 input parameters) Param[3]: position (type: int) Function 430: TextJoin() (3 input parameters) Name: TextJoin - Return type: const char * + Return type: char * Description: Join text strings with delimiter Param[1]: textList (type: const char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) Function 431: TextSplit() (3 input parameters) Name: TextSplit - Return type: const char ** + Return type: char ** Description: Split text into multiple strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) @@ -3731,27 +3731,27 @@ Function 433: TextFindIndex() (2 input parameters) Param[2]: find (type: const char *) Function 434: TextToUpper() (1 input parameters) Name: TextToUpper - Return type: const char * + Return type: char * Description: Get upper case version of provided string Param[1]: text (type: const char *) Function 435: TextToLower() (1 input parameters) Name: TextToLower - Return type: const char * + Return type: char * Description: Get lower case version of provided string Param[1]: text (type: const char *) Function 436: TextToPascal() (1 input parameters) Name: TextToPascal - Return type: const char * + Return type: char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) Function 437: TextToSnake() (1 input parameters) Name: TextToSnake - Return type: const char * + Return type: char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) Function 438: TextToCamel() (1 input parameters) Name: TextToCamel - Return type: const char * + Return type: char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) Function 439: TextToInteger() (1 input parameters) diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index 734f96465..c2c645977 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -2453,12 +2453,12 @@ - + - + @@ -2472,19 +2472,19 @@ - + - + - + - + - + From b554b53ede67a934e3c0b9bf971fc57629be640f Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:36:52 +0100 Subject: [PATCH 23/33] fix pixel offset issue with `DrawRectangleLines` (#4669) --- src/rshapes.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/rshapes.c b/src/rshapes.c index 07c685b6e..f482079c8 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -807,22 +807,25 @@ void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Col // but it solves another issue: https://github.com/raysan5/raylib/issues/3884 void DrawRectangleLines(int posX, int posY, int width, int height, Color color) { - Matrix mat = rlGetMatrixModelview(); - float zoomFactor = 0.5f/mat.m0; + Matrix mat = rlGetMatrixTransform(); + float xOffset = 0.5f/mat.m0; + float yOffset = 0.5f/mat.m5; + rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f((float)posX - zoomFactor, (float)posY); - rlVertex2f((float)posX + (float)width + zoomFactor, (float)posY); + rlVertex2f((float)posX + xOffset, (float)posY + yOffset); + rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset); - rlVertex2f((float)posX + (float)width, (float)posY - zoomFactor); - rlVertex2f((float)posX + (float)width, (float)posY + (float)height + zoomFactor); + rlVertex2f((float)posX + (float)width - xOffset, (float)posY + yOffset); + rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset); - rlVertex2f((float)posX + (float)width + zoomFactor, (float)posY + (float)height); - rlVertex2f((float)posX - zoomFactor, (float)posY + (float)height); + rlVertex2f((float)posX + (float)width - xOffset, (float)posY + (float)height - yOffset); + rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset); - rlVertex2f((float)posX, (float)posY + (float)height + zoomFactor); - rlVertex2f((float)posX, (float)posY - zoomFactor); + rlVertex2f((float)posX + xOffset, (float)posY + (float)height - yOffset); + rlVertex2f((float)posX + xOffset, (float)posY + yOffset); rlEnd(); + /* // Previous implementation, it has issues... but it does not require view matrix... #if defined(SUPPORT_QUADS_DRAW_MODE) @@ -845,7 +848,7 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color) rlVertex2f((float)posX + 1, (float)posY + (float)height); rlVertex2f((float)posX + 1, (float)posY + 1); rlEnd(); -//#endif +#endif */ } From eee86dd7c9b7b71aad131f56ebeb9ad6dd05ca69 Mon Sep 17 00:00:00 2001 From: Le Juez Victor <90587919+Bigfoot71@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:37:57 +0100 Subject: [PATCH 24/33] [build][CMake] Fix cmake configuration issue for Android (#4671) * fix cmake configuration issue for Android * review comment --- cmake/LibraryConfigurations.cmake | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake index fb7898306..00dda033a 100644 --- a/cmake/LibraryConfigurations.cmake +++ b/cmake/LibraryConfigurations.cmake @@ -69,6 +69,14 @@ elseif (${PLATFORM} MATCHES "Android") set(CMAKE_POSITION_INDEPENDENT_CODE ON) list(APPEND raylib_sources ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c) include_directories(${ANDROID_NDK}/sources/android/native_app_glue) + + # NOTE: We remove '-Wl,--no-undefined' (set by default) as it conflicts with '-Wl,-undefined,dynamic_lookup' needed + # for compiling with the missing 'void main(void)' declaration in `android_main()`. + # We also remove other unnecessary or problematic flags. + + string(REPLACE "-Wl,--no-undefined -Qunused-arguments" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + string(REPLACE "-static-libstdc++" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -u ANativeActivity_onCreate -Wl,-undefined,dynamic_lookup") find_library(OPENGL_LIBRARY OpenGL) From 43dbaf21e7aff7f97148fe3f860d16ef571a2d04 Mon Sep 17 00:00:00 2001 From: Hakunamawatta <48947000+Hakunamawatta@users.noreply.github.com> Date: Sat, 11 Jan 2025 03:40:13 +1100 Subject: [PATCH 25/33] [examples] Fix broken link (#4674) --- examples/text/text_draw_3d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/text/text_draw_3d.c b/examples/text/text_draw_3d.c index ed4e6ce67..8d23b0450 100644 --- a/examples/text/text_draw_3d.c +++ b/examples/text/text_draw_3d.c @@ -286,7 +286,7 @@ int main(void) DrawGrid(10, 2.0f); // Use a shader to handle the depth buffer issue with transparent textures - // NOTE: more info at https://bedroomcoders.co.uk/raylib-billboards-advanced-use/ + // NOTE: more info at https://bedroomcoders.co.uk/posts/198 BeginShaderMode(alphaDiscard); // Draw the 3D text above the red cube From 34f431b422d8d9850c4bec85d33449e60c27610f Mon Sep 17 00:00:00 2001 From: Michael Kearns <1312115+mobiuscog@users.noreply.github.com> Date: Fri, 10 Jan 2025 16:40:48 +0000 Subject: [PATCH 26/33] Update xcode-frameworks dependency for latest zig (#4675) * Update build.zig.zon for latest framework commit * Update build.zig.zon with correct hash * Update build.zig.zon with the 'really' correct hash --- build.zig.zon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 557028e45..077865978 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,8 +5,8 @@ .dependencies = .{ .xcode_frameworks = .{ - .url = "git+https://github.com/hexops/xcode-frameworks#a6bf82e032d4d9923ad5c222d466710fcc05f249", - .hash = "12208da4dfcd9b53fb367375fb612ec73f38e53015f1ce6ae6d6e8437a637078e170", + .url = "git+https://github.com/hexops/xcode-frameworks#9a45f3ac977fd25dff77e58c6de1870b6808c4a7", + .hash = "122098b9174895f9708bc824b0f9e550c401892c40a900006459acf2cbf78acd99bb", .lazy = true, }, .emsdk = .{ From 08b089f620c361e68f82782463c9e9a318d15d1f Mon Sep 17 00:00:00 2001 From: veins1 <19636663+veins1@users.noreply.github.com> Date: Fri, 10 Jan 2025 21:41:40 +0500 Subject: [PATCH 27/33] Reviewed shaders_deferred_render (#4676) Fixed: g-buffer textures binding Fixed: Clearing screen with white would leak onto g-buffer textures Reviewed comments --- examples/shaders/shaders_deferred_render.c | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/shaders/shaders_deferred_render.c b/examples/shaders/shaders_deferred_render.c index 52c713aa7..e5c549e5a 100644 --- a/examples/shaders/shaders_deferred_render.c +++ b/examples/shaders/shaders_deferred_render.c @@ -134,14 +134,15 @@ int main(void) } // Now we initialize the sampler2D uniform's in the deferred shader. - // We do this by setting the uniform's value to the color channel slot we earlier - // bound our textures to. + // We do this by setting the uniform's values to the texture units that + // we later bind our g-buffer textures to. rlEnableShader(deferredShader.id); - - rlSetUniformSampler(rlGetLocationUniform(deferredShader.id, "gPosition"), 0); - rlSetUniformSampler(rlGetLocationUniform(deferredShader.id, "gNormal"), 1); - rlSetUniformSampler(rlGetLocationUniform(deferredShader.id, "gAlbedoSpec"), 2); - + int texUnitPosition = 0; + int texUnitNormal = 1; + int texUnitAlbedoSpec = 2; + SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gPosition"), &texUnitPosition, RL_SHADER_UNIFORM_SAMPLER2D); + SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gNormal"), &texUnitNormal, RL_SHADER_UNIFORM_SAMPLER2D); + SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gAlbedoSpec"), &texUnitAlbedoSpec, RL_SHADER_UNIFORM_SAMPLER2D); rlDisableShader(); // Assign out lighting shader to model @@ -208,11 +209,10 @@ int main(void) // Draw // --------------------------------------------------------------------------------- BeginDrawing(); - - ClearBackground(RAYWHITE); - + // Draw to the geometry buffer by first activating it rlEnableFramebuffer(gBuffer.framebuffer); + rlClearColor(0, 0, 0, 0); rlClearScreenBuffers(); // Clear color and depth buffer rlDisableColorBlend(); @@ -246,14 +246,14 @@ int main(void) BeginMode3D(camera); rlDisableColorBlend(); rlEnableShader(deferredShader.id); - // Activate our g-buffer textures - // These will now be bound to the sampler2D uniforms `gPosition`, `gNormal`, + // Bind our g-buffer textures + // We are binding them to locations that we earlier set in sampler2D uniforms `gPosition`, `gNormal`, // and `gAlbedoSpec` - rlActiveTextureSlot(0); + rlActiveTextureSlot(texUnitPosition); rlEnableTexture(gBuffer.positionTexture); - rlActiveTextureSlot(1); + rlActiveTextureSlot(texUnitNormal); rlEnableTexture(gBuffer.normalTexture); - rlActiveTextureSlot(2); + rlActiveTextureSlot(texUnitAlbedoSpec); rlEnableTexture(gBuffer.albedoSpecTexture); // Finally, we draw a fullscreen quad to our default framebuffer @@ -269,8 +269,8 @@ int main(void) rlBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, 0x00000100); // GL_DEPTH_BUFFER_BIT rlDisableFramebuffer(); - // Since our shader is now done and disabled, we can draw our lights in default - // forward rendering + // Since our shader is now done and disabled, we can draw spheres + // that represent light positions in default forward rendering BeginMode3D(camera); rlEnableShader(rlGetShaderIdDefault()); for(int i = 0; i < MAX_LIGHTS; i++) From 2b2694a89fdfa85a90ce6e311d2477f2bca7be5d Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 10 Jan 2025 22:36:11 +0100 Subject: [PATCH 28/33] Fix #4680 --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 2806235cc..a90a60387 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1931,7 +1931,7 @@ bool IsFileExtension(const char *fileName, const char *ext) { #if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_TEXT_MANIPULATION) int extCount = 0; - const char **checkExts = TextSplit(ext, ';', &extCount); // WARNING: Module required: rtext + char **checkExts = TextSplit(ext, ';', &extCount); // WARNING: Module required: rtext char fileExtLower[MAX_FILE_EXTENSION_LENGTH + 1] = { 0 }; strncpy(fileExtLower, TextToLower(fileExt), MAX_FILE_EXTENSION_LENGTH); // WARNING: Module required: rtext From 62d8969a56909a4721114860cbe1350b5dcb20eb Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 10 Jan 2025 22:56:25 +0100 Subject: [PATCH 29/33] Reviewed shader formating --- .../shaders/resources/shaders/glsl100/pbr.fs | 157 +++++++++--------- .../shaders/resources/shaders/glsl100/pbr.vs | 19 +-- 2 files changed, 91 insertions(+), 85 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/pbr.fs b/examples/shaders/resources/shaders/glsl100/pbr.fs index 70e3b4885..a9cf1a3e0 100644 --- a/examples/shaders/resources/shaders/glsl100/pbr.fs +++ b/examples/shaders/resources/shaders/glsl100/pbr.fs @@ -59,97 +59,104 @@ uniform float ambient; // incrase reflectivity when surface view at larger angle vec3 schlickFresnel(float hDotV,vec3 refl) { - return refl + (1.0 - refl) * pow(1.0 - hDotV,5.0); + return refl + (1.0 - refl)*pow(1.0 - hDotV,5.0); } -float ggxDistribution(float nDotH,float roughness) +float ggxDistribution(float nDotH, float roughness) { - float a = roughness * roughness * roughness * roughness; - float d = nDotH * nDotH * (a - 1.0) + 1.0; - d = PI * d * d; - return a / max(d,0.0000001); + float a = roughness*roughness*roughness*roughness; + float d = nDotH*nDotH*(a - 1.0) + 1.0; + d = PI*d*d; + return a/max(d,0.0000001); } -float geomSmith(float nDotV,float nDotL,float roughness) +float geomSmith(float nDotV, float nDotL, float roughness) { - float r = roughness + 1.0; - float k = r * r / 8.0; - float ik = 1.0 - k; - float ggx1 = nDotV / (nDotV * ik + k); - float ggx2 = nDotL / (nDotL * ik + k); - return ggx1 * ggx2; + float r = roughness + 1.0; + float k = r*r/8.0; + float ik = 1.0 - k; + float ggx1 = nDotV/(nDotV*ik + k); + float ggx2 = nDotL/(nDotL*ik + k); + return ggx1*ggx2; } -vec3 pbr(){ - vec3 albedo = texture2D(albedoMap,vec2(fragTexCoord.x*tiling.x+offset.x,fragTexCoord.y*tiling.y+offset.y)).rgb; - albedo = vec3(albedoColor.x*albedo.x,albedoColor.y*albedo.y,albedoColor.z*albedo.z); - float metallic = clamp(metallicValue,0.0,1.0); - float roughness = clamp(roughnessValue,0.0,1.0); - float ao = clamp(aoValue,0.0,1.0); - if(useTexMRA == 1) { - vec4 mra = texture2D(mraMap, vec2(fragTexCoord.x * tiling.x + offset.x, fragTexCoord.y * tiling.y + offset.y)); - metallic = clamp(mra.r+metallicValue,0.04,1.0); - roughness = clamp(mra.g+roughnessValue,0.04,1.0); - ao = (mra.b+aoValue)*0.5; - } +vec3 pbr() +{ + vec3 albedo = texture2D(albedoMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb; + albedo = vec3(albedoColor.x*albedo.x, albedoColor.y*albedo.y, albedoColor.z*albedo.z); + + float metallic = clamp(metallicValue, 0.0, 1.0); + float roughness = clamp(roughnessValue, 0.0, 1.0); + float ao = clamp(aoValue, 0.0, 1.0); + + if (useTexMRA == 1) + { + vec4 mra = texture2D(mraMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)); + metallic = clamp(mra.r + metallicValue, 0.04, 1.0); + roughness = clamp(mra.g + roughnessValue, 0.04, 1.0); + ao = (mra.b + aoValue)*0.5; + } + vec3 N = normalize(fragNormal); + if (useTexNormal == 1) + { + N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb; + N = normalize(N*2.0 - 1.0); + N = normalize(N*TBN); + } + + vec3 V = normalize(viewPos - fragPosition); + + vec3 e = vec3(0); + e = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb).g*emissiveColor.rgb*emissivePower*float(useTexEmissive); + + // return N;//vec3(metallic,metallic,metallic); + // If dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity + vec3 baseRefl = mix(vec3(0.04), albedo.rgb, metallic); + vec3 Lo = vec3(0.0); // Acumulate lighting lum + for (int i = 0; i < 4; i++) + { + vec3 L = normalize(lights[i].position - fragPosition); // Compute light vector + vec3 H = normalize(V + L); // Compute halfway bisecting vector + float dist = length(lights[i].position - fragPosition); // Compute distance to light + float attenuation = 1.0/(dist*dist*0.23); // Compute attenuation + vec3 radiance = lights[i].color.rgb*lights[i].intensity*attenuation; // Compute input radiance, light energy comming in - vec3 N = normalize(fragNormal); - if(useTexNormal == 1) { - N = texture2D(normalMap, vec2(fragTexCoord.x * tiling.x + offset.y, fragTexCoord.y * tiling.y + offset.y)).rgb; - N = normalize(N * 2.0 - 1.0); - N = normalize(N * TBN); - } + // Cook-Torrance BRDF distribution function + float nDotV = max(dot(N,V), 0.0000001); + float nDotL = max(dot(N,L), 0.0000001); + float hDotV = max(dot(H,V), 0.0); + float nDotH = max(dot(N,H), 0.0); + float D = ggxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H + float G = geomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow + vec3 F = schlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance + + vec3 spec = (D*G*F)/(4.0*nDotV*nDotL); - vec3 V = normalize(viewPos - fragPosition); + // Difuse and spec light can't be above 1.0 + // kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent + vec3 kD = vec3(1.0) - F; - vec3 e = vec3(0); - e = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x+offset.x, fragTexCoord.y*tiling.y+offset.y)).rgb).g * emissiveColor.rgb*emissivePower * float(useTexEmissive); - - //return N;//vec3(metallic,metallic,metallic); - //if dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity - vec3 baseRefl = mix(vec3(0.04),albedo.rgb,metallic); - vec3 Lo = vec3(0.0); // acumulate lighting lum - - for(int i=0;i<4;++i){ - - vec3 L = normalize(lights[i].position - fragPosition); // calc light vector - vec3 H = normalize(V + L); // calc halfway bisecting vector - float dist = length(lights[i].position - fragPosition); // calc distance to light - float attenuation = 1.0 / (dist * dist * 0.23); // calc attenuation - vec3 radiance = lights[i].color.rgb * lights[i].intensity * attenuation; // calc input radiance,light energy comming in - - //Cook-Torrance BRDF distribution function - float nDotV = max(dot(N,V),0.0000001); - float nDotL = max(dot(N,L),0.0000001); - float hDotV = max(dot(H,V),0.0); - float nDotH = max(dot(N,H),0.0); - float D = ggxDistribution(nDotH,roughness); // larger the more micro-facets aligned to H - float G = geomSmith(nDotV,nDotL,roughness); // smaller the more micro-facets shadow - vec3 F = schlickFresnel(hDotV, baseRefl); // fresnel proportion of specular reflectance - - vec3 spec = (D * G * F) / (4.0 * nDotV * nDotL); - // difuse and spec light can't be above 1.0 - // kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent - vec3 kD = vec3(1.0) - F; - //mult kD by the inverse of metallnes , only non-metals should have diffuse light - kD *= 1.0 - metallic; - Lo += ((kD * albedo.rgb / PI + spec) * radiance * nDotL)*float(lights[i].enabled); // angle of light has impact on result - } - vec3 ambient_final = (ambientColor + albedo)* ambient * 0.5; - return ambient_final+Lo*ao+e; + // Mult kD by the inverse of metallnes , only non-metals should have diffuse light + kD *= 1.0 - metallic; + Lo += ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*float(lights[i].enabled); // Angle of light has impact on result + } + + vec3 ambientFinal = (ambientColor + albedo)*ambient*0.5; + + return (ambientFinal + Lo*ao + e); } void main() { - vec3 color = pbr(); - - //HDR tonemapping - color = pow(color,color + vec3(1.0)); - //gamma correction - color = pow(color,vec3(1.0/2.2)); + vec3 color = pbr(); + + // HDR tonemapping + color = pow(color,color + vec3(1.0)); + + // Gamma correction + color = pow(color,vec3(1.0/2.2)); - gl_FragColor = vec4(color,1.0); - + gl_FragColor = vec4(color,1.0); } diff --git a/examples/shaders/resources/shaders/glsl100/pbr.vs b/examples/shaders/resources/shaders/glsl100/pbr.vs index 87e142e07..5a93f784f 100644 --- a/examples/shaders/resources/shaders/glsl100/pbr.vs +++ b/examples/shaders/resources/shaders/glsl100/pbr.vs @@ -26,17 +26,17 @@ const float normalOffset = 0.1; // https://github.com/glslify/glsl-inverse mat3 inverse(mat3 m) { - float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; - float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; - float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; + float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; + float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; - float b01 = a22*a11 - a12*a21; - float b11 = -a22*a10 + a12*a20; - float b21 = a21*a10 - a11*a20; + float b01 = a22*a11 - a12*a21; + float b11 = -a22*a10 + a12*a20; + float b21 = a21*a10 - a11*a20; - float det = a00*b01 + a01*b11 + a02*b21; + float det = a00*b01 + a01*b11 + a02*b21; - return mat3(b01, (-a22*a01 + a02*a21), (a12*a01 - a02*a11), + return mat3(b01, (-a22*a01 + a02*a21), (a12*a01 - a02*a11), b11, (a22*a00 - a02*a20), (-a12*a00 + a02*a10), b21, (-a21*a00 + a01*a20), (a11*a00 - a01*a10))/det; } @@ -44,14 +44,13 @@ mat3 inverse(mat3 m) // https://github.com/glslify/glsl-transpose mat3 transpose(mat3 m) { - return mat3(m[0][0], m[1][0], m[2][0], + return mat3(m[0][0], m[1][0], m[2][0], m[0][1], m[1][1], m[2][1], m[0][2], m[1][2], m[2][2]); } void main() { - // calc binormal from vertex normal and tangent vec3 vertexBinormal = cross(vertexNormal, vertexTangent); // calc fragment normal based on normal transformations From 49b905077d3e2eb3c39efb466a7a7f8ff7c3034b Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jan 2025 19:36:26 +0100 Subject: [PATCH 30/33] remove trailing spaces --- src/rshapes.c | 22 +++++++++++----------- src/rtext.c | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/rshapes.c b/src/rshapes.c index f482079c8..7b967fbdb 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -1163,28 +1163,28 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f P5 ================== P4 */ const Vector2 point[16] = { - {(float)rec.x + innerRadius + 0.5f, rec.y - lineThick + 0.5f}, - {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y - lineThick + 0.5f}, + {(float)rec.x + innerRadius + 0.5f, rec.y - lineThick + 0.5f}, + {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y - lineThick + 0.5f}, {rec.x + rec.width + lineThick - 0.5f, (float)rec.y + innerRadius + 0.5f}, // PO, P1, P2 - {rec.x + rec.width + lineThick - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, + {rec.x + rec.width + lineThick - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height + lineThick - 0.5f}, // P3, P4 - {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height + lineThick - 0.5f}, - {rec.x - lineThick + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, + {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height + lineThick - 0.5f}, + {rec.x - lineThick + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, {rec.x - lineThick + 0.5f, (float)rec.y + innerRadius + 0.5f}, // P5, P6, P7 - {(float)rec.x + innerRadius + 0.5f, rec.y + 0.5f}, + {(float)rec.x + innerRadius + 0.5f, rec.y + 0.5f}, {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + 0.5f}, // P8, P9 - {rec.x + rec.width - 0.5f, (float)rec.y + innerRadius + 0.5f}, + {rec.x + rec.width - 0.5f, (float)rec.y + innerRadius + 0.5f}, {rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, // P10, P11 - {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height - 0.5f}, + {(float)(rec.x + rec.width) - innerRadius - 0.5f, rec.y + rec.height - 0.5f}, {(float)rec.x + innerRadius + 0.5f, rec.y + rec.height - 0.5f}, // P12, P13 - {rec.x + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, + {rec.x + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, {rec.x + 0.5f, (float)rec.y + innerRadius + 0.5f} // P14, P15 }; const Vector2 centers[4] = { - {(float)rec.x + innerRadius + 0.5f, (float)rec.y + innerRadius + 0.5f}, + {(float)rec.x + innerRadius + 0.5f, (float)rec.y + innerRadius + 0.5f}, {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)rec.y + innerRadius + 0.5f}, // P16, P17 - {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, + {(float)(rec.x + rec.width) - innerRadius - 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f}, {(float)rec.x + innerRadius + 0.5f, (float)(rec.y + rec.height) - innerRadius - 0.5f} // P18, P19 }; diff --git a/src/rtext.c b/src/rtext.c index e22e14778..b93fa1c32 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -247,8 +247,8 @@ extern void LoadFontDefault(void) // we must consider data as little-endian order (alpha + gray) ((unsigned short *)imFont.data)[i + j] = 0xffff; } - else - { + else + { ((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xFF; ((unsigned char *)imFont.data)[(i + j)*sizeof(short) + 1] = 0x00; } From 8e450e4446b10999cdd6464abc39ad5986d6f6af Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jan 2025 19:36:46 +0100 Subject: [PATCH 31/33] Reviewed shaders formating to follow raylib coding conventions --- .../shaders/resources/shaders/glsl100/pbr.fs | 57 +++--- .../shaders/resources/shaders/glsl100/pbr.vs | 12 +- .../shaders/resources/shaders/glsl120/pbr.fs | 165 +++++++++--------- .../shaders/resources/shaders/glsl120/pbr.vs | 41 +++-- .../shaders/resources/shaders/glsl330/pbr.fs | 18 +- .../shaders/resources/shaders/glsl330/pbr.vs | 6 +- 6 files changed, 151 insertions(+), 148 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/pbr.fs b/examples/shaders/resources/shaders/glsl100/pbr.fs index a9cf1a3e0..48688ebe9 100644 --- a/examples/shaders/resources/shaders/glsl100/pbr.fs +++ b/examples/shaders/resources/shaders/glsl100/pbr.fs @@ -54,23 +54,22 @@ uniform vec3 viewPos; uniform vec3 ambientColor; uniform float ambient; -// refl in range 0 to 1 -// returns base reflectivity to 1 -// incrase reflectivity when surface view at larger angle -vec3 schlickFresnel(float hDotV,vec3 refl) +// Reflectivity in range 0.0 to 1.0 +// NOTE: Reflectivity is increased when surface view at larger angle +vec3 SchlickFresnel(float hDotV,vec3 refl) { - return refl + (1.0 - refl)*pow(1.0 - hDotV,5.0); + return refl + (1.0 - refl)*pow(1.0 - hDotV, 5.0); } -float ggxDistribution(float nDotH, float roughness) +float GgxDistribution(float nDotH,float roughness) { float a = roughness*roughness*roughness*roughness; float d = nDotH*nDotH*(a - 1.0) + 1.0; d = PI*d*d; - return a/max(d,0.0000001); + return (a/max(d,0.0000001)); } -float geomSmith(float nDotV, float nDotL, float roughness) +float GeomSmith(float nDotV,float nDotL,float roughness) { float r = roughness + 1.0; float k = r*r/8.0; @@ -80,7 +79,7 @@ float geomSmith(float nDotV, float nDotL, float roughness) return ggx1*ggx2; } -vec3 pbr() +vec3 ComputePBR() { vec3 albedo = texture2D(albedoMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb; albedo = vec3(albedoColor.x*albedo.x, albedoColor.y*albedo.y, albedoColor.z*albedo.z); @@ -104,23 +103,23 @@ vec3 pbr() N = normalize(N*2.0 - 1.0); N = normalize(N*TBN); } - + vec3 V = normalize(viewPos - fragPosition); - - vec3 e = vec3(0); - e = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb).g*emissiveColor.rgb*emissivePower*float(useTexEmissive); - + + vec3 emissive = vec3(0); + emissive = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb).g*emissiveColor.rgb*emissivePower*float(useTexEmissive); + // return N;//vec3(metallic,metallic,metallic); // If dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity vec3 baseRefl = mix(vec3(0.04), albedo.rgb, metallic); - vec3 Lo = vec3(0.0); // Acumulate lighting lum + vec3 lightAccum = vec3(0.0); // Acumulate lighting lum for (int i = 0; i < 4; i++) { - vec3 L = normalize(lights[i].position - fragPosition); // Compute light vector - vec3 H = normalize(V + L); // Compute halfway bisecting vector - float dist = length(lights[i].position - fragPosition); // Compute distance to light - float attenuation = 1.0/(dist*dist*0.23); // Compute attenuation + vec3 L = normalize(lights[i].position - fragPosition); // Compute light vector + vec3 H = normalize(V + L); // Compute halfway bisecting vector + float dist = length(lights[i].position - fragPosition); // Compute distance to light + float attenuation = 1.0/(dist*dist*0.23); // Compute attenuation vec3 radiance = lights[i].color.rgb*lights[i].intensity*attenuation; // Compute input radiance, light energy comming in // Cook-Torrance BRDF distribution function @@ -128,9 +127,9 @@ vec3 pbr() float nDotL = max(dot(N,L), 0.0000001); float hDotV = max(dot(H,V), 0.0); float nDotH = max(dot(N,H), 0.0); - float D = ggxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H - float G = geomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow - vec3 F = schlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance + float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H + float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow + vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance vec3 spec = (D*G*F)/(4.0*nDotV*nDotL); @@ -138,25 +137,25 @@ vec3 pbr() // kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent vec3 kD = vec3(1.0) - F; - // Mult kD by the inverse of metallnes , only non-metals should have diffuse light + // Mult kD by the inverse of metallnes, only non-metals should have diffuse light kD *= 1.0 - metallic; - Lo += ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*float(lights[i].enabled); // Angle of light has impact on result + lightAccum += ((kD*albedo.rgb/PI + spec)*radiance*nDotL)*float(lights[i].enabled); // Angle of light has impact on result } vec3 ambientFinal = (ambientColor + albedo)*ambient*0.5; - return (ambientFinal + Lo*ao + e); + return (ambientFinal + lightAccum*ao + emissive); } void main() { - vec3 color = pbr(); - + vec3 color = ComputePBR(); + // HDR tonemapping - color = pow(color,color + vec3(1.0)); + color = pow(color, color + vec3(1.0)); // Gamma correction - color = pow(color,vec3(1.0/2.2)); + color = pow(color, vec3(1.0/2.2)); gl_FragColor = vec4(color,1.0); } diff --git a/examples/shaders/resources/shaders/glsl100/pbr.vs b/examples/shaders/resources/shaders/glsl100/pbr.vs index 5a93f784f..a55c0ea4b 100644 --- a/examples/shaders/resources/shaders/glsl100/pbr.vs +++ b/examples/shaders/resources/shaders/glsl100/pbr.vs @@ -51,16 +51,16 @@ mat3 transpose(mat3 m) void main() { - // calc binormal from vertex normal and tangent + // Compute binormal from vertex normal and tangent vec3 vertexBinormal = cross(vertexNormal, vertexTangent); - // calc fragment normal based on normal transformations - mat3 normalMatrix = transpose(inverse(mat3(matModel))); - // calc fragment position based on model transformations + // Compute fragment normal based on normal transformations + mat3 normalMatrix = transpose(inverse(mat3(matModel))); + + // Compute fragment position based on model transformations fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); fragTexCoord = vertexTexCoord*2.0; - fragNormal = normalize(normalMatrix*vertexNormal); vec3 fragTangent = normalize(normalMatrix*vertexTangent); fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal); @@ -70,5 +70,5 @@ void main() TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal)); // Calculate final vertex position - gl_Position = mvp * vec4(vertexPosition, 1.0); + gl_Position = mvp*vec4(vertexPosition, 1.0); } diff --git a/examples/shaders/resources/shaders/glsl120/pbr.fs b/examples/shaders/resources/shaders/glsl120/pbr.fs index 1c5eee00b..63241709b 100644 --- a/examples/shaders/resources/shaders/glsl120/pbr.fs +++ b/examples/shaders/resources/shaders/glsl120/pbr.fs @@ -22,7 +22,6 @@ varying vec3 fragNormal; varying vec4 shadowPos; varying mat3 TBN; - // Input uniform values uniform int numOfLights; uniform sampler2D albedoMap; @@ -53,102 +52,108 @@ uniform vec3 viewPos; uniform vec3 ambientColor; uniform float ambient; -// refl in range 0 to 1 -// returns base reflectivity to 1 -// incrase reflectivity when surface view at larger angle -vec3 schlickFresnel(float hDotV,vec3 refl) +// Reflectivity in range 0.0 to 1.0 +// NOTE: Reflectivity is increased when surface view at larger angle +vec3 SchlickFresnel(float hDotV,vec3 refl) { - return refl + (1.0 - refl) * pow(1.0 - hDotV,5.0); + return refl + (1.0 - refl)*pow(1.0 - hDotV, 5.0); } -float ggxDistribution(float nDotH,float roughness) +float GgxDistribution(float nDotH,float roughness) { - float a = roughness * roughness * roughness * roughness; - float d = nDotH * nDotH * (a - 1.0) + 1.0; - d = PI * d * d; - return a / max(d,0.0000001); + float a = roughness*roughness*roughness*roughness; + float d = nDotH*nDotH*(a - 1.0) + 1.0; + d = PI*d*d; + return (a/max(d,0.0000001)); } -float geomSmith(float nDotV,float nDotL,float roughness) +float GeomSmith(float nDotV,float nDotL,float roughness) { - float r = roughness + 1.0; - float k = r * r / 8.0; - float ik = 1.0 - k; - float ggx1 = nDotV / (nDotV * ik + k); - float ggx2 = nDotL / (nDotL * ik + k); - return ggx1 * ggx2; + float r = roughness + 1.0; + float k = r*r/8.0; + float ik = 1.0 - k; + float ggx1 = nDotV/(nDotV*ik + k); + float ggx2 = nDotL/(nDotL*ik + k); + return ggx1*ggx2; } -vec3 pbr(){ - vec3 albedo = texture2D(albedoMap,vec2(fragTexCoord.x*tiling.x+offset.x,fragTexCoord.y*tiling.y+offset.y)).rgb; - albedo = vec3(albedoColor.x*albedo.x,albedoColor.y*albedo.y,albedoColor.z*albedo.z); - float metallic = clamp(metallicValue,0.0,1.0); - float roughness = clamp(roughnessValue,0.0,1.0); - float ao = clamp(aoValue,0.0,1.0); - if(useTexMRA == 1) { - vec4 mra = texture2D(mraMap, vec2(fragTexCoord.x * tiling.x + offset.x, fragTexCoord.y * tiling.y + offset.y)); - metallic = clamp(mra.r+metallicValue,0.04,1.0); - roughness = clamp(mra.g+roughnessValue,0.04,1.0); - ao = (mra.b+aoValue)*0.5; - } +vec3 ComputePBR() +{ + vec3 albedo = texture2D(albedoMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb; + albedo = vec3(albedoColor.x*albedo.x, albedoColor.y*albedo.y, albedoColor.z*albedo.z); + + float metallic = clamp(metallicValue, 0.0, 1.0); + float roughness = clamp(roughnessValue, 0.0, 1.0); + float ao = clamp(aoValue, 0.0, 1.0); + + if (useTexMRA == 1) + { + vec4 mra = texture2D(mraMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)); + metallic = clamp(mra.r + metallicValue, 0.04, 1.0); + roughness = clamp(mra.g + roughnessValue, 0.04, 1.0); + ao = (mra.b + aoValue)*0.5; + } + vec3 N = normalize(fragNormal); + if (useTexNormal == 1) + { + N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb; + N = normalize(N*2.0 - 1.0); + N = normalize(N*TBN); + } + vec3 V = normalize(viewPos - fragPosition); - vec3 N = normalize(fragNormal); - if(useTexNormal == 1) { - N = texture2D(normalMap, vec2(fragTexCoord.x * tiling.x + offset.y, fragTexCoord.y * tiling.y + offset.y)).rgb; - N = normalize(N * 2.0 - 1.0); - N = normalize(N * TBN); - } + vec3 emissive = vec3(0); + emissive = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb).g*emissiveColor.rgb*emissivePower*float(useTexEmissive); + + // return N;//vec3(metallic,metallic,metallic); + // If dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity + vec3 baseRefl = mix(vec3(0.04), albedo.rgb, metallic); + vec3 lightAccum = vec3(0.0); // Acumulate lighting lum + + for (int i = 0; i < 4; i++) + { + vec3 L = normalize(lights[i].position - fragPosition); // Compute light vector + vec3 H = normalize(V + L); // Compute halfway bisecting vector + float dist = length(lights[i].position - fragPosition); // Compute distance to light + float attenuation = 1.0/(dist*dist*0.23); // Compute attenuation + vec3 radiance = lights[i].color.rgb*lights[i].intensity*attenuation; // Compute input radiance, light energy comming in + + // Cook-Torrance BRDF distribution function + float nDotV = max(dot(N,V), 0.0000001); + float nDotL = max(dot(N,L), 0.0000001); + float hDotV = max(dot(H,V), 0.0); + float nDotH = max(dot(N,H), 0.0); + float D = GgxDistribution(nDotH, roughness); // Larger the more micro-facets aligned to H + float G = GeomSmith(nDotV, nDotL, roughness); // Smaller the more micro-facets shadow + vec3 F = SchlickFresnel(hDotV, baseRefl); // Fresnel proportion of specular reflectance + + vec3 spec = (D*G*F)/(4.0*nDotV*nDotL); - vec3 V = normalize(viewPos - fragPosition); + // Difuse and spec light can't be above 1.0 + // kD = 1.0 - kS diffuse component is equal 1.0 - spec comonent + vec3 kD = vec3(1.0) - F; - vec3 e = vec3(0); - e = (texture2D(emissiveMap, vec2(fragTexCoord.x*tiling.x+offset.x, fragTexCoord.y*tiling.y+offset.y)).rgb).g * emissiveColor.rgb*emissivePower * float(useTexEmissive); - - //return N;//vec3(metallic,metallic,metallic); - //if dia-electric use base reflectivity of 0.04 otherwise ut is a metal use albedo as base reflectivity - vec3 baseRefl = mix(vec3(0.04),albedo.rgb,metallic); - vec3 Lo = vec3(0.0); // acumulate lighting lum - - for(int i=0;i Date: Sat, 11 Jan 2025 23:38:21 +0100 Subject: [PATCH 32/33] REVIEWED: `TextJoin()`, convert `const char **` to `char**` It generates multiple issues: https://c-faq.com/ansi/constmismatch.html --- src/raylib.h | 2 +- src/rtext.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index f59e1c041..27a8ab049 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1510,7 +1510,7 @@ RLAPI const char *TextFormat(const char *text, ...); RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string RLAPI char *TextReplace(const char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!) RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) -RLAPI char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter +RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor! RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string diff --git a/src/rtext.c b/src/rtext.c index b93fa1c32..d8d290053 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1629,7 +1629,7 @@ char *TextInsert(const char *text, const char *insert, int position) // Join text strings with delimiter // REQUIRES: memset(), memcpy() -char *TextJoin(const char **textList, int count, const char *delimiter) +char *TextJoin(char **textList, int count, const char *delimiter) { static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); From 43db59d1aa65ce9a8359fd76675402271547f9da Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 11 Jan 2025 22:38:42 +0000 Subject: [PATCH 33/33] Update raylib_api.* by CI --- parser/output/raylib_api.json | 2 +- parser/output/raylib_api.lua | 2 +- parser/output/raylib_api.txt | 2 +- parser/output/raylib_api.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json index c7ebeaf38..0044de007 100644 --- a/parser/output/raylib_api.json +++ b/parser/output/raylib_api.json @@ -9678,7 +9678,7 @@ "returnType": "char *", "params": [ { - "type": "const char **", + "type": "char **", "name": "textList" }, { diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua index d3130a7d9..ccf61cb0b 100644 --- a/parser/output/raylib_api.lua +++ b/parser/output/raylib_api.lua @@ -6893,7 +6893,7 @@ return { description = "Join text strings with delimiter", returnType = "char *", params = { - {type = "const char **", name = "textList"}, + {type = "char **", name = "textList"}, {type = "int", name = "count"}, {type = "const char *", name = "delimiter"} } diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt index 4d2ed2c93..896efbaff 100644 --- a/parser/output/raylib_api.txt +++ b/parser/output/raylib_api.txt @@ -3706,7 +3706,7 @@ Function 430: TextJoin() (3 input parameters) Name: TextJoin Return type: char * Description: Join text strings with delimiter - Param[1]: textList (type: const char **) + Param[1]: textList (type: char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) Function 431: TextSplit() (3 input parameters) diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml index c2c645977..241b28ae8 100644 --- a/parser/output/raylib_api.xml +++ b/parser/output/raylib_api.xml @@ -2454,7 +2454,7 @@ - +