From 561cc27403f2815b9dae23cade13d4087979ece4 Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Sat, 6 Dec 2025 10:50:59 -0800 Subject: [PATCH 01/57] [rModels] Support 16 bit vec3 values in gltf reader (#5388) * Support 16 bit vec3 values coming from gltf * Add support for 8 bit normals --- src/rmodels.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/rmodels.c b/src/rmodels.c index fad6ae78b..a7db7690e 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5578,6 +5578,56 @@ static Model LoadGLTF(const char *fileName) vertices[3*k+2] = vt.z; } } + else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16u)) + { + // Init raylib mesh vertices to copy glTF attribute data + model.meshes[meshIndex].vertexCount = (int)attribute->count; + model.meshes[meshIndex].vertices = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + + // Load data into a temp buffer to be converted to raylib data type + unsigned short* temp = (unsigned short*)RL_MALLOC(attribute->count * 3 * sizeof(unsigned short)); + LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp); + + // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float + for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t]; + + RL_FREE(temp); + + // Transform the vertices + float* vertices = model.meshes[meshIndex].vertices; + for (unsigned int k = 0; k < attribute->count; k++) + { + Vector3 vt = Vector3Transform((Vector3) { vertices[3 * k], vertices[3 * k + 1], vertices[3 * k + 2] }, worldMatrix); + vertices[3 * k] = vt.x; + vertices[3 * k + 1] = vt.y; + vertices[3 * k + 2] = vt.z; + } + } + else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16)) + { + // Init raylib mesh vertices to copy glTF attribute data + model.meshes[meshIndex].vertexCount = (int)attribute->count; + model.meshes[meshIndex].vertices = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + + // Load data into a temp buffer to be converted to raylib data type + short* temp = (short*)RL_MALLOC(attribute->count * 3 * sizeof(short)); + LOAD_ATTRIBUTE(attribute, 3, short, temp); + + // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float + for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t]; + + RL_FREE(temp); + + // Transform the vertices + float* vertices = model.meshes[meshIndex].vertices; + for (unsigned int k = 0; k < attribute->count; k++) + { + Vector3 vt = Vector3Transform((Vector3) { vertices[3 * k], vertices[3 * k + 1], vertices[3 * k + 2] }, worldMatrix); + vertices[3 * k] = vt.x; + vertices[3 * k + 1] = vt.y; + vertices[3 * k + 2] = vt.z; + } + } else TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data format not supported, use vec3 float", fileName); } } @@ -5606,6 +5656,78 @@ static Model LoadGLTF(const char *fileName) normals[3*k+2] = nt.z; } } + else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16)) + { + // Init raylib mesh normals to copy glTF attribute data + model.meshes[meshIndex].normals = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + + // Load data into a temp buffer to be converted to raylib data type + short* temp = (short*)RL_MALLOC(attribute->count * 3 * sizeof(short)); + LOAD_ATTRIBUTE(attribute, 3, short, temp); + + // Convert data to raylib normal data type (float) + for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; + + RL_FREE(temp); + + // Transform the normals + float* normals = model.meshes[meshIndex].normals; + for (unsigned int k = 0; k < attribute->count; k++) + { + Vector3 nt = Vector3Normalize(Vector3Transform((Vector3) { normals[3 * k], normals[3 * k + 1], normals[3 * k + 2] }, worldMatrixNormals)); + normals[3 * k] = nt.x; + normals[3 * k + 1] = nt.y; + normals[3 * k + 2] = nt.z; + } + } + else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8u)) + { + // Init raylib mesh normals to copy glTF attribute data + model.meshes[meshIndex].normals = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + + // Load data into a temp buffer to be converted to raylib data type + unsigned char* temp = (unsigned char*)RL_MALLOC(attribute->count * 3 * sizeof(unsigned char)); + LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp); + + // Convert data to raylib normal data type (float) + for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; + + RL_FREE(temp); + + // Transform the normals + float* normals = model.meshes[meshIndex].normals; + for (unsigned int k = 0; k < attribute->count; k++) + { + Vector3 nt = Vector3Normalize(Vector3Transform((Vector3) { normals[3 * k], normals[3 * k + 1], normals[3 * k + 2] }, worldMatrixNormals)); + normals[3 * k] = nt.x; + normals[3 * k + 1] = nt.y; + normals[3 * k + 2] = nt.z; + } + } + else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8)) + { + // Init raylib mesh normals to copy glTF attribute data + model.meshes[meshIndex].normals = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + + // Load data into a temp buffer to be converted to raylib data type + char* temp = (char*)RL_MALLOC(attribute->count * 3 * sizeof(char)); + LOAD_ATTRIBUTE(attribute, 3, char, temp); + + // Convert data to raylib normal data type (float) + for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; + + RL_FREE(temp); + + // Transform the normals + float* normals = model.meshes[meshIndex].normals; + for (unsigned int k = 0; k < attribute->count; k++) + { + Vector3 nt = Vector3Normalize(Vector3Transform((Vector3) { normals[3 * k], normals[3 * k + 1], normals[3 * k + 2] }, worldMatrixNormals)); + normals[3 * k] = nt.x; + normals[3 * k + 1] = nt.y; + normals[3 * k + 2] = nt.z; + } + } else TRACELOG(LOG_WARNING, "MODEL: [%s] Normals attribute data format not supported, use vec3 float", fileName); } } From f9899a71822193b741b154e684c25f0fb6fd0920 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 6 Dec 2025 20:00:19 +0100 Subject: [PATCH 02/57] Reviewed code formating --- src/rmodels.c | 80 +++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index a7db7690e..bea740b92 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5582,50 +5582,50 @@ static Model LoadGLTF(const char *fileName) { // Init raylib mesh vertices to copy glTF attribute data model.meshes[meshIndex].vertexCount = (int)attribute->count; - model.meshes[meshIndex].vertices = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float)); // Load data into a temp buffer to be converted to raylib data type - unsigned short* temp = (unsigned short*)RL_MALLOC(attribute->count * 3 * sizeof(unsigned short)); + unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short)); LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp); // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float - for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t]; + for (unsigned int t = 0; t < attribute->count 3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t]; RL_FREE(temp); // Transform the vertices - float* vertices = model.meshes[meshIndex].vertices; + float *vertices = model.meshes[meshIndex].vertices; for (unsigned int k = 0; k < attribute->count; k++) { - Vector3 vt = Vector3Transform((Vector3) { vertices[3 * k], vertices[3 * k + 1], vertices[3 * k + 2] }, worldMatrix); - vertices[3 * k] = vt.x; - vertices[3 * k + 1] = vt.y; - vertices[3 * k + 2] = vt.z; + Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k + 1], vertices[3*k + 2] }, worldMatrix); + vertices[3*k] = vt.x; + vertices[3*k + 1] = vt.y; + vertices[3*k + 2] = vt.z; } } else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16)) { // Init raylib mesh vertices to copy glTF attribute data model.meshes[meshIndex].vertexCount = (int)attribute->count; - model.meshes[meshIndex].vertices = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float)); // Load data into a temp buffer to be converted to raylib data type - short* temp = (short*)RL_MALLOC(attribute->count * 3 * sizeof(short)); + short *temp = (short *)RL_MALLOC(attribute->count*3*sizeof(short)); LOAD_ATTRIBUTE(attribute, 3, short, temp); // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float - for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t]; + for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t]; RL_FREE(temp); // Transform the vertices - float* vertices = model.meshes[meshIndex].vertices; + float *vertices = model.meshes[meshIndex].vertices; for (unsigned int k = 0; k < attribute->count; k++) { - Vector3 vt = Vector3Transform((Vector3) { vertices[3 * k], vertices[3 * k + 1], vertices[3 * k + 2] }, worldMatrix); - vertices[3 * k] = vt.x; - vertices[3 * k + 1] = vt.y; - vertices[3 * k + 2] = vt.z; + Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k + 1], vertices[3*k + 2] }, worldMatrix); + vertices[3*k] = vt.x; + vertices[3*k + 1] = vt.y; + vertices[3*k + 2] = vt.z; } } else TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data format not supported, use vec3 float", fileName); @@ -5659,73 +5659,73 @@ static Model LoadGLTF(const char *fileName) else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16)) { // Init raylib mesh normals to copy glTF attribute data - model.meshes[meshIndex].normals = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float)); // Load data into a temp buffer to be converted to raylib data type - short* temp = (short*)RL_MALLOC(attribute->count * 3 * sizeof(short)); + short *temp = (short *)RL_MALLOC(attribute->count*3*sizeof(short)); LOAD_ATTRIBUTE(attribute, 3, short, temp); // Convert data to raylib normal data type (float) - for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; + for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; RL_FREE(temp); // Transform the normals - float* normals = model.meshes[meshIndex].normals; + float *normals = model.meshes[meshIndex].normals; for (unsigned int k = 0; k < attribute->count; k++) { - Vector3 nt = Vector3Normalize(Vector3Transform((Vector3) { normals[3 * k], normals[3 * k + 1], normals[3 * k + 2] }, worldMatrixNormals)); - normals[3 * k] = nt.x; - normals[3 * k + 1] = nt.y; - normals[3 * k + 2] = nt.z; + Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals)); + normals[3*k] = nt.x; + normals[3*k + 1] = nt.y; + normals[3*k + 2] = nt.z; } } else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8u)) { // Init raylib mesh normals to copy glTF attribute data - model.meshes[meshIndex].normals = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float)); // Load data into a temp buffer to be converted to raylib data type - unsigned char* temp = (unsigned char*)RL_MALLOC(attribute->count * 3 * sizeof(unsigned char)); + unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char)); LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp); // Convert data to raylib normal data type (float) - for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; + for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; RL_FREE(temp); // Transform the normals - float* normals = model.meshes[meshIndex].normals; + float *normals = model.meshes[meshIndex].normals; for (unsigned int k = 0; k < attribute->count; k++) { - Vector3 nt = Vector3Normalize(Vector3Transform((Vector3) { normals[3 * k], normals[3 * k + 1], normals[3 * k + 2] }, worldMatrixNormals)); - normals[3 * k] = nt.x; - normals[3 * k + 1] = nt.y; - normals[3 * k + 2] = nt.z; + Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals)); + normals[3*k] = nt.x; + normals[3*k + 1] = nt.y; + normals[3*k + 2] = nt.z; } } else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8)) { // Init raylib mesh normals to copy glTF attribute data - model.meshes[meshIndex].normals = (float*)RL_MALLOC(attribute->count * 3 * sizeof(float)); + model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float)); // Load data into a temp buffer to be converted to raylib data type - char* temp = (char*)RL_MALLOC(attribute->count * 3 * sizeof(char)); + char *temp = (char *)RL_MALLOC(attribute->count*3*sizeof(char)); LOAD_ATTRIBUTE(attribute, 3, char, temp); // Convert data to raylib normal data type (float) - for (unsigned int t = 0; t < attribute->count * 3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; + for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t]; RL_FREE(temp); // Transform the normals - float* normals = model.meshes[meshIndex].normals; + float *normals = model.meshes[meshIndex].normals; for (unsigned int k = 0; k < attribute->count; k++) { - Vector3 nt = Vector3Normalize(Vector3Transform((Vector3) { normals[3 * k], normals[3 * k + 1], normals[3 * k + 2] }, worldMatrixNormals)); - normals[3 * k] = nt.x; - normals[3 * k + 1] = nt.y; - normals[3 * k + 2] = nt.z; + Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals)); + normals[3*k] = nt.x; + normals[3*k + 1] = nt.y; + normals[3*k + 2] = nt.z; } } else TRACELOG(LOG_WARNING, "MODEL: [%s] Normals attribute data format not supported, use vec3 float", fileName); From fd8830948ecf8610c77f1d4a8abf5b6a868baf29 Mon Sep 17 00:00:00 2001 From: BoneManSeth <72104908+Sethbones@users.noreply.github.com> Date: Sat, 6 Dec 2025 21:01:47 +0200 Subject: [PATCH 03/57] fix newer NDK version compiling errors (#5389) target already gets assigned by the clang macro it points to, overwriting it causes it to target linux instead of android, making it check for usr directories instead of the NDK's directories --- examples/Makefile.Android | 2 +- projects/4coder/Makefile.Android | 2 +- projects/VSCode/Makefile.Android | 2 +- src/Makefile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/Makefile.Android b/examples/Makefile.Android index c00da171e..cf4ad1257 100644 --- a/examples/Makefile.Android +++ b/examples/Makefile.Android @@ -130,7 +130,7 @@ ifeq ($(ANDROID_ARCH),ARM) CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 endif ifeq ($(ANDROID_ARCH),ARM64) - CFLAGS = -std=c99 -target aarch64 -mfix-cortex-a53-835769 + CFLAGS = -std=c99 -mfix-cortex-a53-835769 endif # Compilation functions attributes options CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC diff --git a/projects/4coder/Makefile.Android b/projects/4coder/Makefile.Android index 29d437b1b..9e6773651 100644 --- a/projects/4coder/Makefile.Android +++ b/projects/4coder/Makefile.Android @@ -96,7 +96,7 @@ ifeq ($(ANDROID_ARCH),ARM) CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 endif ifeq ($(ANDROID_ARCH),ARM64) - CFLAGS = -std=c99 -target aarch64 -mfix-cortex-a53-835769 + CFLAGS = -std=c99 -mfix-cortex-a53-835769 endif # Compilation functions attributes options CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC diff --git a/projects/VSCode/Makefile.Android b/projects/VSCode/Makefile.Android index 7e41ea52f..279790d2a 100644 --- a/projects/VSCode/Makefile.Android +++ b/projects/VSCode/Makefile.Android @@ -96,7 +96,7 @@ ifeq ($(ANDROID_ARCH),ARM) CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 endif ifeq ($(ANDROID_ARCH),ARM64) - CFLAGS = -std=c99 -target aarch64 -mfix-cortex-a53-835769 + CFLAGS = -std=c99 -mfix-cortex-a53-835769 endif # Compilation functions attributes options CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC diff --git a/src/Makefile b/src/Makefile index 41867da1c..bc84abece 100644 --- a/src/Makefile +++ b/src/Makefile @@ -406,7 +406,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID) CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 endif ifeq ($(ANDROID_ARCH),arm64) - CFLAGS += -target aarch64 -mfix-cortex-a53-835769 + CFLAGS += -mfix-cortex-a53-835769 endif ifeq ($(ANDROID_ARCH),x86) CFLAGS += -march=i686 From 8115b7e92202b2c43dc9852b3ac678e45bf3649b Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 6 Dec 2025 20:40:23 +0100 Subject: [PATCH 04/57] Update rmodels.c --- src/rmodels.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rmodels.c b/src/rmodels.c index bea740b92..51e38008e 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5589,7 +5589,7 @@ static Model LoadGLTF(const char *fileName) LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp); // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float - for (unsigned int t = 0; t < attribute->count 3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t]; + for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t]; RL_FREE(temp); From 215ad78d5bf11933a8b6db331ef741807515e99d Mon Sep 17 00:00:00 2001 From: Sebastian Pineda <94144036+spineda2019@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:10:22 -0500 Subject: [PATCH 05/57] Fix build.zig typos (#5390) * fix small typo * other small typos --- build.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.zig b/build.zig index 031a6824d..4e06ca757 100644 --- a/build.zig +++ b/build.zig @@ -155,7 +155,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. ); } - // Sets a flag indiciating the use of a custom `config.h` + // Sets a flag indicating the use of a custom `config.h` try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); if (options.config.len > 0) { // Splits a space-separated list of config flags into multiple flags @@ -187,7 +187,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. try raylib_flags_arr.append(b.allocator, flag); } } else { - // Set default config if no custome config got set + // Set default config if no custom config got set try raylib_flags_arr.appendSlice(b.allocator, &config_h_flags); } @@ -438,7 +438,7 @@ pub const Options = struct { pub fn getOptions(b: *std.Build) Options { return .{ - .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform, + .platform = b.option(PlatformBackend, "platform", "Choose the platform backend for desktop target") orelse defaults.platform, .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio, .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels, .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, From 366300aafee6270ed94e99b3a67d9085353012fa Mon Sep 17 00:00:00 2001 From: JordSant <77529699+JordSant@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:13:05 +0100 Subject: [PATCH 06/57] [examples] Add `shaders_game_of_life` (#5394) * [examples] Add `shaders_game_of_life` * Declaration hides another variable same name --- .../shaders/resources/game_of_life/acorn.png | Bin 0 -> 218 bytes .../resources/game_of_life/breeder.png | Bin 0 -> 1919 bytes .../shaders/resources/game_of_life/glider.png | Bin 0 -> 216 bytes .../resources/game_of_life/glider_gun.png | Bin 0 -> 291 bytes .../resources/game_of_life/oscillators.png | Bin 0 -> 463 bytes .../resources/game_of_life/puffer_train.png | Bin 0 -> 1378 bytes .../resources/game_of_life/r_pentomino.png | Bin 0 -> 213 bytes .../resources/game_of_life/spaceships.png | Bin 0 -> 828 bytes .../resources/game_of_life/still_lifes.png | Bin 0 -> 615 bytes .../resources/shaders/glsl100/game_of_life.fs | 44 ++ .../resources/shaders/glsl120/game_of_life.fs | 42 ++ .../resources/shaders/glsl330/game_of_life.fs | 45 ++ examples/shaders/shaders_game_of_life.c | 350 +++++++++++ examples/shaders/shaders_game_of_life.png | Bin 0 -> 13793 bytes .../examples/shaders_game_of_life.vcxproj | 569 ++++++++++++++++++ 15 files changed, 1050 insertions(+) create mode 100644 examples/shaders/resources/game_of_life/acorn.png create mode 100644 examples/shaders/resources/game_of_life/breeder.png create mode 100644 examples/shaders/resources/game_of_life/glider.png create mode 100644 examples/shaders/resources/game_of_life/glider_gun.png create mode 100644 examples/shaders/resources/game_of_life/oscillators.png create mode 100644 examples/shaders/resources/game_of_life/puffer_train.png create mode 100644 examples/shaders/resources/game_of_life/r_pentomino.png create mode 100644 examples/shaders/resources/game_of_life/spaceships.png create mode 100644 examples/shaders/resources/game_of_life/still_lifes.png create mode 100644 examples/shaders/resources/shaders/glsl100/game_of_life.fs create mode 100644 examples/shaders/resources/shaders/glsl120/game_of_life.fs create mode 100644 examples/shaders/resources/shaders/glsl330/game_of_life.fs create mode 100644 examples/shaders/shaders_game_of_life.c create mode 100644 examples/shaders/shaders_game_of_life.png create mode 100644 projects/VS2022/examples/shaders_game_of_life.vcxproj diff --git a/examples/shaders/resources/game_of_life/acorn.png b/examples/shaders/resources/game_of_life/acorn.png new file mode 100644 index 0000000000000000000000000000000000000000..58ea0b4d1c588535bc857e5ef7cb3b474260c014 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^AT}!p8<4C?sm%aVjKx9jPK-BC>eK@{Ea{HEjtmSN z`?>!lvI6-E$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8X6a z5n0T@pr;JNj1^1m%YcIHC7!;n>@Rs(c=SYXob8hb3K@91IEHXsPyX}k>+5z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vG?BLDy{BLR4&KXw2B00(qQO+^Rk3B4{fu`^gtNa30(F0Z`0uWkbu*WX7 zYKRJmkOt)QJpUPrEnp%7qFA4_(}`&(zWq$8hP;dUpp#@YF=A|?mRn7TJa*Nxb&Ct`$Kf?}c;Bj~r(d`E{W@ralBC-g1{x9$p(Zw{E&p@#f zdjX|gz-2yzaTgOZG1$05x|oX0ush(;WD|-B%s7K#Mwm@fFO1y#zomDv3O3Vf0urRc z2C}$~)3z_GzlZfEFm$~#{Cd{Elqc|GAV^Y-WiQ25LM(=6HB^Py_(kyq1jx$MSaB^I ztqk0>84T&~6sO*VW!La)@rdGawR;N@d&#XV9#^}C4C&T}8TF_Bo^?RDWCknXY-1eI zjj#}4;5^{+8*Iyz+XAAu`)S#}AonItURookfl_7kHpx7BH8A8FaKsL{;v5vu-nB_~awSex)aQ0BxtPa_mqGD^6JZT2kv5K?-@NqS?82Tbg2<7xVkbN9xqTFdFQ7M^b|_ zwV46?-qd4OMje|C*hvRQ2VqX#rYe3Fc2-WJ@IXj8%%POA$ zdk&KlFcJrapuZo2L1KmM48&=`rDwGE_C+ATk{%^{8FZpbLXiN(Zuz5=LMX-J zWOD1r(SXdn393HrKBu;&MmAN;urs^NWYEc?uMbfb82?>M4e!b)E4Og9eOgD-dek-V zn-FH56(F!h&1c^ayK8A33@adDJeFMpSbf(r+Qio@6}rNy0&cx46kOR1TKbeDh%|Cr zN7YOl8=w$ucdrN8ony|g=``PK8a4d-n&@s*V;)o%TJOlcpDol`I~aQpw# ztiaLkD6<+{eNK8Iq&H#2lQ{7vsN~M6;ulQeQw>QlI0cTX0h#iBNid`&7*f(^aOZ(Y z+7bx{CoZN*HNl;U#FdpT+3qM)3VJp~%cDTq3|#(jFOA)MyFE65r1Oth!W0;^0wZ4A z-Khuz0S>2_%z@0U?6cc+AZJZ_eaXEEA&=nXfHCI45#-QN`#Iwb%qpf%UEj%z;P6^j z?I#$R7~$mXB(^m2%GOvJrl}?r;t5vEBHvyIRC_XaSEYqG0!y61oAI_w@2g{WtK)83 zUK2z$&AxM6U7?yMoM-P$)i12OIC}=hnDJ^{hg}Ms&yb|bWRO4 zC>S-Z{?nqLr~NI~fFN0k6;rgsqR~t>X6kW<9(_}w9P@immy2ao8y zJHveike2S}UNk4R#mq($2ZQ9qeCeuz-i^PzeQ>jDNqq$Yb+AmkzBEO9W_K;~dLnz* z6BSJ$KnhY>ocz=H2bN(dHptAY32P<&M_}a$KU-o)Gs!KME<2Sf0c=f8vV!5XCXxlV ziWCDWmR4A+N40OjjTQ_moP!xnMj*ykeGO|fXu5eEEI5i7T2?>BBM>;#v zggY=;0{}Kb$0Cs3sR@b=8!gYnx`%RmW(G_s*YbT9$qWGv&Ty`!8nWJ4ydHUwuUkVmEUW*2&$UIUn}B_j}4 z1|k(buO@qkkrE6-0HJjGc481;X9H6Pq!oh-TRSnqKq73hzESK3*I?kBpop=LtSX-p$AF~rMn;}Tf+3LPu4PIXHmK!}Hkp_* z0Z{;Pe;o)E*9d3O>0|mnB{&!&297e$kdn-hl3++-l7HVm^}8B2ZLa_T002ovPDHLk FV1l3@Y~}y} literal 0 HcmV?d00001 diff --git a/examples/shaders/resources/game_of_life/glider.png b/examples/shaders/resources/game_of_life/glider.png new file mode 100644 index 0000000000000000000000000000000000000000..921adb8ed5e4361628af0df83a7000b078b0ee15 GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^tRT$61|)m))t&+=#^NA%C&rs6b?Si}mUKs7M+SzC z{oH>NK`IrJJ%W507^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10g0sLQ zvY3HEPZ@+6E0)@q0R`DhJbhi+U-Gc9v$Cm$-Sq?t>3O<1hHzYu?Kb3NP!Kru;nA`G z^KV6}cWexHKFri-w@u~dJBAD;hr=#8=4Yz8#o1Mb+BF2lb^~=Xc)I$ztaD0e0swAE BH=h6i literal 0 HcmV?d00001 diff --git a/examples/shaders/resources/game_of_life/glider_gun.png b/examples/shaders/resources/game_of_life/glider_gun.png new file mode 100644 index 0000000000000000000000000000000000000000..29b65d3de8ae04baa7be9ae31a29d9704cc1eab5 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^YCz1*!3HFS`Tx5CDaPU;cPGZ1Cw1z99F}xPUq=Rp zjs4tz5?O(Kg=CK)Uj~LMpst1%28Lfip@tU>45bDP46hOx7_4S6Fo+k-*%fF5l;AAz zh%9Dc&{GCs#)_r(Wk5mp5>H=O_Ln>?JZ6HiyD!B9g(^K=978NlpAB*3YcSxDKArdX ze{l6RVK&}loEg_H8;NDy;#1tYmG$C(38n@3*@#~6Qc9G}iX027_oA<62Uil&V>mC``O-mQ!T eYlqfvV6I_vynNnt{d}M!7(8A5T-G@yGywpkz@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vG?BLDy{BLR4&KXw2B00(qQO+^Rk3-1z@fecnz{5u#ZNG@)v8+!P=#7|agfyREZ*vIj^+8xbua zMxBy9KmhLsLY9LSkZK3OX^8EXSt@6b5M5`aHj?a?*2o5g zti=(EFrN4&l<6{ zV7>c;JH^&15MC$ReUD9fN8_4Q?Nj3fZIGJTN;TiwZzYPzv^m0>A+4@s$*N3c002ovPDHLk FV1jQ-vg`l= literal 0 HcmV?d00001 diff --git a/examples/shaders/resources/game_of_life/puffer_train.png b/examples/shaders/resources/game_of_life/puffer_train.png new file mode 100644 index 0000000000000000000000000000000000000000..8d77219b024579726c05be0bb520d0193da6e920 GIT binary patch literal 1378 zcmV-o1)chdP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vG?BLDy{BLR4&KXw2B00(qQO+^Rk3GuBrQ+=K}xk{zd0!_1IYJ82AAPh}|F!?;s^XKOaulDn$ zSDN6zzrUvSJyUC=@XzzaYy1^Jqs8ZW)WW)%%JV#G6Bsw3S=(6x&rd+AP1M#uUT~-p z9$D8s1lHL6c#mdX_tx@FgDd+E*Er&2^IEBSrQ!JdBv34OiJYV6Pr|&PBTh^~m6i4+ z8ni^to}p>Y=3Gr>{BcBR#F-n@*&-R@r%EEBjkJyZ<74F1u*wu#i#l2vTC26$_kLsp zJyYWr;pwQNweL4_YM)lm)HWipOURE(BHZB6;;7Pft^r7*!SNmq>1tjAOKo@*P?Jog z7KB!&k!Issgn8jm>&$c;N0W(Et}<%yCd`hENztWyI;JIPy^g)Rr$w8G24zn7)18x< zYo2&aSO&BTG@2^Fe1B)yvP9F`;?J#|*BI!b@d4?&TLqw5HLg8{U|nW7)Y>Vl$kb6M z+X-wfW=hL>4bi|(i}R0K4ybMsxM^+L`b0FQ2SrXvVP|y=!f-%|lG;scnsXc$YDh?0 zx4@S6_yg6t$i_ABHDb9H_O!~Q*2hn1v-=#a3N)5hX5m*)VfL9FACWvkw`6&>sU2jF z8;~ByG?oLMkmW?Ob^_kauQL$<;Vn1n;9@E#I9!E&ZQ0_)_q$coGdDSfZbaid&C~i- zUL=q-97s&U6~|9-cp^@-v!3wXwLEbnX*+JcDvr+UT*?zCI9yTN*(`PmgM=2h2sk{U z3QE-6;Lw|syTRcI@hA%IzKaroyoy4n!e7LM*nagxf zNK?0R-4nNlgYw-IyH>sO-4i#=_2`}`c_c3Rp7N<%$eUNJGP8s+mQ3Bkx+j>aTWI%$ z$B}qQ_XIO_3+QwU;SL)rjSk%1B_Jt7rO~on%1~(p8OjWmMhEVu4wYtXHg%{pB1q~` zX;g?3L!}V`{tuP*&Vo*B(r7I@aJNLxiKcJJ2GR%aqUDOTfxEM|QzyQ!gu10~sK(P0 zi4_}69V(4FTl!FGWZ*86OnmJh8Kn-~MV^pb0Mgnx`hs7}HjfbwHEXFkXXNQbYC)*X kKX*h4ohrEX`dY#N0tbz~VkKQve*gdg07*qoM6N<$f;TL9mH+?% literal 0 HcmV?d00001 diff --git a/examples/shaders/resources/game_of_life/r_pentomino.png b/examples/shaders/resources/game_of_life/r_pentomino.png new file mode 100644 index 0000000000000000000000000000000000000000..1707f3c12d561bf0aad93a9de91a60aa452f6829 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^tRT$61|)m))t&+=#^NA%C&rs6b?Si}mUKs7M+SzC z{oH>NK`IrJJ%W507^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10g0sLQ zvY3HEPZ@+6E0)@q0R`DhJbhi+U-Gc{uKbLh*2~7Y$eLAE7 literal 0 HcmV?d00001 diff --git a/examples/shaders/resources/game_of_life/spaceships.png b/examples/shaders/resources/game_of_life/spaceships.png new file mode 100644 index 0000000000000000000000000000000000000000..867f6fea32e5dbc5a62f3b52c78a2b762dae507c GIT binary patch literal 828 zcmV-C1H=4@P)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vG?BLDy{BLR4&KXw2B00(qQO+^Rk3#Z zM+~5~_5vx)s^hCNt5N_RWQ!6L;8!wHV_xZxO8a#{}#kLwP6<{^RhPE&&tV?1^ksV6{B*3ClwMKwTfY}4B z*x>fY8N49*P@1Xr&)n5IB!RS7*Az#Ji*GwNuGSWi2wj}6J=Et&j$ znnqnslIGjFGg8V~MHhW|?-~PHl&0p&q1k$9j`T-@YG&sINPwRJKn0Z5j5)l8@QtX7 zewq690CJhfwS_H5=X7S$B%vl4TMq9j9nh(5*1r2z7&QV}**_$~Rwagif>Bu(hPFWa zg8S0KiqJf9t2b(*yDL@AE588uc^zQ;kKAJb0000z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vG?BLDy{BLR4&KXw2B00(qQO+^Rk3kvdguYs+#Ud#*;>d(|Lm}J_;%nX4;!J>rPb4M7YQLIBfn^`1~y(GdYhBAtZwt;lu z2&^=35sL=!Uae*`H|$+oRx3uU`PNw1y~{_su^;qMRpWz@&V(Gh75AeJCjq%WLxpCk~y8kGd=*+rb4e&i@pE=002ovPDHLkV1ksY B1pEL1 literal 0 HcmV?d00001 diff --git a/examples/shaders/resources/shaders/glsl100/game_of_life.fs b/examples/shaders/resources/shaders/glsl100/game_of_life.fs new file mode 100644 index 000000000..70c12ac2c --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/game_of_life.fs @@ -0,0 +1,44 @@ +#version 100 + +precision highp float; + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Input size in pixels of the textures +uniform vec2 resolution; + +void main() +{ + // Size of one pixel in texture coordinates (from 0.0 to 1.0) + float x = 1.0/resolution.x; + float y = 1.0/resolution.y; + + // Status of the current cell (1 = alive, 0 = dead) + int origValue = (texture2D(texture0, fragTexCoord).r < 0.1)? 1 : 0; + + // Sum of alive neighbors + int sumValue = (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top + sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right + + sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right + + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right + + // Game of life rules: + // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise + // Current cell goes from dead to alive when exactly 3 neighbors are alive + if ((origValue == 1 && sumValue == 2) || sumValue == 3) + gl_FragColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black + else + gl_FragColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE +} diff --git a/examples/shaders/resources/shaders/glsl120/game_of_life.fs b/examples/shaders/resources/shaders/glsl120/game_of_life.fs new file mode 100644 index 000000000..611f961bc --- /dev/null +++ b/examples/shaders/resources/shaders/glsl120/game_of_life.fs @@ -0,0 +1,42 @@ +#version 120 + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Input size in pixels of the textures +uniform vec2 resolution; + +void main() +{ + // Size of one pixel in texture coordinates (from 0.0 to 1.0) + float x = 1.0/resolution.x; + float y = 1.0/resolution.y; + + // Status of the current cell (1 = alive, 0 = dead) + int origValue = (texture2D(texture0, fragTexCoord).r < 0.1)? 1 : 0; + + // Sum of alive neighbors + int sumValue = (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top + sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right + + sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right + + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom + sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right + + // Game of life rules: + // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise + // Current cell goes from dead to alive when exactly 3 neighbors are alive + if (((origValue == 1) && (sumValue == 2)) || sumValue == 3) + gl_FragColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black + else + gl_FragColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE +} diff --git a/examples/shaders/resources/shaders/glsl330/game_of_life.fs b/examples/shaders/resources/shaders/glsl330/game_of_life.fs new file mode 100644 index 000000000..cc80861d6 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/game_of_life.fs @@ -0,0 +1,45 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +// Input size in pixels of the textures +uniform vec2 resolution; + +void main() +{ + // Size of one pixel in texture coordinates (from 0.0 to 1.0) + float x = 1.0/resolution.x; + float y = 1.0/resolution.y; + + // Status of the current cell (1 = alive, 0 = dead) + int origValue = (texture(texture0, fragTexCoord).r < 0.1)? 1 : 0; + + // Sum of alive neighbors + int sumValue = (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left + sumValue += (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top + sumValue += (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right + + sumValue += (texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left + sumValue += (texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right + + sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left + sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom + sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right + + // Game of life rules: + // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise + // Current cell goes from dead to alive when exactly 3 neighbors are alive + if (((origValue == 1) && (sumValue == 2)) || sumValue == 3) + finalColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black + else + finalColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE +} diff --git a/examples/shaders/shaders_game_of_life.c b/examples/shaders/shaders_game_of_life.c new file mode 100644 index 000000000..daeb4d789 --- /dev/null +++ b/examples/shaders/shaders_game_of_life.c @@ -0,0 +1,350 @@ +/******************************************************************************************* +* +* raylib [shaders] example - Conway's Game of Life with shaders +* +* Example complexity rating: [★★★☆] 3/4 +* +* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support, +* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version +* +* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* +* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5) +* +* Example 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) 2025 Jordi Santonja (@JordSant) +* +********************************************************************************************/ + +#include "raylib.h" + +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Required for GUI controls + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Interaction mode +typedef enum { + MODE_RUN = 0, + MODE_PAUSE, + MODE_DRAW, +} InteractionMode; + +// Struct to store example preset patterns +typedef struct { + char *name; + char *fileName; + Vector2 position; +} PresetPattern; + +//---------------------------------------------------------------------------------- +// Functions declaration +//---------------------------------------------------------------------------------- +void FreeImageToDraw(Image **imageToDraw); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + const int menuWidth = 100; + const int windowWidth = screenWidth - menuWidth; + const int windowHeight = screenHeight; + + const int worldWidth = 2048; + const int worldHeight = 2048; + + const int randomTiles = 8; // Random preset: divide the world to compute random points in each tile + + const Rectangle worldRectSource = { 0, 0, (float)worldWidth, (float)-worldHeight }; + const Rectangle worldRectDest = { 0, 0, (float)worldWidth, (float)worldHeight }; + const Rectangle textureOnScreen = { 0, 0, (float)windowWidth, (float)windowHeight }; + + const PresetPattern presetPatterns[] = { + { "Glider", "glider", { 0.5f, 0.5f } }, { "R-pentomino", "r_pentomino", { 0.5f, 0.5f } }, { "Acorn", "acorn", { 0.5f,0.5f } }, + { "Spaceships", "spaceships", { 0.1f, 0.5f } }, { "Still lifes", "still_lifes", { 0.5f, 0.5f } }, { "Oscillators", "oscillators", { 0.5f, 0.5f } }, + { "Puffer train", "puffer_train", { 0.1f, 0.5f } }, { "Glider Gun", "glider_gun", { 0.2f, 0.2f } }, { "Breeder", "breeder", { 0.1f, 0.5f } }, + { "Random", "", { 0.5f, 0.5f } } + }; + const int numberOfPresets = sizeof(presetPatterns) / sizeof(presetPatterns[0]); + + // Variable declaration + //-------------------------------------------------------------------------------------- + int zoom = 1; + float offsetX = (worldWidth - windowWidth)/2.0f; // Centered on window + float offsetY = (worldHeight - windowHeight)/2.0f; // Centered on window + int framesPerStep = 1; + int frame = 0; + + int preset = -1; // No button pressed for preset + int mode = MODE_RUN; // Starting mode: running + bool buttonZoomIn = false; // Button states: false not pressed + bool buttonZomOut = false; + bool buttonFaster = false; + bool buttonSlower = false; + + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - conway's game of life"); + + // Load shader + Shader shdrGameOfLife = LoadShader(0, TextFormat("resources/shaders/glsl%i/game_of_life.fs", GLSL_VERSION)); + + // Set shader uniform size of the world + int resolutionLoc = GetShaderLocation(shdrGameOfLife, "resolution"); + const float resolution[2] = { (float)worldWidth, (float)worldHeight }; + SetShaderValue(shdrGameOfLife, resolutionLoc, resolution, SHADER_UNIFORM_VEC2); + + // Define two textures: the current world and the previous world + RenderTexture2D world1 = LoadRenderTexture(worldWidth, worldHeight); + RenderTexture2D world2 = LoadRenderTexture(worldWidth, worldHeight); + BeginTextureMode(world2); + ClearBackground(RAYWHITE); + EndTextureMode(); + + Image startPattern = LoadImage("resources/game_of_life/r_pentomino.png"); + UpdateTextureRec(world2.texture, (Rectangle) { worldWidth / 2.0f, worldHeight / 2.0f, (float)(startPattern.width), (float)(startPattern.height) }, startPattern.data); + UnloadImage(startPattern); + + // Pointers to the two textures, to be swapped + RenderTexture2D *currentWorld = &world2; + RenderTexture2D *previousWorld = &world1; + + // Image to be used in DRAW mode, to be changed with mouse input + Image *imageToDraw = NULL; + + SetTargetFPS(60); // Set at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + frame++; + + // Change zoom: both by buttons or by mouse wheel + float mouseWheelMove = GetMouseWheelMove(); + if (buttonZoomIn || (buttonZomOut && (zoom > 1)) || (mouseWheelMove != 0.0f)) + { + FreeImageToDraw(&imageToDraw); // Zoom change: free the image to draw to be recreated again + + const float centerX = offsetX + (windowWidth/2.0f)/zoom; + const float centerY = offsetY + (windowHeight/2.0f)/zoom; + if (buttonZoomIn || (mouseWheelMove > 0.0f)) + zoom *= 2; + if ((buttonZomOut || (mouseWheelMove < 0.0f)) && (zoom > 1)) + zoom /= 2; + offsetX = centerX - (windowWidth/2.0f)/zoom; + offsetY = centerY - (windowHeight/2.0f)/zoom; + } + + // Change speed: number of frames per step + if (buttonFaster && framesPerStep > 1) framesPerStep--; + if (buttonSlower) framesPerStep++; + + // Mouse management + //---------------------------------------------------------------------------------- + if ((mode == MODE_RUN) || (mode == MODE_PAUSE)) + { + FreeImageToDraw(&imageToDraw); // Free the image to draw: no longer needed in these modes + + // Pan with mouse left button + static Vector2 previousMousePosition = { 0.0f, 0.0f }; + const Vector2 mousePosition = GetMousePosition(); + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && (mousePosition.x < windowWidth)) + { + offsetX -= (mousePosition.x - previousMousePosition.x)/zoom; + offsetY -= (mousePosition.y - previousMousePosition.y)/zoom; + } + previousMousePosition = mousePosition; + } + else // MODE_DRAW + { + const float offsetDecimalX = offsetX - floorf(offsetX); + const float offsetDecimalY = offsetY - floorf(offsetY); + int sizeInWorldX = (int)(ceilf((float)(windowWidth + offsetDecimalX*zoom)/zoom)); + int sizeInWorldY = (int)(ceilf((float)(windowHeight + offsetDecimalY*zoom)/zoom)); + if (offsetX + sizeInWorldX >= worldWidth) + sizeInWorldX = worldWidth - (int)floorf(offsetX); + if (offsetY + sizeInWorldY >= worldHeight) + sizeInWorldY = worldHeight - (int)floorf(offsetY); + + // Create image to draw if not created yet + if (imageToDraw == NULL) + { + RenderTexture2D worldOnScreen = LoadRenderTexture(sizeInWorldX, sizeInWorldY); + BeginTextureMode(worldOnScreen); + DrawTexturePro(currentWorld->texture, (Rectangle) { floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), -(float)(sizeInWorldY) }, + (Rectangle) { 0, 0, (float)(sizeInWorldX), (float)(sizeInWorldY) }, (Vector2) { 0, 0 }, 0.0f, WHITE); + EndTextureMode(); + imageToDraw = (Image*)RL_MALLOC(sizeof(Image)); + *imageToDraw = LoadImageFromTexture(worldOnScreen.texture); + UnloadRenderTexture(worldOnScreen); + } + + const Vector2 mousePosition = GetMousePosition(); + static int firstColor = -1; + if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && (mousePosition.x < windowWidth)) + { + int mouseX = (int)(mousePosition.x + offsetDecimalX*zoom)/zoom; + int mouseY = (int)(mousePosition.y + offsetDecimalY*zoom)/zoom; + if (mouseX >= sizeInWorldX) + mouseX = sizeInWorldX - 1; + if (mouseY >= sizeInWorldY) + mouseY = sizeInWorldY - 1; + if (firstColor == -1) + firstColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1; + const int prevColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1; + ImageDrawPixel(imageToDraw, mouseX, mouseY, (firstColor) ? BLACK : RAYWHITE); + if (prevColor != firstColor) + UpdateTextureRec(currentWorld->texture, (Rectangle){ floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), (float)(sizeInWorldY) }, imageToDraw->data); + } + else + firstColor = -1; + } + + // Load selected preset + //---------------------------------------------------------------------------------- + if (preset >= 0) + { + Image pattern; + if (preset < numberOfPresets - 1) // Preset with pattern image lo load + { + pattern = LoadImage(TextFormat("resources/game_of_life/%s.png", presetPatterns[preset].fileName)); + BeginTextureMode(*currentWorld); + ClearBackground(RAYWHITE); + EndTextureMode(); + UpdateTextureRec(currentWorld->texture, (Rectangle){ worldWidth*presetPatterns[preset].position.x - pattern.width/2.0f, + worldHeight*presetPatterns[preset].position.y - pattern.height/2.0f, + (float)(pattern.width), (float)(pattern.height) }, pattern.data); + } + else // Last preset: Random values + { + pattern = GenImageColor(worldWidth/randomTiles, worldHeight/randomTiles, RAYWHITE); + for (int i = 0; i < randomTiles; i++) + { + for (int j = 0; j < randomTiles; j++) + { + ImageClearBackground(&pattern, RAYWHITE); + for (int x = 0; x < pattern.width; x++) + for (int y = 0; y < pattern.height; y++) + if (GetRandomValue(0, 100) < 15) + ImageDrawPixel(&pattern, x, y, BLACK); + UpdateTextureRec(currentWorld->texture, + (Rectangle){ (float)(pattern.width*i), (float)(pattern.height*j), + (float)(pattern.width), (float)(pattern.height) }, pattern.data); + } + } + } + + UnloadImage(pattern); + mode = MODE_PAUSE; + offsetX = worldWidth * presetPatterns[preset].position.x - windowWidth/zoom/2.0f; + offsetY = worldHeight * presetPatterns[preset].position.y - windowHeight/zoom/2.0f; + } + + // Check window draw inside world limits + if (offsetX < 0) offsetX = 0; + if (offsetY < 0) offsetY = 0; + if (offsetX > worldWidth - (float)(windowWidth)/zoom) + offsetX = worldWidth - (float)(windowWidth)/zoom; + if (offsetY > worldHeight - (float)(windowHeight)/zoom) + offsetY = worldHeight - (float)(windowHeight)/zoom; + + // Rectangles for drawing texture portion to screen + //---------------------------------------------------------------------------------- + const Rectangle textureSourceToScreen = { offsetX, offsetY, (float)windowWidth/zoom, (float)windowHeight/zoom }; + + // Draw to texture + //---------------------------------------------------------------------------------- + if ((mode == MODE_RUN) && ((frame % framesPerStep) == 0)) + { + // Swap worlds + RenderTexture2D *tempWorld = currentWorld; + currentWorld = previousWorld; + previousWorld = tempWorld; + + // Draw to texture + BeginTextureMode(*currentWorld); + BeginShaderMode(shdrGameOfLife); + DrawTexturePro(previousWorld->texture, worldRectSource, worldRectDest, (Vector2){ 0, 0 }, 0.0f, RAYWHITE); + EndShaderMode(); + EndTextureMode(); + } + + // Draw to screen + //---------------------------------------------------------------------------------- + BeginDrawing(); + DrawTexturePro(currentWorld->texture, textureSourceToScreen, textureOnScreen, (Vector2){ 0, 0 }, 0.0f, WHITE); + + DrawLine(windowWidth, 0, windowWidth, screenHeight, (Color){ 218, 218, 218, 255 }); + DrawRectangle(windowWidth, 0, screenWidth - windowWidth, screenHeight, (Color){ 232, 232, 232, 255 }); + + DrawText("Conway's", 704, 4, 20, DARKBLUE); + DrawText(" game of", 704, 19, 20, DARKBLUE); + DrawText(" life", 708, 34, 20, DARKBLUE); + DrawText("in raylib", 757, 42, 6, BLACK); + + DrawText("Presets", 710, 58, 8, GRAY); + preset = -1; + for (int i = 0; i < numberOfPresets; i++) + if (GuiButton((Rectangle){ 710.0f, 70.0f + 18*i, 80.0f, 16.0f }, presetPatterns[i].name)) + preset = i; + + GuiToggleGroup((Rectangle){ 710, 258, 80, 16 }, "Run\nPause\nDraw", &mode); + + DrawText(TextFormat("Zoom: %ix", zoom), 710, 316, 8, GRAY); + buttonZoomIn = GuiButton((Rectangle){ 710, 328, 80, 16 }, "Zoom in"); + buttonZomOut = GuiButton((Rectangle){ 710, 346, 80, 16 }, "Zoom out"); + + DrawText(TextFormat("Speed: %i frame%s", framesPerStep, (framesPerStep > 1)? "s" : ""), 710, 370, 8, GRAY); + buttonFaster = GuiButton((Rectangle){ 710, 382, 80, 16 }, "Faster"); + buttonSlower = GuiButton((Rectangle){ 710, 400, 80, 16 }, "Slower"); + + //------------------------------------------------------------------------------ + + DrawFPS(712, 426); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadShader(shdrGameOfLife); + UnloadRenderTexture(world1); + UnloadRenderTexture(world2); + + FreeImageToDraw(&imageToDraw); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//---------------------------------------------------------------------------------- +// Functions definition +//---------------------------------------------------------------------------------- +void FreeImageToDraw(Image **imageToDraw) +{ + if (*imageToDraw != NULL) + { + UnloadImage(**imageToDraw); + RL_FREE(*imageToDraw); + *imageToDraw = NULL; + } +} diff --git a/examples/shaders/shaders_game_of_life.png b/examples/shaders/shaders_game_of_life.png new file mode 100644 index 0000000000000000000000000000000000000000..8ebc2c12e6920fdab2ba0a85139fb4531b4180c6 GIT binary patch literal 13793 zcmd6Oby!q!x9%RgL_t76O1dRPx;sR=Q*h`O5D*xp1f@%m5~RDO2c%m%q@;7CrSBg6 zzVCeJ-sidJocq@upACEO*|FBU)_Pa`FjP%d{tgZ~4gdgm6cuDN005N+03dBxDBzh- z5TSGcAi;R4rwCP4WCgIma{z!3ZrH#zfCfOoJ>&*J{_Z0WAph8p0#BnrPytl%Hw@fR z!F}Yl7|8A4_KE+okGu|o^7lEx;6BPf_F=@}0rKZ0Ui-f-X}cBhd{8gvGH*6NblSs<#|N$i06O&xq$-&SU?m6RF)P%A%LI~ zKyKOrYEVve$nEE^Do909(a85U{G+#`_QnM*tqzF#7{}dnOR@6b8_?Y z3o0tBs%vV$)z!CsZ|~^r>h9?s866v+n4FrPS^BlSvbwguvAMN>aCmfla{A}&9H|#l z&wqaYYWBbBMF8rBf`*2QhKbY*g5rr(oB$2|5jO^*q&lX#%Y9m&w^&3{(O=42vFUg< zeiOfN{eeS5|73|_AF0}{X8%3K-u*vm_AkZ$L$4VC4;2C$50wBA2Tlc+^)mH_&9%@` zr!=9_nc8gkdlGP@mSN9LGrr`6Llu(X(XFh_-!e&OxLQ|jc-r5=okayQAZFoKUTweR zA$sR;N6*IMCf&oyelBTQCV#vu_$68Jll;eBz`T`04K*V^TWa8byEH-der&|0R-7h@ z-n?$OA?GJ{QQpxrHPnsFFo5~Lv9UbdOV8$@^Bq0P!1wgaDDMkRwc-&_r+>7peJG|G zG^02j`RjN<7Ja^=a;CcfDFQ9}K5G}5PAJ?64w~OuO z#@#oXhheOD%I6sw-og}lP|pKeNsB&EfT>7bpn|46>D{#iS|)&Baa298-M^IL8&&j>&&y8ZasU+ z^4oZ3fLr17=|}#1YWXx~R?$Q1XOj%*qix^9urTCQ$)#tnddGgO#u#gpYe{~hpHc6* zrXQ3vM{$a87!?ccM6;$hr7 zGP24&+f}?5ANAoanM2n@ZwnE3gvKyLjl}TV4d5nd9D^5kj2UIKyY97F#S|aVA~?4j z_8NEvcxIqyCSRQJC)WB2%#A*gZ|O7TefXQ-VKePd2Bx|!5%7Q8H2CMll?>!AayKO? zYVuny)GkXadsKMf)J$%cRyHTg^LYxRg=+#U?p<^{aEcpXfm*4$2wSz_7jul%#0LI4 ztL~bgw||O`#=}OKNLD9s*fn}l1#u_W5f^dI>$-Uub59kuas$vExaLDCmaM7tX;Th=BVRHTV>QEoa zYpTB=fd(%vv(c7Fi0aZs+4Md95E9kfK?=~(m@6Q*2NWgHWz+dqgMOL8Am5hnq^uLQ z^?Bht?2&Q(;mjI75G*7Drv5)8u!09O*{Rv7?X~wwe~`*3EF$cI2V*gEtfJUULYB1i zUVG-ul#WoEBu~rO8(;#SaYu+vXgct`>QL67t{_9FhQ`5Ej`FPa{F*pR0-Z=*0v$t6@&pMi|;9KH7Mb&l*4jpm)8qaE%ueK&9&<65&zLsS5 zJZoUY4XCSd)^lG@xBXJHEjWM16wgls6Gt?z!B_*tJb}8-ovTkCH^AHDMZfsstR(;H z*nxO@#<}h`2ev~d%I9aq`axX-<>|BTL!(zM#l|BdOL=*o_Fi|tk=3Gja$-GL23XMObr!=nvqlI5MKFkztbD~`AIPSPdYC_RP2uj-Xlfa zUrSl@@E0+}zHMG^0Fhqdcwb~bJ*+vxY-Ty@AjX(N+$V&?>60K=l8YbJP{#&NLh$bQ zz^CMmPKP!%AaCD}goS@)W0ha6TS)(8fg5Q6F!JnB$+gV}d%o)Q%I6;R8FOx>tS1UZ z$$!y)S92n5pc>b#2E$n>88Bca{y$Vg+6CP1ICnn9nbivj?sWFGV;m8la*!>)TAown zV%l|K?aVmQrdWQPc6A+JuHJ>F*7hiZPXP{B6Ci>}t!t0|qLST4cUj$wkez$Cqb+3V zDw#_+-^f7omgBOr+7pl@r36Iq)(;8^xcfuXoqB8L1a|O>&at&vs?OJ*y8oD_m z)=979ASUyJJ`Qqn;l(2zV=w4G*kK-bZ{Gl0g;4AEOxguO0n`PuYi()GSltL8|DBDD z7)F7_etO~+x1&zPn_oo=rJ@bbh@{w}u;ilUmI5v#k2A2p)V*8wk7ZRXuc?_Byqm48 zRn=f_XSI69C9^u6B9(#CzD|$7o_|_c1^hcbr4>{@ExDG7&c6_H#1GuB+y6*_(A%YW zk7f5s?a}(FDu%27%=yG%AzG~M*N|ksdyM4VrxEMR0-^$!+kCr@6LMIm_;rg2)LQ?< z2^cBfs4B{wAwtAV>O0-_`AP9J7ASfB*@0Zw4x);d;8HPVCEa!)Z02`2>gPBU*ER`X zABS_Dw0N|rt&GHESuQaH$y3#pWdTaB%RJPgJY0^S{&guOJs3*f0o_mNW0lOKwb4}S zoEKiZbP8*AVSNoc7NFdKl=sFY;-*K})M!Qcml}{;k7$LaV7}R<`nIk8E6t1li#DM> zew_v|_*&$cv=ECllMLky<`w}v?EqwoIKt%VD-=e$r3mYe1s0vTgvWMz-|I&Z;l*mN zr|GQ~5M4qk3v0^t~ ziv)LEa>F{jjb}Cy8m&gy@tiKlZIqAkHnZ^=Llbu&={tYy&~j)cMWh@(fw2Eurelea ztxNEtcMZIoNH%)}Sfz|+5>^m6({X%Tc2cp5Xxe1*dSKfwD98}Df`@+@1|(;&*ScJ< zxi-*~v25L?8IF0z5-h7lz_a?@cd3hXSCfJ^=E2yaX9h+WtCA6?pWMu}hTwIR&9Mf{ zdaO6GIwO2Lo(69{U`RczlIjNFc+>9$pR3LB`2~AO-}A6Dyn*NGcw6is_By4IXLho< z5J{v@&eCbrVq~@~`ygj#FrT9z^hJ_!<9=FKwq6F-YJ#vex&Bvda=gm&#k-nHF<*n; z36*OG14jjInvRYE+3jKJjXe)5)0Ye?NsSxYeQ=jPSzrnv5EA$1`a~Y%c0TAqOA4h3 zYF)ovKYzbkR}+O1pNghwu0U`3c6Tp*WRzqjYx?`Pb2LbV1XLr)<$ZtStZwxR3~QjSsP-cl6BJfP6(!FnhEEe6^- zFG<6C7~_BCE?LTG*!EpHfyCW;l3lB`drHk&@$4a~F{hcA4n zI}6s@z>7KKMt(W2t->;{p?s!Gblq6BcwOd=b&-#6pN-Y{wydq6DtC_f)K*)m6bwF9 zv3Mb1%A9h(A2!2B8=s=8Kb+6Plqvvy{Wu5b+;N_Di)M( z0IMJi=5O(a>(HKVI*PjugI+zG5%y~6qEg~w+^CkFiwFQ;;j*P40+ zcbCX8+VP!H;*ixrWymlU?~ti&auO>x?Mvnotc&8|VKg1)=$RsyLe?*A!RO;)Vbl5! zS-RnL&RMQ`iO9$P~+-c9H zXZb_{nUQbb^a9zn@)=b=qHZcX(Z{rvvdb|E_7dWYliSK-C+*R-dP0;jx&;O?w`?96 zruL31lAQrBWd-JbemvQfAXM3<;M^vQjbm&+0n3(>KZ$9#?55o-82cv>n=bI-L6SWAy<#2ZB5oj2Ko}W9HKEh_(6J2(S_7RVEWr@^6|&J^Pt6` z9cbdj2Dbj37WgSzcT#jlb=q%1QQ;tpI(GvE3}f_@a}?2hN|wFTv*LE{Gyb04;++$p zanFn{Ch0oW{5UMqGk$^nt3L^+Uz3=Bw#g`!&KR6WL9^#g;UG1W>*BJ@>H0iOD2zE1 zhVx%+WJKz1*%lIEiuRD72R29AbV3}59e920EBP_^nfvXoc04k$U)H~MB%G1ruRGIP zPRl*lij`q}->E-F;Tj$=Igt^a0YDDF=y*rw%7L7Yk2mH+rNUb`IamZhl6`TalI;bPYF!&ny44$)e&bTx0zJ5QF?17Vmq&Kqh{vFEy{V~eT?jT0x?uQSZivi4?gfx z@68Vy)ZxL@KI*1BAMdOVFVR^HSbHq}=SAU+fsw(y5w#F6^bfaGIr_nnpS;od7GN1I z&qEYXJa&x7!{SjOTP=Zu0Z;}BMK^Drt6_@zT8=Cv#T+mzhN=}slWZ7b3Wwxh7DS#1 z*9na64xztSc&@r0a!PEWd0#BMikIDvFrJpdKE_ZaUMwIibHM+8`TGV`I2(nnON85j z_b__E*KTT;agJ8a;dYnk8vwO%Lg-Dj@rT^{Ff%%9cm!>eQtaUJ)l8pGbJTA93U=x= z%R|ewM*HId(@~RErv%0r`G8*NqbzMm#kY;Dv0+SQSt2#af3;}`r(4(N96Mw_pf~G% zfajOnBB^7YfitgZSjNSQB>}Z=JLvaXT>JX&<+nfu49E~hb{={GZc7!ycZ$x@&%|YD zgBc}EW+JLcO3rqDP)gas=FpMZO;G1V7f8PhKez;M(cq89(Q!g zVg!7-SUY0ybjPg|YKCxm_=V@GHpakr;n4Lvojw;M4krvfB|*$p4+H7D6Jo3~I=OFv zi1EHVoXW-$Mx=`}1Uv*}D=}IT--pLW^prMfKP2h0O0d!GZO(FRZ=a2wD2muHf6lo9 zV%O+*;oC7j>n+(2%sqW0Z>A**Bm}`xAH+>VUJ5eZ!|o3rpjk;ilLUbBNZdPzrc1@(02m>PCDcUd7Ulp z0iMKsrT9!1a}y5(VBv|5PcZ@jY6e9aNv+p2yL06c+X@~SX2-HtC`8Z8LKoWJF5AJQ zvj!-bH}LUxMoFEWh1JTYWge0_cj2FKJS~S^pri_C=xR!bbwg~X+!I4xd*WmS!0-+_W0nCa_udnj<&1$MO?btZ8} z8c+b7+yHbyWo&XzanmW@UKLSb9wiJ&K!xWw#+lk+XJd8Ix88xg7?elY^8dZl0`{Pl#1S^^)p) z_FP97G@dd&H2#wulVKsarrK_Py+S%!T+?uE9yL1%&_&=6EE4 zGmY|4JOlWyj}b3e5(&`Rfklalq*P@%3Q!Sh3bSh)NWSRLcT=UQoZ|hbvilvjBZ;Zl z!rH#Zg@U-t?B#i?|Dmb27n72n_e@aSykR0f33$tyu-*U)&zA!$kUB*W#!z}npDUEm4>oEW_(a~#ZY zhu{KJURpv2b_8VrEZjXLHuo`>F|?7loAR%HGI;6|ru8F`kK=E-Jm?#dcl6uvp#?3M z(HKbd>MP?>q2Kjo-K(JeT!lM&OE|vO{SUICfPl5w#cE=@xPQ%zaWT@vc*i(1U^Z-PQFek9NCLF$J<#{i z*a0Ai_Zcb>)f!1HZeTdSu)s?tvit))pFwVpv9(q#?d72JQgEEh=MNZ2e5evV2He|M zSH3d|U0>SL(=i$}P!d{1fijttEoJdYj>s#f9nC+)-*3Y#FN->AX~;(s4fs7W8M-9vI>{IbCmES(EVWjA3<~SSm)RX;Ez55fFdQ(h}~-f z_rpsl%Ldoo?3B-zH^%V*%dg-=*h?B5%}T0K3~`A#kD_)_b*AJuJ@k7)$Ivr)le$*S zn$HNnKxJ6TcygQXW#97KrJ(>!Me*1AkiyOUF+Ns>0ievl&(^_aq@Qk7#E;Jwl(t!o z@AdBr6c85vfxzW-4Fj236BTw&Fw!*Dd4ZyPm2%^wtmS&hjr?^&&N>ky0{qn+c)=@HhLC3n93A zrlzKI5wb~bVqr+-Rx#MYB=xB@DQ8LG7iGib;hE7S*5{nuOeh$5 z5?OVN=duG}I3P(wsa_fLsWJ}d>8s*p&stDuiQ|bL{?FnKFm%8^e|)0eq_nQ43V(hl z_F50LPadCY(A%6dhfhva7oO73x79;0zKZLBD6kGw62ud>5mwIRkCrBsyN5&OPr!k-!&QETMNyfuE zp*M-^$A+yY(~5T|^cJFpMhgHqm^mOc|2AVhRmhCAsf5Y)(8uaFUh;qWzdc!5(QxjX zDAL}bLCpAn1vH}I&(i@bow`7Ct^Wh19++hVzv{rry|iwi-4{z#>dzVpI5CHi}O8 z6*gZX8Bp68nKmei#8U>9C-qfv!VI^>cpp?F z{-@9g^=q62qK_iZLGBouUrlK3p$m>lJwSb?CE@X)W zqO*-^B(Eseu6=w3B?ptea1Oj4V7HpdE86?c6jGdou7U>|q3+fF{!x|DNeyqjP8|OY zANvJ-7W970ax1`WYVpO;fQDdKlJ%GdSg96*h5&eYF+k#De3{xzHw+R+cR!6M@> zF#5Rqang|9VP^;OWW=8*cR)uNa&OQXNN|2Ow3>!nfDF!QWVF789se0oyXFu6eG#5K zZsaqdmbfaUGB<=Eq~y^<@_AXto|6C4%)36(%_*y--%)z-^Yim9KObhzKMryOwk1u_ zyw%w1wT--NdGGT03EP1H!5#0W6ONNc)o3y>B?S@;c1;&&=9Ck z@AuC<7SNh>7wX32aObm0MO`eRCKA0lNDbq=2*!3rX7%;s*xa?eQRAjIkoI1rzLv z6F9#z_q44eTRVay6Yh(@QP`|IetZXn;3Pby9$cxIn#*;12^U2C-uqG14g()BJb?_& z{fM~)2-{^dp`R5i804UD2}YDR6~>*Ojil4%CEv#EN~j!L49L`A%Cz;g)!`jGzE1H^ zY5t)rCcpC$sdvF1Eey=pTqf>19)-+$Bgfb<;2Q`RK+S&QfC%({)B_n*)pt~~438p5c_sLD5Oim+pc7ZZAh z4vxwWeGhZdff}9yi&qy7vgr)ClN7n0pRm?Lm_7qowg4`2~qsFBD*C%!9kg<{cKlcQtR$#kb)6Ddl;Z?u*yR0aav3J z2=q(16ByF>%MRXnvfLQHzeOlt-LqX=5K-Gaj@nS&Q5z|G_goK|fqryg`r_(&HHU;> zO=z@v%JUU^QS)h*#$BLIA~s&7bMNpDq#rgRG;=(IKtU;tku12>X*KADU3GB?@vMc`F-iW5go{#%&NC}6x)z6 zlFkhB`(aa3$&r4;FRN;Vb;-{hw_&2s~Q*Bw(@yq2r4{VRrpo)7py zSjHH15w@vRdOe8F@=_t+RQYZa(8~$4i$~2lZ)*uQAd}&PJ;lSC^k3?+auBNATSTXxY>g7^9VWNW z-kcblBFz!Ua=rO``pZw)DiO%-UyDXP-@~+xFH83?zzS#Qf*<~+@ecwlY^{-nEtr!R z`S(=laXpch6WGW~s2Ar3!|}Qf6df_0AzFBZQqBl^J(up;!gD& zCe6y^@i!{ox-QBovF?LsBgWXe(+`5wFGAp~-M61wyI7KfytV5;~g1O6SH{3m^Ji zsf{<83mZffVxfh4rSk0TjBKIR7+KBN$zVlwxj?ywj_XId%pBYql}S&7|JuOA z&Y{kv6bwazVsTq5YAc&T-?&*1oUTFr4rcSrtu+oX6lnr<`oX%oc6K-VdvbdE-e}@1 z8awPq%`U@+`HHBxuW_csklVS@Nq?kf?n;^tzf{m8`|5MBdd?7-ONk?mY@16Cuy+mO z<}(X#GD$lX-l#%|A{CF+2mi3A40`9Bq)YI-vS-1_LenVpZK;s^@yncC-P@q% z?i*_b6A8Jkg|njut;#PrO>XKBQhel)&PrXmcI<-}=d{TQo!?VmP&xJOGCI8Oy}0tL zGolrK^X3hOE#oQJt^6GexO2@Xc-&R(vEv1+Gu!!^wGr0*a{rp#w1p|Jf^%=#{pk0z z5v?Ps90_1TmVlP#9_Z{+3AZ7ku1wB#XP?NYzk1_18=F_Y#xP$#OYU=OXH(hZ@8=h$ z(*i0BO9G3AyAR63jGwakSp|YF2jzQS*s>yICsNBWX@qFp+8jR_U>rJu^sxZI+Qpwg z0%P0Zo;xPEAM5vHdi&Rqujx~l>Uv?1kQp#+O4mGj^1-`adLV%KKg_rzZzCE|zlJyK zIiQ^9n?ef)hONlCddZYOdojJ8KbRziM6r;pMtg>RD`W&mrI=Iq&!GC@cHqA zh5R_)g$2oRX5a&~4_JEF^ngTp8=R+N5` z2co8(z;(A9W5FWLTOhxz480e|xvL7sDNW_1l4i{loO^bZFp zZU529$r}A7r&&^{Jb3S6nk~K$#<^b6O-Vp3H%N%nP48#nj)9eKL6k+#eKpk`cFegm zzLSlE!dz96H{z+#z#z9zAV&CCT};@KDpAYIkP_y_q()q@bdRJ z-B=`xY}A6sa6@2c248YN*Sb=QAfgj-^dij+p$Ul34|Q+V9<}5Al6GVwg?&7!=jP4e z9!|RLxLH`2H@)J2`R9jBrsFz`OP^UJ>rbYaH`S;K?RNn7=n|^8o8_Vv*zw)SXj|Q8f|5Fwwe81C)n6m6ln{jO;<(BwJ!RL;&y60Xx3B(E zJuU0VDU59ZTf&hM?O)7=Wt-Z`lWi@fWA3}iEaoQo>yUJ_mU7h9|Ma!4jbAlOQ|$m^ z!~UHrsb?Dgccq@^&ovFUyCb=Dq11gEf^f0;Mtgi8-xdzfX~!MQJIaB|%Bvp_3_AQ@ z*F?X|1FttwayIOSwGIuy9M-KOOTFL_ zq)$)3xw-Z|E!{sn)P$o z0wCq#@0O->d*mGat~DI6su?^~y)g8&E8O!P36q>_j9)E72A5i7jpl7362~zo-Ej&I zQ$6f89XKq0+SjU-#nc} zfCdmMb`5vRd9WaZq?5v=b~k~O=9VLFy?%eD$5&$1|6ZVQgY6;>uN^@F$Zk5k4s(v0 z3kE*>4dWwLRi#aR-&C(gb!;p@|EpSIGJ`m?Zx2PyE0}&LQ`sJR90_KG9aCgxLWdI^ z&oO-){6_8R?Rfk^2Ar4l-cBL*BT`}L60<_7k$c~=XM8wjn=}8Urk(4tAvV+ z%8K@yERF|BYOZ~qH`faiOeS@zH?@dm!H3lRFxGIcj!#Q8(Kdjid@6JbYMwDw7Oc0b z?sR;%;6pcAnCHS-qSMaek8K4SEUzakdn`;JIk{7&&*QrgKd}-0A?3>s!KJxNXLdfQ zXb~zl;JPm2wCd~5`NN^$h;pjl>_PCC?u0e<=NBe(S9BNbOP`0t0X5b78BDOzk@m#b z5$1KPf99L@Ghxp-$Z$<0@wD^D2(lTpPbyJuX$d=hMLJ<~`R6o_?p3Kc^oUjmwJd4| zaooqpdm*NS-T1Fr#-Ix$dHCaai`!xd?8nREysfI7R>%?KwMsO|GN>%h{Tyu31UP*e z8UHoli;~;}|BC>aU8ccqDFc7ME-N8ziBj$dvT#$u#9h?0P0<$FQRUDrrXnT#XF=%9 z?pqm_INh~nNLFUJo6>t)u0tdHZ?|j?1U3~Gn|u(PVE!j74Y^L`cG;wH_Guy~WOWlC zg%JqEoWcXg>8C#60Je)T!g8j|E-B0DNV{Ztv{zzIE3RU7Y@sVGq>+6{j3W=c2Cm`4 zipLzepgP4+1jIQnNiuz<_JeH#n`QXN01oYKN7nJZ=L8yW+3M#5*m5>F}u8=EB( z{>U66FM)AnO|g8DO|?la5^QxUXT?x11ggPEG;%qgNJco@NuH6bT2+VDD+}b}r|emH%rf-c{a2 z&~vtsuqAE@aU3Lnx7wI_Bzjzu_Z|c&F0)~9@z}d*&hhi(d3H0%&h!+gYPd1AMKOL! zJv(wuj@a(F)?lD`Z9Vs*htbm zOw}_GK>4b15yU=O-T5BHSl0_xB_tzBZ`+B9a-w*6TGv#SkUCP;n7nxe2z)!fkggtD zb65F~+3i0@7|mW?0I;%3_z3ReFixgqs$L$bO@u_NChjjbGXsuFsneLM97X#wVPzSh+{+r`t11KNG@l~AhRS*d@- z<;i->rROiP(TMbG_R$lfGC;4_m5s17{blNU5IYDRO=Xp9ycO+0q0$R*>b=?_W2{u$2#cW)~&@In9- jAGsX&?@Mwqm()z${=5BU6MWzrI-n@4DpMk5_U?ZHeyoOc literal 0 HcmV?d00001 diff --git a/projects/VS2022/examples/shaders_game_of_life.vcxproj b/projects/VS2022/examples/shaders_game_of_life.vcxproj new file mode 100644 index 000000000..0ede87cda --- /dev/null +++ b/projects/VS2022/examples/shaders_game_of_life.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {071E64F3-1396-4A97-97CA-98CAC059B168} + Win32Proj + shaders_game_of_life + 10.0 + shaders_game_of_life + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shaders + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file From efeccfef613729cb2c47c991825b1b5f4ea3d7af Mon Sep 17 00:00:00 2001 From: JordSant <77529699+JordSant@users.noreply.github.com> Date: Tue, 9 Dec 2025 19:14:16 +0100 Subject: [PATCH 07/57] [examples] Add `textures_cellular_automata` (#5395) * [examples] Add `textures_cellular_automata` * Comparison always true. Fixed * Tabs to spaces --- .../textures/textures_cellular_automata.c | 212 +++++++ .../textures/textures_cellular_automata.png | Bin 0 -> 14803 bytes .../textures_cellular_automata.vcxproj | 569 ++++++++++++++++++ 3 files changed, 781 insertions(+) create mode 100644 examples/textures/textures_cellular_automata.c create mode 100644 examples/textures/textures_cellular_automata.png create mode 100644 projects/VS2022/examples/textures_cellular_automata.vcxproj diff --git a/examples/textures/textures_cellular_automata.c b/examples/textures/textures_cellular_automata.c new file mode 100644 index 000000000..d24104200 --- /dev/null +++ b/examples/textures/textures_cellular_automata.c @@ -0,0 +1,212 @@ +/******************************************************************************************* +* +* raylib [textures] example - one-dimensional elementary cellular automata +* +* Example complexity rating: [★★☆☆] 2/4 +* +* Example originally created with raylib 5.6, last time updated with raylib 5.6 +* +* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5) +* +* Example 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) 2025 Jordi Santonja (@JordSant) +* +********************************************************************************************/ + +#include "raylib.h" + +// Initialization constants +//-------------------------------------------------------------------------------------- +const int screenWidth = 800; +const int screenHeight = 450; +const int imageWidth = 800; +const int imageHeight = 800/2; + +// Rule button sizes and positions +const int drawRuleStartX = 585; +const int drawRuleStartY = 10; +const int drawRuleSpacing = 15; +const int drawRuleGroupSpacing = 50; +const int drawRuleSize = 14; +const int drawRuleInnerSize = 10; + +// Preset button sizes +const int presetsSizeX = 42; +const int presetsSizeY = 22; + +const int linesUpdatedPerFrame = 4; + +//---------------------------------------------------------------------------------- +// Functions +//---------------------------------------------------------------------------------- +void ComputeLine(Image *image, int line, int rule) +{ + // Compute next line pixels. Boundaries are not computed, always 0 + for (int i = 1; i < imageWidth - 1; i++) + { + // Get, from the previous line, the 3 pixels states as a binary value + const int prevValue = ((GetImageColor(*image, i - 1, line - 1).r < 5)? 4 : 0) + // Left pixel + ((GetImageColor(*image, i, line - 1).r < 5)? 2 : 0) + // Center pixel + ((GetImageColor(*image, i + 1, line - 1).r < 5)? 1 : 0); // Right pixel + // Get next value from rule bitmask + const bool currValue = (rule & (1 << prevValue)); + // Update pixel color + ImageDrawPixel(image, i, line, (currValue)? BLACK : RAYWHITE); + } +} + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "raylib [textures] example - elementary cellular automata"); + + // Image that contains the cellular automaton + Image image = GenImageColor(imageWidth, imageHeight, RAYWHITE); + // The top central pixel set as black + ImageDrawPixel(&image, imageWidth/2, 0, BLACK); + + Texture2D texture = LoadTextureFromImage(image); + + // Some interesting rules + const int presetValues[] = { 18, 30, 60, 86, 102, 124, 126, 150, 182, 225 }; + const int presetsCount = sizeof(presetValues)/sizeof(presetValues[0]); + + // Variables + int rule = 30; // Starting rule + int line = 1; // Line to compute, starting from line 1. One point in line 0 is already set + + SetTargetFPS(60); + //--------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + // Handle mouse + const Vector2 mouse = GetMousePosition(); + int mouseInCell = -1; // -1: outside any button; 0-7: rule cells; 8+: preset cells + + // Check mouse on rule cells + for (int i = 0; i < 8; i++) + { + const int cellX = drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing; + const int cellY = drawRuleStartY + drawRuleSpacing; + if ((mouse.x >= cellX) && (mouse.x <= cellX + drawRuleSize) && + (mouse.y >= cellY) && (mouse.y <= cellY + drawRuleSize)) + { + mouseInCell = i; // 0-7: rule cells + break; + } + } + + // Check mouse on preset cells + if (mouseInCell < 0) + { + for (int i = 0; i < presetsCount; i++) + { + const int cellX = 4 + (presetsSizeX + 2)*(i/2); + const int cellY = 2 + (presetsSizeY + 2)*(i%2); + if ((mouse.x >= cellX) && (mouse.x <= cellX + presetsSizeX) && + (mouse.y >= cellY) && (mouse.y <= cellY + presetsSizeY)) + { + mouseInCell = i + 8; // 8+: preset cells + break; + } + } + } + + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (mouseInCell >= 0)) + { + // Rule changed both by selecting a preset or toggling a bit + if (mouseInCell < 8) + rule ^= (1 << mouseInCell); + else + rule = presetValues[mouseInCell - 8]; + + // Reset image + ImageClearBackground(&image, RAYWHITE); + ImageDrawPixel(&image, imageWidth/2, 0, BLACK); + line = 1; + } + + // Compute next lines + //---------------------------------------------------------------------------------- + if (line < imageHeight) + { + for (int i = 0; (i < linesUpdatedPerFrame) && (line + i < imageHeight); i++) + ComputeLine(&image, line + i, rule); + line += linesUpdatedPerFrame; + + UpdateTexture(texture, image.data); + } + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(RAYWHITE); + + // Draw cellular automaton texture + DrawTexture(texture, 0, screenHeight - imageHeight, WHITE); + + // Draw preset values + for (int i = 0; i < presetsCount; i++) + { + DrawText(TextFormat("%i", presetValues[i]), 8 + (presetsSizeX + 2)*(i/2), 4 + (presetsSizeY + 2)*(i%2), 20, GRAY); + DrawRectangleLines(4 + (presetsSizeX + 2)*(i/2), 2 + (presetsSizeY + 2)*(i%2), presetsSizeX, presetsSizeY, BLUE); + + // If the mouse is on this preset, highlight it + if (mouseInCell == i + 8) + DrawRectangleLinesEx((Rectangle) { 2 + (presetsSizeX + 2.0f)*(i/2), + (presetsSizeY + 2.0f)*(i%2), + presetsSizeX + 4.0f, presetsSizeY + 4.0f }, 3, RED); + } + + // Draw rule bits + for (int i = 0; i < 8; i++) + { + // The three input bits + for (int j = 0; j < 3; j++) + { + DrawRectangleLines(drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing*j, drawRuleStartY, drawRuleSize, drawRuleSize, GRAY); + if (i & (4 >> j)) + DrawRectangle(drawRuleStartX + 2 - drawRuleGroupSpacing*i + drawRuleSpacing*j, drawRuleStartY + 2, drawRuleInnerSize, drawRuleInnerSize, BLACK); + } + + // The output bit + DrawRectangleLines(drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing, drawRuleStartY + drawRuleSpacing, drawRuleSize, drawRuleSize, BLUE); + if (rule & (1 << i)) + DrawRectangle(drawRuleStartX + 2 - drawRuleGroupSpacing*i + drawRuleSpacing, drawRuleStartY + 2 + drawRuleSpacing, drawRuleInnerSize, drawRuleInnerSize, BLACK); + + // If the mouse is on this rule bit, highlight it + if (mouseInCell == i) + DrawRectangleLinesEx((Rectangle){ drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing - 2.0f, + drawRuleStartY + drawRuleSpacing - 2.0f, + drawRuleSize + 4.0f, drawRuleSize + 4.0f }, 3, RED); + } + + DrawText(TextFormat("RULE: %i", rule), drawRuleStartX + drawRuleSpacing*4, drawRuleStartY + 1, 30, GRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadImage(image); + UnloadTexture(texture); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + diff --git a/examples/textures/textures_cellular_automata.png b/examples/textures/textures_cellular_automata.png new file mode 100644 index 0000000000000000000000000000000000000000..2d88041d2c3641805cb5af8d4b52e059a6947ec4 GIT binary patch literal 14803 zcmbVx1zeO(wD&{F5`rKpvB;tzAz{#|GzcOkAqXm=Aky8UbV;ZPNOws$C@hTbi0}%ac6FNk{+i~D9F%bzs z0{$NeJ|tk9F!u!E`B$6qcbhPei1-&y7}zHM-IiwuJKzWM^B?{TegQb8p`xw=8X_16 z|KO*AYXIcL3Gx$U5OQ*I3JM4%HN#12Dk^GL`qQ)w9A}`M9B0_sxp*$}a&Zg7*xC8S zF9?c=UcP)8$}1@=AtrP2(q%CM2oVJZ1vM2l%gK{0VrSXUiv5p2_;!E}0>lx4WVr!i zIwBG}BK!vc3i?S#^z-wJ3V|pIDcK2f2n8h-IHBegAyOp7q$Ffyq@bY%2r zMHNq+zIm6N`w4?sQ2bj6OsTSiQSZ|(&m}A8UKeE74GfKpZ<|=(yZ^w(*3RC=)y>_*)5|*~^l8|$=iw0vi7%3pQ&L~P%F52k z&C4$+EUJ1}T~k|E-_Y3k{zF$cyr;KsWOQu&^Te0Qsl_G4^2*oMZ)@vF)ZX{~gF`gt z2Z0xX=bz6nX8(y79mtEAl$3;&oWP5S*n>cvj+E@I=m~noo8)(&oaPn_f-oq>zpd<` zfL+qtWwdhsM9IW+dGQ>QKf1S<94M$GvlhJwmli2c?&+S1k8VR4-cOKB@H=`+1J#ZR0Hg50RfA1YK?;t4J_aLyPK$*T4mjvsdYWLvf*}9B4eZ2FC z#2%j5j)|dVkB^xxv~$c#j5D;pKKrOeQ>a zpAWl25Bb;}Y9Squh((;e<43Bw!)#YVM7;w0ldX!Hn0aENTw=%(X`jcnYR|}gz-b^) z)qGyDAUA7T8|88TmZddU=$t#c{0%tSy$xAyaomu*I9@%gdabthV{TLAP4cbNnSQmY zu;g}G5d7nW0jV>W?s|y*R$r~l=ofGO@2}pSk!Yhtzc-lJH#Zrq`G8slc|{`6ufC)Lj%jQ!b&>W%foTn1-2#>W0$c+#WO(Lx8%jTv?TI8 zM7R3dROV-2^J2Tkm}d?SZ#6xbvS_Dx6|fE>szQO@%lojm#d80(0R~vJjc9C*sc(;Q zTnjC`-%h|t`ozUk8COp!C5W~8B#vg-zuzr?deK+5z&_>H`k_a^@8ahRD}oi4m7OFX zeZSzy+!(Grfb5+{3VcwSFirC1aNfz+il5F3zvP|Um!gxH35c`R!_xQXm3;)0!!KRF zDSe&2yU!)vb6r*d+S$s`uzT>f$Xus*c3x=jnQ{J$s*YedgjR9SdY5rbcRUpqxmzA} z#XP`Zyi~Z_ePpr9uVO}v&EezBd*@|g7F|!?9m@4HE1jpmc0%-2jCP#8UABz<|7+U+ z@3_`xwIpj^fBA~24PmtU=wt({QSfNci005&vyRTqIMyWqDl;4bdv=L4F7Oa|Wr*sV3*r zwC@L;FEERy&$S+@k%qu4hrhoq7Ey6E8IeVqT)yU$M3kU_h+D10KHFoo;!r<7wp>Y9 zVS9N0T}S&hJWxZvqLra>o8u1a+)PQjJ;px&WEd%mR(F2&)zizWF^grlZq}c!bQpPb zLlGhxU4KlZMvU-^hw=pBfuvgwY_2ZK2a};8vW4@KJ9=lB)Y#l}Ffp{7vx$p(#~)>V z^pTHvoZ+Sd+5hdaoVTa97bn*lb>z~cIrqSNZvoenLlP2$2jV0ov@LWSQdtD!wMgV# zOUxVr=fVnl9l6O>a;~w@$!FX)Au{1GTT?mpq&C+Nt6U^OJqxkEZkLHp=6-*r{i&)g zeWnvG`p8)e#!D1V0?WUVp1S<_v+QixYa50Vq}rBK`(-7S^ACoc6lJihQEm$c=DfP~ z)srV@6dg2zV{(V%zX&)2h>&54oj?^pik~klkn(@}bd0&d+$1XNgc<1XYcJkfNf{#b zY3YTt3_(cGXlv>|LxQ%qon_b*)!aG0WU!_I1H|MS)9~ z%eFU15~Cb90bm!{in1oVJgB}oB_J@#>zVd^YrE{M?c{V~O%UMv&1Vk|)E)tM&1@%( zJcOQH?z@lZyB9z9LEL7ABqnv8Rt6<^^UB;CFaJ2W8;=e>qwtyJn`g-j;c}^~07?;Y zWetX-$bMkgFtMX4iPGraUoiPk`h%!aVf?p0RSarya6$KDn~L z(zW0It}=2U@an~!+r$-mG*_d7Ra7W?cB10!YhRKT#C@?h(ayP**mzYm+pABCX-cGg zA_mRlDgiv0ej{!WWjbqm!{ppxjtFEo5c(ztF#%B1j!JxSuo|%I+`l)^=2Vn(|1~yy z{ySU}ei;vJzPX$%KY8%-Zm@6CvMXFezRLBZJ|3`{y01cnG71{y;3J{!Z5(@i@#Nr2 ziC$4vv)J@YMl0E?D}lp>uyh2Q{ZL|IFQ9hu>urZ+=i~_nXn>O{T z2zGKt%sT{Lz{<*N^KXD`EKC~@WcuYFVJx(~bx)`y6|(W5$}VQ7!vm5Sd(2ZGIg2Ku zet5fd&z$+Tkv@L5`r3i4yvDm%TR}tC$`H|M7+GZ$t&Wdu7M#r@L>NrKP3I>3Si!Mt82z z6`2j@e$fewR(u&BT&d@zbQ;dSyl}v7!>y_5r!q1y{X9Xh-Z&>I=)M`^YqvPNOSdHA zs0c6>;`}I7I+#1NXlN@SZL$v}@_5mb}i8_l~kLm^bT!p}!NeZcOzQ5~O_{$#rB`qc@<^>k^f zH9X*UR!%)W$aX@4=s8QrK7vD%go`9ID}oRBzddCxMxRMLO?@<*JQKKO);MAZgT*2g zBqVk)Btz%N${in{*AyT+75=3pQ4_}X*gz?BZ@A8v^Q7{_CvG`&E!7{Dgp8Aow`P}7 zDOfl^(965R;T_bGNttr%HkBIF$lA!Fv(;^L_bGb+J))sY-Q+A1EN1cVa@PC3<%TcE zv*oa-4)^o1Gb>K8?jI?VPS>{v&rLoMYL=6!NP9`KOt!!O!)2slo*xhBxwppM&hDn+ zC}X`d5JjK)sH3NYC*5x>5RhsVxTHR|+#IFsaVlbyI`gEYoF$=p5D+4fSVFdJA+qjV$5vhCK=Y3>$&viRsSb{OtX7on# z+XpY-ymqSHQxUiHMMN$5ZN|6^i6afO#T&1z$G)3BdZo-7L2*a*0m)Ziu?1K5#Niw2 zjP(<>Yjy|OT&O2wE{UUn+mI*R45`5SO0H~#v8tt^?$v@*%BeIScp+dT9oX&T?aJja zA)w{cEcv5&;2m_ZKCUtxa5;zebSB%}9VfMZFb%6ukq?kJf_3q+a z-_0Ja#-y%IlW=`!s;e|t7@>Z9gGaTU&yN=U9rg-%KT`9=zW?N4SCeV)fT@KLq?gSs zjabTc?Rfj7Yt69vtWL4HP-*iMHl1cek9$}J@>&KY{05Hwl$W{O0pdpeLxHa6)A__| z_iRpi!{~{+C3j-bq?Z5Z#aF_idNX-jN>rZK52*Jy@IQX5)mKp67<;jnXD)Faf|!t+QxMi-6Wja`~Kv>tEQv3HiA5;szd4-NY8ArY#=+|vh|h9ymfW|n5SAEB607O6v=K}>Q><4 zgfkGaeso1CqP{NNed2PSIStn)PA=O;qBz>Y+y6Q~Y;Yje(PhtfChhP_t}^gI_}TXr z5jytCkfWPet(SM2Nt*I`BkXqPlJ6$NNL$Uyc-*kpQy*{~@7sS;U~T&%6_9Q-DgH`V zwb`sUE;|z{&Y`1WyL*sYnPbK3Ta7I|2*3Kh`$-ck+`py}M1OOlJ)z5yihU(|tijR= z!s`JG>iC{l_pJJ}cG!j5XLH$GV!owm%f2%%!;Ikk`?0ik*#k#oZOvT0$ML+wLtdDM zv;30trD7$Mb{0z=DoJpjZQl3qXXlc42&&O6FTScqqH3-OS zjq!|rFq{xIi`0v_K61UUA~EAd@+wEekOXNO@{^&~5A&6=k1~hrYo}PFlnicHC|ZXN zd2yguKNs3fCD;u(JZKcZ8qq20wvwbaADak+vHm_6yZ-A;%=olmcE(=wT-i$zebvb; zo%t`T_xYJ&NXcypnZ?Guygl^;AGcZi5~g+ifV2xkSNWu0^H|6F-itE04Lcr8CLejl z7TLh)p2gqAUO3Z4o5JHPG2GwYy$)pbrP{q!iDjM!rb?{Yn3uUkNv2oY_q(4AYUimJ z7H{ye_p)#yqt1+0wL~1xXfvrkxHYb`e*g=XWH)#PeC2tj z_iEGJ+@!QK;oCtsw^1LQh(g{cT^+azksxx~_$F*}I5@iXv@p^|RX7gn)icB5NP6O6 zSm_4DWbGlF;rKc2&!73r`J+c__szrO*c{dRsgK$3MMVHjcMHy~zC2A9^YwJN)eMEj zwePZRX6z9SW;w~bx8I)}5A8YBP70w5wUNYDi65%YN;mXwe<|IP)@A;5YHh^~j_POH z>M(7kRblPv`3?()WKvcCE4=@{elY6&I2JgkEMb=`Z58Q6HjH+`0~J zIZaPnmXcKEzoFiR35qGu5J~H>td=XeOgILLx>2}MeL)06⪚yb3S@1F18GP0lXh2 zU9Io-;%F;JagkI>Wf9{s z{S7g4-Y7iK?!@mPuJ=$~CY%Ah@+{|Ex^%KXP(mP~!)x8!qa6ltoFsfnaCgq0e%{myWcLY4}njUqICH$+00Pft{?lC)kw zkTP!>Gc-zWtl5Jzc*ee9#RHy?Hl_m4j-D)`&&%-3?>b#Bf(aJ4lsdWMOe7&8V?*l3 zzGk7CXKd0udRwVI?fJ+l6O~N>em+x8lSkG2c5QEna|r!(Uxy9xxcM1t2UJO}#Xe|vorNdR-l&sVy7q+DiQ`@AOKE#+>E2_JS&R+L zB>HW%D;S3m7HV0w$uS@6!psx)CND}wDk`E^-c<42bF&b9lE$=xsrU+%uoFhToW#(-Y^g&b)wvA4G5WsBRmHE?rue)43tp)2-@#A~1UZIwjt89@=UK z52r1}$VwncSU3uZyHko(3zhtDF?I%&JWZuO~Oykcz8e}6Aa`o6Lx@FOHBNj4g=CEP~-{TK*o>P2eT z&As=1wygpoYf)w$jDeJwTMR?#MHPJb*LG~WY27E-KgWj z?YA{`e9n@g#E^wx(GKz&13VDw=bLJEJkp9khsKl+Y& zsQc~SF#BMU#k=k%hIeNXGmlnfkDO%5E*;a2VK12m*jZq-ru%kov^Gp{3{Rw26I}^j zd-b&9m4F1fLeD2aA0Z**6I*WbwotZs$n{9BoAn|@&YGJ$iG-EXH2Mo{f|cFiQx;>r z-GpAt?b}zGIE{PoK&w3T!?f;&&6>+-0*$S0)vh^eI4E*B;YZL?-oKYD)0 zj&Tw=Mv~&1gAzw$Zg_qZpxMz3o{}z}eq)FvIe#uL^@lsjGGdyubzev0^Va5PHm|bx zrhTTpVj{v2QlLC2%HMdchZTV0CxOqY*;(LERYWd&s!BwYy@CN?htx($#7G z@*eE<>@$|dwcR5c_8PWTY!bZQv9Yw<= z^fe4_-b3{HBL4}%*23})y7XYb$&A`cqOO)CP~47=7~rb_0Q;tC;KxRJoBz?Uyg#nK z(RpK4)>`>Ea`I+N^0UgD;Y5Hpl9URttZ34y*p>~d_gmjZU+BVe4@;u5yoG2Ft^9?G zrdgH{vECZ`XK8_tPkD_2AVkvs`P>ridw(1{-s4@t^>h3;Wuqy{m|W>^clnowdx=MC z=x5Q7Q!#Q5zK`GeMYI?RofcHx`FP+V0C2 zCJFQ3EIrK_wUT-Q^u9WgD6?AJLRt9Xc8E%w{81$oR|PwyR`-i%S;BW^9L{WH??kV^ zVNtpNU@Slsdq@T_+JeSolaR zfaSnGpE!;Xksg8%n^fUPcF}G3qHtr3Vte|70imj3u_YB47qYQ z%q=CDzNtI7I*3Kn-W6-SzmRm1^)bzM$^4Dwe1Bh^r)`>KfsfKHi2&+@t&NO+e;j7# z_Rf!^A3BkW)T_t&L<@cd;je|X-Kj6}NSoRU2>jfN;iUqX;s`e>pleA~`~!`SBUK0@ z6RB_1vnHYx42&NiANEigH&*bw<4o?YZ)8+r9!N~JP`bWupZjA=IZ&z^60|-(elY*c zxUB_}*-rf2&?qA#!@{D4AhidjjpGJ!Zqy)nXi@RP`mCYO*>rj=Vw7pIjMl!_pr z%v%sJoP!hhfo|9v7}fbVX>B#Kf^L+Un$MQ0H4Sy3!A_hXF- ze#k%lv{kJCdqM=$StozDqz^w%@KppV7Z>Lk^k9wK!$BV|6&DMwo=rZi1jv{wY~7N+ z_q{l*3>*btEvx!Qbzy?4LvUgS41ZtTqi+k`_z$8|`QNMV2yz z-N?La%jA_FIXUROTX8Yk{@up$SO?LaY*2R7++lH5t7%(@gB>I=R$8`HuCUc8@8%Tf z0oG!}_;{&L|4f8k$`>AtkQj#;HzKy{*P{DG88WfvI^{Y|fOMEU0`F zWPuzvxb^uOh{{k}_Nt5@4A==UU@A;}ro+#S!5)LL!YAU~H34m~9X85M+ReaMXCf&4 zliN=T-7T=40J^b5(1GRs;+93GG5WKe1ESp#)?LyNx>6cK4#s0(+`xCAZ(rlq#zN3V z&;cXL7eYApf-wQ@zj7R7u3q`&8XC@T%8{qO7-h~h)$wEcCv{6y~dV-6V+0U;$_ z^DUpJ1!G5ly}~hO=^cVVsjr#NmfSI)ZLAY~(fE%lbWMNV8+00c_jERnk2A@Q6prox zb=p7YR^bK+_4%zbM8MD}t<#$dWHYtimwyKp^vEQ%;xjYu>)GUG0>=gBW}{#ps6-fO z2Spap54S*p+;)F3H^W|m!wF1h2k>NVl3D76VUb;`IXdkGT6UetQxA@VW8X2T$${%J zJ)i?FKYNEF!PinyNGWxX%AZPJ6{!(NFtC7OcE>S7%SqMc;=mX_zy`Ou?O1O=Ki^Bp z{+=)z9j_TSa(<8`MMx4_k-F`GU16;NP+8 z7tun`gK2+Q4S9RWj03aQC7_r<%U5C9C5&!1a&IOGr9t5aGp_U|)P{hP*&fW;wy+nY z`_sVAD0is8#V(jK4TAmOupDof39hMp;tsuGvHQeFergh-*}5D8t`syG6kl!FWPv&d zH3V0oZ0kbZu1k#l;XmR4vizx|1Yu0Yc_F2OW3qsaIe6{Q0We1V{vGhx>qYM71ob>+ zh+7+|9qR>PS4t5nzLpZ8Q52b1aXYj~P*P2VRs?_X0Qv}%m(O+e4&0-acdlq43B z?~{C>@9kCDYho-=!_iRib+L_jmb0;xf~!Kl53YtReuUF@z#@w{o{UNP_sWa=gDa&W z78 z^t!#Kba2oANo-UNxqHuzvF0=T>L1LGvTrp`zmkILRO^ z`JAxi>Ks^gT$POxZJkTUL5G?{4TmJOpou2JYZxkUNZV}TJk&z)(aMccUax0AXyV-B z%treylh9pnx0G+$+qx`-180=9g9rBods&V7&YJK-QB(%O5NzrD+dU z(z~eFIM6`+pLRtg(^;9xR&osAT@<+3AP)11+vJJRuV86<)a`WmH5=)PV6?&XDB4PM z`gVN~xR8oFFFylvpML}|pTVX|a6=O3m&wVPLTeG~6CKOX+(6O+wTKQ_06Sf1?_(6W zW|XE67vkk(Af3zNm_<<`CEt!^|I_H_cL_44*;a85sFr_$dgQ6;!;(J+8H_8w9muXF z(Us>|f-aY6MaJdU?HH-}vHwENZWmj-?TY1WzT@C4f_V$>Xdn!k%>)H#HbfUqO1QEY!QObkb-;<}$% z+tTSdVmYfl*3bL}Zo=v`5WIX=Sq-^R4f4M=D}Mk6knG7*?y;Np zxUmR({BwO-O>H&l_p~j;@LFKup03?FK%#^(J@S--EDe6&H9~Qkt!X{-qodr*AGZ*U zqdLdupcvI4vd0e4kcs$!Ue)8Z8C&c1zy<|EYJ`G=x8xf!bEhY%#!8b-V2X*VxLJ|a=-J25dHCtJ&?*Q4? zV)ym=nO{Q;#;2xe&YP_6bpiTw$S4UI|Y=G+|F z)*F*aM1LC?Ra`$9;|NFS>p5XO$R8z)XIGDm5x|<)bfPt|%zG->W z70V(+pEvb)mYGTD%&gqiaX$?Z!KDa98VnL$|%!3=`1a(cf8!00O1 zS!i2aIMs$eXMtPFrx8-(+-hvpqD4kppt^+p8H^cb{mIHBEpVeBgfUANlKy&jbVX&} zP$aiMQnMA^^^;C{o@(=R3tWP*Kk`;0)8hKLfmu!Af0&Si?Giq&B4`-JWW2YfD+7=G zhj+*C{4uN=q}&B=a1jbMMwB0f{d<|)(1kjYPF?HkpIhv7x1KZq^+&&?Y)Q3NUwTRT zHz)AGK2cOwyBjYw9^*;(i^nfG|9hG>usgru)|4Zi-r5+cSLMf{yFe<;V6ONLjlA0K zBiPzD(FxYLB>1YUN$4JUWX6j8GX_F=yCqGa#9NX5F~XAF7GA#KttqXc5&XS-!oe4j z!eQYY)rLazRj8Ghp<*mW|Cy)pi979GA8)O9+4$7 zUr?yiA6hYZO%R9#L)h(TQN2tgc+8Nm{N)kWxvQMEeF-#IS1a7H0T|;XQ<(0)-in0j z0fNU&0c1?DI^h^Kq6)Mrj_nioqY6I?R557-1Y=o*ynf;< zO~+eCnrm{lFFi(ZXh`OwaAK@gL9tC;r|k8?)IEk%>msI zI!>~qW14E^K?-Lkm=ZrvM&~yGzd* zfXKG4He#X9)3w5iJ^@!I5hRvK)gS}V>UV$8>IXYI&PG3q?Mp?ow1HhvGD8rxg6z%~ zK?d$&o*xM$tBsln0ii6(noh}^AQ(I&)cGAWua;m>=w`R`gBYCZdRtPUZ*y;zQ|tZg z`d$FPC3NzET^6|h5pJ!?*2}Yh_%RCMU)NUG5HiMu2k+YCDR`sCoQXg5ifu8_=8OKI z`{>m?Wr-5pWA6{o{{+v{Y(lEhd>=$Nv^u1;8e zqKnoN$&6>OhIpjlJ7Cv}I7CMXN^M;hL07iGG~ZLJfvGgY!C7_a!z|_cY@ANQk-#@j zko5dgdHXAOtQGE7H|UBfPI`o!Itj0i1rT6Tqss}oPZ)E)DhJL)gGU!%y>tuKq>KLu z>6;yKm4vR)@vI%)oX~J$3?TY*Hf4!2=$mRF3lywI9C+i7Yrhv_(-=zbFr{d`*xaB8~m-(2_Uq(zmtQzpIdU@A{;{;eE)#Wd1sC!Q@vE&i|N0`?n?zbwlyiA@T7Qb8LQpVJWV zn4lOV%cp&-3!uUuSMf5Jsv++JPIEH%%UdE9k0F8N*Idm9;FWRlhpJdx` z@@{tDsbVG?#*X{b-^hXQx}X0UblPxc>^WG3W6ghevu|m^KN4T+L5SW9r#7rjBUGlT zN}_&#Nxl_~Oit)V*{~~zOq27hTO_zv#pNwc(P|VE<{4{J1jA0V|7jkm>WB>3Ok#Rl z&T5!v1n&EmNT`LS7nICGB0sY4H=q6D~0Wcr>n! zv|oIcq!M+|1)_>$MDZSjcvYd!mJIgT$d}Got7F1-DHZRtim!v?ckkk?v(F8`m}cH1 z+_T`gfW_l}1WL#lZr6Kh + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68} + Win32Proj + textures_cellular_automata + 10.0 + textures_cellular_automata + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\textures + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file From be6007be9314d87684dd907b4a8477656efdab51 Mon Sep 17 00:00:00 2001 From: Gregory Mitchell Date: Tue, 9 Dec 2025 12:18:43 -0600 Subject: [PATCH 08/57] fix: sha1 computation on messages longer than 31 bytes (#5397) --- src/rcore.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 3a9a47359..20c882e79 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2926,8 +2926,15 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize) memcpy(msg, data, dataSize); msg[dataSize] = 128; // Write the '1' bit - unsigned int bitsLen = 8*dataSize; - msg[newDataSize-1] = bitsLen; + unsigned long long bitsLen = 8ULL * dataSize; + msg[newDataSize-1] = (unsigned char)(bitsLen); + msg[newDataSize-2] = (unsigned char)(bitsLen >> 8); + msg[newDataSize-3] = (unsigned char)(bitsLen >> 16); + msg[newDataSize-4] = (unsigned char)(bitsLen >> 24); + msg[newDataSize-5] = (unsigned char)(bitsLen >> 32); + msg[newDataSize-6] = (unsigned char)(bitsLen >> 40); + msg[newDataSize-7] = (unsigned char)(bitsLen >> 48); + msg[newDataSize-8] = (unsigned char)(bitsLen >> 56); // Process the message in successive 512-bit chunks for (int offset = 0; offset < newDataSize; offset += (512/8)) From 19a1683641cc9497babb0ccde461bfd7aa668eb7 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 9 Dec 2025 19:25:08 +0100 Subject: [PATCH 09/57] REXM: Updated examples --- examples/Makefile | 4 + examples/Makefile.Web | 19 + examples/README.md | 14 +- examples/examples_list.txt | 4 + examples/shaders/shaders_game_of_life.c | 4 +- examples/shapes/shapes_penrose_tile.c | 2 +- examples/text/text_strings_management.c | 2 +- .../textures/textures_cellular_automata.c | 4 +- .../examples/shapes_ball_physics.vcxproj | 2 +- .../examples/shapes_penrose_tile.vcxproj | 569 ++++++++++++++++++ .../examples/text_strings_management.vcxproj | 569 ++++++++++++++++++ projects/VS2022/raylib.sln | 168 +++++- tools/rexm/reports/examples_issues.md | 1 + tools/rexm/reports/examples_validation.md | 4 + 14 files changed, 1324 insertions(+), 42 deletions(-) create mode 100644 projects/VS2022/examples/shapes_penrose_tile.vcxproj create mode 100644 projects/VS2022/examples/text_strings_management.vcxproj diff --git a/examples/Makefile b/examples/Makefile index 48cfba97a..06a0c2729 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -583,6 +583,7 @@ SHAPES = \ shapes/shapes_math_angle_rotation \ shapes/shapes_math_sine_cosine \ shapes/shapes_mouse_trail \ + shapes/shapes_penrose_tile \ shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ shapes/shapes_rectangle_scaling \ @@ -602,6 +603,7 @@ TEXTURES = \ textures/textures_background_scrolling \ textures/textures_blend_modes \ textures/textures_bunnymark \ + textures/textures_cellular_automata \ textures/textures_fog_of_war \ textures/textures_gif_player \ textures/textures_image_channel \ @@ -640,6 +642,7 @@ TEXT = \ text/text_input_box \ text/text_rectangle_bounds \ text/text_sprite_fonts \ + text/text_strings_management \ text/text_unicode_emojis \ text/text_unicode_ranges \ text/text_words_alignment \ @@ -685,6 +688,7 @@ SHADERS = \ shaders/shaders_depth_writing \ shaders/shaders_eratosthenes_sieve \ shaders/shaders_fog_rendering \ + shaders/shaders_game_of_life \ shaders/shaders_hot_reloading \ shaders/shaders_hybrid_rendering \ shaders/shaders_julia_set \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 522b50fe0..d638ace51 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -571,6 +571,7 @@ SHAPES = \ shapes/shapes_math_angle_rotation \ shapes/shapes_math_sine_cosine \ shapes/shapes_mouse_trail \ + shapes/shapes_penrose_tile \ shapes/shapes_pie_chart \ shapes/shapes_rectangle_advanced \ shapes/shapes_rectangle_scaling \ @@ -590,6 +591,7 @@ TEXTURES = \ textures/textures_background_scrolling \ textures/textures_blend_modes \ textures/textures_bunnymark \ + textures/textures_cellular_automata \ textures/textures_fog_of_war \ textures/textures_gif_player \ textures/textures_image_channel \ @@ -628,6 +630,7 @@ TEXT = \ text/text_input_box \ text/text_rectangle_bounds \ text/text_sprite_fonts \ + text/text_strings_management \ text/text_unicode_emojis \ text/text_unicode_ranges \ text/text_words_alignment \ @@ -673,6 +676,7 @@ SHADERS = \ shaders/shaders_depth_writing \ shaders/shaders_eratosthenes_sieve \ shaders/shaders_fog_rendering \ + shaders/shaders_game_of_life \ shaders/shaders_hot_reloading \ shaders/shaders_hybrid_rendering \ shaders/shaders_julia_set \ @@ -934,6 +938,9 @@ shapes/shapes_math_sine_cosine: shapes/shapes_math_sine_cosine.c shapes/shapes_mouse_trail: shapes/shapes_mouse_trail.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) +shapes/shapes_penrose_tile: shapes/shapes_penrose_tile.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + shapes/shapes_pie_chart: shapes/shapes_pie_chart.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -992,6 +999,9 @@ textures/textures_bunnymark: textures/textures_bunnymark.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file textures/resources/raybunny.png@resources/raybunny.png +textures/textures_cellular_automata: textures/textures_cellular_automata.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + textures/textures_fog_of_war: textures/textures_fog_of_war.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) @@ -1143,6 +1153,9 @@ text/text_sprite_fonts: text/text_sprite_fonts.c --preload-file text/resources/sprite_fonts/alpha_beta.png@resources/sprite_fonts/alpha_beta.png \ --preload-file text/resources/sprite_fonts/jupiter_crash.png@resources/sprite_fonts/jupiter_crash.png +text/text_strings_management: text/text_strings_management.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) + text/text_unicode_emojis: text/text_unicode_emojis.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file text/resources/dejavu.fnt@resources/dejavu.fnt \ @@ -1351,6 +1364,12 @@ shaders/shaders_fog_rendering: shaders/shaders_fog_rendering.c --preload-file shaders/resources/shaders/glsl100/lighting.vs@resources/shaders/glsl100/lighting.vs \ --preload-file shaders/resources/shaders/glsl100/fog.fs@resources/shaders/glsl100/fog.fs +shaders/shaders_game_of_life: shaders/shaders_game_of_life.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ + --preload-file shaders/resources/shaders/glsl100/game_of_life.fs@resources/shaders/glsl100/game_of_life.fs \ + --preload-file shaders/resources/game_of_life/r_pentomino.png@resources/game_of_life/r_pentomino.png \ + --preload-file shaders/resources/game_of_life/.png@resources/game_of_life/.png + shaders/shaders_hot_reloading: shaders/shaders_hot_reloading.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/shaders/glsl100/reload.fs@resources/shaders/glsl100/reload.fs diff --git a/examples/README.md b/examples/README.md index 148caffe0..d64ed7608 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ You may find it easier to use than other toolchains, especially when it comes to - `zig build [module]` to compile all examples for a module (e.g. `zig build core`) - `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`) -## EXAMPLES COLLECTION [TOTAL: 201] +## EXAMPLES COLLECTION [TOTAL: 205] ### category: core [47] @@ -73,7 +73,7 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind | [core_text_file_loading](core/core_text_file_loading.c) | core_text_file_loading | ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) | | [core_compute_hash](core/core_compute_hash.c) | core_compute_hash | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | -### category: shapes [37] +### category: shapes [38] Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. @@ -116,8 +116,9 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes]( | [shapes_rlgl_color_wheel](shapes/shapes_rlgl_color_wheel.c) | shapes_rlgl_color_wheel | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | | [shapes_rlgl_triangle](shapes/shapes_rlgl_triangle.c) | shapes_rlgl_triangle | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | | [shapes_ball_physics](shapes/shapes_ball_physics.c) | shapes_ball_physics | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) | +| [shapes_penrose_tile](shapes/shapes_penrose_tile.c) | shapes_penrose_tile | ⭐⭐⭐⭐️ | 5.5 | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) | -### category: textures [28] +### category: textures [29] Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/rtextures.c) module. @@ -151,8 +152,9 @@ Examples using raylib textures functionality, including image/textures loading/g | [textures_screen_buffer](textures/textures_screen_buffer.c) | textures_screen_buffer | ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) | | [textures_textured_curve](textures/textures_textured_curve.c) | textures_textured_curve | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) | | [textures_sprite_stacking](textures/textures_sprite_stacking.c) | textures_sprite_stacking | ⭐⭐☆☆ | 5.6-dev | 6.0 | [Robin](https://github.com/RobinsAviary) | +| [textures_cellular_automata](textures/textures_cellular_automata.c) | textures_cellular_automata | ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | -### category: text [15] +### category: text [16] Examples using raylib text functionality, including sprite fonts loading/generation and text drawing, provided by raylib [text](../src/rtext.c) module. @@ -173,6 +175,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat | [text_codepoints_loading](text/text_codepoints_loading.c) | text_codepoints_loading | ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) | | [text_inline_styling](text/text_inline_styling.c) | text_inline_styling | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) | | [text_words_alignment](text/text_words_alignment.c) | text_words_alignment | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | +| [text_strings_management](text/text_strings_management.c) | text_strings_management | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) | ### category: models [27] @@ -208,7 +211,7 @@ Examples using raylib models functionality, including models loading/generation | [models_decals](models/models_decals.c) | models_decals | ⭐⭐⭐⭐️ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) | | [models_directional_billboard](models/models_directional_billboard.c) | models_directional_billboard | ⭐⭐☆☆ | 5.6-dev | 5.6 | [Robin](https://github.com/RobinsAviary) | -### category: shaders [32] +### category: shaders [33] Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module. @@ -246,6 +249,7 @@ Examples using raylib shaders functionality, including shaders loading, paramete | [shaders_lightmap_rendering](shaders/shaders_lightmap_rendering.c) | shaders_lightmap_rendering | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) | | [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) | shaders_rounded_rectangle | ⭐⭐⭐☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) | | [shaders_depth_rendering](shaders/shaders_depth_rendering.c) | shaders_depth_rendering | ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) | +| [shaders_game_of_life](shaders/shaders_game_of_life.c) | shaders_game_of_life | ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | ### category: audio [9] diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 2373fcc9b..1d4fcaf9e 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -208,3 +208,7 @@ others;easings_testbed;★★★☆;2.5;3.0;2019;2025;"Juan Miguel López";@flas others;raylib_opengl_interop;★★★★;3.8;4.0;2021;2025;"Stephan Soller";@arkanis others;embedded_files_loading;★★☆☆;3.0;3.5;2020;2025;"Kristian Holmgren";@defutura others;web_basic_window;★☆☆☆;5.6-dev;5.6-dev;2014;2025;"Ramon Santamaria";@raysan5 +shaders;shaders_game_of_life;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant +shapes;shapes_penrose_tile;★★★★;5.5;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto +text;text_strings_management;★★★☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto +textures;textures_cellular_automata;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant diff --git a/examples/shaders/shaders_game_of_life.c b/examples/shaders/shaders_game_of_life.c index daeb4d789..654e92643 100644 --- a/examples/shaders/shaders_game_of_life.c +++ b/examples/shaders/shaders_game_of_life.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [shaders] example - Conway's Game of Life with shaders +* raylib [shaders] example - game of life * * Example complexity rating: [★★★☆] 3/4 * @@ -97,7 +97,7 @@ int main(void) bool buttonFaster = false; bool buttonSlower = false; - InitWindow(screenWidth, screenHeight, "raylib [shaders] example - conway's game of life"); + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - game of life"); // Load shader Shader shdrGameOfLife = LoadShader(0, TextFormat("resources/shaders/glsl%i/game_of_life.fs", GLSL_VERSION)); diff --git a/examples/shapes/shapes_penrose_tile.c b/examples/shapes/shapes_penrose_tile.c index 354ebb457..304dca3cc 100644 --- a/examples/shapes/shapes_penrose_tile.c +++ b/examples/shapes/shapes_penrose_tile.c @@ -4,7 +4,7 @@ * * Example complexity rating: [★★★★] 4/4 * -* Example originally created with raylib 5.5 +* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev * Based on: https://processing.org/examples/penrosetile.html * * Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5) diff --git a/examples/text/text_strings_management.c b/examples/text/text_strings_management.c index d6b4aeb57..6c110e6ef 100644 --- a/examples/text/text_strings_management.c +++ b/examples/text/text_strings_management.c @@ -60,7 +60,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - InitWindow(screenWidth, screenHeight, "raylib [shapes] example - strings management"); + InitWindow(screenWidth, screenHeight, "raylib [text] example - strings management"); TextParticle textParticles[MAX_TEXT_PARTICLES] = { 0 }; int particleCount = 0; diff --git a/examples/textures/textures_cellular_automata.c b/examples/textures/textures_cellular_automata.c index d24104200..affeeda93 100644 --- a/examples/textures/textures_cellular_automata.c +++ b/examples/textures/textures_cellular_automata.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [textures] example - one-dimensional elementary cellular automata +* raylib [textures] example - cellular automata * * Example complexity rating: [★★☆☆] 2/4 * @@ -64,7 +64,7 @@ int main(void) { // Initialization //-------------------------------------------------------------------------------------- - InitWindow(screenWidth, screenHeight, "raylib [textures] example - elementary cellular automata"); + InitWindow(screenWidth, screenHeight, "raylib [textures] example - cellular automata"); // Image that contains the cellular automaton Image image = GenImageColor(imageWidth, imageHeight, RAYWHITE); diff --git a/projects/VS2022/examples/shapes_ball_physics.vcxproj b/projects/VS2022/examples/shapes_ball_physics.vcxproj index 47bec68f2..9b7e98658 100644 --- a/projects/VS2022/examples/shapes_ball_physics.vcxproj +++ b/projects/VS2022/examples/shapes_ball_physics.vcxproj @@ -51,7 +51,7 @@ - {6B1A933E-71B8-4C1F-9E79-02D98830E671} + {0653AFAF-5578-4C02-AF29-0C873E7634AE} Win32Proj shapes_ball_physics 10.0 diff --git a/projects/VS2022/examples/shapes_penrose_tile.vcxproj b/projects/VS2022/examples/shapes_penrose_tile.vcxproj new file mode 100644 index 000000000..bde99f8c1 --- /dev/null +++ b/projects/VS2022/examples/shapes_penrose_tile.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC} + Win32Proj + shapes_penrose_tile + 10.0 + shapes_penrose_tile + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\shapes + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/examples/text_strings_management.vcxproj b/projects/VS2022/examples/text_strings_management.vcxproj new file mode 100644 index 000000000..41b9b3ac0 --- /dev/null +++ b/projects/VS2022/examples/text_strings_management.vcxproj @@ -0,0 +1,569 @@ + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {1F4722E7-F78E-413F-A106-D3490211EA57} + Win32Proj + text_strings_management + 10.0 + text_strings_management + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\text + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + \ No newline at end of file diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index b541b10fe..f0ff823da 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -421,7 +421,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_rlgl_triangle", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_sprite_stacking", "examples\textures_sprite_stacking.vcxproj", "{FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_ball_physics", "examples\shapes_ball_physics.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_ball_physics", "examples\shapes_ball_physics.vcxproj", "{0653AFAF-5578-4C02-AF29-0C873E7634AE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_game_of_life", "examples\shaders_game_of_life.vcxproj", "{071E64F3-1396-4A97-97CA-98CAC059B168}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_penrose_tile", "examples\shapes_penrose_tile.vcxproj", "{7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "text_strings_management", "examples\text_strings_management.vcxproj", "{1F4722E7-F78E-413F-A106-D3490211EA57}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_cellular_automata", "examples\textures_cellular_automata.vcxproj", "{0A0FC982-6E31-401F-BA77-3C5E8AB02C68}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -5237,30 +5245,126 @@ Global {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x64.Build.0 = Release|x64 {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x86.ActiveCfg = Release|Win32 {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x86.Build.0 = Release|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|ARM64.Build.0 = Debug|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.ActiveCfg = Debug|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x64.Build.0 = Debug|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.ActiveCfg = Debug|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Debug|x86.Build.0 = Debug|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x64.Build.0 = Release.DLL|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release.DLL|x86.Build.0 = Release.DLL|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.ActiveCfg = Release|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|ARM64.Build.0 = Release|ARM64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.ActiveCfg = Release|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x64.Build.0 = Release|x64 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.ActiveCfg = Release|Win32 - {6B1A933E-71B8-4C1F-9E79-02D98830E671}.Release|x86.Build.0 = Release|Win32 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|ARM64.Build.0 = Debug|ARM64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|x64.ActiveCfg = Debug|x64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|x64.Build.0 = Debug|x64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|x86.ActiveCfg = Debug|Win32 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|x86.Build.0 = Debug|Win32 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|ARM64.ActiveCfg = Release|ARM64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|ARM64.Build.0 = Release|ARM64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|x64.ActiveCfg = Release|x64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|x64.Build.0 = Release|x64 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|x86.ActiveCfg = Release|Win32 + {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|x86.Build.0 = Release|Win32 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|ARM64.Build.0 = Debug|ARM64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|x64.ActiveCfg = Debug|x64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|x64.Build.0 = Debug|x64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|x86.ActiveCfg = Debug|Win32 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|x86.Build.0 = Debug|Win32 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|ARM64.ActiveCfg = Release|ARM64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|ARM64.Build.0 = Release|ARM64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|x64.ActiveCfg = Release|x64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|x64.Build.0 = Release|x64 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|x86.ActiveCfg = Release|Win32 + {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|x86.Build.0 = Release|Win32 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|ARM64.Build.0 = Debug|ARM64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|x64.ActiveCfg = Debug|x64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|x64.Build.0 = Debug|x64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|x86.ActiveCfg = Debug|Win32 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|x86.Build.0 = Debug|Win32 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|ARM64.ActiveCfg = Release|ARM64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|ARM64.Build.0 = Release|ARM64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|x64.ActiveCfg = Release|x64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|x64.Build.0 = Release|x64 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|x86.ActiveCfg = Release|Win32 + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|x86.Build.0 = Release|Win32 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|ARM64.Build.0 = Debug|ARM64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|x64.ActiveCfg = Debug|x64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|x64.Build.0 = Debug|x64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|x86.ActiveCfg = Debug|Win32 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|x86.Build.0 = Debug|Win32 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|ARM64.ActiveCfg = Release|ARM64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|ARM64.Build.0 = Release|ARM64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|x64.ActiveCfg = Release|x64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|x64.Build.0 = Release|x64 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|x86.ActiveCfg = Release|Win32 + {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|x86.Build.0 = Release|Win32 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|x64.Build.0 = Debug.DLL|x64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|ARM64.Build.0 = Debug|ARM64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|x64.ActiveCfg = Debug|x64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|x64.Build.0 = Debug|x64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|x86.ActiveCfg = Debug|Win32 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|x86.Build.0 = Debug|Win32 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|x64.ActiveCfg = Release.DLL|x64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|x64.Build.0 = Release.DLL|x64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|x86.Build.0 = Release.DLL|Win32 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|ARM64.ActiveCfg = Release|ARM64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|ARM64.Build.0 = Release|ARM64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|x64.ActiveCfg = Release|x64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|x64.Build.0 = Release|x64 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|x86.ActiveCfg = Release|Win32 + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -5428,7 +5532,7 @@ Global {C54703BF-D68A-480D-BE27-49B62E45D582} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} {0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {CC132A4D-D081-4C26-BFB9-AB11984054F8} + {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {6BFF72EA-7362-4A3B-B6E5-9A3655BBBDA3} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} {6777EC3C-077C-42FC-B4AD-B799CE55CCE4} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} {A61DAD9C-271C-4E95-81AA-DB4CD58564D4} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} @@ -5437,9 +5541,9 @@ Global {3B27F358-2679-4F38-B297-17B536F580BB} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {718FCBD0-591D-448C-B7D5-9F1CA8544E7B} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {19CA0070-B4B2-4394-90B7-D0C259AA35BA} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} - {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} - {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {278D8859-20B1-428F-8448-064F46E1F021} - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {278D8859-20B1-428F-8448-064F46E1F021} + {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} + {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} {8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021} {A4662163-83E7-4309-8CAA-B0BF13655FE6} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {5F4B766F-DD52-4B53-B6C3-BC7611E17F20} = {278D8859-20B1-428F-8448-064F46E1F021} @@ -5473,7 +5577,11 @@ Global {32FE2658-1D70-442E-8672-0AC5C6F0BD7B} = {278D8859-20B1-428F-8448-064F46E1F021} {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F} = {278D8859-20B1-428F-8448-064F46E1F021} {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} - {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021} + {0653AFAF-5578-4C02-AF29-0C873E7634AE} = {278D8859-20B1-428F-8448-064F46E1F021} + {071E64F3-1396-4A97-97CA-98CAC059B168} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9} + {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC} = {278D8859-20B1-428F-8448-064F46E1F021} + {1F4722E7-F78E-413F-A106-D3490211EA57} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} + {0A0FC982-6E31-401F-BA77-3C5E8AB02C68} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29} diff --git a/tools/rexm/reports/examples_issues.md b/tools/rexm/reports/examples_issues.md index 081170806..fceb44429 100644 --- a/tools/rexm/reports/examples_issues.md +++ b/tools/rexm/reports/examples_issues.md @@ -27,3 +27,4 @@ Example elements validated: | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | diff --git a/tools/rexm/reports/examples_validation.md b/tools/rexm/reports/examples_validation.md index 831dbd978..7635a8714 100644 --- a/tools/rexm/reports/examples_validation.md +++ b/tools/rexm/reports/examples_validation.md @@ -221,3 +221,7 @@ Example elements validated: | raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | | embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_penrose_tile | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| text_strings_management | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| textures_cellular_automata | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 91ac3cc707750e987a6bfe8cd072d3e26a430bb6 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 9 Dec 2025 20:02:38 +0100 Subject: [PATCH 10/57] FIX: `LoadRandomSequence()`, using `GetRandomValue()` #5393 --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 20c882e79..5a630b99e 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1765,7 +1765,7 @@ int *LoadRandomSequence(unsigned int count, int min, int max) for (int i = 0; i < (int)count;) { - value = (rand()%(abs(max - min) + 1) + min); + value = GetRandomValue(min, max); dupValue = false; for (int j = 0; j < i; j++) From 3adfde42f7e83c5a8e09afc34b8cac3626466a1b Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Dec 2025 09:21:33 +0100 Subject: [PATCH 11/57] REVIEWED: `rlLoadTeexture()`, max mipmap levels to use #5400 --- src/rlgl.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 6884ad183..6f3620067 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3384,10 +3384,12 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, #if defined(GRAPHICS_API_OPENGL_33) if (mipmapCount > 1) { - // Activate Trilinear filtering if mipmaps are available + // Activate trilinear filtering if mipmaps are available glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount); // Required for user-defined mip count + + // Define thee maximum number of mipmap levels to be used, 0 is default texture size + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount - 1); } #endif From f2a900a60d88004f9adc7bcc2151eb54497570e6 Mon Sep 17 00:00:00 2001 From: Marcos De La Torre <35145332+Marcos-D@users.noreply.github.com> Date: Wed, 10 Dec 2025 00:23:40 -0800 Subject: [PATCH 12/57] [rcore] Fix modulo bias in `GetRandomValue()` (#5392) * Fix modulo bias in GetRandomValue(); implement rejection sampling for uniformity * Replace do-while with for-loop in GetRandomValue rejection sampling --- src/rcore.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 5a630b99e..04f419eee 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1743,7 +1743,30 @@ int GetRandomValue(int min, int max) TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX); } - value = (rand()%(abs(max - min) + 1) + min); + int range = (max - min) + 1; + + // Degenerate/overflow case: fall back to min (same behavior as "always min" instead of UB) + if (range <= 0) + { + value = min; + } + else + { + // Rejection sampling to get a uniform integer in [min, max] + unsigned long c = (unsigned long)RAND_MAX + 1UL; // number of possible rand() results + unsigned long m = (unsigned long)range; // size of the target interval + unsigned long t = c - (c % m); // largest multiple of m <= c + unsigned long r; + + for (;;) + { + r = (unsigned long)rand(); + if (r < t) break; // Only accept values within the fair region + } + + + value = min + (int)(r % m); + } #endif return value; } From bc2057345be3e504b895edb6bfabce5fe7345996 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Dec 2025 09:30:18 +0100 Subject: [PATCH 13/57] REVIEWED: `GetRandomValue()`, explained the new approach to get more uniform random values range --- src/rcore.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 04f419eee..c40fdbae4 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1742,21 +1742,24 @@ int GetRandomValue(int min, int max) { TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX); } + + // NOTE: This one-line approach produces a non-uniform distribution, + // as stated by Donald Knuth in the book The Art of Programming, so + // using below approach for more uniform results + //value = (rand()%(abs(max - min) + 1) + min); + // More uniform range solution int range = (max - min) + 1; // Degenerate/overflow case: fall back to min (same behavior as "always min" instead of UB) - if (range <= 0) - { - value = min; - } + if (range <= 0) value = min; else { // Rejection sampling to get a uniform integer in [min, max] unsigned long c = (unsigned long)RAND_MAX + 1UL; // number of possible rand() results unsigned long m = (unsigned long)range; // size of the target interval - unsigned long t = c - (c % m); // largest multiple of m <= c - unsigned long r; + unsigned long t = c - (c%m); // largest multiple of m <= c + unsigned long r = 0; for (;;) { @@ -1764,8 +1767,7 @@ int GetRandomValue(int min, int max) if (r < t) break; // Only accept values within the fair region } - - value = min + (int)(r % m); + value = min + (int)(r%m); } #endif return value; From 5e8118daf24240fe82db00dd0e90bf355edabe82 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Dec 2025 09:46:06 +0100 Subject: [PATCH 14/57] Update shaders_game_of_life.c --- examples/shaders/shaders_game_of_life.c | 74 ++++++++++++------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/examples/shaders/shaders_game_of_life.c b/examples/shaders/shaders_game_of_life.c index 654e92643..fa841d066 100644 --- a/examples/shaders/shaders_game_of_life.c +++ b/examples/shaders/shaders_game_of_life.c @@ -60,6 +60,8 @@ int main(void) //-------------------------------------------------------------------------------------- const int screenWidth = 800; const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - game of life"); const int menuWidth = 100; const int windowWidth = screenWidth - menuWidth; @@ -80,10 +82,9 @@ int main(void) { "Puffer train", "puffer_train", { 0.1f, 0.5f } }, { "Glider Gun", "glider_gun", { 0.2f, 0.2f } }, { "Breeder", "breeder", { 0.1f, 0.5f } }, { "Random", "", { 0.5f, 0.5f } } }; - const int numberOfPresets = sizeof(presetPatterns) / sizeof(presetPatterns[0]); + + const int numberOfPresets = sizeof(presetPatterns)/sizeof(presetPatterns[0]); - // Variable declaration - //-------------------------------------------------------------------------------------- int zoom = 1; float offsetX = (worldWidth - windowWidth)/2.0f; // Centered on window float offsetY = (worldHeight - windowHeight)/2.0f; // Centered on window @@ -97,8 +98,6 @@ int main(void) bool buttonFaster = false; bool buttonSlower = false; - InitWindow(screenWidth, screenHeight, "raylib [shaders] example - game of life"); - // Load shader Shader shdrGameOfLife = LoadShader(0, TextFormat("resources/shaders/glsl%i/game_of_life.fs", GLSL_VERSION)); @@ -115,7 +114,7 @@ int main(void) EndTextureMode(); Image startPattern = LoadImage("resources/game_of_life/r_pentomino.png"); - UpdateTextureRec(world2.texture, (Rectangle) { worldWidth / 2.0f, worldHeight / 2.0f, (float)(startPattern.width), (float)(startPattern.height) }, startPattern.data); + UpdateTextureRec(world2.texture, (Rectangle){ worldWidth/2.0f, worldHeight/2.0f, (float)(startPattern.width), (float)(startPattern.height) }, startPattern.data); UnloadImage(startPattern); // Pointers to the two textures, to be swapped @@ -143,10 +142,8 @@ int main(void) const float centerX = offsetX + (windowWidth/2.0f)/zoom; const float centerY = offsetY + (windowHeight/2.0f)/zoom; - if (buttonZoomIn || (mouseWheelMove > 0.0f)) - zoom *= 2; - if ((buttonZomOut || (mouseWheelMove < 0.0f)) && (zoom > 1)) - zoom /= 2; + if (buttonZoomIn || (mouseWheelMove > 0.0f)) zoom *= 2; + if ((buttonZomOut || (mouseWheelMove < 0.0f)) && (zoom > 1)) zoom /= 2; offsetX = centerX - (windowWidth/2.0f)/zoom; offsetY = centerY - (windowHeight/2.0f)/zoom; } @@ -156,7 +153,6 @@ int main(void) if (buttonSlower) framesPerStep++; // Mouse management - //---------------------------------------------------------------------------------- if ((mode == MODE_RUN) || (mode == MODE_PAUSE)) { FreeImageToDraw(&imageToDraw); // Free the image to draw: no longer needed in these modes @@ -177,10 +173,8 @@ int main(void) const float offsetDecimalY = offsetY - floorf(offsetY); int sizeInWorldX = (int)(ceilf((float)(windowWidth + offsetDecimalX*zoom)/zoom)); int sizeInWorldY = (int)(ceilf((float)(windowHeight + offsetDecimalY*zoom)/zoom)); - if (offsetX + sizeInWorldX >= worldWidth) - sizeInWorldX = worldWidth - (int)floorf(offsetX); - if (offsetY + sizeInWorldY >= worldHeight) - sizeInWorldY = worldHeight - (int)floorf(offsetY); + if (offsetX + sizeInWorldX >= worldWidth) sizeInWorldX = worldWidth - (int)floorf(offsetX); + if (offsetY + sizeInWorldY >= worldHeight) sizeInWorldY = worldHeight - (int)floorf(offsetY); // Create image to draw if not created yet if (imageToDraw == NULL) @@ -192,6 +186,7 @@ int main(void) EndTextureMode(); imageToDraw = (Image*)RL_MALLOC(sizeof(Image)); *imageToDraw = LoadImageFromTexture(worldOnScreen.texture); + UnloadRenderTexture(worldOnScreen); } @@ -201,32 +196,30 @@ int main(void) { int mouseX = (int)(mousePosition.x + offsetDecimalX*zoom)/zoom; int mouseY = (int)(mousePosition.y + offsetDecimalY*zoom)/zoom; - if (mouseX >= sizeInWorldX) - mouseX = sizeInWorldX - 1; - if (mouseY >= sizeInWorldY) - mouseY = sizeInWorldY - 1; - if (firstColor == -1) - firstColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1; + if (mouseX >= sizeInWorldX) mouseX = sizeInWorldX - 1; + if (mouseY >= sizeInWorldY) mouseY = sizeInWorldY - 1; + if (firstColor == -1) firstColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1; const int prevColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1; + ImageDrawPixel(imageToDraw, mouseX, mouseY, (firstColor) ? BLACK : RAYWHITE); - if (prevColor != firstColor) - UpdateTextureRec(currentWorld->texture, (Rectangle){ floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), (float)(sizeInWorldY) }, imageToDraw->data); + + if (prevColor != firstColor) UpdateTextureRec(currentWorld->texture, (Rectangle){ floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), (float)(sizeInWorldY) }, imageToDraw->data); } - else - firstColor = -1; + else firstColor = -1; } // Load selected preset - //---------------------------------------------------------------------------------- if (preset >= 0) { Image pattern; if (preset < numberOfPresets - 1) // Preset with pattern image lo load { pattern = LoadImage(TextFormat("resources/game_of_life/%s.png", presetPatterns[preset].fileName)); + BeginTextureMode(*currentWorld); ClearBackground(RAYWHITE); EndTextureMode(); + UpdateTextureRec(currentWorld->texture, (Rectangle){ worldWidth*presetPatterns[preset].position.x - pattern.width/2.0f, worldHeight*presetPatterns[preset].position.y - pattern.height/2.0f, (float)(pattern.width), (float)(pattern.height) }, pattern.data); @@ -240,9 +233,12 @@ int main(void) { ImageClearBackground(&pattern, RAYWHITE); for (int x = 0; x < pattern.width; x++) + { for (int y = 0; y < pattern.height; y++) - if (GetRandomValue(0, 100) < 15) - ImageDrawPixel(&pattern, x, y, BLACK); + { + if (GetRandomValue(0, 100) < 15) ImageDrawPixel(&pattern, x, y, BLACK); + } + } UpdateTextureRec(currentWorld->texture, (Rectangle){ (float)(pattern.width*i), (float)(pattern.height*j), (float)(pattern.width), (float)(pattern.height) }, pattern.data); @@ -251,26 +247,25 @@ int main(void) } UnloadImage(pattern); + mode = MODE_PAUSE; - offsetX = worldWidth * presetPatterns[preset].position.x - windowWidth/zoom/2.0f; - offsetY = worldHeight * presetPatterns[preset].position.y - windowHeight/zoom/2.0f; + offsetX = worldWidth*presetPatterns[preset].position.x - windowWidth/zoom/2.0f; + offsetY = worldHeight*presetPatterns[preset].position.y - windowHeight/zoom/2.0f; } // Check window draw inside world limits if (offsetX < 0) offsetX = 0; if (offsetY < 0) offsetY = 0; - if (offsetX > worldWidth - (float)(windowWidth)/zoom) - offsetX = worldWidth - (float)(windowWidth)/zoom; - if (offsetY > worldHeight - (float)(windowHeight)/zoom) - offsetY = worldHeight - (float)(windowHeight)/zoom; + if (offsetX > worldWidth - (float)(windowWidth)/zoom) offsetX = worldWidth - (float)(windowWidth)/zoom; + if (offsetY > worldHeight - (float)(windowHeight)/zoom) offsetY = worldHeight - (float)(windowHeight)/zoom; // Rectangles for drawing texture portion to screen - //---------------------------------------------------------------------------------- const Rectangle textureSourceToScreen = { offsetX, offsetY, (float)windowWidth/zoom, (float)windowHeight/zoom }; + //---------------------------------------------------------------------------------- // Draw to texture //---------------------------------------------------------------------------------- - if ((mode == MODE_RUN) && ((frame % framesPerStep) == 0)) + if ((mode == MODE_RUN) && ((frame%framesPerStep) == 0)) { // Swap worlds RenderTexture2D *tempWorld = currentWorld; @@ -284,10 +279,12 @@ int main(void) EndShaderMode(); EndTextureMode(); } + //---------------------------------------------------------------------------------- // Draw to screen //---------------------------------------------------------------------------------- BeginDrawing(); + DrawTexturePro(currentWorld->texture, textureSourceToScreen, textureOnScreen, (Vector2){ 0, 0 }, 0.0f, WHITE); DrawLine(windowWidth, 0, windowWidth, screenHeight, (Color){ 218, 218, 218, 255 }); @@ -301,8 +298,7 @@ int main(void) DrawText("Presets", 710, 58, 8, GRAY); preset = -1; for (int i = 0; i < numberOfPresets; i++) - if (GuiButton((Rectangle){ 710.0f, 70.0f + 18*i, 80.0f, 16.0f }, presetPatterns[i].name)) - preset = i; + if (GuiButton((Rectangle){ 710.0f, 70.0f + 18*i, 80.0f, 16.0f }, presetPatterns[i].name)) preset = i; GuiToggleGroup((Rectangle){ 710, 258, 80, 16 }, "Run\nPause\nDraw", &mode); @@ -314,8 +310,6 @@ int main(void) buttonFaster = GuiButton((Rectangle){ 710, 382, 80, 16 }, "Faster"); buttonSlower = GuiButton((Rectangle){ 710, 400, 80, 16 }, "Slower"); - //------------------------------------------------------------------------------ - DrawFPS(712, 426); EndDrawing(); From dad93abcf850420c1f22d8c9ac7523680953f81f Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Dec 2025 18:49:52 +0100 Subject: [PATCH 15/57] REXM: Ignore some warnings on GCC/Clang --- tools/rexm/rexm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 72b962874..f1701a3ca 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -72,6 +72,12 @@ // Create local commit with changes on example renaming //#define RENAME_AUTO_COMMIT_CREATION +#if defined(__GNUC__) // GCC and Clang + #pragma GCC diagnostic push + // Avoid GCC/Clang complaining about sprintf() second parameter not being a string literal (being TextFormat()) + #pragma GCC diagnostic ignored "-Wformat-security" +#endif + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -2917,3 +2923,6 @@ static bool TextInList(const char *text, const char **list, int listCount) return result; } +#if defined(__GNUC__) // GCC and Clang + #pragma GCC diagnostic pop +#endif From f3f02b3e17b788594cf510a41912ebc5f80e67b3 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Dec 2025 19:06:41 +0100 Subject: [PATCH 16/57] REXM: examples validation and update --- examples/core/core_clipboard_text.c | 2 ++ examples/examples_list.txt | 10 +++++----- tools/rexm/reports/examples_issues.md | 14 +++++++------- tools/rexm/reports/examples_validation.md | 20 ++++++++++---------- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/examples/core/core_clipboard_text.c b/examples/core/core_clipboard_text.c index 2f8e5712b..59de6509c 100644 --- a/examples/core/core_clipboard_text.c +++ b/examples/core/core_clipboard_text.c @@ -2,6 +2,8 @@ * * raylib [core] example - clipboard text * +* Example complexity rating: [★★☆☆] 2/4 +* * Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev * * Example contributed by Ananth S (@Ananth1839) and reviewed by Ramon Santamaria (@raysan5) diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 1d4fcaf9e..925ad9454 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -51,7 +51,7 @@ core;core_input_actions;★★☆☆;5.5;5.6;2025;2025;"Jett";@JettMonstersGoBoo core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal core;core_highdpi_testbed;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 core;core_screen_recording;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 -core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ananth S";@Ananth1839 +core;core_clipboard_text;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ananth S";@Ananth1839 core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04 core;core_compute_hash;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5 @@ -91,6 +91,7 @@ shapes;shapes_math_angle_rotation;★☆☆☆;5.6-dev;5.6;2025;2025;"Kris";@kri shapes;shapes_rlgl_color_wheel;★★★☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary shapes;shapes_rlgl_triangle;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary shapes;shapes_ball_physics;★★☆☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto +shapes;shapes_penrose_tile;★★★★;5.5;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto textures;textures_logo_raylib;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 textures;textures_srcrec_dstrec;★★★☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5 textures;textures_image_drawing;★★☆☆;1.4;1.4;2016;2025;"Ramon Santamaria";@raysan5 @@ -119,6 +120,7 @@ textures;textures_image_rotate;★★☆☆;1.0;1.0;2014;2025;"Ramon Santamaria" textures;textures_screen_buffer;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers textures;textures_textured_curve;★★★☆;4.5;4.5;2022;2025;"Jeffery Myers";@JeffM2501 textures;textures_sprite_stacking;★★☆☆;5.6-dev;6.0;2025;2025;"Robin";@RobinsAviary +textures;textures_cellular_automata;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant text;text_sprite_fonts;★☆☆☆;1.7;3.7;2017;2025;"Ramon Santamaria";@raysan5 text;text_font_spritefont;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5 text;text_font_filters;★★☆☆;1.3;4.2;2015;2025;"Ramon Santamaria";@raysan5 @@ -134,6 +136,7 @@ text;text_3d_drawing;★★★★;3.5;4.0;2021;2025;"Vlad Adrian";@demizdor text;text_codepoints_loading;★★★☆;4.2;4.2;2022;2025;"Ramon Santamaria";@raysan5 text;text_inline_styling;★★★☆;5.6-dev;5.6-dev;2025;2025;"Wagner Barongello";@SultansOfCode text;text_words_alignment;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates +text;text_strings_management;★★★☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto models;models_animation_playing;★★☆☆;2.5;3.5;2019;2025;"Culacant";@culacant models;models_billboard_rendering;★★★☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5 models;models_box_collisions;★☆☆☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5 @@ -193,6 +196,7 @@ shaders;shaders_basic_pbr;★★★★;5.0;5.5;2023;2025;"Afan OLOVCIC";@_DevDad shaders;shaders_lightmap_rendering;★★★☆;4.5;4.5;2019;2025;"Jussi Viitala";@nullstare shaders;shaders_rounded_rectangle;★★★☆;5.5;5.5;2025;2025;"Anstro Pleuton";@anstropleuton shaders;shaders_depth_rendering;★★★☆;5.6-dev;5.6-dev;2025;2025;"Luís Almeida";@luis605 +shaders;shaders_game_of_life;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant audio;audio_module_playing;★☆☆☆;1.5;3.5;2016;2025;"Ramon Santamaria";@raysan5 audio;audio_music_stream;★☆☆☆;1.3;4.2;2015;2025;"Ramon Santamaria";@raysan5 audio;audio_raw_stream;★★★☆;1.6;4.2;2015;2025;"Ramon Santamaria";@raysan5 @@ -208,7 +212,3 @@ others;easings_testbed;★★★☆;2.5;3.0;2019;2025;"Juan Miguel López";@flas others;raylib_opengl_interop;★★★★;3.8;4.0;2021;2025;"Stephan Soller";@arkanis others;embedded_files_loading;★★☆☆;3.0;3.5;2020;2025;"Kristian Holmgren";@defutura others;web_basic_window;★☆☆☆;5.6-dev;5.6-dev;2014;2025;"Ramon Santamaria";@raysan5 -shaders;shaders_game_of_life;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant -shapes;shapes_penrose_tile;★★★★;5.5;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto -text;text_strings_management;★★★☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto -textures;textures_cellular_automata;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant diff --git a/tools/rexm/reports/examples_issues.md b/tools/rexm/reports/examples_issues.md index fceb44429..14e7a61c5 100644 --- a/tools/rexm/reports/examples_issues.md +++ b/tools/rexm/reports/examples_issues.md @@ -21,10 +21,10 @@ Example elements validated: | **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|[WMETA]| |:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|:-----:| | core_highdpi_testbed | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| rlgl_standalone | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| rlgl_compute_shader | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | -| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | +| rlgl_standalone | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | +| rlgl_compute_shader | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | +| easings_testbed | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ | +| embedded_files_loading | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | +| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | diff --git a/tools/rexm/reports/examples_validation.md b/tools/rexm/reports/examples_validation.md index 7635a8714..45c195415 100644 --- a/tools/rexm/reports/examples_validation.md +++ b/tools/rexm/reports/examples_validation.md @@ -104,6 +104,7 @@ Example elements validated: | shapes_rlgl_color_wheel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_rlgl_triangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shapes_ball_physics | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shapes_penrose_tile | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -132,6 +133,7 @@ Example elements validated: | textures_screen_buffer | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_textured_curve | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | textures_sprite_stacking | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| textures_cellular_automata | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | text_sprite_fonts | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | text_font_spritefont | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | text_font_filters | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -147,6 +149,7 @@ Example elements validated: | text_codepoints_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | text_inline_styling | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | text_words_alignment | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| text_strings_management | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_animation_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_billboard_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | models_box_collisions | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -206,6 +209,7 @@ Example elements validated: | shaders_lightmap_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_rounded_rectangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | shaders_depth_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | | audio_module_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_music_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_raw_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | @@ -215,13 +219,9 @@ Example elements validated: | audio_sound_multi | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_sound_positioning | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | audio_spectrum_visualizer | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| rlgl_standalone | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| rlgl_compute_shader | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | -| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| shapes_penrose_tile | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| text_strings_management | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | -| textures_cellular_automata | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| rlgl_standalone | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | +| rlgl_compute_shader | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | +| easings_testbed | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | +| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ | +| embedded_files_loading | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | +| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | From 2d8e346945352461ab97ad299d4e840a5cd8a0d8 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Dec 2025 19:14:28 +0100 Subject: [PATCH 17/57] Update update_examples.yml --- .github/workflows/update_examples.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update_examples.yml b/.github/workflows/update_examples.yml index 7feba7d89..c4ada2bd1 100644 --- a/.github/workflows/update_examples.yml +++ b/.github/workflows/update_examples.yml @@ -29,8 +29,9 @@ jobs: shell: bash - name: Build and run rexm tool (requires GNU Makefile) - # "rexm update" validates and updates all required examples in raylib and even raylib.com repos, - # note that it calls examples/Makefile.Web internally, so it requires [make] tool available + # "rexm validate" validates examples collection, looking for inconsistencies, it does not rebuild examples + # "rexm update" validates and updates all examples with inconsistencies, pushing fixes to raylib and raylib.com repos + # note that rexm calls examples/Makefile.Web internally, so it requires [make] tool available run: | sudo apt-get update && sudo apt-get install -y libopengl0 libglu1-mesa libx11-dev libxrandr-dev libxcursor-dev libxi-dev libxinerama-dev libgl1-mesa-dev libglu1-mesa-dev cd "${{ github.workspace }}/src" @@ -47,7 +48,7 @@ jobs: export REXM_EXAMPLES_COLLECTION_FILE_PATH="${{ github.workspace }}/examples/examples_list.txt" export REXM_EXAMPLES_VS2022_SLN_FILE="${{ github.workspace }}/projects/VS2022/raylib.sln" export EMSDK_PATH="${{ github.workspace }}/emsdk-cache/emsdk-main" - ./rexm update + ./rexm validate shell: bash - name: Commit changes to raylib repo (DISABLED) From 71a35f661e92c72e1b1bbc10856789fb14efe14c Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 12:33:05 +0100 Subject: [PATCH 18/57] Update rexm.c --- tools/rexm/rexm.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index f1701a3ca..aa491ff23 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -1008,6 +1008,7 @@ int main(int argc, char *argv[]) LOG("INFO: Scanning available example (.c) files to be added to collection...\n"); FilePathList clist = LoadDirectoryFilesEx(exBasePath, ".c", true); + // Load examples collection list file (raylib/examples/examples_list.txt) char *exList = LoadFileText(exCollectionFilePath); char *exListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); bool listUpdated = false; @@ -1024,7 +1025,7 @@ int main(int argc, char *argv[]) for (int i = 1; i < lineCount; i++) { - if ((TextFindIndex(exListUpdated, exListLines[i]) == -1) || (exListLines[i][0] == '#')) + if ((TextFindIndex(exListUpdated, exListLines[i]) == -1) || (exListLines[i][0] == '#')) exListUpdatedOffset += sprintf(exListUpdated + exListUpdatedOffset, "%s\n", exListLines[i]); else listUpdated = true; } @@ -2328,7 +2329,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName) // Example found in collection exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo)); - strcpy(exInfo->name, GetFileNameWithoutExt(exFileName)); + strncpy(exInfo->name, GetFileNameWithoutExt(exFileName), 128 - 1); strncpy(exInfo->category, exInfo->name, TextFindIndex(exInfo->name, "_")); char *exText = LoadFileText(exFileName); @@ -2511,7 +2512,7 @@ static char **LoadExampleResourcePaths(const char *filePath, int *resPathCount) if (!end) break; // WARNING: Some paths could be for saving files, not loading, those "resource" files must be omitted - // HACK: Just check previous position from pointer for function name including the string and the index "distance" + // TODO: HACK: Just check previous position from pointer for function name including the string and the index "distance" // This is a quick solution, the good one would be getting the data loading function names... int functionIndex01 = TextFindIndex(ptr - 40, "ExportImage"); // Check ExportImage() int functionIndex02 = TextFindIndex(ptr - 10, "TraceLog"); // Check TraceLog() @@ -2869,8 +2870,8 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath) char exTitle[64] = { 0 }; // Example title: fileName without extension, replacing underscores by spaces // Get example name: replace underscore by spaces - strcpy(exName, GetFileNameWithoutExt(exHtmlPathCopy)); - strcpy(exTitle, exName); + strncpy(exName, GetFileNameWithoutExt(exHtmlPathCopy), 64 - 1); + strncpy(exTitle, exName, 64 - 1); for (int i = 0; (i < 256) && (exTitle[i] != '\0'); i++) { if (exTitle[i] == '_') exTitle[i] = ' '; } // Get example category from exName: copy until first underscore From 2a566544d4dabdd29628747e0ea2f18de063b69a Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 12:59:55 +0100 Subject: [PATCH 19/57] ADDED: Multiply security checks to avoid crashes on wrongly provided string data #4751 - REVIEWED: Checking `NULL` input on functions getting `const char *text`, to avoid crashes - REVIEWED: `strcpy()` usage, prioritize `strncpy()` with limited copy to buffer size - REPLACED: `strlen()` by `TextLength()` on [rtext] module - REVIEWED: Replaced some early returns (but keeping others, for easier code following) --- src/raudio.c | 15 +- src/raylib.h | 2 +- src/rcore.c | 70 +++++---- src/rlgl.h | 8 +- src/rmodels.c | 16 +- src/rtext.c | 403 ++++++++++++++++++++++++++---------------------- src/rtextures.c | 19 ++- src/utils.c | 4 +- 8 files changed, 289 insertions(+), 248 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index d208bb6eb..429a746eb 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1140,7 +1140,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName) // Get file name from path and convert variable name to uppercase char varFileName[256] = { 0 }; - strcpy(varFileName, GetFileNameWithoutExt(fileName)); + strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; } // Add wave information @@ -2739,11 +2739,13 @@ static const char *GetFileExtension(const char *fileName) return dot; } -// String pointer reverse break: returns right-most occurrence of charset in s -static const char *strprbrk(const char *s, const char *charset) +// String pointer reverse break: returns right-most occurrence of charset in text +static const char *strprbrk(const char *text, const char *charset) { const char *latestMatch = NULL; - for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { } + + for (; (text != NULL) && (text = strpbrk(text, charset)); latestMatch = text++) { } + return latestMatch; } @@ -2766,7 +2768,7 @@ static const char *GetFileNameWithoutExt(const char *filePath) static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 }; memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH); - if (filePath != NULL) strcpy(fileName, GetFileName(filePath)); // Get filename with extension + if (filePath != NULL) strncpy(fileName, GetFileName(filePath), MAX_FILENAMEWITHOUTEXT_LENGTH - 1); // Get filename with extension int size = (int)strlen(fileName); // Get size in bytes @@ -2864,7 +2866,8 @@ static bool SaveFileText(const char *fileName, char *text) if (file != NULL) { - int count = fprintf(file, "%s", text); + int count = 0; + if (text != NULL) count = fprintf(file, "%s", text); if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName); else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName); diff --git a/src/raylib.h b/src/raylib.h index 96dc316ae..c2aa4997d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1145,7 +1145,7 @@ RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previ RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success -RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success +RLAPI bool ChangeDirectory(const char *dirPath); // Change working directory, return true on success RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths diff --git a/src/rcore.c b/src/rcore.c index c40fdbae4..dbc864020 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -113,7 +113,7 @@ #include // Required for: srand(), rand(), atexit() #include // Required for: sprintf() [Used in OpenURL()] -#include // Required for: strlen(), strcpy(), strcmp(), strrchr(), memset() +#include // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset() #include // Required for: time() [Used in InitTimer()] #include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] @@ -1837,8 +1837,8 @@ void TakeScreenshot(const char *fileName) unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; - char path[512] = { 0 }; - strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName)); + char path[MAX_FILEPATH_LENGTH] = { 0 }; + strncpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName), MAX_FILEPATH_LENGTH - 1); ExportImage(image, path); // WARNING: Module required: rtextures RL_FREE(imgData); @@ -2022,7 +2022,7 @@ bool IsFileExtension(const char *fileName, const char *ext) int extLen = (int)strlen(ext); char *extList = (char *)RL_CALLOC(extLen + 1, 1); char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 }; - strcpy(extList, ext); + strncpy(extList, ext, extLen); extListPtrs[0] = extList; for (int i = 0; i < extLen; i++) @@ -2130,11 +2130,11 @@ const char *GetFileExtension(const char *fileName) } // String pointer reverse break: returns right-most occurrence of charset in s -static const char *strprbrk(const char *s, const char *charset) +static const char *strprbrk(const char *text, const char *charset) { const char *latestMatch = NULL; - for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { } + for (; (text != NULL) && (text = strpbrk(text, charset)); latestMatch = text++) { } return latestMatch; } @@ -2161,7 +2161,7 @@ const char *GetFileNameWithoutExt(const char *filePath) if (filePath != NULL) { - strcpy(fileName, GetFileName(filePath)); // Get filename.ext without path + strncpy(fileName, GetFileName(filePath), MAX_FILENAME_LENGTH - 1); // Get filename.ext without path int size = (int)strlen(fileName); // Get size in bytes for (int i = size; i > 0; i--) // Reverse search '.' @@ -2233,7 +2233,7 @@ const char *GetPrevDirectoryPath(const char *dirPath) memset(prevDirPath, 0, MAX_FILEPATH_LENGTH); int pathLen = (int)strlen(dirPath); - if (pathLen <= 3) strcpy(prevDirPath, dirPath); + if (pathLen <= 3) strncpy(prevDirPath, dirPath, MAX_FILEPATH_LENGTH - 1); for (int i = (pathLen - 1); (i >= 0) && (pathLen > 3); i--) { @@ -2472,12 +2472,12 @@ int MakeDirectory(const char *dirPath) } // Change working directory, returns true on success -bool ChangeDirectory(const char *dir) +bool ChangeDirectory(const char *dirPath) { - bool result = CHDIR(dir); + bool result = CHDIR(dirPath); - if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dir); - else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dir); + if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dirPath); + else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dirPath); return (result == 0); } @@ -2708,6 +2708,9 @@ unsigned char *DecodeDataBase64(const char *text, int *outputSize) ['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59, ['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63 }; + + *outputSize = 0; + if (text == NULL) return NULL; // Compute expected size and padding int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings! @@ -3952,7 +3955,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const { if (IsFileExtension(path, filter)) { - strcpy(files->paths[files->count], path); + strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); files->count++; } } @@ -3960,14 +3963,14 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const { if (strstr(filter, DIRECTORY_FILTER_TAG) != NULL) { - strcpy(files->paths[files->count], path); + strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); files->count++; } } } else { - strcpy(files->paths[files->count], path); + strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); files->count++; } } @@ -4011,13 +4014,13 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi { if (IsFileExtension(path, filter)) { - strcpy(files->paths[files->count], path); + strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); files->count++; } } else { - strcpy(files->paths[files->count], path); + strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); files->count++; } @@ -4031,7 +4034,7 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi { if ((filter != NULL) && (strstr(filter, DIRECTORY_FILTER_TAG) != NULL)) { - strcpy(files->paths[files->count], path); + strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1); files->count++; } @@ -4334,22 +4337,25 @@ const char *TextFormat(const char *text, ...) char *currentBuffer = buffers[index]; memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using - - va_list args; - va_start(args, text); - int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); - va_end(args); - - // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred - if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH) + + if (text != NULL) { - // Inserting "..." at the end of the string to mark as truncated - char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0" - snprintf(truncBuffer, 4, "..."); - } + va_list args; + va_start(args, text); + int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); + va_end(args); - index += 1; // Move to next buffer for next function call - if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; + // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred + if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH) + { + // Inserting "..." at the end of the string to mark as truncated + char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0" + snprintf(truncBuffer, 4, "..."); + } + + index += 1; // Move to next buffer for next function call + if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; + } return currentBuffer; } diff --git a/src/rlgl.h b/src/rlgl.h index 6f3620067..67bd90251 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2492,12 +2492,12 @@ void rlLoadExtensions(void *loader) const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string // NOTE: We have to duplicate string because glGetString() returns a const string - int size = strlen(extensions) + 1; // Get extensions string size in bytes - char *extensionsDup = (char *)RL_CALLOC(size, sizeof(char)); - strcpy(extensionsDup, extensions); + int extSize = (int)strlen(extensions); // Get extensions string size in bytes + char *extensionsDup = (char *)RL_CALLOC(extSize + 1, sizeof(char)); // Allocate space for copy with additional EOL byte + strncpy(extensionsDup, extensions, extSize); extList[numExt] = extensionsDup; - for (int i = 0; i < size; i++) + for (int i = 0; i < extSize; i++) { if (extensionsDup[i] == ' ') { diff --git a/src/rmodels.c b/src/rmodels.c index 51e38008e..98209add8 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -2060,7 +2060,7 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName) // Get file name from path and convert variable name to uppercase char varFileName[256] = { 0 }; - strcpy(varFileName, GetFileNameWithoutExt(fileName)); + strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } // Add image information @@ -4306,8 +4306,8 @@ static Model LoadOBJ(const char *fileName) return model; } - char currentDir[1024] = { 0 }; - strcpy(currentDir, GetWorkingDirectory()); // Save current working directory + char currentDir[MAX_FILEPATH_LENGTH] = { 0 }; + strncpy(currentDir, GetWorkingDirectory(), MAX_FILEPATH_LENGTH - 1); // Save current working directory const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness if (CHDIR(workingDir) != 0) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir); @@ -5025,10 +5025,8 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou for (unsigned int j = 0; j < iqmHeader->num_poses; j++) { // If animations and skeleton are in the same file, copy bone names to anim - if (iqmHeader->num_joints > 0) - memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char)); - else - strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); // Default bone name otherwise + if (iqmHeader->num_joints > 0) memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char)); + else memcpy(animations[a].bones[j].name, "ANIMJOINTNAME", 13); // Default bone name otherwise animations[a].bones[j].parent = poses[j].parent; } @@ -6970,7 +6968,7 @@ static Model LoadM3D(const char *fileName) // Add a special "no bone" bone model.bones[i].parent = -1; - strcpy(model.bones[i].name, "NO BONE"); + memcpy(model.bones[i].name, "NO BONE", 7); model.bindPose[i].translation.x = 0.0f; model.bindPose[i].translation.y = 0.0f; model.bindPose[i].translation.z = 0.0f; @@ -7062,7 +7060,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou // A special, never transformed "no bone" bone, used for boneless vertices animations[a].bones[i].parent = -1; - strcpy(animations[a].bones[i].name, "NO BONE"); + memcpy(animations[a].bones[i].name, "NO BONE", 7); // M3D stores frames at arbitrary intervals with sparse skeletons. We need full skeletons at // regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones diff --git a/src/rtext.c b/src/rtext.c index c17fbe9bf..74f68544e 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -67,7 +67,7 @@ #include // Required for: malloc(), free() #include // Required for: vsprintf() -#include // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] +#include // Required for: strcmp(), strstr(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] #include // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] #include // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] @@ -164,9 +164,8 @@ extern void LoadFontDefault(void) { #define BIT_CHECK(a,b) ((a) & (1u << (b))) - // check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return - if (defaultFont.glyphs != NULL && !isGpuReady) - return; + // Check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return + if ((defaultFont.glyphs != NULL) && !isGpuReady) return; // NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl @@ -1453,29 +1452,31 @@ Rectangle GetGlyphAtlasRec(Font font, int codepoint) char **LoadTextLines(const char *text, int *count) { char **lines = NULL; + int lineCount = 0; - if (text == NULL) { *count = 0; return lines; } - - int lineCount = 1; - int textSize = (int)strlen(text); - - // First text scan pass to get required line count - for (int i = 0; i < textSize; i++) + if (text != NULL) { - if (text[i] == '\n') lineCount++; - } + int textSize = TextLength(text); + lineCount = 1; - lines = (char **)RL_CALLOC(lineCount, sizeof(char *)); - for (int i = 0, l = 0, lineLen = 0; i <= textSize; i++) - { - if ((text[i] == '\n') || (text[i] == '\0')) + // First text scan pass to get required line count + for (int i = 0; i < textSize; i++) { - lines[l] = (char *)RL_CALLOC(lineLen + 1, 1); - strncpy(lines[l], &text[i - lineLen], lineLen); - lineLen = 0; - l++; + if (text[i] == '\n') lineCount++; + } + + lines = (char **)RL_CALLOC(lineCount, sizeof(char *)); + for (int i = 0, l = 0, lineLen = 0; i <= textSize; i++) + { + if ((text[i] == '\n') || (text[i] == '\0')) + { + lines[l] = (char *)RL_CALLOC(lineLen + 1, 1); + strncpy(lines[l], &text[i - lineLen], lineLen); + lineLen = 0; + l++; + } + else lineLen++; } - else lineLen++; } *count = lineCount; @@ -1517,23 +1518,26 @@ const char *TextFormat(const char *text, ...) static int index = 0; char *currentBuffer = buffers[index]; - memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using - - va_list args; - va_start(args, text); - int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); - va_end(args); - - // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred - if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH) + memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using + + if (text != NULL) { - // Inserting "..." at the end of the string to mark as truncated - char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0" - snprintf(truncBuffer, 4, "..."); - } + va_list args; + va_start(args, text); + int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args); + va_end(args); - index += 1; // Move to next buffer for next function call - if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; + // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred + if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH) + { + // Inserting "..." at the end of the string to mark as truncated + char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0" + snprintf(truncBuffer, 4, "..."); + } + + index += 1; // Move to next buffer for next function call + if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0; + } return currentBuffer; } @@ -1545,13 +1549,16 @@ int TextToInteger(const char *text) int value = 0; int sign = 1; - if ((text[0] == '+') || (text[0] == '-')) + if (text != NULL) { - if (text[0] == '-') sign = -1; - text++; - } + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1; + text++; + } - for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); + for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); + } return value*sign; } @@ -1564,22 +1571,25 @@ float TextToFloat(const char *text) float value = 0.0f; float sign = 1.0f; - if ((text[0] == '+') || (text[0] == '-')) + if (text != NULL) { - if (text[0] == '-') sign = -1.0f; - text++; - } - - int i = 0; - for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); - - if (text[i++] == '.') - { - float divisor = 10.0f; - for (; ((text[i] >= '0') && (text[i] <= '9')); i++) + if ((text[0] == '+') || (text[0] == '-')) { - value += ((float)(text[i] - '0'))/divisor; - divisor = divisor*10.0f; + if (text[0] == '-') sign = -1.0f; + text++; + } + + int i = 0; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); + + if (text[i++] == '.') + { + float divisor = 10.0f; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) + { + value += ((float)(text[i] - '0'))/divisor; + divisor = divisor*10.0f; + } } } @@ -1631,26 +1641,23 @@ const char *TextSubtext(const char *text, int position, int length) static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - int textLength = TextLength(text); - - if (position >= textLength) + if (text != NULL) { - return buffer; //First char is already '\0' by memset + int textLength = TextLength(text); + + if (position >= textLength) return buffer; // First char is already '\0' by memset + + int maxLength = textLength - position; + if (length > maxLength) length = maxLength; + if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1; + + // NOTE: Alternative: memcpy(buffer, text + position, length) + + for (int c = 0; c < length; c++) buffer[c] = text[position + c]; + + buffer[length] = '\0'; } - int maxLength = textLength - position; - if (length > maxLength) length = maxLength; - if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1; - - // NOTE: Alternative: memcpy(buffer, text + position, length) - - for (int c = 0 ; c < length ; c++) - { - buffer[c] = text[position + c]; - } - - buffer[length] = '\0'; - return buffer; } @@ -1684,7 +1691,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end) if (beginIndex > -1) { - int beginLen = (int)strlen(begin); + int beginLen = TextLength(begin); int endIndex = TextFindIndex(text + beginIndex + beginLen, end); if (endIndex > -1) @@ -1700,84 +1707,86 @@ char *GetTextBetween(const char *text, const char *begin, const char *end) } // Replace text string -// REQUIRES: strstr(), strncpy(), strcpy() +// REQUIRES: strstr(), strncpy() // TODO: If (replacement == "") remove "search" text // WARNING: Allocated memory must be manually freed char *TextReplace(const char *text, const char *search, const char *replacement) { char *result = NULL; - if (!text || !search) return NULL; // Sanity check - - char *insertPoint = NULL; // Next insert point - char *temp = NULL; // Temp pointer - int searchLen = 0; // Search string length of (the string to remove) - int replaceLen = 0; // Replacement length (the string to replace by) - int lastReplacePos = 0; // Distance between next search and end of last replace - int count = 0; // Number of replacements - - searchLen = TextLength(search); - if (searchLen == 0) return NULL; // Empty search causes infinite loop during count - - replaceLen = TextLength(replacement); - - // Count the number of replacements needed - insertPoint = (char *)text; - for (count = 0; (temp = strstr(insertPoint, search)); count++) insertPoint = temp + searchLen; - - // Allocate returning string and point temp to it - temp = result = (char *)RL_MALLOC(TextLength(text) + (replaceLen - searchLen)*count + 1); - - if (!result) return NULL; // Memory could not be allocated - - // First time through the loop, all the variable are set correctly from here on, - // - 'temp' points to the end of the result string - // - 'insertPoint' points to the next occurrence of replace in text - // - 'text' points to the remainder of text after "end of replace" - while (count--) + if ((text != NULL) && (search != NULL)) { - insertPoint = (char *)strstr(text, search); - lastReplacePos = (int)(insertPoint - text); - temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; - temp = strcpy(temp, replacement) + replaceLen; - text += lastReplacePos + searchLen; // Move to next "end of replace" - } + char *insertPoint = NULL; // Next insert point + char *temp = NULL; // Temp pointer + int searchLen = 0; // Search string length of (the string to remove) + int replaceLen = 0; // Replacement length (the string to replace by) + int lastReplacePos = 0; // Distance between next search and end of last replace + int count = 0; // Number of replacements - // Copy remaind text part after replacement to result (pointed by moving temp) - strcpy(temp, text); + searchLen = TextLength(search); + if (searchLen == 0) return NULL; // Empty search causes infinite loop during count + + replaceLen = TextLength(replacement); + + // Count the number of replacements needed + insertPoint = (char *)text; + for (count = 0; (temp = strstr(insertPoint, search)); count++) insertPoint = temp + searchLen; + + // Allocate returning string and point temp to it + temp = result = (char *)RL_MALLOC(TextLength(text) + (replaceLen - searchLen)*count + 1); + + if (!result) return NULL; // Memory could not be allocated + + // First time through the loop, all the variable are set correctly from here on, + // - 'temp' points to the end of the result string + // - 'insertPoint' points to the next occurrence of replace in text + // - 'text' points to the remainder of text after "end of replace" + while (count--) + { + insertPoint = (char *)strstr(text, search); + lastReplacePos = (int)(insertPoint - text); + temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; + temp = strcpy(temp, replacement) + replaceLen; + text += lastReplacePos + searchLen; // Move to next "end of replace" + } + + // Copy remaind text part after replacement to result (pointed by moving temp) + strcpy(temp, text); + } return result; } // Replace text between two specific strings -// REQUIRES: strlen(), strncpy() +// REQUIRES: strncpy() // NOTE: If (replacement == NULL) remove "begin"[ ]"end" text // WARNING: Returned string must be freed by user char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement) { char *result = NULL; - if (!text || !begin || !end) return NULL; // Sanity check - - int beginIndex = TextFindIndex(text, begin); - - if (beginIndex > -1) + if ((text != NULL) && (begin != NULL) && (end != NULL)) { - int beginLen = (int)strlen(begin); - int endIndex = TextFindIndex(text + beginIndex + beginLen, end); + int beginIndex = TextFindIndex(text, begin); - if (endIndex > -1) + if (beginIndex > -1) { - endIndex += (beginIndex + beginLen); + int beginLen = TextLength(begin); + int endIndex = TextFindIndex(text + beginIndex + beginLen, end); - int textLen = (int)strlen(text); - int replaceLen = (replacement == NULL)? 0 : (int)strlen(replacement); - int toreplaceLen = endIndex - beginIndex - beginLen; - result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char)); + if (endIndex > -1) + { + endIndex += (beginIndex + beginLen); - strncpy(result, text, beginIndex + beginLen); // Copy first text part - if (replacement != NULL) strncpy(result + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided) - strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part + int textLen = TextLength(text); + int replaceLen = (replacement == NULL)? 0 : TextLength(replacement); + int toreplaceLen = endIndex - beginIndex - beginLen; + result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char)); + + strncpy(result, text, beginIndex + beginLen); // Copy first text part + if (replacement != NULL) strncpy(result + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided) + strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part + } } } @@ -1788,16 +1797,21 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c // WARNING: Allocated memory must be manually freed char *TextInsert(const char *text, const char *insert, int position) { - int textLen = TextLength(text); - int insertLen = TextLength(insert); + char *result = NULL; - char *result = (char *)RL_MALLOC(textLen + insertLen + 1); + if ((text != NULL) && (insert != NULL)) + { + int textLen = TextLength(text); + int insertLen = TextLength(insert); - for (int i = 0; i < position; i++) result[i] = text[i]; - for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; - for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; + result = (char *)RL_MALLOC(textLen + insertLen + 1); - result[textLen + insertLen] = '\0'; // Make sure text string is valid! + for (int i = 0; i < position; i++) result[i] = text[i]; + for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; + for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; + + result[textLen + insertLen] = '\0'; // Add EOL + } return result; } @@ -1879,11 +1893,13 @@ char **TextSplit(const char *text, char delimiter, int *count) // Append text at specific position and move cursor // WARNING: It's up to the user to make sure appended text does not overflow the buffer! -// REQUIRES: strcpy() void TextAppend(char *text, const char *append, int *position) { - strcpy(text + *position, append); - *position += TextLength(append); + if ((text != NULL) && (append != NULL)) + { + TextCopy(text + *position, append); + *position += TextLength(append); + } } // Find first text occurrence within a string @@ -1891,11 +1907,13 @@ void TextAppend(char *text, const char *append, int *position) int TextFindIndex(const char *text, const char *search) { int position = -1; - if (text == NULL) return position; - char *ptr = (char *)strstr(text, search); + if (text != NULL) + { + char *ptr = (char *)strstr(text, search); - if (ptr != NULL) position = (int)(ptr - text); + if (ptr != NULL) position = (int)(ptr - text); + } return position; } @@ -2029,24 +2047,29 @@ char *TextToCamel(const char *text) // WARNING: Allocated memory must be manually freed char *LoadUTF8(const int *codepoints, int length) { - // We allocate enough memory to fit all possible codepoints - // NOTE: 5 bytes for every codepoint should be enough - char *text = (char *)RL_CALLOC(length*5, 1); - const char *utf8 = NULL; - int size = 0; - - for (int i = 0, bytes = 0; i < length; i++) + char *text = NULL; + + if ((codepoints != NULL) && (length > 0)) { - utf8 = CodepointToUTF8(codepoints[i], &bytes); - memcpy(text + size, utf8, bytes); - size += bytes; - } + // We allocate enough memory to fit all possible codepoints + // NOTE: 5 bytes for every codepoint should be enough + text = (char *)RL_CALLOC(length*5, 1); + const char *utf8 = NULL; + int size = 0; - // Create second buffer and copy data manually to it - char *temp = (char *)RL_CALLOC(size + 1, 1); - memcpy(temp, text, size); - RL_FREE(text); - text = temp; + for (int i = 0, bytes = 0; i < length; i++) + { + utf8 = CodepointToUTF8(codepoints[i], &bytes); + memcpy(text + size, utf8, bytes); + size += bytes; + } + + // Create second buffer and copy data manually to it + char *temp = (char *)RL_CALLOC(size + 1, 1); + memcpy(temp, text, size); + RL_FREE(text); + text = temp; + } return text; } @@ -2060,28 +2083,31 @@ void UnloadUTF8(char *text) // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter int *LoadCodepoints(const char *text, int *count) { - int textLength = TextLength(text); - - int codepointSize = 0; + int *codepoints = NULL; int codepointCount = 0; - - // Allocate a big enough buffer to store as many codepoints as text bytes - int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int)); - - for (int i = 0; i < textLength; codepointCount++) + + if (text != NULL) { - codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize); - i += codepointSize; + int textLength = TextLength(text); + + // Allocate a big enough buffer to store as many codepoints as text bytes + int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int)); + + int codepointSize = 0; + for (int i = 0; i < textLength; codepointCount++) + { + codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize); + i += codepointSize; + } + + // Create second buffer and copy data manually to it + int *temp = (int *)RL_CALLOC(codepointCount, sizeof(int)); + for (int i = 0; i < codepointCount; i++) temp[i] = codepoints[i]; + RL_FREE(codepoints); + codepoints = temp; } - // Create second buffer and copy data manually to it - int *temp = (int *)RL_CALLOC(codepointCount, sizeof(int)); - for (int i = 0; i < codepointCount; i++) temp[i] = codepoints[i]; - RL_FREE(codepoints); - codepoints = temp; - *count = codepointCount; - return codepoints; } @@ -2098,14 +2124,15 @@ int GetCodepointCount(const char *text) unsigned int length = 0; const char *ptr = text; - while (*ptr != '\0') + if (ptr != NULL) { - int next = 0; - GetCodepointNext(ptr, &next); - - ptr += next; - - length++; + while (*ptr != '\0') + { + int next = 0; + GetCodepointNext(ptr, &next); + ptr += next; + length++; + } } return length; @@ -2170,11 +2197,14 @@ int GetCodepoint(const char *text, int *codepointSize) 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - // NOTE: on decode errors we return as soon as possible + int codepoint = 0x3f; // Codepoint (defaults to '?') - int octet = (unsigned char)(text[0]); // The first UTF8 octet *codepointSize = 1; + if (text == NULL) return codepoint; + + // NOTE: on decode errors we return as soon as possible + int octet = (unsigned char)(text[0]); // The first UTF8 octet if (octet <= 0x7f) { @@ -2266,6 +2296,7 @@ int GetCodepointNext(const char *text, int *codepointSize) const char *ptr = text; int codepoint = 0x3f; // Codepoint (defaults to '?') *codepointSize = 1; + if (text == NULL) return codepoint; // Get current codepoint and bytes processed if (0xf0 == (0xf8 & ptr[0])) @@ -2304,15 +2335,15 @@ int GetCodepointPrevious(const char *text, int *codepointSize) { const char *ptr = text; int codepoint = 0x3f; // Codepoint (defaults to '?') - int cpSize = 0; - *codepointSize = 0; + *codepointSize = 1; + if (text == NULL) return codepoint; // Move to previous codepoint do ptr--; while (((0x80 & ptr[0]) != 0) && ((0xc0 & ptr[0]) == 0x80)); + int cpSize = 0; codepoint = GetCodepointNext(ptr, &cpSize); - if (codepoint != 0) *codepointSize = cpSize; return codepoint; diff --git a/src/rtextures.c b/src/rtextures.c index 17065822a..24f21e333 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -771,7 +771,7 @@ bool ExportImageAsCode(Image image, const char *fileName) // Get file name from path and convert variable name to uppercase char varFileName[256] = { 0 }; - strcpy(varFileName, GetFileNameWithoutExt(fileName)); + strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } // Add image information @@ -1125,17 +1125,19 @@ Image GenImageCellular(int width, int height, int tileSize) Image GenImageText(int width, int height, const char *text) { Image image = { 0 }; - - int textLength = (int)strlen(text); - int imageViewSize = width*height; - + + int imageSize = width*height; image.width = width; image.height = height; image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE; - image.data = RL_CALLOC(imageViewSize, 1); + image.data = RL_CALLOC(imageSize, 1); image.mipmaps = 1; - memcpy(image.data, text, (textLength > imageViewSize)? imageViewSize : textLength); + if (text != NULL) + { + int textLength = (int)strlen(text); + memcpy(image.data, text, (textLength > imageSize)? imageSize : textLength); + } return image; } @@ -1484,8 +1486,9 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co { Image imText = { 0 }; #if defined(SUPPORT_MODULE_RTEXT) + if (text == NULL) return imText; + int size = (int)strlen(text); // Get size in bytes of text - int textOffsetX = 0; // Image drawing position X int textOffsetY = 0; // Offset between lines (on linebreak '\n') diff --git a/src/utils.c b/src/utils.c index 892f96cf4..44facea3a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -105,7 +105,7 @@ void TraceLog(int logType, const char *text, ...) { #if defined(SUPPORT_TRACELOG) // Message has level below current threshold, don't emit - if (logType < logTypeLevel) return; + if ((logType < logTypeLevel) || (text == NULL)) return; va_list args; va_start(args, text); @@ -313,7 +313,7 @@ bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileN // Get file name from path char varFileName[256] = { 0 }; - strcpy(varFileName, GetFileNameWithoutExt(fileName)); + strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); for (int i = 0; varFileName[i] != '\0'; i++) { // Convert variable name to uppercase From ae438e804e338d56e0d50873be4e6486bc66a817 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 12:00:15 +0000 Subject: [PATCH 20/57] rlparser: update raylib_api.* by CI --- tools/rlparser/output/raylib_api.json | 2 +- tools/rlparser/output/raylib_api.lua | 2 +- tools/rlparser/output/raylib_api.txt | 2 +- tools/rlparser/output/raylib_api.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json index a1af3c9fc..ce17825a3 100644 --- a/tools/rlparser/output/raylib_api.json +++ b/tools/rlparser/output/raylib_api.json @@ -4646,7 +4646,7 @@ "params": [ { "type": "const char *", - "name": "dir" + "name": "dirPath" } ] }, diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua index 20043c12d..1b5075c35 100644 --- a/tools/rlparser/output/raylib_api.lua +++ b/tools/rlparser/output/raylib_api.lua @@ -4167,7 +4167,7 @@ return { description = "Change working directory, return true on success", returnType = "bool", params = { - {type = "const char *", name = "dir"} + {type = "const char *", name = "dirPath"} } }, { diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt index 3578e41df..bc55918ce 100644 --- a/tools/rlparser/output/raylib_api.txt +++ b/tools/rlparser/output/raylib_api.txt @@ -1763,7 +1763,7 @@ Function 143: ChangeDirectory() (1 input parameters) Name: ChangeDirectory Return type: bool Description: Change working directory, return true on success - Param[1]: dir (type: const char *) + Param[1]: dirPath (type: const char *) Function 144: IsPathFile() (1 input parameters) Name: IsPathFile Return type: bool diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml index ea7792612..5c83e9b86 100644 --- a/tools/rlparser/output/raylib_api.xml +++ b/tools/rlparser/output/raylib_api.xml @@ -1111,7 +1111,7 @@ - + From 6f7cd3a9ab1ded457e198bdf7789e599771ff56e Mon Sep 17 00:00:00 2001 From: Jeffery Myers Date: Thu, 11 Dec 2025 04:37:17 -0800 Subject: [PATCH 21/57] [core] Camera2d comment updates (#5401) * Make the comments on the camera 2d fields more clear about what space each one is in. * rlparser: update raylib_api.* by CI --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/raylib.h | 8 ++++---- tools/rlparser/output/raylib_api.json | 8 ++++---- tools/rlparser/output/raylib_api.lua | 8 ++++---- tools/rlparser/output/raylib_api.txt | 8 ++++---- tools/rlparser/output/raylib_api.xml | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index c2aa4997d..ba80e40c7 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -334,10 +334,10 @@ typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D // Camera2D, defines position/orientation in 2d space typedef struct Camera2D { - Vector2 offset; // Camera offset (displacement from target) - Vector2 target; // Camera target (rotation and zoom origin) - float rotation; // Camera rotation in degrees - float zoom; // Camera zoom (scaling), should be 1.0f by default + Vector2 offset; // Camera offset (screen space offset from window origin) + Vector2 target; // Camera target (world space target point that is mapped to screen space offset) + float rotation; // Camera rotation in degrees (pivots around target) + float zoom; // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale } Camera2D; // Mesh, vertex data and vao/vbo diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json index ce17825a3..66d8e9f30 100644 --- a/tools/rlparser/output/raylib_api.json +++ b/tools/rlparser/output/raylib_api.json @@ -769,22 +769,22 @@ { "type": "Vector2", "name": "offset", - "description": "Camera offset (displacement from target)" + "description": "Camera offset (screen space offset from window origin)" }, { "type": "Vector2", "name": "target", - "description": "Camera target (rotation and zoom origin)" + "description": "Camera target (world space target point that is mapped to screen space offset)" }, { "type": "float", "name": "rotation", - "description": "Camera rotation in degrees" + "description": "Camera rotation in degrees (pivots around target)" }, { "type": "float", "name": "zoom", - "description": "Camera zoom (scaling), should be 1.0f by default" + "description": "Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale" } ] }, diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua index 1b5075c35..192ad963a 100644 --- a/tools/rlparser/output/raylib_api.lua +++ b/tools/rlparser/output/raylib_api.lua @@ -769,22 +769,22 @@ return { { type = "Vector2", name = "offset", - description = "Camera offset (displacement from target)" + description = "Camera offset (screen space offset from window origin)" }, { type = "Vector2", name = "target", - description = "Camera target (rotation and zoom origin)" + description = "Camera target (world space target point that is mapped to screen space offset)" }, { type = "float", name = "rotation", - description = "Camera rotation in degrees" + description = "Camera rotation in degrees (pivots around target)" }, { type = "float", name = "zoom", - description = "Camera zoom (scaling), should be 1.0f by default" + description = "Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale" } } }, diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt index bc55918ce..f60f8fc81 100644 --- a/tools/rlparser/output/raylib_api.txt +++ b/tools/rlparser/output/raylib_api.txt @@ -399,10 +399,10 @@ Struct 13: Camera3D (5 fields) Struct 14: Camera2D (4 fields) Name: Camera2D Description: Camera2D, defines position/orientation in 2d space - Field[1]: Vector2 offset // Camera offset (displacement from target) - Field[2]: Vector2 target // Camera target (rotation and zoom origin) - Field[3]: float rotation // Camera rotation in degrees - Field[4]: float zoom // Camera zoom (scaling), should be 1.0f by default + Field[1]: Vector2 offset // Camera offset (screen space offset from window origin) + Field[2]: Vector2 target // Camera target (world space target point that is mapped to screen space offset) + Field[3]: float rotation // Camera rotation in degrees (pivots around target) + Field[4]: float zoom // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale Struct 15: Mesh (17 fields) Name: Mesh Description: Mesh, vertex data and vao/vbo diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml index 5c83e9b86..1bbeb175c 100644 --- a/tools/rlparser/output/raylib_api.xml +++ b/tools/rlparser/output/raylib_api.xml @@ -155,10 +155,10 @@ - - - - + + + + From 8fa5f1fe2cf7efeda59a5d935a259ccb1cb97f1c Mon Sep 17 00:00:00 2001 From: Jordi Santonja <77529699+JordSant@users.noreply.github.com> Date: Thu, 11 Dec 2025 13:38:08 +0100 Subject: [PATCH 22/57] [examples] Fixed `shaders_game_of_life` for web (#5399) * [examples] Fixed `shaders_game_of_life` for web * Fixed image loadig for rexm --- examples/Makefile.Web | 9 ++++++++- examples/shaders/shaders_game_of_life.c | 23 ++++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/examples/Makefile.Web b/examples/Makefile.Web index d638ace51..7101ed7e3 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -1367,8 +1367,15 @@ shaders/shaders_fog_rendering: shaders/shaders_fog_rendering.c shaders/shaders_game_of_life: shaders/shaders_game_of_life.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ --preload-file shaders/resources/shaders/glsl100/game_of_life.fs@resources/shaders/glsl100/game_of_life.fs \ + --preload-file shaders/resources/game_of_life/acorn.png@resources/game_of_life/acorn.png \ + --preload-file shaders/resources/game_of_life/breeder.png@resources/game_of_life/breeder.png \ + --preload-file shaders/resources/game_of_life/glider.png@resources/game_of_life/glider.png \ + --preload-file shaders/resources/game_of_life/glider_gun.png@resources/game_of_life/glider_gun.png \ + --preload-file shaders/resources/game_of_life/oscillators.png@resources/game_of_life/oscillators.png \ + --preload-file shaders/resources/game_of_life/puffer_train.png@resources/game_of_life/puffer_train.png \ --preload-file shaders/resources/game_of_life/r_pentomino.png@resources/game_of_life/r_pentomino.png \ - --preload-file shaders/resources/game_of_life/.png@resources/game_of_life/.png + --preload-file shaders/resources/game_of_life/spaceships.png@resources/game_of_life/spaceships.png \ + --preload-file shaders/resources/game_of_life/still_lifes.png@resources/game_of_life/still_lifes.png shaders/shaders_hot_reloading: shaders/shaders_hot_reloading.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \ diff --git a/examples/shaders/shaders_game_of_life.c b/examples/shaders/shaders_game_of_life.c index fa841d066..9b9242a0d 100644 --- a/examples/shaders/shaders_game_of_life.c +++ b/examples/shaders/shaders_game_of_life.c @@ -42,7 +42,6 @@ typedef enum { // Struct to store example preset patterns typedef struct { char *name; - char *fileName; Vector2 position; } PresetPattern; @@ -77,10 +76,10 @@ int main(void) const Rectangle textureOnScreen = { 0, 0, (float)windowWidth, (float)windowHeight }; const PresetPattern presetPatterns[] = { - { "Glider", "glider", { 0.5f, 0.5f } }, { "R-pentomino", "r_pentomino", { 0.5f, 0.5f } }, { "Acorn", "acorn", { 0.5f,0.5f } }, - { "Spaceships", "spaceships", { 0.1f, 0.5f } }, { "Still lifes", "still_lifes", { 0.5f, 0.5f } }, { "Oscillators", "oscillators", { 0.5f, 0.5f } }, - { "Puffer train", "puffer_train", { 0.1f, 0.5f } }, { "Glider Gun", "glider_gun", { 0.2f, 0.2f } }, { "Breeder", "breeder", { 0.1f, 0.5f } }, - { "Random", "", { 0.5f, 0.5f } } + { "Glider", { 0.5f, 0.5f } }, { "R-pentomino", { 0.5f, 0.5f } }, { "Acorn", { 0.5f,0.5f } }, + { "Spaceships", { 0.1f, 0.5f } }, { "Still lifes", { 0.5f, 0.5f } }, { "Oscillators", { 0.5f, 0.5f } }, + { "Puffer train", { 0.1f, 0.5f } }, { "Glider Gun", { 0.2f, 0.2f } }, { "Breeder", { 0.1f, 0.5f } }, + { "Random", { 0.5f, 0.5f } } }; const int numberOfPresets = sizeof(presetPatterns)/sizeof(presetPatterns[0]); @@ -214,8 +213,18 @@ int main(void) Image pattern; if (preset < numberOfPresets - 1) // Preset with pattern image lo load { - pattern = LoadImage(TextFormat("resources/game_of_life/%s.png", presetPatterns[preset].fileName)); - + switch (preset) + { + case 0: pattern = LoadImage("resources/game_of_life/glider.png"); break; + case 1: pattern = LoadImage("resources/game_of_life/r_pentomino.png"); break; + case 2: pattern = LoadImage("resources/game_of_life/acorn.png"); break; + case 3: pattern = LoadImage("resources/game_of_life/spaceships.png"); break; + case 4: pattern = LoadImage("resources/game_of_life/still_lifes.png"); break; + case 5: pattern = LoadImage("resources/game_of_life/oscillators.png"); break; + case 6: pattern = LoadImage("resources/game_of_life/puffer_train.png"); break; + case 7: pattern = LoadImage("resources/game_of_life/glider_gun.png"); break; + case 8: pattern = LoadImage("resources/game_of_life/breeder.png"); break; + } BeginTextureMode(*currentWorld); ClearBackground(RAYWHITE); EndTextureMode(); From 2853b28d6d51049543383e0854bb332b9f6ad900 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 18:21:57 +0100 Subject: [PATCH 23/57] REVIEWED: Avoid program crash if GPU data is tried to be loaded before `InitWindow()` #4751 Following raylib design, a warning log message is shown and program can continue execution. Some early return checks have been added on most critical functions. [rtext] Previous implementation checking `isGpuReady` cross-module variable is not needed any more, resulting in a more decoupled code, load failure is managed at rlgl level --- src/platforms/rcore_android.c | 2 -- src/rcore.c | 19 ++++++------- src/rlgl.h | 21 ++++++++++++--- src/rmodels.c | 4 +++ src/rtext.c | 51 +++++++++++++++-------------------- 5 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 88b3b4bba..0caa6f222 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -84,7 +84,6 @@ typedef struct { // Global Variables Definition //---------------------------------------------------------------------------------- extern CoreData CORE; // Global CORE state context -extern bool isGpuReady; // Flag to note GPU has been initialized successfully static PlatformData platform = { 0 }; // Platform specific data //---------------------------------------------------------------------------------- @@ -1042,7 +1041,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // Initialize OpenGL context (states and resources) // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); - isGpuReady = true; // Setup default viewport // NOTE: It updated CORE.Window.render.width and CORE.Window.render.height diff --git a/src/rcore.c b/src/rcore.c index dbc864020..72db47da6 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -387,11 +387,6 @@ RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported s CoreData CORE = { 0 }; // Global CORE state context -// Flag to note GPU acceleration is available, -// referenced from other modules to support GPU data loading -// NOTE: Useful to allow Texture, RenderTexture, Font.texture, Mesh.vaoId/vboId, Shader loading -bool isGpuReady = false; - #if defined(SUPPORT_SCREEN_CAPTURE) static int screenshotCounter = 0; // Screenshots counter #endif @@ -697,7 +692,6 @@ void InitWindow(int width, int height, const char *title) // Initialize rlgl default data (buffers and shaders) // NOTE: Current fbo size stored as globals in rlgl for convenience rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); - isGpuReady = true; // Flag to note GPU has been initialized successfully // Setup default viewport SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height); @@ -1266,7 +1260,14 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) shader.id = rlLoadShaderCode(vsCode, fsCode); - if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault(); + if (shader.id == 0) + { + // Shader could not be loaded but we still load the location points to avoid potential crashes + // NOTE: All locations set to -1 (no location) + shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); + for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; + } + else if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault(); else if (shader.id > 0) { // After custom shader loading, we TRY to set default location names @@ -1282,9 +1283,9 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode) // NOTE: If any location is not found, loc point becomes -1 + // Load shader locations array + // NOTE: All locations set to -1 (no location) shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); - - // All locations reset to -1 (no location) for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1; // Get handles to GLSL input attribute locations diff --git a/src/rlgl.h b/src/rlgl.h index 67bd90251..2124d0daf 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1153,6 +1153,7 @@ static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static rlglData RLGL = { 0 }; #endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +static bool isGpuReady = false; #if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3) // NOTE: VAO functionality is exposed through extensions (OES) @@ -2283,6 +2284,8 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint // Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states void rlglInit(int width, int height) { + isGpuReady = true; + // Enable OpenGL debug context if required #if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43) if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL)) @@ -2395,6 +2398,7 @@ void rlglClose(void) #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) swClose(); // Unload sofware renderer resources #endif + isGpuReady = false; } // Load OpenGL extensions @@ -2799,6 +2803,7 @@ int *rlGetShaderLocsDefault(void) rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) { rlRenderBatch batch = { 0 }; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return batch; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes) @@ -3253,6 +3258,7 @@ bool rlCheckRenderBatchLimit(int vCount) unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding @@ -3411,6 +3417,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // In case depth textures not supported, we force renderbuffer usage @@ -3469,6 +3476,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) int mipSize = size; @@ -3813,6 +3821,7 @@ unsigned char *rlReadScreenPixels(int width, int height) unsigned int rlLoadFramebuffer(void) { unsigned int fboId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; } #if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) glGenFramebuffers(1, &fboId); // Create the framebuffer object @@ -3928,6 +3937,7 @@ void rlUnloadFramebuffer(unsigned int id) unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glGenBuffers(1, &id); @@ -3942,6 +3952,7 @@ unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic) unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glGenBuffers(1, &id); @@ -4107,12 +4118,12 @@ void rlDisableStatePointer(int vertexAttribType) unsigned int rlLoadVertexArray(void) { unsigned int vaoId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return vaoId; } + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (RLGL.ExtSupported.vao) - { - glGenVertexArrays(1, &vaoId); - } + if (RLGL.ExtSupported.vao) glGenVertexArrays(1, &vaoId); #endif + return vaoId; } @@ -4167,6 +4178,7 @@ void rlUnloadVertexBuffer(unsigned int vboId) unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) unsigned int vertexShaderId = 0; @@ -4309,6 +4321,7 @@ unsigned int rlCompileShader(const char *shaderCode, int type) unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) { unsigned int programId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) GLint success = 0; diff --git a/src/rmodels.c b/src/rmodels.c index 98209add8..7458624fa 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -1282,6 +1282,8 @@ void UploadMesh(Mesh *mesh, bool dynamic) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) mesh->vaoId = rlLoadVertexArray(); + if (mesh->vaoId == 0) return; + rlEnableVertexArray(mesh->vaoId); // NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data @@ -1470,6 +1472,8 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform) // Bind shader program rlEnableShader(material.shader.id); + if (material.shader.locs == NULL) return; + // Send required data to shader (matrices, values) //----------------------------------------------------- // Upload to shader material.colDiffuse diff --git a/src/rtext.c b/src/rtext.c index 74f68544e..994869b06 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -127,13 +127,12 @@ //---------------------------------------------------------------------------------- // Global variables //---------------------------------------------------------------------------------- -extern bool isGpuReady; #if defined(SUPPORT_DEFAULT_FONT) // Default font provided by raylib // NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core] static Font defaultFont = { 0 }; #endif -static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines) +static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines) //---------------------------------------------------------------------------------- // Other Modules Functions Declaration (required by text) @@ -164,8 +163,8 @@ extern void LoadFontDefault(void) { #define BIT_CHECK(a,b) ((a) & (1u << (b))) - // Check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return - if ((defaultFont.glyphs != NULL) && !isGpuReady) return; + // Check to see if we have already allocated the font for an image, and if we don't need to upload, then just return + if (defaultFont.glyphs != NULL) return; // NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl @@ -263,17 +262,14 @@ extern void LoadFontDefault(void) counter++; } - if (isGpuReady) - { - defaultFont.texture = LoadTextureFromImage(imFont); + defaultFont.texture = LoadTextureFromImage(imFont); - // we have already loaded the font glyph data an image, and the GPU is ready, we are done - // if we don't do this, we will leak memory by reallocating the glyphs and rects - if (defaultFont.glyphs != NULL) - { - UnloadImage(imFont); - return; - } + // we have already loaded the font glyph data an image, and the GPU is ready, we are done + // if we don't do this, we will leak memory by reallocating the glyphs and rects + if (defaultFont.glyphs != NULL) + { + UnloadImage(imFont); + return; } // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount @@ -330,7 +326,7 @@ extern void LoadFontDefault(void) extern void UnloadFontDefault(void) { for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image); - if (isGpuReady) UnloadTexture(defaultFont.texture); + UnloadTexture(defaultFont.texture); RL_FREE(defaultFont.glyphs); RL_FREE(defaultFont.recs); defaultFont.glyphCount = 0; @@ -384,17 +380,15 @@ Font LoadFont(const char *fileName) { Image image = LoadImage(fileName); if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR); + else font = GetFontDefault(); UnloadImage(image); } - if (isGpuReady) + if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName); + else { - if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName); - else - { - SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance) - TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount); - } + SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance) + TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount); } return font; @@ -515,7 +509,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar) }; // Set font with all data parsed from image - if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture + font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture font.glyphCount = index; font.glyphPadding = 0; @@ -584,7 +578,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING; Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0); - if (isGpuReady) font.texture = LoadTextureFromImage(atlas); + font.texture = LoadTextureFromImage(atlas); // Update glyphs[i].image to use alpha, required to be used on ImageDrawText() for (int i = 0; i < font.glyphCount; i++) @@ -1008,7 +1002,7 @@ void UnloadFont(Font font) if (font.texture.id != GetFontDefault().texture.id) { UnloadFontData(font.glyphs, font.glyphCount); - if (isGpuReady) UnloadTexture(font.texture); + UnloadTexture(font.texture); RL_FREE(font.recs); TRACELOGD("FONT: Unloaded font data from RAM and VRAM"); @@ -1339,8 +1333,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing { Vector2 textSize = { 0 }; - if ((isGpuReady && (font.texture.id == 0)) || - (text == NULL) || (text[0] == '\0')) return textSize; // Security check + if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check int size = TextLength(text); // Get size in bytes of text int tempByteCounter = 0; // Used to count longer text line num chars @@ -2481,7 +2474,7 @@ static Font LoadBMFont(const char *fileName) RL_FREE(imFonts); - if (isGpuReady) font.texture = LoadTextureFromImage(fullFont); + font.texture = LoadTextureFromImage(fullFont); // Fill font characters info data font.baseSize = fontSize; @@ -2523,7 +2516,7 @@ static Font LoadBMFont(const char *fileName) UnloadImage(fullFont); UnloadFileText(fileText); - if (isGpuReady && (font.texture.id == 0)) + if (font.texture.id == 0) { UnloadFont(font); font = GetFontDefault(); From b465b4e2eafea11d931130809ff2cc3592d1aed1 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 21:41:25 +0100 Subject: [PATCH 24/57] RENAMED: Variable names for consistency, `textLength` (length in bytes) vs `textSize` (measure in pixels) --- src/raudio.c | 4 ++-- src/rcore.c | 46 +++++++++++++++++++++++----------------------- src/rlgl.h | 8 ++++---- src/rtext.c | 6 +++--- src/rtextures.c | 4 ++-- src/utils.c | 4 ++-- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index 429a746eb..c65aaa134 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -2770,9 +2770,9 @@ static const char *GetFileNameWithoutExt(const char *filePath) if (filePath != NULL) strncpy(fileName, GetFileName(filePath), MAX_FILENAMEWITHOUTEXT_LENGTH - 1); // Get filename with extension - int size = (int)strlen(fileName); // Get size in bytes + int fileNameLength = (int)strlen(fileName); // Get size in bytes - for (int i = 0; (i < size) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++) + for (int i = 0; (i < fileNameLength) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++) { if (fileName[i] == '.') { diff --git a/src/rcore.c b/src/rcore.c index 72db47da6..dfe7b3398 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2009,10 +2009,10 @@ bool IsFileExtension(const char *fileName, const char *ext) if (fileExt != NULL) { - int fileExtLen = (int)strlen(fileExt); + int fileExtLength = (int)strlen(fileExt); char fileExtLower[16] = { 0 }; char *fileExtLowerPtr = fileExtLower; - for (int i = 0; (i < fileExtLen) && (i < 16); i++) + for (int i = 0; (i < fileExtLength) && (i < 16); i++) { // Copy and convert to lower-case if ((fileExt[i] >= 'A') && (fileExt[i] <= 'Z')) fileExtLower[i] = fileExt[i] + 32; @@ -2020,13 +2020,13 @@ bool IsFileExtension(const char *fileName, const char *ext) } int extCount = 1; - int extLen = (int)strlen(ext); - char *extList = (char *)RL_CALLOC(extLen + 1, 1); + int extLength = (int)strlen(ext); + char *extList = (char *)RL_CALLOC(extLength + 1, 1); char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 }; - strncpy(extList, ext, extLen); + strncpy(extList, ext, extLength); extListPtrs[0] = extList; - for (int i = 0; i < extLen; i++) + for (int i = 0; i < extLength; i++) { // Convert to lower-case if extension is upper-case if ((extList[i] >= 'A') && (extList[i] <= 'Z')) extList[i] += 32; @@ -2163,9 +2163,9 @@ const char *GetFileNameWithoutExt(const char *filePath) if (filePath != NULL) { strncpy(fileName, GetFileName(filePath), MAX_FILENAME_LENGTH - 1); // Get filename.ext without path - int size = (int)strlen(fileName); // Get size in bytes + int fileNameLenght = (int)strlen(fileName); // Get size in bytes - for (int i = size; i > 0; i--) // Reverse search '.' + for (int i = fileNameLenght; i > 0; i--) // Reverse search '.' { if (fileName[i] == '.') { @@ -2232,11 +2232,11 @@ const char *GetPrevDirectoryPath(const char *dirPath) { static char prevDirPath[MAX_FILEPATH_LENGTH] = { 0 }; memset(prevDirPath, 0, MAX_FILEPATH_LENGTH); - int pathLen = (int)strlen(dirPath); + int dirPathLength = (int)strlen(dirPath); - if (pathLen <= 3) strncpy(prevDirPath, dirPath, MAX_FILEPATH_LENGTH - 1); + if (dirPathLength <= 3) strncpy(prevDirPath, dirPath, MAX_FILEPATH_LENGTH - 1); - for (int i = (pathLen - 1); (i >= 0) && (pathLen > 3); i--) + for (int i = (dirPathLength - 1); (i >= 0) && (dirPathLength > 3); i--) { if ((dirPath[i] == '\\') || (dirPath[i] == '/')) { @@ -2323,8 +2323,8 @@ const char *GetApplicationDirectory(void) if (_NSGetExecutablePath(appDir, &size) == 0) { - int len = strlen(appDir); - for (int i = len; i >= 0; --i) + int appDirLength = (int)strlen(appDir); + for (int i = appDirLength; i >= 0; --i) { if (appDir[i] == '/') { @@ -2346,8 +2346,8 @@ const char *GetApplicationDirectory(void) if (sysctl(mib, 4, appDir, &size, NULL, 0) == 0) { - int len = strlen(appDir); - for (int i = len; i >= 0; --i) + int appDirLength = (int)strlen(appDir); + for (int i = appDirLength; i >= 0; --i) { if (appDir[i] == '/') { @@ -2442,12 +2442,12 @@ int MakeDirectory(const char *dirPath) if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid) // Copy path string to avoid modifying original - int len = (int)strlen(dirPath) + 1; - char *pathcpy = (char *)RL_CALLOC(len, 1); - memcpy(pathcpy, dirPath, len); + int dirPathLength = (int)strlen(dirPath) + 1; + char *pathcpy = (char *)RL_CALLOC(dirPathLength, 1); + memcpy(pathcpy, dirPath, dirPathLength); // Iterate over pathcpy, create each subdirectory as needed - for (int i = 0; (i < len) && (pathcpy[i] != '\0'); i++) + for (int i = 0; (i < dirPathLength) && (pathcpy[i] != '\0'); i++) { if (pathcpy[i] == ':') i++; else @@ -2499,10 +2499,10 @@ bool IsFileNameValid(const char *fileName) if ((fileName != NULL) && (fileName[0] != '\0')) { - int length = (int)strlen(fileName); + int fileNameLength = (int)strlen(fileName); bool allPeriods = true; - for (int i = 0; i < length; i++) + for (int i = 0; i < fileNameLength; i++) { // Check invalid characters if ((fileName[i] == '<') || @@ -2528,7 +2528,7 @@ bool IsFileNameValid(const char *fileName) if (valid) { // Check invalid DOS names - if (length >= 3) + if (fileNameLength >= 3) { if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'N')) || // CON ((fileName[0] == 'P') && (fileName[1] == 'R') && (fileName[2] == 'N')) || // PRN @@ -2536,7 +2536,7 @@ bool IsFileNameValid(const char *fileName) ((fileName[0] == 'N') && (fileName[1] == 'U') && (fileName[2] == 'L'))) valid = false; // NUL } - if (length >= 4) + if (fileNameLength >= 4) { if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'M') && ((fileName[3] >= '0') && (fileName[3] <= '9'))) || // COM0-9 ((fileName[0] == 'L') && (fileName[1] == 'P') && (fileName[2] == 'T') && ((fileName[3] >= '0') && (fileName[3] <= '9')))) valid = false; // LPT0-9 diff --git a/src/rlgl.h b/src/rlgl.h index 2124d0daf..c294e0e27 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2496,12 +2496,12 @@ void rlLoadExtensions(void *loader) const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string // NOTE: We have to duplicate string because glGetString() returns a const string - int extSize = (int)strlen(extensions); // Get extensions string size in bytes - char *extensionsDup = (char *)RL_CALLOC(extSize + 1, sizeof(char)); // Allocate space for copy with additional EOL byte - strncpy(extensionsDup, extensions, extSize); + int extensionsLength = (int)strlen(extensions); // Get extensions string size in bytes + char *extensionsDup = (char *)RL_CALLOC(extensionsLength + 1, sizeof(char)); // Allocate space for copy with additional EOL byte + strncpy(extensionsDup, extensions, extensionsLength); extList[numExt] = extensionsDup; - for (int i = 0; i < extSize; i++) + for (int i = 0; i < extensionsLength; i++) { if (extensionsDup[i] == ' ') { diff --git a/src/rtext.c b/src/rtext.c index 994869b06..53e2c0aa5 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1449,17 +1449,17 @@ char **LoadTextLines(const char *text, int *count) if (text != NULL) { - int textSize = TextLength(text); + int textLength = TextLength(text); lineCount = 1; // First text scan pass to get required line count - for (int i = 0; i < textSize; i++) + for (int i = 0; i < textLength; i++) { if (text[i] == '\n') lineCount++; } lines = (char **)RL_CALLOC(lineCount, sizeof(char *)); - for (int i = 0, l = 0, lineLen = 0; i <= textSize; i++) + for (int i = 0, l = 0, lineLen = 0; i <= textLength; i++) { if ((text[i] == '\n') || (text[i] == '\0')) { diff --git a/src/rtextures.c b/src/rtextures.c index 24f21e333..9ec2c33a0 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1488,7 +1488,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co #if defined(SUPPORT_MODULE_RTEXT) if (text == NULL) return imText; - int size = (int)strlen(text); // Get size in bytes of text + int textLength = (int)strlen(text); // Get length of text in bytes int textOffsetX = 0; // Image drawing position X int textOffsetY = 0; // Offset between lines (on linebreak '\n') @@ -1499,7 +1499,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co // Create image to store text imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK); - for (int i = 0; i < size;) + for (int i = 0; i < textLength;) { // Get next codepoint from byte string and glyph index in font int codepointByteCount = 0; diff --git a/src/utils.c b/src/utils.c index 44facea3a..15161b443 100644 --- a/src/utils.c +++ b/src/utils.c @@ -142,8 +142,8 @@ void TraceLog(int logType, const char *text, ...) default: break; } - unsigned int textSize = (unsigned int)strlen(text); - memcpy(buffer + strlen(buffer), text, (textSize < (MAX_TRACELOG_MSG_LENGTH - 12))? textSize : (MAX_TRACELOG_MSG_LENGTH - 12)); + unsigned int textLength = (unsigned int)strlen(text); + memcpy(buffer + strlen(buffer), text, (textLength < (MAX_TRACELOG_MSG_LENGTH - 12))? textLength : (MAX_TRACELOG_MSG_LENGTH - 12)); strcat(buffer, "\n"); vprintf(buffer, args); fflush(stdout); From 9c04b1de822d1adfa9353c2d9ff62d9b53713246 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 13 Dec 2025 11:58:04 +0100 Subject: [PATCH 25/57] REVIEWED: Store canvas name id at platform initialization Useful to support multiple canvases running different wasm instances in same webpage --- src/platforms/rcore_web.c | 67 +++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 2d2f8d1c0..7324e121e 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -76,6 +76,8 @@ typedef struct { bool ourFullscreen; // Internal var to filter our handling of fullscreen vs the user handling of fullscreen int unmaximizedWidth; // Internal var to store the unmaximized window (canvas) width int unmaximizedHeight; // Internal var to store the unmaximized window (canvas) height + + char canvasId[64]; // Keep current canvas id where wasm app is running } PlatformData; //---------------------------------------------------------------------------------- @@ -142,7 +144,11 @@ static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPoin static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData); static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData); -static const char *GetCanvasId(void); +// JS: Set the canvas id provided by the module configuration +EM_JS(void, SetCanvasIdJs, (char *out, int outSize), { + var canvasId = "#" + Module.canvas.id; + stringToUTF8(canvasId, out, outSize); +}); //---------------------------------------------------------------------------------- // Module Functions Declaration @@ -233,7 +239,7 @@ void ToggleFullscreen(void) // This option does not seem to work at all: // emscripten_request_pointerlock() and emscripten_request_fullscreen() are affected by web security, // the user must click once on the canvas to hide the pointer or transition to full screen - //emscripten_request_fullscreen("#canvas", false); + //emscripten_request_fullscreen(platform.canvasId, false); // Option 2: Request fullscreen for the canvas element with strategy // This option does not seem to work at all @@ -245,7 +251,7 @@ void ToggleFullscreen(void) // .canvasResizedCallback = EmscriptenWindowResizedCallback, // .canvasResizedCallbackUserData = NULL // }; - //emscripten_request_fullscreen_strategy("#canvas", EM_FALSE, &strategy); + //emscripten_request_fullscreen_strategy(platform.canvasId, EM_FALSE, &strategy); // Option 3: Request fullscreen for the canvas element with strategy // It works as expected but only inside the browser (client area) @@ -256,10 +262,10 @@ void ToggleFullscreen(void) .canvasResizedCallback = EmscriptenWindowResizedCallback, .canvasResizedCallbackUserData = NULL }; - emscripten_enter_soft_fullscreen("#canvas", &strategy); + emscripten_enter_soft_fullscreen(platform.canvasId, &strategy); int width, height; - emscripten_get_canvas_element_size("#canvas", &width, &height); + emscripten_get_canvas_element_size(platform.canvasId, &width, &height); TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height); CORE.Window.fullscreen = true; // Toggle fullscreen flag @@ -271,7 +277,7 @@ void ToggleFullscreen(void) //emscripten_exit_soft_fullscreen(); int width, height; - emscripten_get_canvas_element_size("#canvas", &width, &height); + emscripten_get_canvas_element_size(platform.canvasId, &width, &height); TRACELOG(LOG_WARNING, "Emscripten: Exit fullscreen: Canvas size: %i x %i", width, height); CORE.Window.fullscreen = false; // Toggle fullscreen flag @@ -866,7 +872,7 @@ void EnableCursor(void) // Disables cursor (lock cursor) void DisableCursor(void) { - emscripten_request_pointerlock(GetCanvasId(), 1); + emscripten_request_pointerlock(platform.canvasId, 1); // Set cursor position in the middle SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); @@ -1097,6 +1103,8 @@ void PollInputEvents(void) // Initialize platform: graphics, inputs and more int InitPlatform(void) { + SetCanvasIdJs(platform.canvasId, 64); // Get the current canvas id + glfwSetErrorCallback(ErrorCallback); // Initialize GLFW internal global state @@ -1347,14 +1355,14 @@ int InitPlatform(void) //---------------------------------------------------------------------------- // Setup window events callbacks emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenFullscreenChangeCallback); - emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback); - emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback); + emscripten_set_blur_callback(platform.canvasId, platform.handle, 1, EmscriptenFocusCallback); + emscripten_set_focus_callback(platform.canvasId, platform.handle, 1, EmscriptenFocusCallback); emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback); // WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review - // Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas) + // Check fullscreen change events(note this is done on the window since most browsers don't support this on canvas) // emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback); - // Check Resize event (note this is done on the window since most browsers don't support this on #canvas) + // Check Resize event (note this is done on the window since most browsers don't support this on canvas) emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback); // Trigger resize callback to force initial size @@ -1362,15 +1370,15 @@ int InitPlatform(void) // Setup input events // NOTE: Keyboard callbacks only used to consume some events, libglfw.js takes care of the actual input - //emscripten_set_keypress_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback); // WRNING: Breaks input - //emscripten_set_keydown_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback); - emscripten_set_click_callback(GetCanvasId(), NULL, 1, EmscriptenMouseCallback); + //emscripten_set_keypress_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback); // WRNING: Breaks input + //emscripten_set_keydown_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback); + emscripten_set_click_callback(platform.canvasId, NULL, 1, EmscriptenMouseCallback); emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenPointerlockCallback); - emscripten_set_mousemove_callback(GetCanvasId(), NULL, 1, EmscriptenMouseMoveCallback); - emscripten_set_touchstart_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback); - emscripten_set_touchend_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback); - emscripten_set_touchmove_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback); - emscripten_set_touchcancel_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback); + emscripten_set_mousemove_callback(platform.canvasId, NULL, 1, EmscriptenMouseMoveCallback); + emscripten_set_touchstart_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback); + emscripten_set_touchend_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback); + emscripten_set_touchmove_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback); + emscripten_set_touchcancel_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback); emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback); emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback); //---------------------------------------------------------------------------- @@ -1691,7 +1699,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but // we are looking for actual CSS size: canvas.style.width and canvas.style.height // EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight); - emscripten_get_element_css_size(GetCanvasId(), &canvasWidth, &canvasHeight); + emscripten_get_element_css_size(platform.canvasId, &canvasWidth, &canvasHeight); for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++) { @@ -1802,7 +1810,7 @@ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent * if (height < (int)CORE.Window.screenMin.height) height = CORE.Window.screenMin.height; else if ((height > (int)CORE.Window.screenMax.height) && (CORE.Window.screenMax.height > 0)) height = CORE.Window.screenMax.height; - emscripten_set_canvas_element_size(GetCanvasId(), width, height); + emscripten_set_canvas_element_size(platform.canvasId, width, height); SetupViewport(width, height); // Reset viewport and projection matrix for new size @@ -1845,21 +1853,4 @@ static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const Emscripte } //------------------------------------------------------------------------------------------------------- -// JS: Get the canvas id provided by the module configuration -EM_JS(char *, GetCanvasIdJs, (), { - var canvasId = "#" + Module.canvas.id; - var lengthBytes = lengthBytesUTF8(canvasId) + 1; - var stringOnWasmHeap = _malloc(lengthBytes); - stringToUTF8(canvasId, stringOnWasmHeap, lengthBytes); - return stringOnWasmHeap; -}); - -// Get canvas id (using embedded JS function) -static const char *GetCanvasId(void) -{ - static char *canvasId = NULL; - if (canvasId == NULL) canvasId = GetCanvasIdJs(); - return canvasId; -} - // EOF From c96669e1238830b5af04aab705aa83cd6d6c6876 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 13 Dec 2025 13:03:41 +0100 Subject: [PATCH 26/57] REVIEWED: Webpage reference comments starting with `REF:`, more consistent with `TODO:` and `NOTE:` comments --- src/platforms/rcore_android.c | 4 ++-- src/platforms/rcore_desktop_glfw.c | 12 ++++++------ src/platforms/rcore_desktop_sdl.c | 4 ++-- src/platforms/rcore_desktop_win32.c | 2 +- src/platforms/rcore_drm.c | 4 ++-- src/platforms/rcore_memory.c | 2 +- src/platforms/rcore_web.c | 10 +++++----- src/rcore.c | 4 ++-- src/rlgl.h | 4 ++-- src/rmodels.c | 4 ++-- src/rtext.c | 2 +- src/rtextures.c | 4 ++-- src/utils.c | 4 ++-- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 0caa6f222..bc8a25f8f 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -1162,8 +1162,8 @@ static GamepadButton AndroidTranslateGamepadButton(int button) static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) { // If additional inputs are required check: - // Ref: https://developer.android.com/ndk/reference/group/input - // Ref: https://developer.android.com/training/game-controllers/controller-input + // REF: https://developer.android.com/ndk/reference/group/input + // REF: https://developer.android.com/training/game-controllers/controller-input int type = AInputEvent_getType(event); int source = AInputEvent_getSource(event); diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 211e0f701..8bd4b3a69 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1122,7 +1122,7 @@ double GetTime(void) // NOTE: This function is only safe to use if you control the URL given // A user could craft a malicious string performing another action // Only call this function yourself not with user input or make sure to check the string yourself -// Ref: https://github.com/raysan5/raylib/issues/686 +// REF: https://github.com/raysan5/raylib/issues/686 void OpenURL(const char *url) { // Security check to (partially) avoid malicious code @@ -1234,8 +1234,8 @@ void PollInputEvents(void) // Map touch position to mouse position for convenience // WARNING: If the target desktop device supports touch screen, this behaviour should be reviewed! // TODO: GLFW does not support multi-touch input yet - // Ref: https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch - // Ref: https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages + // REF: https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch + // REF: https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; // Check if gamepads are ready @@ -1347,7 +1347,7 @@ void PollInputEvents(void) // Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform() // We need to provide these because GLFWallocator expects function pointers with specific signatures // Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch -// Ref: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator +// REF: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator static void *AllocateWrapper(size_t size, void *user) { (void)user; @@ -1945,8 +1945,8 @@ static void CharCallback(GLFWwindow *window, unsigned int codepoint) { // NOTE: Registers any key down considering OS keyboard layout but // does not detect action events, those should be managed by user... - // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 - // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char + // REF: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 + // REF: https://www.glfw.org/docs/latest/input_guide.html#input_char // Check if there is space available in the queue if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 36235a6c8..995336ec0 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1129,7 +1129,7 @@ Vector2 GetWindowScaleDPI(void) #ifndef USING_VERSION_SDL3 // NOTE: SDL_GetWindowDisplayScale was only added on SDL3 - // Ref: https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale + // REF: https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale // TODO: Implement the window scale factor calculation manually TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform"); #else @@ -1279,7 +1279,7 @@ double GetTime(void) // NOTE: This function is only safe to use if you control the URL given // A user could craft a malicious string performing another action // Only call this function yourself not with user input or make sure to check the string yourself -// Ref: https://github.com/raysan5/raylib/issues/686 +// REF: https://github.com/raysan5/raylib/issues/686 void OpenURL(const char *url) { // Security check to (partially) avoid malicious code diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 8a4050332..29702921f 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1239,7 +1239,7 @@ double GetTime(void) // NOTE: This function is only safe to use if you control the URL given // A user could craft a malicious string performing another action // Only call this function yourself not with user input or make sure to check the string yourself -// Ref: https://github.com/raysan5/raylib/issues/686 +// REF: https://github.com/raysan5/raylib/issues/686 void OpenURL(const char *url) { // Security check to (partially) avoid malicious code on target platform diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 68d5b9685..640799b0a 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -220,7 +220,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = { 248, 0, 0, 0, 0, 0, 0, 0, // Gamepads are mapped according to: - // Ref: https://www.kernel.org/doc/html/next/input/gamepad.html + // REF: https://www.kernel.org/doc/html/next/input/gamepad.html // Those mappings are standardized, but that doesn't mean people follow // the standards, so this is more of an approximation [BTN_DPAD_UP] = GAMEPAD_BUTTON_LEFT_FACE_UP, @@ -1013,7 +1013,7 @@ double GetTime(void) // NOTE: This function is only safe to use if you control the URL given // A user could craft a malicious string performing another action // Only call this function yourself not with user input or make sure to check the string yourself -// Ref: https://github.com/raysan5/raylib/issues/686 +// REF: https://github.com/raysan5/raylib/issues/686 void OpenURL(const char *url) { TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform"); diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c index f78b72fed..5a3947561 100644 --- a/src/platforms/rcore_memory.c +++ b/src/platforms/rcore_memory.c @@ -383,7 +383,7 @@ double GetTime(void) // NOTE: This function is only safe to use if you control the URL given. // A user could craft a malicious string performing another action. // Only call this function yourself not with user input or make sure to check the string yourself. -// Ref: https://github.com/raysan5/raylib/issues/686 +// REF: https://github.com/raysan5/raylib/issues/686 void OpenURL(const char *url) { // Security check to (partially) avoid malicious code on target platform diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 7324e121e..dc779d0fb 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -131,7 +131,7 @@ static void MouseEnterCallback(GLFWwindow *window, int enter); // Emscripten window callback events 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 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); static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData); @@ -165,7 +165,7 @@ EM_JS(void, SetCanvasIdJs, (char *out, int outSize), { bool WindowShouldClose(void) { // Emscripten Asyncify is required to run synchronous code in asynchronous JS - // Ref: https://emscripten.org/docs/porting/asyncify.html + // REF: https://emscripten.org/docs/porting/asyncify.html // WindowShouldClose() is not called on a web-ready raylib application if using emscripten_set_main_loop() // and encapsulating one frame execution on a UpdateDrawFrame() function, @@ -243,7 +243,7 @@ void ToggleFullscreen(void) // Option 2: Request fullscreen for the canvas element with strategy // This option does not seem to work at all - // Ref: https://github.com/emscripten-core/emscripten/issues/5124 + // REF: https://github.com/emscripten-core/emscripten/issues/5124 // EmscriptenFullscreenStrategy strategy = { // .scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH, //EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT, // .canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF, @@ -1520,8 +1520,8 @@ static void CharCallback(GLFWwindow *window, unsigned int key) // NOTE: Registers any key down considering OS keyboard layout but // does not detect action events, those should be managed by user... - // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 - // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char + // REF: https://github.com/glfw/glfw/issues/668#issuecomment-166794907 + // REF: https://www.glfw.org/docs/latest/input_guide.html#input_char // Check if there is space available in the queue if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) diff --git a/src/rcore.c b/src/rcore.c index dfe7b3398..24ebb6dec 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1660,8 +1660,8 @@ float GetFrameTime(void) // Wait for some time (stop program execution) // NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could // take longer than expected... for that reason we use the busy wait loop -// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected -// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32! +// REF: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected +// REF: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32! void WaitTime(double seconds) { if (seconds < 0) return; // Security check diff --git a/src/rlgl.h b/src/rlgl.h index c294e0e27..b5955e613 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3914,7 +3914,7 @@ void rlUnloadFramebuffer(unsigned int id) // TODO: Review warning retrieving object name in WebGL // WARNING: WebGL: INVALID_ENUM: getFramebufferAttachmentParameter: invalid parameter name - // Ref: https://registry.khronos.org/webgl/specs/latest/1.0/ + // REF: https://registry.khronos.org/webgl/specs/latest/1.0/ glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId); unsigned int depthIdU = (unsigned int)depthId; @@ -4485,7 +4485,7 @@ void rlSetUniformMatrices(int locIndex, const Matrix *matrices, int count) glUniformMatrix4fv(locIndex, count, true, (const float *)matrices); #elif defined(GRAPHICS_API_OPENGL_ES2) // WARNING: WebGL does not support Matrix transpose ("true" parameter) - // Ref: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/uniformMatrix + // REF: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/uniformMatrix glUniformMatrix4fv(locIndex, count, false, (const float *)matrices); #endif } diff --git a/src/rmodels.c b/src/rmodels.c index 7458624fa..1502e46af 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5998,8 +5998,8 @@ static Model LoadGLTF(const char *fileName) //---------------------------------------------------------------------------------------------------- // Load animation data - // Ref: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins - // Ref: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes + // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins + // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes // // LIMITATIONS: // - Only supports 1 armature per file, and skips loading it if there are multiple armatures diff --git a/src/rtext.c b/src/rtext.c index 53e2c0aa5..0efd7504b 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -167,7 +167,7 @@ extern void LoadFontDefault(void) if (defaultFont.glyphs != NULL) return; // NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement - // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl + // REF: http://www.utf8-chartable.de/unicode-utf8-table.pl defaultFont.glyphCount = 224; // Number of glyphs included in our default font defaultFont.glyphPadding = 0; // Characters padding diff --git a/src/rtextures.c b/src/rtextures.c index 9ec2c33a0..02a9ff1a5 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -4203,7 +4203,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout) /*else if (layout == CUBEMAP_LAYOUT_PANORAMA) { // TODO: Implement panorama by converting image to square faces... - // Ref: https://github.com/denivip/panorama/blob/master/panorama.cpp + // REF: https://github.com/denivip/panorama/blob/master/panorama.cpp } */ else { @@ -5410,7 +5410,7 @@ int GetPixelDataSize(int width, int height, int format) // Module Internal Functions Definition //---------------------------------------------------------------------------------- // Convert half-float (stored as unsigned short) to float -// Ref: https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308 +// REF: https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308 static float HalfToFloat(unsigned short x) { float result = 0.0f; diff --git a/src/utils.c b/src/utils.c index 15161b443..09158893a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -446,7 +446,7 @@ void InitAssetManager(AAssetManager *manager, const char *dataPath) } // Replacement for fopen() -// Ref: https://developer.android.com/ndk/reference/group/asset +// REF: https://developer.android.com/ndk/reference/group/asset FILE *android_fopen(const char *fileName, const char *mode) { if (mode[0] == 'w') @@ -454,7 +454,7 @@ FILE *android_fopen(const char *fileName, const char *mode) // NOTE: fopen() is mapped to android_fopen() that only grants read access to // assets directory through AAssetManager but we want to also be able to // write data when required using the standard stdio FILE access functions - // Ref: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only + // REF: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only #undef fopen return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode); #define fopen(name, mode) android_fopen(name, mode) From 6f5cabf60ceb60c44e7c7b5f1b1db9e89f1da9a3 Mon Sep 17 00:00:00 2001 From: Kaluub <60589762+Kaluub@users.noreply.github.com> Date: Sun, 14 Dec 2025 11:43:54 -0500 Subject: [PATCH 27/57] Fix misleading example text. (#5409) --- examples/core/core_2d_camera.c | 4 ++-- examples/core/core_2d_camera.png | Bin 21470 -> 8530 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/core/core_2d_camera.c b/examples/core/core_2d_camera.c index b752a9640..7e5a14a70 100644 --- a/examples/core/core_2d_camera.c +++ b/examples/core/core_2d_camera.c @@ -125,8 +125,8 @@ int main(void) DrawRectangle( 10, 10, 250, 113, Fade(SKYBLUE, 0.5f)); DrawRectangleLines( 10, 10, 250, 113, BLUE); - DrawText("Free 2d camera controls:", 20, 20, 10, BLACK); - DrawText("- Right/Left to move Offset", 40, 40, 10, DARKGRAY); + DrawText("Free 2D camera controls:", 20, 20, 10, BLACK); + DrawText("- Right/Left to move player", 40, 40, 10, DARKGRAY); DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, DARKGRAY); DrawText("- A / S to Rotate", 40, 80, 10, DARKGRAY); DrawText("- R to reset Zoom and Rotation", 40, 100, 10, DARKGRAY); diff --git a/examples/core/core_2d_camera.png b/examples/core/core_2d_camera.png index d2f9e634f6fc1798e8466900973fb961f0133c9a..a0fdabb497a870bf7abd19a273b0d57b984d57a6 100644 GIT binary patch literal 8530 zcmZ`W3(=}Y*&RK$WQ)>73#rg3$&%fWEYVP@>_m|)k)^bt zRHRZ$cq|Fo*Q`a%d!5m*-}`w#pZAYG&YW}Z>%Q;n`d;7bd)=o{6C+*0g^~*qLV~;W zv`i7=V<1F$PFVnVmfB=j!XJS%dIy{l5_*CEBV1c2v>YJ@+NGtr*FAo)r8M)HZEVB$ zPnTj(c&Dqr)p4slTGtDv&H!%=?~lQ*y4=B`uPrV|!}t-r3B@syD#f1OX@ z)xyO>VsCE|mv3)8_OF9=@wu|sb}g$m>_rTpgxK=D%dzH$OE-@A(tU))f7EEGSNV|c zyjr(kI4I0AsY`uCwHBk`aiW@ z%j7SPc$V0Gq~yj71=)J_eyJ~xFrg8M2nC8T5W*w~rb;YkWVNKZN0v2VLvE15`<}QD z6;I~c!YmWd=l|daxgLDtbr}X@9as2{Nd&c}J}6RN(Cyy#*wI+$oeHIBO)Vop3Viww!)goOJQp$zHEDFiEYKTD4C^g`5oI(q^*1 zOB$ndGnrtQBmn!jHRWpi^}bj+;bFFBaj`m?)w}vw->2NV>1~-Uvqp#R)fzvuP{VvD z8#R_colPzM8C;mu*W>IvzJn|8;q{*W>)Ehi(%c01ov$E5(*>_dtEaW++QtThD;kmt z=_^V^Ngsb2MUMV3qTXq3ey!7+q+IxId7ZJ(no1?1(qix4TdQt-_$#aU>cvWdR~EKS zeZz`V--YMCPMvNpiL)4(8yJ}io>FtWlwcE~AWcADKgbZy{z!4>k|*|J1Fh-`&!R1c zV;}kC-YszGl{QxrRyg0WvqgXWP4$tfL#tHI&e{t-uNO)9TJQZhZ zz&6M}MYHU-82j#=<5U&j9q&9_+#Tn+bvnZ}D`STKMSVj3a#a6L`z-5g6_Vl~h-Q&- zrw^4(zWUsTr;2X}=bqn>_K_OP6}CsU)dj=$3adX>;h|UJfI#FZg_=xOg(`9FyT7_PEeNc^yX@KJ=tM9AYn`4T+c7=(|@%&2;{f|;syxoq)qb+Y|R zti*k|t><1#QiA6|d{acrxoVrPMB5=B{i!!e+-*}L2vvS9ZsupcnH5$qo}6h38!vCF zpM2>hyi}vYTF=499A3zdK{59i1?FWu8zOV}QsOU0*ZxqPY_^Fo4oxqg`P++QX6rFF z8=<>q$>XM0Z*E8WgF#;nSMEP@Q@^_`)u zlU6r+n)GdCGOF9~>HFd&j>5!qzxC>`hBW>no7K0JcID07YTl@aP~VyU(ZU@$LXJ;< zjgBop=RI4#G&thRLM5}1kbT*b)g#Z(wVw8z%{wF4X3;$UHUDw>%g0NLBlc|j9oFPd zxk?_nT3!{6+`Pg2oQ~s@_k1W>t;Gm)cjy<*(@}rn^BY9o*H7YKV)34d%1K2 zEh6MHc-!kpxB5=m-@u3tC|mq^m~`{+_od#OAhgwWpTxB0u|(lPQhxDyh4sj)8>7#z!(sFtFs+p-KCGX~j*^1Lg+D9xbRfmV19?xuiTD{3{?o+zIy!cAT z67Khbru4*B6Laa+_qow|V~gl@_u~Q%HcxMx+T-5-^Tx1X>CE7c;s`=nU_0NjfeX`7 zd3Pkd4pzAw>+`6Ky>D>Hc4#o;{pN0EC>^xJKZcsDC4!c3>I$}g_`O}dbJE7&$!nt2TV|N;{waf0D33ncORbbs30vc|WS%D>2aOSUtYdb@aZUSJkpE zgEMYZF&1927Oqv_<;Y6OcsmT;=NED@X>Keikk^eX*>I{*l-o5XwQwS@$c|nqvzqh zhVmi6qD1uAQaZPLG=I&5Cq5nOxR78vETxs_O3^=&DCpf*GJ)Cp&R$oNuyYBo>Wd>w zS!+SoP=QT2P#coT7NO0MD6jDfET_j)1R?PO>ks8AYvV91m(S7|l=!5@_Wu5*yryXw zz>~!aZ}F=xOwYMI{VU^r{U(jW%S|{n85 zP4NLoDvKxAh_Xs=9Lt^&h6F?GX4AS{{b;vvc(2H0dii~PF9&Snw|yybdW|5}pG@JjY5~VC5 z-rDfrLiBD4qf>-|4f>9LEcKao&Zzm`SN_1UxvqsoLP5{ONO$Tts?JSjmM)$#A6F2d zisuKBdqJ3;;mq1swE9lmF!np#ucEn900+j0y)Lyz>@(uO0mEWqp_BWwOl!B3MHmQ0 z9?1N}*^EPAON`2(oj+=G_^<0zPHi5%W6vX(vR9rKy!eu~lI0@gD7n|@;6D*Y)^ka5 zRAy70Mk~y+#^+=Debl)L6O{?wn|2xVk3 zvs0m**-QoaOda(dAba;Mnw^pIzTY@#W26(!;R_|&kv^rInTV*4-NO5mRLF%|dRy*Ifk(UFti^h~Tc~<1)`8DOS4Ar=`9rcfZ zp{`{|_0zwUJT~g{++XE7b)-Nl?&RMy`5COg7d*?8tIBiNE1s(pU51hk(r8UMq>e-m z8xzhxkviJ9eS8OV7oH1%e`E#z*Ru6gg( zS9JR-=bvJ(uO;dA=~;XGz-SAEb{B}z3hg#xL2WL9;TOszMMLwpzAfg~{`-o)3G*;@_?RBD;`Yg5FR$35jC zr2IYA&pT>{Vj{?kTbX?t?fc0Pj*odRWg<@M31cTp*2HfuiohGDvX%HX7$63oNn`x( zm}*pNMDAU{cZQJSYj8{5bKY*`s|r>f&ct05dEw8>>|%N{O6-x1LpK%waL-Y|UgF4|^H6V?q4v6}HG8B8L=z=m2*$NtzO7L0lg4DP z07>iHzFeEwV~4+~cdSvw*rh<1ZL_J@*1!Acf;=Q=Vo(6cVX44@yJ{Z1RNQ zqIr(a@?_>+gvZhtVsDJWow@itx=F-?$g3EgoAI6DF=Th~9vcA4v8%Xe&YO`a`~LXA zd_7=Di{BZdlI)3lnSZwcmA!x$y<^L9NAq_tVeBmj;w-mnynMdL$`BkYo7e-3Yq*GR zuKk0Xclg#utXTNti?|asR|CY3tx+DO(!VjVJDfkD$;rpP85svo*vVU5los1WdYBGNZ{-K=OBAoq&0@Y3rPb zEq*na{)5sdj{EcTi2~GEt9i#8!zSQf3Ljk*9t+f54jy6mlPFlQesnLU5yeX)xMaa8V!Vm6->jk*>UjL_)KbTb$QpHSgiKt1!EZzz|KIg1cSb zK5!8Pj!5ibcLKsQEhOo6xm_ZF0Aa->1g9fuw0aUBt?OgSSxPJ;b# ztYYl<<-%9D)ok{v00qoRy$xa*s;tq;xBv^4833%WTd zSJ_Zt^Y-H~sZFMaa2zm3d%S({$G#Hh@iIIm*joTh)dty2d_-GC>2y)FoZcdk7G?&T zU7|D-b;8b1S=P_C7CwEDTBnfZoO=FvAb;&YY_u(_sOL@$&w+ibF}p-LirTy*LZjW7 z<&TV9uvu{XDvNlxs7FD^@ub02;KoafaE@uGx1;VoGinXt)DnivGfDC6f48XWTb5TT zk-rCxLPQz?PHU|jMJg`tQ*9&6QW-AgVu2Q&l!%XM3=#b#w}OX3(#pxkz&=0)2O^6(+ELQ8CE_T^R@6Tn7Yj$ezXQHqx|+cB?IdVQf$*>@++I^fI_imdD|+ znZ>+qsA*a#KNxM=C#L0sGDwsb2-}2mQPAhJE>Q;V$Qk@Zyta)jm%!VzVlcY78)BC8 zLLuu*I!&oASBpPaoIu1Be1By+2DkNT-l(}8HiGJ8FtqTvV1J$zx34K(V>k`wt9Ff5 z4-vB3O$>x$8Q@aGV%pT?Ic7TQ+{0(HIUn){J3HGHO;N17A-E~+m= z7bGq7l*2E_TO2H3Lc=l*AeKvtgO200iaZ&Z73fzzzkhyS87BQ}`p%5nMi@V~1%s+F zUXJG!@`S@RegjR}77G@WrKM|c7AZ*)PCf^#*t)^*ACC+cGllPKOe*21;G$#$=X3^M zK!n&%G7Ndpj@cp6Zc#-+*Sr?4R7D(>WsEcia>bce8GVdlqrE5n1lOH&iP}yMh38$O z40%AGg56KS&hCb@kl84HjU2v|s19DTl{}oVZ`hGKW#EFcDo7-bJo)D8$0HBnZr9at zmXqLaca*hB2{X_{?KC45J)i|J;qZn8sB%uV$#&EkP8dNUE3mI57E?>k=jB>$z+!qD zBZZIgB?|$*ayRn09Xl+;h%6HeEX-CLl(iSkERd_@j38O4K@=!A!^VE2sn%3F(vG1q z>T=OXZ5`cRW|8r8<7+hFgcfn+3I1AjxzVW?c0?tus*t=sg6@>3AUHyN2;u;sU?L?- zWp9lVr%7j9pHd==(9y&ahCFm6Zk|W-sx)0tfwdExSx)pcYb>zQ2h+~r(8*|anL!$3 zcJm_gIi)p!|T(T&Y=`UBg9Wo;3aT3IKpjANN~6*p)ARpH54byBA~5iKsaA`&yVkYi4~Tzj||GLrZK z64>DtXtv%O0*WJtD6H?nbGMCvZ7{&Bjzju^J=O}IJ=;$ZQ2!z*u@)3zGz~fO7Ps?; zXJ;vaxZKVOuSsx&fR%0+rm~nOJMh}b$G#rJF4H-g7yt|JSL4|N_AZwX;T-f721}w# z08_~ad0B)!PY{XA*SgMEH^q07;+WKP;tMg-=vG{;ps&iJRJ(YbUh?AQC>Tg?hxLFr zTxlSNp&ei-;M4(7J*voxE=r~3c8a~gQ@Y{0!g_Ym1^y5@O1v?ywa`~@8HR}n5Bn%< zHyew*&0<2Jv~+y|-;LL#AqSt~!Z?s0IlL#4hzYUy@$0I*7y|^riAnW{1(%+V~5zz51 z1pi9|#wu=Y&x*8k;~<9{S7KJ$88vz1Dw-0og=G4_d@m%$Hz*#=JL;9fhx($_uw?V@ z9A-?wThMjKfqrP(B-oPzPst(t7bU8Cc~wWK5W*KJAW~y3*e}!eObp<2N>&CowP)e{ zp2t(8k$?Qz9Oi^FS%kJ8uwbG=*jdk01E|Mx4`fal<%>MU?LuMlL(nmdKRJ3W3?|bz@diko4Cd7%6qWV^ z-SkbPy@}6l*b{qc3^g8J zk_7?kRi-}d0#)+715nXE_@%>35OkChxs%sGBunA%)o8J6=VcTi;@fBV#oG@8*j6#H z`Q$*T(_RMC$Ez+#QN%v0Aj**DsZb;bPWo2Am;EjNKd(;Muf@*tnk%5R0Q5~76X&%v z2sM5<$aW|Mr37689IDxG#Oi=)z>P)F+c1)3_`WsEh0KTaL$D0rF*zR1pyW+0{PVY? z%D_GJcMB@>6xQSV8$LAtiX|yanZ*tS%xc5>Id|XU|C0H$bxnN%I_rw75B(%wu*Vmb+F**PO=<-Dh zb$%D@zweVnpq7ZzPz6Ax;jkV18;5haJ{On>-KGfO{k#@`*%pu$O^xfZv&Jf(tKqYb zY)c=(bh;q*B@e6E26F-2UJ9R;3IwkxUlBXW;l!phfU?-J?}Q>h?$5G-VeK&i$YGTn zb~4eeRv%XUAtjaYakL<{cHYVx9ll$gBeIu!knB}h^2DVDAxn^;-vrs&-v=j)@c|Hh^e|@z9f<2ec5u2@=1Hp5$9E7fg9UZs0t$FRgt0YL zh^-F0WCkOT_FBB`p|YQ(N)h~VoiwHcW?q3TfTqTyU4uJd3?FzAimi8LLpkpPCRQ}Q zK>!(r7!jw5pqUZo`;I?k1mTBa=sIf)hPyT@BL<1kkQThoOq)iaJ&;MnT0Y+E33nHQ z`onfXXy5Ml#;qbd-OGfP;Lv14Z8Dfj-VUa^UeiG_!RO1%(zwYDAZ+xOO5)B$(?uS< zVOF;Jxao1=Yb5E}*X&E+oB#Djr5Nd}^6xJ$ z;0p=3Tn-1RBfK;2|BganmoB3dyVDu(vz;Wscc<`&;xxD+!$6V# za9pedcYLQ=5_DtD$=0P;w)_R32M{_jGdDAQ??Pq6dmGSlh@JoTKm|0_k)bd`7Y+$f z^x%kLZ}}O|*^?5muw%y;5^EhacAB=^;6KrsphJPTN`$rW_1S)xaY1)L!6dKYofEE| pS^);tqw#0B|L_l=e=fVYe6!C5xOPvpt>GTprER2@v(qZze*kLFeNX@Z literal 21470 zcmaJ}c|gqR|DUOmp{XWErqVHT?iL**otld2AabltYncuiu{J4^YpO979TRPcD3g?9 zw@6xxoeqlCY80Eh6k8Orxv$^*d7jUwto8l*BONo(=Xu`8>-~Bk&m{ZL@X{G*G?2ky z==gX~nayBmnll*8O12jKW?0D4S_Wgz0iP-Eb7K~UtS?ylVPDXY6uC;m{_+=wiHCHl zAk)iJEMSSg_(i&qZ+(Ml=(kMCw>HxF(ie`>M4_JYKmG`B==2arX@v@ArT?#O)LXFv zimz913Nusd#;pJNK@ycJS1H&`zJ8i|r;&=weLJ|ad&}awq$JH13oock?WO$g*A?md z`X7!2FA_CeXAfW&yd9)m>1w3mY0o-ab2F$s=bj;V{?v2okv5<1S<_S_H?79IV|~i# zlWHzcCl0<`rfH++6u<@K~AZw@Gdyi*PK%oifIe1{af5xYbw)gcEN9`IK&Q61$_P9)R(zXrUsC$qr=3leBWwnVt_9qiRLo9Dk z7uLf2zni93!FDtG)=mvJ+1B*ZuVf7EaSP|~s7?O%b&cK=uZHsyHs=kuxh>c*b(AHa zTavl4#dh|LYK^XbhOYWsk9FGLcxpa;BOFmZxJ0z|ITl0S5DleOiMq$>o=5ZBlWrVk zjv{XBi;PmvveFp78%yMDsw`R}U|D-IN;z8ty`BX-8x38wbJchkR+j0wH{uWHhK??d zFwfU5*i@cqT=e>u4=+$|Elj8A#+D>?2U z4P{MtTESI)V+|yTcC&IW&vo0Hwt}F_E7;y?>;MfAHr~DiI%vC8mfEUj4_radI^V0&^OUgu5;J2e-i}zk1Zcl zow0u86G=_N#-epmhSzF~t`wdaCTp6tF}yBJ;e1%=Z8rX8#$mnpjlWbp-n3xczIiR8 zr8AWC`-esugqAL`qm0?Y8SBKc&uJORsNi{9_06ylcf*F<<%jdUpn|frO&zYB+JAQ3+>bESn>WBKA_@Vjd)Z>6M&_s0&sipqn`d*`=Yd~$ zPvm8P=anfBrWGq*#y4jdnSZmVsdi+Ug@@G|^~Ft%f?;6>M;b&vO|1>ijbYiM9YLw9 zFN-{-U|U@=DFr(zqk|nrdP+x|aC;U9)TYi_pfe|QWt-e;{K`zz3w-?DI@rf#NI@QxgH!&+g5O;Mp6^f-qs37$e8nB zo1L~thtWpg=gJ!0yg3JJU5{?Pad5rPiCx^-eUYN&KPz7kvfSy(wmMgNHCgr7ufi8? z>y0{X_}5khJA1Zgc%;2fIO;I^a3rhAn1Ek}<2b`aQ6pZQPun?Y48<yj8Gc$i0acy!`wCA}T*=(bu?`J-VP)1$8klP_`Hu4#>T9y;=zI+h- zz?+~4+ng+fotA8?TV937Wk1dvm_KaCyLQW3$!4z=Y*kiJs=Qg1r~)|%h5}mF4~(lg zWw=3Lk}7AEam6Usn0+7r@zP|@34kx&wNa6?hivI_&|fCV_VSco0Z201^;hc@%f&%4 zKYff<4dzO;SZzre*4mYIUpuzjcEY+bS$PQ2zfRQWYD|AQO4Pbmz|#7jExwspDKMIe z?W~Z`xS?%pG+J|*hDBa0Q~UNW`}XN=$=7-qrRtX4FvF03iqFXIXPEjs7{Wll@Go6< zyZ0S+XkR2ySr5IP}uF_I;s@2cZK(>i21K z#$GOZXH%PvleWjgSLuJoq!=tKhlpzs+LoV+)`=8bC#t01#~?G#wxNQ&G!_nc(@wa!FKKh(L2YJo>n~#h5x2xw7;UCbG0jHEm-j)Jo2Sh^)+h4YEAEdDzLYC> z?eSH;x+kBvg6G>}7nr%tKqGjQhiHm|e>ZJ1AXeR|(t$`3>e7i=qW*l9?Sl9_zlV?3 zESteR<#6J?c6jHuW&LA4cU@ayQdoX|=%l81Zab@30`1BR=WGK5bs(nXFAm5xH+8)l zE;tNi1p>y`Ea4x;J0DL=(Q1bXoXzFcUu%3j^A|poxhFB`jhFF3l@q&3bS_9IWI^h} zoen>zF-vmv)~^n++pRd0EA;#};j->>6T46wg>giO*Gr3(nMXFrW;@w`Y<*bFeH6AF z4)TDrkISfwmpWM}S304c3)ixxVeSFv&ZcPHry@^1XeM7%<4Fv+<(maLno&oajH=ti z6~<+?50mw4!pz3m8I*Ub3|Q4WrxmuOO>hyL==P-bAGd<_>+ZSFGxL`(2=bV5Yu3Fq zWT#enURNyH+q>7vH~rYp>u@!tgQHKVgEX8_s6Hn6_-5Io~TDG?v0#%5lq}JW7IjD=U-aw zZ_%Xidbw0zr)_mal3|5e$_1?rWvuIFjqL*c>RlF&-#O>;_#TVkc1Wef6j+-A2AkMn-guv3FVdI(gn>jm_FNEv`eB>=13O?K3|5yPx^0SJNBbxt;p^)#c8r z?g?xDFq20o?_pKNT`|-P{6XZk#-Xsqsa~g{qFEj{y$Osbvof?iCuwL&=H`}fK0M;j zxt5w=*ABcuWX$gYP^fFS7?YE_H)&#ELA@O&umN5t47uS}C-z^nWS8mINFt4UF{Up% zknftfxiMNYgLN+L6T!h>K_J`)kiay2)nkV|J`uq86!Ep$jYviv?!RzzA9C1MlXf(O z8-xmq0KX>!p4h#S#2S766y_CAY4TjF+_e5@W|kSHHc=u_8E9B^0nwTZtiM#3Sr6PU z&&Ae*5jEnPWC8Ge;bz7x6UE!~U*c|iT~6ySfyc~;1VpUI1coND#2)imLc%rEh;cTD z2Oasx#;B0SPXu)EW(0K6ry< z7+#ZjnD&as9N69@WqLt&96QeaF4ORK%47;xlXT)TY(eHD;N4(|Nc?|dfRzj-K)6i6 zDg?ksW}7Lx0%XC4Y<=!ZN zO@nJqUIp$Ss;|kBKUH4`i zn;_BH&XU(ZHO5Sxp6T>BqB7R2hzC}_}e{0Z~_-wZ^4q^8f57Kv{qlz zp89>;4CYbe%IZs}>n(yf1%KA~TMk5o)u5TSa2$fr7pW^NK;)}Z*dCYun5FsGC3dXC zh{G0(ugRKr4GZw3}8YmuHLg z4$tie)GmL4zXSYND$Ms{r>qc}Id-IUoUN7=Ktgs%rg|CU%vmM+(ZkGd0X|EWJxlbY zpP}C^2u!!RyfeV8h_CvCNS5~x?OENU=2#E$5cdREs-tiKBQ=8|p5#~4{=m59w}>n^ znI)W7BJvO!G6|MF6azJ}-7 z|KCg737ZUu9Ks3mf6H3c=o4y-wO+^H09%;ELRLTa^iv-n1+Z?^02J_`{fmg4EW|#!0?yXzfQm-0+_{J{z#hvqIQCiC%y5DQ!R2;|};+#=8>YVA$ z$qQDTf3R?NV_MjR8*+xk&|u84KP1-wt@k9Moeg|;bl1Q%VZkQugqHC7?F|lNPR?-; z-{NsHafn;WgS#lgFzUMZ6N!m^AE|`bSYv&*0*=? zQXhf6k7dbkTU$ydu#XJ(m|p9@E{t()sWf_Yar6l9uKH%XgduMwEoJI=UJHqf?4biW z1?d?^2vp+Fo*ro55N8@xo)y%xH6Ym8EI(>QarAh_x$e5~=IvFBwN7n#6*g<^%9|2> zpypLpBy98$Z9)W@(}*KT3AmH9dAZZ@cGD@}dKG$lEdM(pa|1tfv~%11!QoFvRopLA zFJ7qmZ2)3X2915n@wCB4QShCwr+CU^nMtSdG4~uj-&@|DDcWP7DsHL`>tf;63#e2N z!f%g@kw)VH%w;nLm=R8ArAR8vKY^oh6#mxO$UHA9t=v&TGa#W8fr_TKx0>(Wu?>kqcNiyYkVdt zLeK@4%}4}2h6)C0jc18GYBUW_<$_l<+@Nq7h_q;VFb%~WRBtUDt(^H6rceFv|d?H1H4@>#X2Ysu69P1z^<(1_Sy3_Wfx2X?n9kPf12FIc z>ijRP6yf z_4|GQ+r(=d4KJBY?0Kb87atK>l43ANbBKn;QebW)DC*1%$M}IFST4}XKe@b&qs9Ri z!>;kpU27jzmZvv6ahhAvz1#qgHO6_RTV3|g^jl+obDGX7pSpxs_hgx`stU69I2c=b ziXh@=LUtjTY@~tMJA503b92T(#0TB?T~L)B8Q7*jJIqBGX8qptxl?4K=H0O_KkG*= zcvE!1^t;I0NsBKS*gO`#Fgs$Cc6gTVv0-;D`xU*&dz;WyELvlC%(42E-t85>w`Zh} zK!rcC_QQ-a!wpa`lvH6ZC=DdBEvtL8D)))B`C&xvx`73{jrx3%p2W^6c8qLWe*9s6 z>UiB{J@=Ny3~o(JozgihZ{C%IjYnVIiW_eFA@p%w-hsEGt?9Jc_p)1}|KjiB`#oIG zy*VH+%s+UU%XVkmnYG{dbgoz3^62E~{~9#VcHf{)>Khw0=XZlQah8|p?e2$&a3Ivt z8PO0_p|zz%s@Hg=*;RZ0T(N~zxw!GGV&ffE~69#2=xm4T;MXM7n~!nTyIYfu=s8I zYttVS^%)i)M)#<<4)FT=#uo&FiuQ}x)~Q-AdhMRk!sRU;6P#L*41bGeOJBsN$e-1M zF`%TvDHdwZLMfk+c)15#YOhQ`kE6rC8Zn&bP~U)}Z432Gb6f0Q+b{Nplo=FRSD>s! zLkHJ$Qfz=jp`<8>!ftxa|14+262cZ`!jM55-LmZ=$9O=@rWSINw#}G7U4AhasY*ELsW(H4hzIH0K@QUIhl7 zCU0YuYrvz4*`6j)7DUf<*>nN24)06zn4#p z#3^#^c-H{$ryHLI?o}UKjgj}uUut!k`<>0dz4v2kxj5`~m1A}(9MoGTRj_L$)1gSD z3Ue1#?&a1mRGCAyZTc>|Cg1j~S9+U?l>{F%Ne9&(yxCUuP$MV`7O*6^D}!@>2+`86CyZaU?tah>Uf_&c zomb)EmpmZ(v^6S1b>^VgS0!&~nFj(X2g9%r_$FEQ3DJHtaL?Lk_sOQh2D!m z&1geLMTzB*Pnc;m283_^<0?AL5Of%8Xb^!p=ckogtVIFO%8T}ruW;R=dGMfLjsNgj z`C8InRvm+j`9YuQ48KAC9lKr$h4ABQS99fSNL}Php#}{V;UtqYJ0nUZ5L}UMg!LfW z@-n`D($DG%dijZ6km-cVo}oB@;*(sg4{hgqO0(WNCk@z+(vH*6d8%?C;*W%Og=p&z zz`aj0Uyt481?Q6IwUtLjX~{0VG6Agq!;}JYUv{7*g7B63&=LsN@U|VoZ~o zTAx|4O8&X$!ab6yGs1`GF!QYS{vXTb+~x8*?M&PGZeSR7sgx@U58|FQBU{JtG4s!n z@Ad|vP-m<|^ryULki9nNm*7iaA%4x+SyT`Ce1#UBnEn-JTxrns4(}$nR zP8nb2p>wt3RLP#qa7Cznrz4RYK9LGIH&HuWSu#rm0+@~CgOYP2BJ@N^DH^xTbBG7FKIyJ$jQ!~mT z%4N{a%9f`BooOim$b~yokg;fAr%w85>5>`gAuf-0>E2v{^7wRM&uo&{rbabEVJzdc z@*L{J0v@15Ia6>e%w7I$)~VVe-L>Zvb~ZZPVCF^c#db!c)xXMQz>K`RVpNr(sG8>n zo+87fRwcp>Ej8G4FPWD=18jH_1F=i8b0*sFVbTKm_okTv5Zzq-8!C~3-JwsyB%Or( zNuREF(Xuwe(RW9qtEp`EJ#b&q+Gvzc2b!RYB5IX<8n_wHJ;ft)z!=*>V4_vGDUET& z#3P`I)#qnC*qpOz^?~2jx@?_)I*9Xri48Db!;^kb=qWY^e(|83J_(C&{$h+Qs0Z*V zABYv5I!;MPeHMk;MFdVR7!6bi_luJmWw70GecM$SXlRzeR6wiy+OJHyr1cI5)5ljC zS@}{Zi^DH8>@^xOrBF9c=>m&aZ;9nQAuHO4&AFLS0~wAi`V>Y;PjhphgQwOcycxHu zRMR8z)@0Z~U_O5ImkKtJrz*z;s>i=al;fWVNNNlh0#G(7`SZD>TV8TL-Wizo;4JNB zzHI+hpoLcVw^JO!c;=ipL)_#Gm>L0=az66S`9HugOGjc&3vrSi=f_2SAq-jqNGEV| z$8lTs02@iGQRSzDPE4vc5Ji8&rhz=d5^>POgIAqL#$GxEuc^YRL!93by_m08QHxAh3X$Y=@2zsxra1Gq!l_B@3Q^ z3y){qTl~MQk#iLp0_X8gWHwn=6#7_ulgj(j-XeU=!Lcp-K1Ar9U3|Az6}2eXJJzAZ zYJJm^_plSj)TjT;E;%o_!Y47Dt32ZYCVBz4#9h*N?+WTve?~_OYWi9NkjJBe9}KP; zHnGlcB&(Ic*@64*i-O@5-l>(2z)=G4;PMg~Dv0wlFNP%aLSOZtF-W5r`VPB>p0(!x z9qbV+f9jq6RH*mu98bji;);f1(EQw11GHF!$p>iU(grLKG2}G=MMMntET;M%xx%y)SS8 zSo{)q$-dhNtG@n;c5ce%GJx8S2~0iGWQMl=1apKWUCi+PEV21s>own3L#FUyu)-8nGeeB*%nq6<#N^s{@7Frk>Rtz~VW@ZU zN*!1o_op^w=T{$6_(oStA^`LU9~CuBjAV0fGYt_nji88-I0DySB)-s($0Z4N*X%~| zqZoyqwyo1m_xC+Eu#sBdrzndEk48;npoO0lmZeZhnptY(XDsuO=IhoXfyPrTF0Mi! zr!C`F(r%ZT__u#Y3>Q2v=V|VS4qI57J*~TMX?QcuS;3xL^5+GN=J^DRqpLI%Uxa}6;AdpRG>}8>tsHjGp zHo+N2LRk<0wuckfQvZ};RpmRQ&dkpNDjK0gMP}cjp@BbS*kr)8@-G1yNCLfLM`_l* z4{zgjMRC$1L!r)F>VhjqP$mU6Y1uPz1_k!N`6^^;P%&KXBAR1*!c*Fbgv9O|+=@gc zr>aaCznE{({@9vT5!VAI!)TksG|;Rdq8g1H<2;kBwt z44!GI;Ah%nF0>6MN09P*`6~xfU!;L%=#C!3>J<%s`{gCSf+bDT)tPQ{0VT9TlMY-( zC#YQ9J1{}f-ZyYSu(6^a3SpPjR0YkBv}UrC-VX?3)X6z79fAgJyxfiI>sNpwXG4Q_ z4^(jiCTF)NhGT&h+{OaS#*U~OZHcV24YC)o&UYT-QkZc(lo-qQKSOje(gs0dGaiS* zc@UV<7QnPvnM!y$9;^9v1VmD>oKkG!!sEnpswZwkIVv#T(5i{hT+K=^=xX6<2s)5! z)lV*huPFxJbT~qf7k=dC{sqg!EK;=I-^7#d;ui=&2BUwQCJ9|tB(!mBM}qV?wUSukG;49_Sv~?)GV0o}YI7fe7*g*m zi&l-4GyDkH&zz0mt>0gt!W-ud3a2RrHxMS{3U?QL})hM3P z-+N49tIgc12xOUW`rESFfp#K&&&4#=p9I5Cn)F6|VIjn+o9d;8A;`1dS@W=G2~05Y z`h28|Ac+RP1NP!CD) zDW+_G5<<%dW;)DET;ZL78R4%u1%S!Zj*8~I6zj$@DckqKw(mmg7~B4Ow*Qr0$RA@&U;`~I$31?G69e8y$o>nZaBg9$rQFSuVypMOmiNeVA z+E92}G1hOk2CXz14p0&U-Z;Lnmotd|>GTI;3+6hr3YqKX#(%Xgq*<^CXaa^Q#1WfS zQs6D%<6(&u^z(*eHD(V=3}JIZYZ73>S7~Ree7&k1%Zu&ZKwJu~35Ow(U3iqs(;X8S zR~d|SJVw5Z&50qMj#czg$e5iv)1lE*TpaCEyQ`mJS5(S_stf>LJ9CSXIVj&Zko>Ds z#cIiRhV`=%JjmusnFGZF83_Oh1R|k#q5RYBsqQKk?r-jzmD1;T@ z+1ogGTz1to9%ZrAAQax-Jb~c_6Ubi|fowPOVZISF(3xT+!E<=Bg;a?_mMxK)D@4)H zB=NW}A_OxvRM2zsV=+q=D;J}ok@%oo4>4r)B4-m^Sn5txad;v`q8))}gWdd|V zQCx&HMl^$jju%+X?l5(NhPo$W`_Me!CtmtbB1bq zJ+Z~nji1}%1qdI?D6a-QCIWM1#>xsLsCa{*Vk8!A@hp2l#qRL}WK2I*;v<2{cvFc9AEg=EIkZ65 zLXo3ny#Vzvpd@BTVDKgmT?(p}R0dmUnH7P!$JbK)J{a2K<9=q|23yPmptw!AQ4E=F z-b|b~lvptuBBof?F?{UyQF~CrVn-;N7_bSIv#SA^L2Lu?>?%kTfmJoMSReu)Ad$3y z%i9KW0f^rvp(LV3(%Q$F4v2aB5Zgx+Z)mjl9zKD(`jc)C!e_)3&*39Nkl^1WjoARK zB=|xoKty#_`}t?;K|%OAg}`fo&IF#ro~RrU+RGL%5D)u^-wmNb9z~F}suxKI^fhM3 zOs{-m_yG#l5kIEECRTmKoA3wOAj5FRoY0ao41E-roz;_x2`wh;yRzi#3E=reAi#5n zni)Um%D-PuhJ8h?iIqP3$HxS~whnaL)qyL?kReA)&WC!~vMHNcLG`c1^1* z7pM{v)h)cs2x^z)O-HC*uIlk#c(HO*RLE;d9Lcx_d5D{+1z7&7+YAVwfeN44!iFXPhB|Q!0+3u%magT#YUS0bj&15tq|1;k z{i7z!LY5A)>~X`(V&OdJ=Dx6G7q&82wTU0e6p=7q2^Mvn(hozk3NmZKPzCO0DU-uU z4&0J4Bg5I$^ST#uwyfQFFTfbtaY11Bi20qSgL;IFG3vOv%*oUfl`a4ujj6vdh%?RU zH=iJ01j15)k~2|G!^2zYJZw{Y;Grw<&UP64E+aHDfp*t! z8KW>mH(Q7KYf`pJdfc9VaZug0;RI;W_7i8rZC-FsA)T7uyK)zUV(c#EZk}nSWm1R z@Zkl8n>+_gq_a6)FEm@(dWZN7aKJ~dppy*9lb=FL4dmq(U34fV&N75tH`tG?Tjr$pTTv5I zTo+#-8RF>TLs80@>p_XKuRzv=L_cffPT-mVy2qs&QD4}zW)=&Vq#N&-#` z8B1M0-VpfyMz;U)RvQJl^<>{227sRc0ei?kfV&|W)R_Zu2%a~XVwTl4SD^6H?4w36 zeTLf?;&PcP=^>7lVYeuMHJ{9qTz{QgV_7SPLi`oV2uWyOK|*9f5u_CG$mDQrg6x)n z;OoC<295nwDxKi+Zm`CSW)$D=6W4?~$yqLMCDM;Vy_}v&NU&fPx@yO-Z*Zzz?%zMW zxOyTAoj_q7Ng z0xmF_HijiMVMjXYfo^l}ha_wO)iu~;4qHVIOvJR*vR@3BLg^J;?5ou7nj}7 z{cgbIxr3JliY`ce=u2rzK1?_1Lk$llT$52H#A+G#)mljT0Rs@V#_P5~AhLr#>^dq8 zN)g6*I2hKiGmr%y4AiNH_=&E@(6-i<3)N3vhvaDBj`t&j{?YIQ&M38iL>m-p zQNjem1&pT>wh;NbEXg-QAHwMI-cM4ZIBp!qp z>&8*S^Mf>&P$n23gt3kmd(^{uOL0*~m#1`R>iyz%?vj;<9Zx_R1DMON^wv=l2=rj! ze(KI=87cm-YX%kVR(k=zs(VW<4o|2>g{L_Ac~pHnPm_*^!0AlVD_|NDWm0zZo}n8L zsjc6vD3B?bBx@4x0?8sQTR??~UH{#;?klL&XvPn5Le{>E-dU|4GyF$OvqI>*L*B58 zp7E}S_B9kV#zD&(KMGxmvShb}GI#gOgZ?g9Rgdo;jOaB}Vg zOLjTP>lGz0*sK?(GxN2&G@J{V-gHM}`W6fH#;G z`olnMr8D!9@TNjpgmZ_>t2NXMmtRC+yrY*X5k()O8_ybiYba@nP4t>zs$g(`*D!bQ z>z(-W(KT8zF=(bIe#{Dl-1{OB-Pl?Kj~&hz0@PZcyNd$KBzpaN!ZUrT?1DK0jQ`Jg zgr5GeF~CAg8ooWD>WwtGT7`q0Kp)CM8{pebHIgk<6h^13MbhW8-y=e5NWqm%<^Lo` zHKTf9?JS;OCcRI{RUKG6MIlhZh9MC&OcDZx4y|=;Xi@8&3($ymQS1oJI90J{h+9Hd zkov0>(GH*;ByWHQ+@Z4L_?j)z8I1_60ql84Euc0|n+vD=! zqhtMeufPCyJyktG7pv6E30nriq6VGNJLNarlX`)V0g!AB>N>Bv?hwMzy525a51~$1 zsZ%j_@rCJdpH|QsXT^gnP?>+mi0#&)b3f`mH>41TT-$q4XoM;QZcTcdbnvZ*&nVS6 z7ZfNOpqX&0O%mUCvjtM<7$j2BU~**_`Z-*U#Wf>ij5;+)r--_+*JHL39CC$Z&NU#R{~_@E8L`q@L2Ce4|el+ z@`)&DRN?ngUw|D$uXS?~>a_}-vDY;Zj0=j+e9TRHfb?>j4*H(ZB1HZb?M;OX=;|{7 zbfIA@I72@d35f9+nX*4W8lh8I2|6DXC?xD^YwLGG;+S*C!fLf@h5IB^Q>8bp?=!2~ ztvZxzQT+s^qo~vidYJP!C2G(^^Njv;Kc?zUGq=ph8V!3P8M zw8zwkKyB^3=9)ox`l^|ZB`{iop8t*Rb;5X0w?WMnx`8)nVc{j>P()y-R&GSOZW$PF z1q4d3jlWGei-#48KB5RGK^>F79!R|1!AIIQy`gN;0tshoeC5Q5Aro z)M_MbM~r#4dI%ey1vXlWX$pKnQ}JM!kGW+Rk4N zN6q@AZwSRCSe*Y37MGaSq5}HDSx&%X0yk_U#fYUOHvprD?Jgw*uAIQ!$ z!EH_|*j->ZtyLAW5!s(XZYXdtP>(Wp>O)`*rAG9|@PjiT%7KeC60$D_*#a=F*Tf%$ zq3nQ&OTYlqI|MmD2H@g;bJ{gjHPGHm?;Z1MsQiKVOUum=18YlZ1kpq5>3s#%+<+nA z!Yl$77(_%*oI7bbrU%_qx=@JI2Cd z3mZaeXiS|%E~=uZ*7cs5c>~II{X?a5t|LRRfQfU1A1Y%|dHt(!2P~&gLIyaP5z%uf ztPV2XhWdQ`J0|c1(bQyD1@M$tC1@C;gWy~>=@V= z%XS-30;rkyx+}W0uUl*GvlszpdJ+WqdsQ*0)bzYBU&1R24-?=yicW^ZuL};psN4@t zeNyfRzx)9O1g%*E@%}>LZ(_Yxq?B(yU+)*P-U(Q*0-737EPDn`rcQz`wiJj-R}(3J zZvmHZ;NvHFsHPM4u2;GwQ;WmcWIk;j?tN(n0+<5n-2m;sr)0T6dO3Tt+l!7DNXapmtekW1PxT2ZVn@xD|*Sy-GM69^4Ymp>u72^pP_FU*XkqRRp*WqUF6+ za4LzcfSQ+y!rjOjS$DtwMMSN3P*nJh+XUhC)kcNdx{orTN1!F4^eP96V|u_jTLu@S z%lHgn14eMWuvfd7F__OlcNa?2_vD@CEJIqG2!HP(xz-R;Ljp7eKN7(2(U~FX8vxy1 z?(Iw)mfqf)_U%~^Q0Zvo^IzSV< z;5?<4TGu^3$te~PkSYU^;u8OHgjm^(hk(>W=xN_f>_18Q z`w{u{Y7~OCfmj0fe5N*3lR%98Icx&P)X{XnJJ34%NFz85`A8!$+>0nS*=EO!JQ?Fy z=q5VyvekWZ#ot+g(>a@aj(q^cO{Z(Q)2ZJ>O7}z5Y=MI!vC-Y`TI@WMhcLTbiYlPE zlbuXsYp+o;ptJ_dSxy9R;N-ATxzFGPJm@rrHUTN*0}+Eh0ZNu(npQfBH5Ro4V^T(= zP8nrO)ORY>A5rjkI)OuIEy+(s(r5(1)pB}qsug$eah#Ht6S-u9{ldr{A`~9*>_|^M zGpW;O_i(WtEt?$(%Sy~v%Agkm@VAwWg~3oM@^ah}K|Y5h4gW(Y9Dj}oDeSisXB$mB z8+_0W)cz{Rg(0Gs(VrA;432&#Y;c7fvS7ZNs~W7~2mw`$sjG%l#-N&Hs9+*Z0O2kUlG`@@VH)i)vaTaVrdhgX(UW8*pqL*=$Q7%r} z@kYB)`EN7a2?hNNiHqEzvTo)rVumJF<5`k3C3_Zv#lwqtt)fm#%N2qb#I>F09(t3h z%~Az{vE}^Ypo^MlY(jFW&$`Ts-xxG zeYpnnOWVWh5#V!jN=c-kOIsnjBLmTVJIVI^Art_`?4i+PC)lK>?esb4BEbAoO!Ok5 zE&zq3t-X01Lcis zofZzw6uCfbfwx>B!uu@VGpC@cDCeI>>$xyA9$BM_nB+~Hz|zlD2hc#94pTc08W75Y z{n3J<6wWZn9VWk#lo2sVF6o=Qj!2rG)b7(o3XJrDAp!@p1gZ-mVQLrFhBx>W$j*h1 zF&zAfd2@yTz$k<9AMSC2Q;p$*HW+@9#GI5Br_xu*#Dw1*A^-*%J-}O? z=3G5AEy&C1;(g)Xw-CB$u(#aIsgGbQz#D96QeU0eOZ0>2j~KE*?R;R3d-oH>ms0YV z_Fx*O^BV=3ykz|BppqF!$*OU5vIo%x#fPs*cb9@Sb7*%1TN+81Oy~i0(pHA+v{3SA zop*5r&j99SuEN^41sM&wdyXTC(bU zli7J_riNa%hNPf>VbNH?BoM4>UQiP4BHw?~3oNkTKfTei7qH%Az-pa4eR)m7o~;8q zhAzhiU2@Y64ZnfjsPfGKtX_GE3+noz<+}g7+-1Dn_L!-60@6;`Bm_Ls$s)Eei!O6< zIK~AoVwgBgk(1UnkU`iupytzn1JL~lIPC^#Z6&5ugl4y)D%nD715tGd^MbIY>Zd&P zSzKVfEi?`_5ztar0>q*J%@L>{nWsn% tpyWTCgqAW6T)jX1n+d~S;p0;nH-6I`<9@%ig8~11rp}o1vxhkT{{UR=YBvA? From 50250098608897e7daa78b7d58da281dbb83eb59 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 14 Dec 2025 19:45:28 +0100 Subject: [PATCH 28/57] REVIEWED: Make sure all variables are initialized on definition, prioritize one line per variable definitions --- src/external/rlsw.h | 8 +++--- src/platforms/rcore_desktop_glfw.c | 3 +- src/platforms/rcore_memory.c | 2 +- src/rmodels.c | 8 +++--- src/rtext.c | 14 +++++++-- src/rtextures.c | 46 ++++++++++++++++++++---------- 6 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 025216e39..80fb02c4f 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -2217,7 +2217,7 @@ static inline bool sw_triangle_face_culling(void) const float *h2 = RLSW.vertexBuffer[2].homogeneous; // Compute a value proportional to the signed area in the projected 2D plane, - // calculated directly using homogeneous coordinates BEFORE division by w. + // calculated directly using homogeneous coordinates BEFORE division by w // This is the determinant of the matrix formed by the (x, y, w) components // of the vertices, which correctly captures the winding order in homogeneous // space and its relationship to the projected 2D winding order, even with @@ -2235,13 +2235,13 @@ static inline bool sw_triangle_face_culling(void) // Discard the triangle if its winding order (determined by the sign // of the homogeneous area/determinant) matches the culled direction // A positive hSgnArea typically corresponds to a counter-clockwise - // winding in the projected space when all w > 0. + // winding in the projected space when all w > 0 // This test is robust for points with w > 0 or w < 0, correctly // capturing the change in orientation when crossing the w=0 plane // The culling logic remains the same based on the signed area/determinant // A value of 0 for hSgnArea means the points are collinear in (x, y, w) - // space, which corresponds to a degenerate triangle projection. + // space, which corresponds to a degenerate triangle projection // Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false) // and should be handled by the clipper if necessary return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0) : (hSgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise" @@ -2602,7 +2602,7 @@ static inline bool sw_quad_face_culling(void) // space, which corresponds to a degenerate triangle projection // Such quads might also be degenerate or non-planar. They are typically // not culled by this test (0 < 0 is false, 0 > 0 is false) - // and should be handled by the clipper if necessary. + // and should be handled by the clipper if necessary return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0.0f) : (hSgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise" } diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 8bd4b3a69..d6ed11c2f 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -894,7 +894,8 @@ Vector2 GetMonitorPosition(int monitor) if ((monitor >= 0) && (monitor < monitorCount)) { - int x, y; + int x = 0; + int y = 0; glfwGetMonitorPos(monitors[monitor], &x, &y); return (Vector2){ (float)x, (float)y }; diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c index 5a3947561..1b7a55fd8 100644 --- a/src/platforms/rcore_memory.c +++ b/src/platforms/rcore_memory.c @@ -428,7 +428,7 @@ void SetMouseCursor(int cursor) TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); } -// Get physical key name. +// Get physical key name const char *GetKeyName(int key) { TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform"); diff --git a/src/rmodels.c b/src/rmodels.c index 1502e46af..883f98660 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3655,7 +3655,7 @@ void GenMeshTangents(Mesh *mesh) for (int t = 0; t < mesh->triangleCount; t++) { // Get triangle vertex indices - int i0, i1, i2; + int i0 = 0, i1 = 0, i2 = 0; if (mesh->indices != NULL) { @@ -4150,7 +4150,7 @@ RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform) // Test against all triangles in mesh for (int i = 0; i < triangleCount; i++) { - Vector3 a, b, c; + Vector3 a = 0, b = 0, c = 0; Vector3 *vertdata = (Vector3 *)mesh.vertices; if (mesh.indices) @@ -4193,8 +4193,8 @@ RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3 RayCollision collision = { 0 }; Vector3 edge1 = { 0 }; Vector3 edge2 = { 0 }; - Vector3 p, q, tv; - float det, invDet, u, v, t; + Vector3 p = 0, q = 0, tv = 0; + float det = 0.0f, invDet = 0.0f, u = 0.0f, v = 0.0f, t = 0.0f; // Find vectors for two edges sharing V1 edge1 = Vector3Subtract(p2, p1); diff --git a/src/rtext.c b/src/rtext.c index 0efd7504b..f04f9ade4 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -649,7 +649,9 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz // Calculate font basic metrics // NOTE: ascent is equivalent to font baseline - int ascent, descent, lineGap; + int ascent = 0; + int descent = 0; + int lineGap = 0; stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); // In case no chars count provided, default to 95 @@ -2483,7 +2485,15 @@ static Font LoadBMFont(const char *fileName) font.glyphs = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo)); font.recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle)); - int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX, pageID; + int charId = 0; + int charX = 0; + int charY = 0; + int charWidth = 0; + int charHeight = 0; + int charOffsetX = 0; + int charOffsetY = 0; + int charAdvanceX = 0; + int pageID = 0; for (int i = 0; i < glyphCount; i++) { diff --git a/src/rtextures.c b/src/rtextures.c index 02a9ff1a5..4208b40bd 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1727,7 +1727,8 @@ void ImageResizeNN(Image *image, int newWidth, int newHeight) int xRatio = (int)((image->width << 16)/newWidth) + 1; int yRatio = (int)((image->height << 16)/newHeight) + 1; - int x2, y2; + int x2 = 0; + int y2 = 0; for (int y = 0; y < newHeight; y++) { for (int x = 0; x < newWidth; x++) @@ -2488,8 +2489,13 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) Color oldPixel = WHITE; Color newPixel = WHITE; - int rError, gError, bError; - unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition + int rError = 0; + int gError = 0; + int bError = 0; + unsigned short rPixel = 0; // Used for 16bit pixel composition + unsigned short gPixel = 0; + unsigned short bPixel = 0; + unsigned short aPixel = 0; #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -4006,7 +4012,9 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color // [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend() // [ ] TODO: Support 16bit and 32bit (float) channels drawing - Color colSrc, colDst, blend; + Color colSrc = { 0 }; + Color colDst = { 0 }; + Color blend = { 0 }; bool blendRequired = true; // Fast path: Avoid blend if source has no alpha to blend @@ -4681,17 +4689,23 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, bottomBorder = patchHeight - topBorder; } - Vector2 vertA, vertB, vertC, vertD; - vertA.x = 0.0f; // outer left - vertA.y = 0.0f; // outer top - vertB.x = leftBorder; // inner left - vertB.y = topBorder; // inner top - vertC.x = patchWidth - rightBorder; // inner right - vertC.y = patchHeight - bottomBorder; // inner bottom - vertD.x = patchWidth; // outer right - vertD.y = patchHeight; // outer bottom + Vector2 vertA = { 0 }; + Vector2 vertB = { 0 }; + Vector2 vertC = { 0 }; + Vector2 vertD = { 0 }; + vertA.x = 0.0f; // Outer left + vertA.y = 0.0f; // Outer top + vertB.x = leftBorder; // Inner left + vertB.y = topBorder; // Inner top + vertC.x = patchWidth - rightBorder; // Inner right + vertC.y = patchHeight - bottomBorder; // Inner bottom + vertD.x = patchWidth; // Outer right + vertD.y = patchHeight; // Outer bottom - Vector2 coordA, coordB, coordC, coordD; + Vector2 coordA = { 0 }; + Vector2 coordB = { 0 }; + Vector2 coordC = { 0 }; + Vector2 coordD = { 0 }; coordA.x = nPatchInfo.source.x/width; coordA.y = nPatchInfo.source.y/height; coordB.x = (nPatchInfo.source.x + leftBorder)/width; @@ -4907,7 +4921,9 @@ Vector3 ColorToHSV(Color color) { Vector3 hsv = { 0 }; Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; - float min, max, delta; + float min = 0.0f; + float max = 0.0f; + float delta = 0.0f; min = rgb.x < rgb.y? rgb.x : rgb.y; min = min < rgb.z? min : rgb.z; From 9a337f3b3b6c8208574fea3eebd0bd46bc9a386e Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 14 Dec 2025 19:52:18 +0100 Subject: [PATCH 29/57] ADDED: Support software renderer on Web, blitting framebuffer data directly to a 2d canvas This improvement is just a prove of concept, at this moment `PLATFORM_WEB` is limited in terms of software rendering by `GLFW` that only allows creating a WebGL canvas context with `glfwCreateWindow()`. We can skip that call but then some GLFW functionality is not available (windowing, inputs). The best solution is replacing GLFW completely by a pure Emscripten implementation for `PLATFORM_WEB`. --- src/platforms/rcore_web.c | 52 ++++++++++++++++++++++++++++++++++++--- src/rcore.c | 2 +- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index dc779d0fb..934f778c3 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -78,6 +78,11 @@ typedef struct { int unmaximizedHeight; // Internal var to store the unmaximized window (canvas) height char canvasId[64]; // Keep current canvas id where wasm app is running + // NOTE: Useful when trying to run multiple wasms in different canvases in same webpage + +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + unsigned int *pixels; // Pointer to pixel data buffer (RGBA 32bit format) +#endif } PlatformData; //---------------------------------------------------------------------------------- @@ -264,7 +269,8 @@ void ToggleFullscreen(void) }; emscripten_enter_soft_fullscreen(platform.canvasId, &strategy); - int width, height; + int width = 0; + int height = 0; emscripten_get_canvas_element_size(platform.canvasId, &width, &height); TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height); @@ -883,7 +889,32 @@ void DisableCursor(void) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // Update framebuffer + rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels); + + // Copy framebuffer data into canvas + EM_ASM({ + const width = $0; + const height = $1; + const ptr = $2; + + // Get canvas and 2d context created + const canvas = Module.canvas; + const ctx = canvas.getContext('2d'); + + if (!Module.__img || (Module.__img.width !== width) || (Module.__img.height !== height)) { + Module.__img = ctx.createImageData(width, height); + } + + const src = HEAPU8.subarray(ptr, ptr + width*height*4); // RGBA (4 bytes) + Module.__img.data.set(src); + ctx.putImageData(Module.__img, 0, 0); + + }, CORE.Window.screen.width, CORE.Window.screen.height, platform.pixels); +#else glfwSwapBuffers(platform.handle); +#endif } //---------------------------------------------------------------------------------- @@ -974,7 +1005,7 @@ void SetMouseCursor(int cursor) } } -// Get physical key name. +// Get physical key name const char *GetKeyName(int key) { TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform"); @@ -1214,7 +1245,21 @@ int InitPlatform(void) // Init fullscreen toggle required var: platform.ourFullscreen = false; - + +#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + // Avoid creating a WebGL canvas, avoid calling glfwCreateWindow() + emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height); + EM_ASM({ + const canvas = document.getElementById("canvas"); + Module.canvas = canvas; + }); + + // Load memory framebuffer with desired screen size + // NOTE: Despite using a software framebuffer for blitting, GLFW still creates a WebGL canvas, + // but it is not being used, on SwapScreenBuffer() the pure software renderer is used + // TODO: Consider requesting another type of canvas, not a WebGL one --> Replace GLFW-web by Emscripten? + platform.pixels = (unsigned int *)RL_CALLOC(CORE.Window.screen.width*CORE.Window.screen.height, sizeof(unsigned int)); +#else if (CORE.Window.fullscreen) { // remember center for switchinging from fullscreen to window @@ -1289,6 +1334,7 @@ int InitPlatform(void) TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window"); return -1; } +#endif // WARNING: glfwCreateWindow() title doesn't work with emscripten emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " "); diff --git a/src/rcore.c b/src/rcore.c index 24ebb6dec..19228cc8e 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -117,7 +117,7 @@ #include // Required for: time() [Used in InitTimer()] #include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] -#if defined(PLATFORM_MEMORY) +#if defined(PLATFORM_MEMORY) || defined(PLATFORM_WEB) #define SW_GL_FRAMEBUFFER_COPY_BGRA false #endif #define RLGL_IMPLEMENTATION From a0fd5ab1d90e0c34d9e6e173b08f23453f7561ff Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 14 Dec 2025 19:59:12 +0100 Subject: [PATCH 30/57] Update rmodels.c --- src/rmodels.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 883f98660..2347ca0e6 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -4150,7 +4150,9 @@ RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform) // Test against all triangles in mesh for (int i = 0; i < triangleCount; i++) { - Vector3 a = 0, b = 0, c = 0; + Vector3 a = { 0 }; + Vector3 b = { 0 }; + Vector3 c = { 0 }; Vector3 *vertdata = (Vector3 *)mesh.vertices; if (mesh.indices) @@ -4193,7 +4195,9 @@ RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3 RayCollision collision = { 0 }; Vector3 edge1 = { 0 }; Vector3 edge2 = { 0 }; - Vector3 p = 0, q = 0, tv = 0; + Vector3 p = { 0 }; + Vector3 q = { 0 }; + Vector3 tv = { 0 }; float det = 0.0f, invDet = 0.0f, u = 0.0f, v = 0.0f, t = 0.0f; // Find vectors for two edges sharing V1 From 8d246fdaff8ae5f23593f70c827029d3e8d43a7c Mon Sep 17 00:00:00 2001 From: ALONZO Robin Date: Mon, 15 Dec 2025 00:03:31 +0100 Subject: [PATCH 31/57] Fix EXTERNAL_CONFIG_FLAGS being defined even when no custom config is used when building with zig (#5410) --- build.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.zig b/build.zig index 4e06ca757..5d2902111 100644 --- a/build.zig +++ b/build.zig @@ -155,9 +155,9 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. ); } - // Sets a flag indicating the use of a custom `config.h` - try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); if (options.config.len > 0) { + // Sets a flag indicating the use of a custom `config.h` + try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS"); // Splits a space-separated list of config flags into multiple flags // // Note: This means certain flags like `-x c++` won't be processed properly. From d74556d35cca3befc6ac924695f863b8c3827d1f Mon Sep 17 00:00:00 2001 From: RANDRIA Luca Date: Mon, 15 Dec 2025 20:49:40 +0300 Subject: [PATCH 32/57] Modify text_words_alignment.c (#5411) --- examples/text/text_words_alignment.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/text/text_words_alignment.c b/examples/text/text_words_alignment.c index 6cfd2a85c..a558d5b11 100644 --- a/examples/text/text_words_alignment.c +++ b/examples/text/text_words_alignment.c @@ -19,6 +19,8 @@ #include "raymath.h" // Required for: Lerp() +#include + typedef enum TextAlignment { TEXT_ALIGN_LEFT = 0, TEXT_ALIGN_TOP = 0, @@ -58,7 +60,7 @@ int main(void) // And of course the font... Font font = GetFontDefault(); - // Intialize the alignment variables + // Initialize the alignment variables TextAlignment hAlign = TEXT_ALIGN_CENTRE; TextAlignment vAlign = TEXT_ALIGN_MIDDLE; @@ -72,8 +74,7 @@ int main(void) //---------------------------------------------------------------------------------- if (IsKeyPressed(KEY_LEFT)) { - hAlign = hAlign - 1; - if (hAlign < 0) hAlign = 0; + if (hAlign > 0) hAlign = hAlign - 1; } if (IsKeyPressed(KEY_RIGHT)) @@ -84,8 +85,7 @@ int main(void) if (IsKeyPressed(KEY_UP)) { - vAlign = vAlign - 1; - if (vAlign < 0) vAlign = 0; + if (vAlign > 0) vAlign = vAlign - 1; } if (IsKeyPressed(KEY_DOWN)) @@ -95,7 +95,8 @@ int main(void) } // One word per second - wordIndex = (int)GetTime()%wordCount; + if (wordCount > 0) wordIndex = (int)GetTime()%wordCount; + else wordIndex = 0; //---------------------------------------------------------------------------------- // Draw @@ -132,4 +133,4 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} From cbe31759ab1b578b5f5c58b81cd67dcc2db1047e Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 15 Dec 2025 18:52:27 +0100 Subject: [PATCH 33/57] Fix #5405 --- src/rmodels.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 2347ca0e6..40af4afc4 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -127,10 +127,13 @@ // Defines and Macros //---------------------------------------------------------------------------------- #ifndef MAX_MATERIAL_MAPS - #define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported + #define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported #endif #ifndef MAX_MESH_VERTEX_BUFFERS - #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh + #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh +#endif +#ifndef MAX_FILEPATH_LENGTH + #define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) #endif //---------------------------------------------------------------------------------- From 615fc36eeb4570be90ba53308f99ba97755281ff Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 15 Dec 2025 18:56:14 +0100 Subject: [PATCH 34/57] Fix #5406 --- src/rlgl.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index b5955e613..97f892eb5 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1762,11 +1762,6 @@ void rlTextureParameters(unsigned int id, int param, int value) { glBindTexture(GL_TEXTURE_2D, id); -#if !defined(GRAPHICS_API_OPENGL_11) - // Reset anisotropy filter, in case it was set - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); -#endif - switch (param) { case RL_TEXTURE_WRAP_S: @@ -1786,6 +1781,9 @@ void rlTextureParameters(unsigned int id, int param, int value) case RL_TEXTURE_FILTER_ANISOTROPIC: { #if !defined(GRAPHICS_API_OPENGL_11) + // Reset anisotropy filter, in case it was set + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f) { From cf0d6fc664f1d0775c6b21ed79feaa1e38b2ddb4 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 15 Dec 2025 20:44:28 +0100 Subject: [PATCH 35/57] REVIEWED: Alignment with other platforms --- src/external/RGFW.h | 17630 ++++++++++++++++----------- src/platforms/rcore_desktop_rgfw.c | 5 - 2 files changed, 10239 insertions(+), 7396 deletions(-) diff --git a/src/external/RGFW.h b/src/external/RGFW.h index 7205bf9d8..b913d4f2d 100644 --- a/src/external/RGFW.h +++ b/src/external/RGFW.h @@ -1,8 +1,8 @@ /* * -* RGFW 1.7.5-dev +* RGFW 1.8.1 -* Copyright (C) 2022-25 ColleagueRiley +* Copyright (C) 2022-25 Riley Mabb (@ColleagueRiley) * * libpng license * @@ -33,19 +33,12 @@ /* #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included #define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found - #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl) - #define RGFW_BUFFER - (optional) 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) - #define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api) - This version doesn't work for desktops (I'm pretty sure) - #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2) - #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3) + #define RGFW_EGL - (optional) compile with OpenGL functions, allowing you to use to use EGL instead of the native OpenGL functions #define RGFW_DIRECTX - (optional) include integration directX functions (windows only) #define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros - #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY) - #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX) + #define RGFW_WEBGPU - (optional) use WebGPU for rendering + #define RGFW_NATIVE - (optional) define native RGFW types that use native API structures - #define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress) #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS #define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11) #define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland @@ -62,8 +55,9 @@ #define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU) #define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name #define RGFW_NO_DPI - do not calculate DPI (no XRM nor libShcore included) - #define RGFW_BUFFER_BGR - use the BGR format for bufffers instead of RGB, saves processing time #define RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may result in a spike in memory usage or worse performance) (eg. WM_TIMER and XSyncValue) + #define RGFW_NO_INFO - do not define the RGFW_info struct (without RGFW_IMPLEMENTATION) + #define RGFW_NO_GLXWINDOW - do not use GLXWindow #define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc) #define RGFW_FREE x - choose the default deallocation function (defaults to standard free) @@ -89,20 +83,17 @@ macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -fram u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF}; int main() { - RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(100, 100, 500, 500), (u64)0); + RGFW_window* win = RGFW_createWindow("name", 100, 100, 500, 500, (u64)0); + RGFW_event event; - RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4); + RGFW_window_setExitKey(win, RGFW_escape); + RGFW_window_setIcon(win, icon, 3, 3, RGFW_formatRGBA8); while (RGFW_window_shouldClose(win) == RGFW_FALSE) { - while (RGFW_window_checkEvent(win)) { - if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_escape)) - break; - } - - RGFW_window_swapBuffers(win); - - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + while (RGFW_window_checkEvent(win, &event)) { + if (event.type == RGFW_quit) + break; + } } RGFW_window_close(win); @@ -143,25 +134,40 @@ int main() { /* Credits : - EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing + EimaMei/Sacode : Code review, helped with X11, MacOS and Windows support, Silicon, siliapp.h -> referencing - stb - This project is heavily inspired by the stb single header files + stb : This project is heavily inspired by the stb single header files - GLFW: - certain parts of winapi and X11 are very poorly documented, - GLFW's source code was referenced and used throughout the project. + SDL, GLFW and other online resources : reference implementations contributors : (feel free to put yourself here if you contribute) - krisvers -> code review - EimaMei (SaCode) -> code review - Code-Nycticebus -> bug fixes - Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs + krisvers (@krisvers) -> code review + EimaMei (@SaCode) -> code review + Nycticebus (@Code-Nycticebus) -> bug fixes + Rob Rohan (@robrohan) -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs AICDG (@THISISAGOODNAME) -> vulkan support (example) @Easymode -> support, testing/debugging, bug fixes and reviews Joshua Rowe (omnisci3nce) - bug fix, review (macOS) @lesleyrs -> bug fix, review (OpenGL) - Nick Porcino (meshula) - testing, organization, review (MacOS, examples) - @DarekParodia -> code review (X11) (C++) + Nick Porcino (@meshula) - testing, organization, review (MacOS, examples) + @therealmarrakesh -> documentation + @DarekParodia -> code review (X11) (C++) + @NishiOwO -> fix BSD support, fix OSMesa example + @BaynariKattu -> code review and documentation + Miguel Pinto (@konopimi) -> code review, fix vulkan example + @m-doescode -> code review (wayland) + Robert Gonzalez (@uni-dos) -> code review (wayland) + @TheLastVoyager -> code review + @yehoravramenko -> code review (winapi) + @halocupcake -> code review (OpenGL) + @GideonSerf -> documentation + Alexandre Almeida (@M374LX) -> code review (keycodes) + Vũ Xuân Trường (@wanwanvxt) -> code review (winapi) + Lucas (@lightspeedlucas) -> code review (msvc++) + Jeffery Myers (@JeffM2501) -> code review (msvc) + Zeni (@zenitsuyo) -> documentation + TheYahton (@TheYahton) -> documentation + nonexistant_object (@DiarrheaMcgee */ #if _MSC_VER @@ -179,6 +185,74 @@ int main() { #endif #endif +#if defined(RGFW_EGL) && !defined(RGFW_OPENGL) + #define RGFW_OPENGL +#endif + +/* these OS macros look better & are standardized */ +/* plus it helps with cross-compiling */ + +#ifdef __EMSCRIPTEN__ + #define RGFW_WASM +#endif + +#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND) + #define RGFW_MACOS_X11 + #define RGFW_UNIX +#endif + +#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */ + #define RGFW_WINDOWS +#endif +#if defined(RGFW_WAYLAND) + #define RGFW_DEBUG /* wayland will be in debug mode by default for now */ + #define RGFW_UNIX + #ifdef RGFW_OPENGL + #define RGFW_EGL + #endif + #ifdef RGFW_X11 + #define RGFW_DYNAMIC + #endif +#endif +#if (!defined(RGFW_WAYLAND) && !defined(RGFW_X11)) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) + #define RGFW_MACOS_X11 + #define RGFW_X11 + #define RGFW_UNIX +#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) + #define RGFW_MACOS +#endif + +#ifndef RGFW_ASSERT + #include + #define RGFW_ASSERT assert +#endif + +#if !defined(__STDC_VERSION__) + #define RGFW_C89 +#endif + +#if !defined(RGFW_SNPRINTF) && (defined(RGFW_X11) || defined(RGFW_WAYLAND)) + + /* required for X11 errors */ + #include + + #ifdef RGFW_C89 + #include + static int RGFW_c89_snprintf(char *dst, size_t size, const char *format, ...) { + va_list args; + size_t count = 0; + va_start(args, format); + count = (size_t)vsprintf(dst, format, args); + RGFW_ASSERT(count + 1 < size && "Buffer overflow"); + va_end(args); + return (int)count; + } + #define RGFW_SNPRINTF RGFW_c89_snprintf + #else + #define RGFW_SNPRINTF snprintf + #endif /*RGFW_C89*/ +#endif + #ifndef RGFW_USERPTR #define RGFW_USERPTR NULL #endif @@ -191,17 +265,16 @@ int main() { #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f) #endif +#ifndef RGFW_MIN + #define RGFW_MIN(x, y) ((x < y) ? x : y) +#endif + #ifndef RGFW_ALLOC #include #define RGFW_ALLOC malloc #define RGFW_FREE free #endif -#ifndef RGFW_ASSERT - #include - #define RGFW_ASSERT assert -#endif - #if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET) #include #endif @@ -233,6 +306,31 @@ int main() { #define RGFW_ATOF(num) atof(num) #endif +#if !defined(RGFW_PRINTF) && ( defined(RGFW_DEBUG) || defined(RGFW_WAYLAND) ) + /* required when using RGFW_DEBUG */ + #include + #define RGFW_PRINTF printf +#endif + +#ifndef RGFW_MAX_PATH + #define RGFW_MAX_PATH 260 /* max length of a path (for drag andn drop) */ +#endif +#ifndef RGFW_MAX_DROPS + #define RGFW_MAX_DROPS 260 /* max items you can drop at once */ +#endif + +#ifndef RGFW_MAX_EVENTS + #define RGFW_MAX_EVENTS 32 +#endif + +#ifndef RGFW_MAX_MONITORS + #define RGFW_MAX_MONITORS 6 +#endif + +#ifndef RGFW_COCOA_FRAME_NAME + #define RGFW_COCOA_FRAME_NAME NULL +#endif + #ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */ #define RGFW_NO_MONITOR #define RGFW_NO_PASSTHROUGH @@ -267,16 +365,11 @@ int main() { #endif #endif -#ifndef RGFW_ENUM - #define RGFW_ENUM(type, name) type name; enum -#endif - - #if defined(__cplusplus) && !defined(__EMSCRIPTEN__) extern "C" { #endif - /* makes sure the header file part is only defined once by default */ +/* makes sure the header file part is only defined once by default */ #ifndef RGFW_HEADER #define RGFW_HEADER @@ -307,1023 +400,31 @@ int main() { #define RGFW_INT_DEFINED #endif +typedef ptrdiff_t RGFW_ssize_t; + #ifndef RGFW_BOOL_DEFINED #define RGFW_BOOL_DEFINED typedef u8 RGFW_bool; #endif -#define RGFW_BOOL(x) (RGFW_bool)((x) ? RGFW_TRUE : RGFW_FALSE) /* force an value to be 0 or 1 */ +#define RGFW_BOOL(x) (RGFW_bool)((x) != 0) /* force a value to be 0 or 1 */ #define RGFW_TRUE (RGFW_bool)1 #define RGFW_FALSE (RGFW_bool)0 -/* these OS macros look better & are standardized */ -/* plus it helps with cross-compiling */ +#define RGFW_ENUM(type, name) type name; enum +#define RGFW_BIT(x) (1 << (x)) -#ifdef __EMSCRIPTEN__ - #define RGFW_WASM - - #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU) - #define RGFW_OPENGL - #endif - - #ifdef RGFW_EGL - #undef RGFW_EGL - #endif - - #include - #include - - #ifdef RGFW_WEBGPU - #include - #endif -#endif - -#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS_X11 - #define RGFW_UNIX - #undef __APPLE__ -#endif - -#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */ - #define RGFW_WINDOWS - /* make sure the correct architecture is defined */ - #if defined(_WIN64) - #define _AMD64_ - #undef _X86_ - #else - #undef _AMD64_ - #ifndef _X86_ - #define _X86_ - #endif - #endif - - #ifndef RGFW_NO_XINPUT - #ifdef __MINGW32__ /* try to find the right header */ - #include - #else - #include - #endif - #endif -#endif -#if defined(RGFW_WAYLAND) - #define RGFW_DEBUG /* wayland will be in debug mode by default for now */ - #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) - #define RGFW_EGL - #define RGFW_OPENGL - #include - #endif - - #define RGFW_UNIX - #include -#endif -#if !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS_X11 - #define RGFW_X11 - #define RGFW_UNIX - #include - #include -#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS - #if !defined(RGFW_BUFFER_BGR) - #define RGFW_BUFFER_BGR - #else - #undef RGFW_BUFFER_BGR - #endif -#endif - -#if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL) - #define RGFW_EGL -#endif - -#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API) - #define RGFW_OPENGL -#endif - -#ifdef RGFW_EGL - #include -#elif defined(RGFW_OSMESA) - #ifdef RGFW_WINDOWS - #define OEMRESOURCE - #include - #ifndef GLAPIENTRY - #define GLAPIENTRY APIENTRY - #endif - #ifndef GLAPI - #define GLAPI WINGDIAPI - #endif - #endif - - #ifndef __APPLE__ - #include - #else - #include - #endif -#endif - -#if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER) - #pragma comment(lib, "opengl32") -#endif - -#if defined(RGFW_OPENGL) && defined(RGFW_X11) - #ifndef GLX_MESA_swap_control - #define GLX_MESA_swap_control - #endif - #include /* GLX defs, xlib.h, gl.h */ -#endif - -#define RGFW_COCOA_FRAME_NAME NULL - -/*! (unix) Toggle use of wayland. This will be on by default if you use `RGFW_WAYLAND` (if you don't use RGFW_WAYLAND, you don't expose WAYLAND functions) - this is mostly used to allow you to force the use of XWayland -*/ -RGFWDEF void RGFW_useWayland(RGFW_bool wayland); -RGFWDEF RGFW_bool RGFW_usingWayland(void); -/* - regular RGFW stuff -*/ - -#define RGFW_key u8 - -typedef RGFW_ENUM(u8, RGFW_eventType) { - /*! event codes */ - RGFW_eventNone = 0, /*!< no event has been sent */ - RGFW_keyPressed, /* a key has been pressed */ - RGFW_keyReleased, /*!< a key has been released */ - /*! key event note - the code of the key pressed is stored in - RGFW_event.key - !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! - - while a string version is stored in - RGFW_event.KeyString - - RGFW_event.keyMod holds the current keyMod - this means if CapsLock, NumLock are active or not - */ - RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */ - RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */ - RGFW_mousePosChanged, /*!< the position of the mouse has been changed */ - /*! mouse event note - the x and y of the mouse can be found in the vector, RGFW_event.point - - RGFW_event.button holds which mouse button was pressed - */ - RGFW_gamepadConnected, /*!< a gamepad was connected */ - RGFW_gamepadDisconnected, /*!< a gamepad was disconnected */ - RGFW_gamepadButtonPressed, /*!< a gamepad button was pressed */ - RGFW_gamepadButtonReleased, /*!< a gamepad button was released */ - RGFW_gamepadAxisMove, /*!< an axis of a gamepad was moved */ - /*! gamepad event note - RGFW_event.gamepad holds which gamepad was altered, if any - RGFW_event.button holds which gamepad button was pressed - - RGFW_event.axis holds the data of all the axises - RGFW_event.axisesCount says how many axises there are - */ - RGFW_windowMoved, /*!< the window was moved (by the user) */ - RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */ - RGFW_focusIn, /*!< window is in focus now */ - RGFW_focusOut, /*!< window is out of focus now */ - RGFW_mouseEnter, /* mouse entered the window */ - RGFW_mouseLeave, /* mouse left the window */ - RGFW_windowRefresh, /* The window content needs to be refreshed */ - - /* attribs change event note - The event data is sent straight to the window structure - with win->r.x, win->r.y, win->r.w and win->r.h - */ - RGFW_quit, /*!< the user clicked the quit button */ - RGFW_DND, /*!< a file has been dropped into the window */ - RGFW_DNDInit, /*!< the start of a dnd event, when the place where the file drop is known */ - /* dnd data note - The x and y coords of the drop are stored in the vector RGFW_event.point - - RGFW_event.droppedFilesCount holds how many files were dropped - - This is also the size of the array which stores all the dropped file string, - RGFW_event.droppedFiles - */ - RGFW_windowMaximized, /*!< the window was maximized */ - RGFW_windowMinimized, /*!< the window was minimized */ - RGFW_windowRestored, /*!< the window was restored */ - RGFW_scaleUpdated /*!< content scale factor changed */ -}; - -/*! mouse button codes (RGFW_event.button) */ -typedef RGFW_ENUM(u8, RGFW_mouseButton) { - RGFW_mouseLeft = 0, /*!< left mouse button is pressed */ - RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */ - RGFW_mouseRight, /*!< right mouse button is pressed */ - RGFW_mouseScrollUp, /*!< mouse wheel is scrolling up */ - RGFW_mouseScrollDown, /*!< mouse wheel is scrolling down */ - RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5, - RGFW_mouseFinal -}; - -#ifndef RGFW_MAX_PATH -#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */ -#endif -#ifndef RGFW_MAX_DROPS -#define RGFW_MAX_DROPS 260 /* max items you can drop at once */ -#endif - -#define RGFW_BIT(x) (1 << x) - -/* for RGFW_event.lockstate */ -typedef RGFW_ENUM(u8, RGFW_keymod) { - RGFW_modCapsLock = RGFW_BIT(0), - RGFW_modNumLock = RGFW_BIT(1), - RGFW_modControl = RGFW_BIT(2), - RGFW_modAlt = RGFW_BIT(3), - RGFW_modShift = RGFW_BIT(4), - RGFW_modSuper = RGFW_BIT(5), - RGFW_modScrollLock = RGFW_BIT(6) -}; - -/*! gamepad button codes (based on xbox/playstation), you may need to change these values per controller */ -typedef RGFW_ENUM(u8, RGFW_gamepadCodes) { - RGFW_gamepadNone = 0, /*!< or PS X button */ - RGFW_gamepadA, /*!< or PS X button */ - RGFW_gamepadB, /*!< or PS circle button */ - RGFW_gamepadY, /*!< or PS triangle button */ - RGFW_gamepadX, /*!< or PS square button */ - RGFW_gamepadStart, /*!< start button */ - RGFW_gamepadSelect, /*!< select button */ - RGFW_gamepadHome, /*!< home button */ - RGFW_gamepadUp, /*!< dpad up */ - RGFW_gamepadDown, /*!< dpad down */ - RGFW_gamepadLeft, /*!< dpad left */ - RGFW_gamepadRight, /*!< dpad right */ - RGFW_gamepadL1, /*!< left bump */ - RGFW_gamepadL2, /*!< left trigger */ - RGFW_gamepadR1, /*!< right bumper */ - RGFW_gamepadR2, /*!< right trigger */ - RGFW_gamepadL3, /* left thumb stick */ - RGFW_gamepadR3, /*!< right thumb stick */ - RGFW_gamepadFinal -}; - -/*! basic vector type, if there's not already a point/vector type of choice */ -#ifndef RGFW_point - typedef struct RGFW_point { i32 x, y; } RGFW_point; -#endif - -/*! basic rect type, if there's not already a rect type of choice */ -#ifndef RGFW_rect - typedef struct RGFW_rect { i32 x, y, w, h; } RGFW_rect; -#endif - -/*! basic area type, if there's not already a area type of choice */ -#ifndef RGFW_area - typedef struct RGFW_area { u32 w, h; } RGFW_area; -#endif - -#if defined(__cplusplus) && !defined(__APPLE__) -#define RGFW_POINT(x, y) {(i32)x, (i32)y} -#define RGFW_RECT(x, y, w, h) {(i32)x, (i32)y, (i32)w, (i32)h} -#define RGFW_AREA(w, h) {(u32)w, (u32)h} -#else -#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)} -#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)} -#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)} -#endif - -#ifndef RGFW_NO_MONITOR - /* monitor mode data | can be changed by the user (with functions)*/ - typedef struct RGFW_monitorMode { - RGFW_area area; /*!< monitor workarea size */ - u32 refreshRate; /*!< monitor refresh rate */ - u8 red, blue, green; - } RGFW_monitorMode; - - /*! structure for monitor data */ - typedef struct RGFW_monitor { - i32 x, y; /*!< x - y of the monitor workarea */ - char name[128]; /*!< monitor name */ - float scaleX, scaleY; /*!< monitor content scale */ - float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */ - float physW, physH; /*!< monitor physical size in inches */ - - RGFW_monitorMode mode; - } RGFW_monitor; - - /*! get an array of all the monitors (max 6) */ - RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len); - /*! get the primary monitor */ - RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); - - typedef RGFW_ENUM(u8, RGFW_modeRequest) { - RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */ - RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */ - RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */ - RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB - }; - - /*! request a specific mode */ - RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); - /*! check if 2 monitor modes are the same */ - RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request); -#endif - -/* RGFW mouse loading */ -typedef void RGFW_mouse; - -/*!< loads mouse icon from bitmap (similar to RGFW_window_setIcon). Icon NOT resized by default */ -RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels); -/*!< frees RGFW_mouse data */ -RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse); - -/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_event struct) */ -/*! Event structure for checking/getting events */ -typedef struct RGFW_event { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_point point; /*!< mouse x, y of event (or drop point) */ - RGFW_point vector; /*!< raw mouse movement */ - float scaleX, scaleY; /*!< DPI scaling */ - - RGFW_key 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 */ - - RGFW_bool repeat; /*!< key press event repeated (the key is being held) */ - RGFW_keymod keyMod; - - u8 button; /* !< which mouse (or gamepad) button was pressed */ - double scroll; /*!< the raw mouse scroll value */ - - u16 gamepad; /*! which gamepad this event applies to (if applicable to any) */ - u8 axisesCount; /*!< number of axises */ - - u8 whichAxis; /* which axis was effected */ - RGFW_point axis[4]; /*!< x, y of axises (-100 to 100) */ - - /*! drag and drop data */ - /* 260 max paths with a max length of 260 */ - char** droppedFiles; /*!< dropped files */ - size_t droppedFilesCount; /*!< house many files were dropped */ - - void* _win; /*!< the window this event applies too (for event queue events) */ -} RGFW_event; - -/*! source data for the window (used by the APIs) */ -#ifdef RGFW_WINDOWS -typedef struct RGFW_window_src { - HWND window; /*!< source window */ - HDC hdc; /*!< source HDC */ - u32 hOffset; /*!< height offset for window */ - HICON hIconSmall, hIconBig; /*!< source window icons */ - #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) - HGLRC ctx; /*!< source graphics context */ - #elif defined(RGFW_OSMESA) - OSMesaContext ctx; - #elif defined(RGFW_EGL) - EGLSurface EGL_surface; - EGLDisplay EGL_display; - EGLContext EGL_context; - #endif - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - HDC hdcMem; - HBITMAP bitmap; - u8* bitmapBits; - #endif - RGFW_area maxSize, minSize, aspectRatio; /*!< for setting max/min resize (RGFW_WINDOWS) */ -} RGFW_window_src; -#elif defined(RGFW_UNIX) -typedef struct RGFW_window_src { -#if defined(RGFW_X11) - Display* display; /*!< source display */ - Window window; /*!< source window */ - #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) - GLXContext ctx; /*!< source graphics context */ - GLXFBConfig bestFbc; - #elif defined(RGFW_OSMESA) - OSMesaContext ctx; - #elif defined(RGFW_EGL) - EGLSurface EGL_surface; - EGLDisplay EGL_display; - EGLContext EGL_context; - #endif - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - XImage* bitmap; - #endif - GC gc; - XVisualInfo visual; - #ifdef RGFW_ADVANCED_SMOOTH_RESIZE - i64 counter_value; - XID counter; - #endif - RGFW_rect r; -#endif /* RGFW_X11 */ -#if defined(RGFW_WAYLAND) - struct wl_display* wl_display; - struct wl_surface* surface; - struct wl_buffer* wl_buffer; - struct wl_keyboard* keyboard; - - struct wl_compositor* compositor; - struct xdg_surface* xdg_surface; - struct xdg_toplevel* xdg_toplevel; - struct zxdg_toplevel_decoration_v1* decoration; - struct xdg_wm_base* xdg_wm_base; - struct wl_shm* shm; - struct wl_seat *seat; - u8* buffer; - #if defined(RGFW_EGL) - struct wl_egl_window* eglWindow; - #endif - #if defined(RGFW_EGL) && !defined(RGFW_X11) - EGLSurface EGL_surface; - EGLDisplay EGL_display; - EGLContext EGL_context; - #elif defined(RGFW_OSMESA) && !defined(RGFW_X11) - OSMesaContext ctx; - #endif -#endif /* RGFW_WAYLAND */ -} RGFW_window_src; -#endif /* RGFW_UNIX */ -#if defined(RGFW_MACOS) -typedef struct RGFW_window_src { - void* window; -#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) - void* ctx; /*!< source graphics context */ -#elif defined(RGFW_OSMESA) - OSMesaContext ctx; -#elif defined(RGFW_EGL) - EGLSurface EGL_surface; - EGLDisplay EGL_display; - EGLContext EGL_context; -#endif - - void* view; /* apple viewpoint thingy */ - void* mouse; -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) -#endif -} RGFW_window_src; -#elif defined(RGFW_WASM) -typedef struct RGFW_window_src { - #if defined(RGFW_WEBGPU) - WGPUInstance ctx; - WGPUDevice device; - WGPUQueue queue; - #elif defined(RGFW_OSMESA) - OSMesaContext ctx; - #else - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; - #endif -} RGFW_window_src; -#endif - -/*! Optional arguments for making a windows */ -typedef RGFW_ENUM(u32, RGFW_windowFlags) { - RGFW_windowNoInitAPI = RGFW_BIT(0), /* do NOT init an API (including the software rendering buffer) (mostly for bindings. you can also use `#define RGFW_NO_API`) */ - RGFW_windowNoBorder = RGFW_BIT(1), /*!< the window doesn't have a border */ - RGFW_windowNoResize = RGFW_BIT(2), /*!< the window cannot be resized by the user */ - RGFW_windowAllowDND = RGFW_BIT(3), /*!< the window supports drag and drop */ - RGFW_windowHideMouse = RGFW_BIT(4), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_mouseShow`) */ - RGFW_windowFullscreen = RGFW_BIT(5), /*!< the window is fullscreen by default */ - RGFW_windowTransparent = RGFW_BIT(6), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */ - RGFW_windowCenter = RGFW_BIT(7), /*! center the window on the screen */ - RGFW_windowOpenglSoftware = RGFW_BIT(8), /*! use OpenGL software rendering */ - RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /*! (cocoa only), change directory to resource folder */ - RGFW_windowScaleToMonitor = RGFW_BIT(10), /*! scale the window to the screen */ - RGFW_windowHide = RGFW_BIT(11), /*! the window is hidden */ - RGFW_windowMaximize = RGFW_BIT(12), - RGFW_windowCenterCursor = RGFW_BIT(13), - RGFW_windowFloating = RGFW_BIT(14), /*!< create a floating window */ - RGFW_windowFreeOnClose = RGFW_BIT(15), /*!< free (RGFW_window_close) the RGFW_window struct when the window is closed (by the end user) */ - RGFW_windowFocusOnShow = RGFW_BIT(16), /*!< focus the window when it's shown */ - RGFW_windowMinimize = RGFW_BIT(17), /*!< focus the window when it's shown */ - RGFW_windowFocus = RGFW_BIT(18), /*!< if the window is in focus */ - RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize -}; - -typedef struct RGFW_window { - RGFW_window_src src; /*!< src window data */ - -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */ - /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */ - RGFW_area bufferSize; -#endif - void* userPtr; /* ptr for usr data */ - - RGFW_event event; /*!< current event */ - - RGFW_rect r; /*!< the x, y, w and h of the struct */ - - /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */ - RGFW_key exitKey; - RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */ - - u32 _flags; /*!< windows flags (for RGFW to check) */ - RGFW_rect _oldRect; /*!< rect before fullscreen */ -} RGFW_window; /*!< window structure for managing the window */ - -#if defined(RGFW_X11) || defined(RGFW_MACOS) - typedef u64 RGFW_thread; /*!< thread type unix */ -#else - typedef void* RGFW_thread; /*!< thread type for windows */ -#endif - -/*! scale monitor to window size */ -RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win); - -/** * @defgroup Window_management -* @{ */ - - -/*! - * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM - * by default the class name will == the root window's name -*/ -RGFWDEF void RGFW_setClassName(const char* name); -RGFWDEF void RGFW_setXInstName(const char* name); /*!< X11 instance name (window name will by used by default) */ - -/*! (cocoa only) change directory to resource folder */ -RGFWDEF void RGFW_moveToMacOSResourceDir(void); - -/* NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window */ - -RGFWDEF RGFW_window* RGFW_createWindow( - const char* name, /* name of the window */ - RGFW_rect rect, /* rect of window */ - RGFW_windowFlags flags /* extra arguments ((u32)0 means no flags used)*/ -); /*!< function to create a window and struct */ - -RGFWDEF RGFW_window* RGFW_createWindowPtr( - const char* name, /* name of the window */ - RGFW_rect rect, /* rect of window */ - RGFW_windowFlags flags, /* extra arguments (NULL / (u32)0 means no flags used) */ - RGFW_window* win /* ptr to the window struct you want to use */ -); /*!< function to create a window (without allocating a window struct) */ - -RGFWDEF void RGFW_window_initBuffer(RGFW_window* win); -RGFWDEF void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area); -RGFWDEF void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area); - -/*! set the window flags (will undo flags if they don't match the old ones) */ -RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags); - -/*! get the size of the screen to an area struct */ -RGFWDEF RGFW_area RGFW_getScreenSize(void); - - -/*! - this function checks an *individual* event (and updates window structure attributes) - this means, using this function without a while loop may cause event lag - - ex. - - while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one] - - this function is optional if you choose to use event callbacks, - although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents` -*/ - -RGFWDEF RGFW_event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/ - -/*! - for RGFW_window_eventWait and RGFW_window_checkEvents - waitMS -> Allows the function to keep checking for events even after `RGFW_window_checkEvent == NULL` - if waitMS == 0, the loop will not wait for events - if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns - if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event -*/ -typedef RGFW_ENUM(i32, RGFW_eventWait) { - RGFW_eventNoWait = 0, - RGFW_eventWaitNext = -1 -}; - -/*! sleep until RGFW gets an event or the timer ends (defined by OS) */ -RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS); - -/*! - check all the events until there are none left. - This should only be used if you're using callbacks only -*/ -RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS); - -/*! - tell RGFW_window_eventWait to stop waiting (to be ran from another thread) -*/ -RGFWDEF void RGFW_stopCheckEvents(void); - -/*! window managment functions */ -RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */ - -/*! move a window to a given point */ -RGFWDEF void RGFW_window_move(RGFW_window* win, - RGFW_point v /*!< new pos */ -); - -#ifndef RGFW_NO_MONITOR - /*! move window to a specific monitor */ - RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */); -#endif - -/*! resize window to a current size/area */ -RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */ - RGFW_area a /*!< new size */ -); - -/*! set window aspect ratio */ -RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a); -/*! set the minimum dimensions of a window */ -RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a); -/*! set the maximum dimensions of a window */ -RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a); - -RGFWDEF void RGFW_window_focus(RGFW_window* win); /*!< sets the focus to this window */ -RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); /*!< checks the focus to this window */ -RGFWDEF void RGFW_window_raise(RGFW_window* win); /*!< raise the window (to the top) */ -RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window */ -RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); /*!< turn fullscreen on / off for a window */ -RGFWDEF void RGFW_window_center(RGFW_window* win); /*!< center the window */ -RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/ -RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/ -RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); /*!< make the window a floating window */ -RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); /*!< sets the opacity of a window */ - -RGFWDEF RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win); - -/*! if the window should have a border or not (borderless) based on bool value of `border` */ -RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border); -RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win); - -/*! turn on / off dnd (RGFW_windowAllowDND stil must be passed to the window)*/ -RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow); -/*! check if DND is allowed */ -RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win); - - -#ifndef RGFW_NO_PASSTHROUGH - /*! turn on / off mouse passthrough */ - RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough); -#endif - -/*! rename window to a given string */ -RGFWDEF void RGFW_window_setName(RGFW_window* win, - const char* name -); - -RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, /*!< source window */ - u8* icon /*!< icon bitmap */, - RGFW_area a /*!< width and height of the bitmap */, - i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */ -); /*!< image MAY be resized by default, set both the taskbar and window icon */ - -typedef RGFW_ENUM(u8, RGFW_icon) { - RGFW_iconTaskbar = RGFW_BIT(0), - RGFW_iconWindow = RGFW_BIT(1), - RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow -}; -RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type); - -/*!< sets mouse to RGFW_mouse icon (loaded from a bitmap struct) */ -RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse); - -/*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */ -RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse); - -RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */ -/* - Locks cursor at the center of the window - win->event.point becomes raw mouse movement data - - this is useful for a 3D camera -*/ -RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area); -/*! if the mouse is held by RGFW */ -RGFWDEF RGFW_bool RGFW_window_mouseHeld(RGFW_window* win); -/*! stop holding the mouse and let it move freely */ -RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win); - -/*! hide the window */ -RGFWDEF void RGFW_window_hide(RGFW_window* win); -/*! show the window */ -RGFWDEF void RGFW_window_show(RGFW_window* win); - -/* - makes it so `RGFW_window_shouldClose` returns true or overrides a window close - by modifying window flags -*/ -RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose); - -/*! where the mouse is on the screen */ -RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void); - -/*! where the mouse is on the window */ -RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win); - -/*! show the mouse or hide the mouse */ -RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show); -/*! if the mouse is hidden */ -RGFWDEF RGFW_bool RGFW_window_mouseHidden(RGFW_window* win); -/*! move the mouse to a given point */ -RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v); - -/*! if the window should close (RGFW_close was sent or escape was pressed) */ -RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win); -/*! if the window is fullscreen */ -RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win); -/*! if the window is hidden */ -RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win); -/*! if the window is minimized */ -RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win); -/*! if the window is maximized */ -RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win); -/*! if the window is floating */ -RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win); -/** @} */ - -/** * @defgroup Monitor -* @{ */ - -#ifndef RGFW_NO_MONITOR -/* - scale the window to the monitor. - This is run by default if the user uses the arg `RGFW_scaleToMonitor` during window creation -*/ -RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win); -/*! get the struct of the window's monitor */ -RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); -#endif - -/** @} */ - -/** * @defgroup Input -* @{ */ - -/*! 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 RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/ - -RGFWDEF RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code) */ - -RGFWDEF RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code) */ -RGFWDEF RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code) */ - -/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */ -RGFWDEF RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code */); - -/*! if a mouse button is pressed */ -RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); -/*! if a mouse button is held */ -RGFWDEF RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); -/*! if a mouse button was released */ -RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); -/*! if a mouse button was pressed (checks previous state only) */ -RGFWDEF RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); -/** @} */ - -/** * @defgroup Clipboard -* @{ */ -typedef ptrdiff_t RGFW_ssize_t; - -RGFWDEF const char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */ -/*! read clipboard data or send a NULL str to just get the length of the clipboard data */ -RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity); -RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */ -/** @} */ - - - -/** * @defgroup error handling -* @{ */ -typedef RGFW_ENUM(u8, RGFW_debugType) { - RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo -}; - -typedef RGFW_ENUM(u8, RGFW_errorCode) { - RGFW_noError = 0, /*!< no error */ - RGFW_errOpenglContext, RGFW_errEGLContext, /*!< error with the OpenGL context */ - RGFW_errWayland, - RGFW_errDirectXContext, - RGFW_errIOKit, - RGFW_errClipboard, - RGFW_errFailedFuncLoad, - RGFW_errBuffer, - RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL, - RGFW_warningWayland, RGFW_warningOpenGL -}; - -typedef struct RGFW_debugContext { RGFW_window* win; RGFW_monitor* monitor; u32 srcError; } RGFW_debugContext; - -#if defined(__cplusplus) && !defined(__APPLE__) -#define RGFW_DEBUG_CTX(win, err) {win, NULL, err} -#define RGFW_DEBUG_CTX_MON(monitor) {_RGFW.root, &monitor, 0} -#else -#define RGFW_DEBUG_CTX(win, err) (RGFW_debugContext){win, NULL, err} -#define RGFW_DEBUG_CTX_MON(monitor) (RGFW_debugContext){_RGFW.root, &monitor, 0} -#endif - -typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg); -RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func); -RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg); -/** @} */ - -/** - - - event callbacks. - These are completely optional, so you can use the normal - RGFW_checkEvent() method if you prefer that - -* @defgroup Callbacks -* @{ -*/ - -/*! RGFW_windowMoved, the window and its new rect value */ -typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_windowResized, the window and its new rect value */ -typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_windowRestored, the window and its new rect value */ -typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_windowMaximized, the window and its new rect value */ -typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_windowMinimized, the window and its new rect value */ -typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win, RGFW_rect r); -/*! RGFW_quit, the window that was closed */ -typedef void (* RGFW_windowQuitfunc)(RGFW_window* win); -/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */ -typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus); -/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */ -typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, RGFW_bool status); -/*! RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */ -typedef void (* RGFW_mousePosfunc)(RGFW_window* win, RGFW_point point, RGFW_point vector); -/*! RGFW_DNDInit, the window, the point of the drop on the windows */ -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 mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */ -typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool 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, RGFW_mouseButton button, double scroll, RGFW_bool pressed); -/*! RGFW_gamepadButtonPressed, 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_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed); -/*! RGFW_gamepadAxisMove, the window that got the event, the gamepad in question, the axis values and the axis count */ -typedef void (* RGFW_gamepadAxisfunc)(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis); -/*! RGFW_gamepadConnected / RGFW_gamepadDisconnected, the window that got the event, the gamepad in question, if the controller was connected (else it was disconnected) */ -typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, RGFW_bool connected); -/*! RGFW_dnd, the window that had the drop, the drop data and the number of files dropped */ -typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount); -/*! RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */ -typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY); - -/*! set callback for a window move event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func); -/*! set callback for a window resize event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func); -/*! set callback for a window quit event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func); -/*! set callback for a mouse move event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func); -/*! set callback for a window refresh event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func); -/*! set callback for a window focus change event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func); -/*! set callback for a mouse notify event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func); -/*! set callback for a drop event event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func); -/*! set callback for a start of a drop event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func); -/*! set callback for a key (press / release) event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func); -/*! set callback for a mouse button (press / release) event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func); -/*! set callback for a controller button (press / release) event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_gamepadButtonfunc RGFW_setGamepadButtonCallback(RGFW_gamepadButtonfunc func); -/*! set callback for a gamepad axis move event. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_gamepadAxisfunc RGFW_setGamepadAxisCallback(RGFW_gamepadAxisfunc func); -/*! set callback for when a controller is connected or disconnected. Returns the previous callback function (if it was set) */ -RGFWDEF RGFW_gamepadfunc RGFW_setGamepadCallback(RGFW_gamepadfunc func); -/*! set call back for when window is maximized. Returns the previous callback function (if it was set) */ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowResizedfunc func); -/*! set call back for when window is minimized. Returns the previous callback function (if it was set) */ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowResizedfunc func); -/*! set call back for when window is restored. Returns the previous callback function (if it was set) */ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowRestoredCallback(RGFW_windowResizedfunc func); -/*! set callback for when the DPI changes. Returns previous callback function (if it was set) */ -RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func); -/** @} */ - -/** * @defgroup Threads -* @{ */ - -#ifndef RGFW_NO_THREADS -/*! threading functions */ - -/*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */ -/* - I'd suggest you use sili's threading functions instead - if you're going to use sili - which is a good idea generally -*/ - -#if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WASM) || defined(RGFW_CUSTOM_BACKEND) - typedef void* (* RGFW_threadFunc_ptr)(void*); -#else - typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter); -#endif - -RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread */ -RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread */ -RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */ -RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */ -#endif - -/** @} */ - -/** * @defgroup gamepad -* @{ */ - -typedef RGFW_ENUM(u8, RGFW_gamepadType) { - RGFW_gamepadMicrosoft = 0, RGFW_gamepadSony, RGFW_gamepadNintendo, RGFW_gamepadLogitech, RGFW_gamepadUnknown -}; - -/*! gamepad count starts at 0*/ -RGFWDEF u32 RGFW_isPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); -RGFWDEF u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); -RGFWDEF u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); -RGFWDEF u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); -RGFWDEF RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis); -RGFWDEF const char* RGFW_getGamepadName(RGFW_window* win, u16 controller); -RGFWDEF size_t RGFW_getGamepadCount(RGFW_window* win); -RGFWDEF RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller); - -/** @} */ - -/** * @defgroup graphics_API -* @{ */ - -/*!< make the window the current opengl drawing context - - NOTE: - if you want to switch the graphics context's thread, - you have to run RGFW_window_makeCurrent(NULL); on the old thread - then RGFW_window_makeCurrent(valid_window) on the new thread -*/ -RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win); - -/*! get current RGFW window graphics context */ -RGFWDEF RGFW_window* RGFW_getCurrent(void); - -/* supports openGL, directX, OSMesa, EGL and software rendering */ -RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */ -RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval); -/*!< render the software rendering buffer (this is called by RGFW_window_swapInterval) */ -RGFWDEF void RGFW_window_swapBuffers_software(RGFW_window* win); - -typedef void (*RGFW_proc)(void); /* function pointer equivalent of void* */ - -/*! native API functions */ -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) -/*!< create an opengl context for the RGFW window, run by createWindow by default (unless the RGFW_windowNoInitAPI is included) */ -RGFWDEF void RGFW_window_initOpenGL(RGFW_window* win); -/*!< called by `RGFW_window_close` by default (unless the RGFW_windowNoInitAPI is set) */ -RGFWDEF void RGFW_window_freeOpenGL(RGFW_window* win); - -/*! OpenGL init hints */ -typedef RGFW_ENUM(u8, RGFW_glHints) { - RGFW_glStencil = 0, /*!< set stencil buffer bit size (8 by default) */ - RGFW_glSamples, /*!< set number of sampiling buffers (4 by default) */ - RGFW_glStereo, /*!< use GL_STEREO (GL_FALSE by default) */ - RGFW_glAuxBuffers, /*!< number of aux buffers (0 by default) */ - RGFW_glDoubleBuffer, /*!< request double buffering */ - RGFW_glRed, RGFW_glGreen, RGFW_glBlue, RGFW_glAlpha, /*!< set RGBA bit sizes */ - RGFW_glDepth, - RGFW_glAccumRed, RGFW_glAccumGreen, RGFW_glAccumBlue,RGFW_glAccumAlpha, /*!< set accumulated RGBA bit sizes */ - RGFW_glSRGB, /*!< request sRGA */ - RGFW_glRobustness, /*!< request a robust context */ - RGFW_glDebug, /*!< request opengl debugging */ - RGFW_glNoError, /*!< request no opengl errors */ - RGFW_glReleaseBehavior, - RGFW_glProfile, - RGFW_glMajor, RGFW_glMinor, - RGFW_glFinalHint = 32, /*!< the final hint (not for setting) */ - RGFW_releaseFlush = 0, RGFW_glReleaseNone, /* RGFW_glReleaseBehavior options */ - RGFW_glCore = 0, RGFW_glCompatibility /*!< RGFW_glProfile options */ -}; -RGFWDEF void RGFW_setGLHint(RGFW_glHints hint, i32 value); -RGFWDEF RGFW_bool RGFW_extensionSupported(const char* extension, size_t len); /*!< check if whether the specified API extension is supported by the current OpenGL or OpenGL ES context */ -RGFWDEF RGFW_proc RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */ -RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */ -RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); /*!< swap opengl buffer (only) called by RGFW_window_swapInterval */ -void* RGFW_getCurrent_OpenGL(void); /*!< get the current context (OpenGL backend (GLX) (WGL) (EGL) (cocoa) (webgl))*/ - -RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len); /*!< check if whether the specified platform-specific API extension is supported by the current OpenGL or OpenGL ES context */ -#endif #ifdef RGFW_VULKAN + #if defined(RGFW_WAYLAND) && defined(RGFW_X11) - #define VK_USE_PLATFORM_WAYLAND_KHR - #define VK_USE_PLATFORM_XLIB_KHR - #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface")) - #elif defined(RGFW_WAYLAND) #define VK_USE_PLATFORM_WAYLAND_KHR #define VK_USE_PLATFORM_XLIB_KHR - #define RGFW_VK_SURFACE "VK_KHR_wayland_surface" - #elif defined(RGFW_X11) + #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface")) + #elif defined(RGFW_WAYLAND) + #define VK_USE_PLATFORM_WAYLAND_KHR + #define VK_USE_PLATFORM_XLIB_KHR + #define RGFW_VK_SURFACE "VK_KHR_wayland_surface" + #elif defined(RGFW_X11) #define VK_USE_PLATFORM_XLIB_KHR #define RGFW_VK_SURFACE "VK_KHR_xlib_surface" #elif defined(RGFW_WINDOWS) @@ -1337,63 +438,39 @@ RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t #define RGFW_VK_SURFACE NULL #endif -/* if you don't want to use the above macros */ -RGFWDEF const char** RGFW_getVKRequiredInstanceExtensions(size_t* count); /*!< gets (static) extension array (and size (which will be 2)) */ - -#include - -RGFWDEF VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface); -RGFWDEF RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex); -#endif -#ifdef RGFW_DIRECTX -#ifndef RGFW_WINDOWS - #undef RGFW_DIRECTX -#else - #define OEMRESOURCE - #include - - #ifndef __cplusplus - #define __uuidof(T) IID_##T - #endif -RGFWDEF int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain); -#endif #endif -/** @} */ -/** * @defgroup Supporting -* @{ */ +/*! @brief The stucture that contains information about the current RGFW instance */ +typedef struct RGFW_info RGFW_info; -/*! optional init/deinit function */ -RGFWDEF i32 RGFW_init(void); /*!< is called by default when the first window is created by default */ -RGFWDEF void RGFW_deinit(void); /*!< is called by default when the last open window is closed */ +/*! @brief The window stucture for interfacing with the window */ +typedef struct RGFW_window RGFW_window; -RGFWDEF double RGFW_getTime(void); /*!< get time in seconds since RGFW_setTime, which ran when the first window is open */ -RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds RGFW_setTime, which ran when the first window is open */ -RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */ -RGFWDEF void RGFW_setTime(double time); /*!< set timer in seconds */ -RGFWDEF u64 RGFW_getTimerValue(void); /*!< get API timer value */ -RGFWDEF u64 RGFW_getTimerFreq(void); /*!< get API time freq */ +/*! @brief The source window stucture for interfacing with the underlying windowing API (e.g. winapi, wayland, cocoa, etc) */ +typedef struct RGFW_window_src RGFW_window_src; -/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */ -RGFWDEF u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap); +/*! @brief The color format for pixel data */ +typedef RGFW_ENUM(u8, RGFW_format) { + RGFW_formatRGB8 = 0, /*!< 8-bit RGB (3 channels) */ + RGFW_formatBGR8, /*!< 8-bit BGR (3 channels) */ + RGFW_formatRGBA8, /*!< 8-bit RGBA (4 channels) */ + RGFW_formatARGB8, /*!< 8-bit RGBA (4 channels) */ + RGFW_formatBGRA8, /*!< 8-bit BGRA (4 channels) */ + RGFW_formatABGR8, /*!< 8-bit BGRA (4 channels) */ + RGFW_formatCount +}; -/*!< change which window is the root window */ -RGFWDEF void RGFW_setRootWindow(RGFW_window* win); -RGFWDEF RGFW_window* RGFW_getRootWindow(void); +/*! @brief a stucture for interfacing with the underlying native image (e.g. XImage, HBITMAP, etc) */ +typedef struct RGFW_nativeImage RGFW_nativeImage; -/*! standard event queue, used for injecting events and returning source API callback events like any other queue check */ -/* these are all used internally by RGFW */ -void RGFW_eventQueuePush(RGFW_event event); -RGFW_event* RGFW_eventQueuePop(RGFW_window* win); +/*! @brief a stucture for interfacing with pixel data as a renderable surface */ +typedef struct RGFW_surface RGFW_surface; -/* for C++ / C89 */ -#define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(e); } +/*! a raw pointer to the underlying mouse handle for setting and creating custom mouse icons */ +typedef void RGFW_mouse; -/*! - key codes and mouse icon enums -*/ -#undef RGFW_key +/*! @brief RGFW's abstract keycodes */ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_keyNULL = 0, RGFW_escape = '\033', @@ -1408,13 +485,11 @@ typedef RGFW_ENUM(u8, RGFW_key) { 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', @@ -1441,20 +516,17 @@ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_x = 'x', RGFW_y = 'y', RGFW_z = 'z', - RGFW_period = '.', RGFW_comma = ',', RGFW_slash = '/', RGFW_bracket = '[', - RGFW_closeBracket = ']', + RGFW_closeBracket = ']', RGFW_semicolon = ';', RGFW_apostrophe = '\'', RGFW_backSlash = '\\', RGFW_return = '\n', RGFW_enter = RGFW_return, - RGFW_delete = '\177', /* 127 */ - RGFW_F1, RGFW_F2, RGFW_F3, @@ -1467,7 +539,19 @@ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_F10, RGFW_F11, RGFW_F12, - + RGFW_F13, + RGFW_F14, + RGFW_F15, + RGFW_F16, + RGFW_F17, + RGFW_F18, + RGFW_F19, + RGFW_F20, + RGFW_F21, + RGFW_F22, + RGFW_F23, + RGFW_F24, + RGFW_F25, RGFW_capsLock, RGFW_shiftL, RGFW_controlL, @@ -1482,41 +566,262 @@ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_left, RGFW_right, RGFW_insert, + RGFW_menu, RGFW_end, RGFW_home, RGFW_pageUp, RGFW_pageDown, - RGFW_numLock, - RGFW_KP_Slash, - RGFW_multiply, - RGFW_KP_Minus, - RGFW_KP_1, - RGFW_KP_2, - RGFW_KP_3, - RGFW_KP_4, - RGFW_KP_5, - RGFW_KP_6, - RGFW_KP_7, - RGFW_KP_8, - RGFW_KP_9, - RGFW_KP_0, - RGFW_KP_Period, - RGFW_KP_Return, + RGFW_kpSlash, + RGFW_kpMultiply, + RGFW_kpPlus, + RGFW_kpMinus, + RGFW_kpEqual, + RGFW_kp1, + RGFW_kp2, + RGFW_kp3, + RGFW_kp4, + RGFW_kp5, + RGFW_kp6, + RGFW_kp7, + RGFW_kp8, + RGFW_kp9, + RGFW_kp0, + RGFW_kpPeriod, + RGFW_kpReturn, RGFW_scrollLock, RGFW_printScreen, RGFW_pause, + RGFW_world1, + RGFW_world2, RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */ - }; +}; + +/*! @brief abstract mouse button codes */ +typedef RGFW_ENUM(u8, RGFW_mouseButton) { + RGFW_mouseLeft = 0, /*!< left mouse button is pressed */ + RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */ + RGFW_mouseRight, /*!< right mouse button is pressed */ + RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5, + RGFW_mouseFinal +}; + +/*! abstract key modifier codes */ +typedef RGFW_ENUM(u8, RGFW_keymod) { + RGFW_modCapsLock = RGFW_BIT(0), + RGFW_modNumLock = RGFW_BIT(1), + RGFW_modControl = RGFW_BIT(2), + RGFW_modAlt = RGFW_BIT(3), + RGFW_modShift = RGFW_BIT(4), + RGFW_modSuper = RGFW_BIT(5), + RGFW_modScrollLock = RGFW_BIT(6) +}; + +/*! @brief codes for the event types that can be sent */ +typedef RGFW_ENUM(u8, RGFW_eventType) { + RGFW_eventNone = 0, /*!< no event has been sent */ + RGFW_keyPressed, /* a key has been pressed */ + RGFW_keyReleased, /*!< a key has been released */ + /*! key event note + the code of the key pressed is stored in + RGFW_event.key.value + !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! + + while a string version is stored in + RGFW_event.key.valueString + + RGFW_event.key.mod holds the current mod + this means if CapsLock, NumLock are active or not + */ + RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */ + RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */ + RGFW_mouseScroll, /*!< a mouse scroll event */ + RGFW_mousePosChanged, /*!< the position of the mouse has been changed */ + /*! mouse event note + the x and y of the mouse can be found in the vector, RGFW_x, y + + RGFW_event.button.value holds which mouse button was pressed + */ + RGFW_windowMoved, /*!< the window was moved (by the user) */ + RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */ + RGFW_focusIn, /*!< window is in focus now */ + RGFW_focusOut, /*!< window is out of focus now */ + RGFW_mouseEnter, /* mouse entered the window */ + RGFW_mouseLeave, /* mouse left the window */ + RGFW_windowRefresh, /* The window content needs to be refreshed */ + + /* attribs change event note + The event data is sent straight to the window structure + with win->x, win->y, win->w and win->h + */ + RGFW_quit, /*!< the user clicked the quit button */ + RGFW_dataDrop, /*!< a file has been dropped into the window */ + RGFW_dataDrag, /*!< the start of a drag and drop event, when the file is being dragged */ + /* drop data note + The x and y coords of the drop are stored in the vector RGFW_x, y + + RGFW_event.drop.count holds how many files were dropped + + This is also the size of the array which stores all the dropped file string, + RGFW_event.drop.files + */ + RGFW_windowMaximized, /*!< the window was maximized */ + RGFW_windowMinimized, /*!< the window was minimized */ + RGFW_windowRestored, /*!< the window was restored */ + RGFW_scaleUpdated /*!< content scale factor changed */ +}; + +/*! @brief flags for toggling wether or not an event should be processed */ +typedef RGFW_ENUM(u32, RGFW_eventFlag) { + RGFW_keyPressedFlag = RGFW_BIT(RGFW_keyPressed), + RGFW_keyReleasedFlag = RGFW_BIT(RGFW_keyReleased), + RGFW_mouseScrollFlag = RGFW_BIT(RGFW_mouseScroll), + RGFW_mouseButtonPressedFlag = RGFW_BIT(RGFW_mouseButtonPressed), + RGFW_mouseButtonReleasedFlag = RGFW_BIT(RGFW_mouseButtonReleased), + RGFW_mousePosChangedFlag = RGFW_BIT(RGFW_mousePosChanged), + RGFW_mouseEnterFlag = RGFW_BIT(RGFW_mouseEnter), + RGFW_mouseLeaveFlag = RGFW_BIT(RGFW_mouseLeave), + RGFW_windowMovedFlag = RGFW_BIT(RGFW_windowMoved), + RGFW_windowResizedFlag = RGFW_BIT(RGFW_windowResized), + RGFW_focusInFlag = RGFW_BIT(RGFW_focusIn), + RGFW_focusOutFlag = RGFW_BIT(RGFW_focusOut), + RGFW_windowRefreshFlag = RGFW_BIT(RGFW_windowRefresh), + RGFW_windowMaximizedFlag = RGFW_BIT(RGFW_windowMaximized), + RGFW_windowMinimizedFlag = RGFW_BIT(RGFW_windowMinimized), + RGFW_windowRestoredFlag = RGFW_BIT(RGFW_windowRestored), + RGFW_scaleUpdatedFlag = RGFW_BIT(RGFW_scaleUpdated), + RGFW_quitFlag = RGFW_BIT(RGFW_quit), + RGFW_dataDropFlag = RGFW_BIT(RGFW_dataDrop), + RGFW_dataDragFlag = RGFW_BIT(RGFW_dataDrag), + + RGFW_keyEventsFlag = RGFW_keyPressedFlag | RGFW_keyReleasedFlag, + RGFW_mouseEventsFlag = RGFW_mouseButtonPressedFlag | RGFW_mouseButtonReleasedFlag | RGFW_mousePosChangedFlag | RGFW_mouseEnterFlag | RGFW_mouseLeaveFlag | RGFW_mouseScrollFlag , + RGFW_windowEventsFlag = RGFW_windowMovedFlag | RGFW_windowResizedFlag | RGFW_windowRefreshFlag | RGFW_windowMaximizedFlag | RGFW_windowMinimizedFlag | RGFW_windowRestoredFlag | RGFW_scaleUpdatedFlag, + RGFW_focusEventsFlag = RGFW_focusInFlag | RGFW_focusOutFlag, + RGFW_dataDropEventsFlag = RGFW_dataDropFlag | RGFW_dataDragFlag, + RGFW_allEventFlags = RGFW_keyEventsFlag | RGFW_mouseEventsFlag | RGFW_windowEventsFlag | RGFW_focusEventsFlag | RGFW_dataDropEventsFlag | RGFW_quitFlag +}; + +/*! Event structure(s) and union for checking/getting events */ + +/*! @brief common event data across all events */ +typedef struct RGFW_commonEvent { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_window* win; /*!< the window this event applies too (for event queue events) */ +} RGFW_commonEvent; + +/*! @brief event data for any mouse button event (press/release) */ +typedef struct RGFW_mouseButtonEvent { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_window* win; /*!< the window this event applies too (for event queue events) */ + u8 value; /* !< which mouse button was pressed */ +} RGFW_mouseButtonEvent; + +/*! @brief event data for any mouse scroll event */ +typedef struct RGFW_mouseScrollEvent { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_window* win; /*!< the window this event applies too (for event queue events) */ + float x, y; /*!< the raw mouse scroll value */ +} RGFW_mouseScrollEvent; + +/*! @brief event data for any mouse position event (RGFW_mousePosChanged) */ +typedef struct RGFW_mousePosEvent { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_window* win; /*!< the window this event applies too (for event queue events) */ + i32 x, y; /*!< mouse x, y of event (or drop point) */ + float vecX, vecY; /*!< raw mouse movement */ +} RGFW_mousePosEvent; + +/*! @brief event data for any key event (press/release) */ +typedef struct RGFW_keyEvent { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_window* win; /*!< the window this event applies too (for event queue events) */ + RGFW_key value; /*!< 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 sym; /*!< mapped key char of the event */ + RGFW_bool repeat; /*!< key press event repeated (the key is being held) */ + RGFW_keymod mod; +} RGFW_keyEvent; + +/*! @brief event data for any data drop event */ +typedef struct RGFW_dataDropEvent { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_window* win; /*!< the window this event applies too (for event queue events) */ + /* 260 max paths with a max length of 260 */ + char** files; /*!< dropped files */ + size_t count; /*!< how many files were dropped */ +} RGFW_dataDropEvent; + +/*! @brief event data for any data drag event */ +typedef struct RGFW_dataDragEvent { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_window* win; /*!< the window this event applies too (for event queue events) */ + i32 x, y; /*!< mouse x, y of event (or drop point) */ +} RGFW_dataDragEvent; + +/*! @brief event data for when the window scale (DPI) is updated */ +typedef struct RGFW_scaleUpdatedEvent { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_window* win; /*!< the window this event applies too (for event queue events) */ + float x, y; /*!< DPI scaling */ +} RGFW_scaleUpdatedEvent; + +/*! @brief union for all of the event stucture types */ +typedef union RGFW_event { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_commonEvent common; /*!< common event data (e.g.) type and win */ + RGFW_mouseButtonEvent button; /*!< data for a button press/release */ + RGFW_mouseScrollEvent scroll; /*!< data for a mouse scroll */ + RGFW_mousePosEvent mouse; /*!< data for mouse motion events */ + RGFW_keyEvent key; /*!< data for key press/release/hold events */ + RGFW_dataDropEvent drop; /*!< dropping a file events */ + RGFW_dataDragEvent drag; /* data for dragging a file events */ + RGFW_scaleUpdatedEvent scale; /* data for monitor scaling events */ +} RGFW_event; + +/*! + @!brief codes for for RGFW_the code is stupid and C++ waitForEvent + waitMS -> Allows the function to keep checking for events even after there are no more events + if waitMS == 0, the loop will not wait for events + if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns + if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event +*/ +typedef RGFW_ENUM(i32, RGFW_eventWait) { + RGFW_eventNoWait = 0, + RGFW_eventWaitNext = -1 +}; -/*! converts api keycode to the RGFW unmapped/physical key */ -RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode); -/*! converts RGFW keycode to the unmapped/physical api key */ -RGFWDEF u32 RGFW_rgfwToApiKey(u32 keycode); -/*! converts RGFW keycode to the mapped keychar */ -RGFWDEF u8 RGFW_rgfwToKeyChar(u32 keycode); +/*! @brief optional bitwise arguments for making a windows, these can be OR'd together */ +typedef RGFW_ENUM(u32, RGFW_windowFlags) { + RGFW_windowNoBorder = RGFW_BIT(0), /*!< the window doesn't have a border */ + RGFW_windowNoResize = RGFW_BIT(1), /*!< the window cannot be resized by the user */ + RGFW_windowAllowDND = RGFW_BIT(2), /*!< the window supports drag and drop */ + RGFW_windowHideMouse = RGFW_BIT(3), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_showMouse`) */ + RGFW_windowFullscreen = RGFW_BIT(4), /*!< the window is fullscreen by default */ + RGFW_windowTransparent = RGFW_BIT(5), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */ + RGFW_windowCenter = RGFW_BIT(6), /*! center the window on the screen */ + RGFW_windowScaleToMonitor = RGFW_BIT(8), /*! scale the window to the screen */ + RGFW_windowHide = RGFW_BIT(9), /*! the window is hidden */ + RGFW_windowMaximize = RGFW_BIT(10), /*!< maximize the window on creation */ + RGFW_windowCenterCursor = RGFW_BIT(11), /*!< center the cursor to the window on creation */ + RGFW_windowFloating = RGFW_BIT(12), /*!< create a floating window */ + RGFW_windowFocusOnShow = RGFW_BIT(13), /*!< focus the window when it's shown */ + RGFW_windowMinimize = RGFW_BIT(14), /*!< focus the window when it's shown */ + RGFW_windowFocus = RGFW_BIT(15), /*!< if the window is in focus */ + RGFW_windowOpenGL = RGFW_BIT(17), /*!< create an OpenGL context (you can also do this manually with RGFW_window_createContext_OpenGL) */ + RGFW_windowEGL = RGFW_BIT(18), /*!< create an EGL context (you can also do this manually with RGFW_window_createContext_EGL) */ + RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize +}; + +/*! @brief the types of icon to set */ +typedef RGFW_ENUM(u8, RGFW_icon) { + RGFW_iconTaskbar = RGFW_BIT(0), + RGFW_iconWindow = RGFW_BIT(1), + RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow +}; + +/*! @brief standard mouse icons */ typedef RGFW_ENUM(u8, RGFW_mouseIcons) { RGFW_mouseNormal = 0, RGFW_mouseArrow, @@ -1529,46 +834,2188 @@ typedef RGFW_ENUM(u8, RGFW_mouseIcons) { RGFW_mouseResizeNESW, RGFW_mouseResizeAll, RGFW_mouseNotAllowed, + RGFW_mouseIconCount, RGFW_mouseIconFinal = 16 /* padding for alignment */ }; + +/*! @brief the type of debug message */ +typedef RGFW_ENUM(u8, RGFW_debugType) { + RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo +}; + +/*! @brief error codes for known failure types */ +typedef RGFW_ENUM(u8, RGFW_errorCode) { + RGFW_noError = 0, /*!< no error */ + RGFW_errOutOfMemory, + RGFW_errOpenGLContext, RGFW_errEGLContext, /*!< error with the OpenGL context */ + RGFW_errWayland, RGFW_errX11, + RGFW_errDirectXContext, + RGFW_errIOKit, + RGFW_errClipboard, + RGFW_errFailedFuncLoad, + RGFW_errBuffer, + RGFW_errEventQueue, + RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL, + RGFW_warningWayland, RGFW_warningOpenGL +}; + +/*! @brief callback function type for debug messags */ +typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, const char* msg); + +/*! @brief RGFW_windowMoved, the window and its new rect value */ +typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, i32 x, i32 y); +/*! @brief RGFW_windowResized, the window and its new rect value */ +typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, i32 w, i32 h); +/*! @brief RGFW_windowRestored, the window and its new rect value */ +typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, i32 x, i32 y, i32 w, i32 h); +/*! @brief RGFW_windowMaximized, the window and its new rect value */ +typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, i32 x, i32 y, i32 w, i32 h); +/*! @brief RGFW_windowMinimized, the window and its new rect value */ +typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win); +/*! @brief RGFW_quit, the window that was closed */ +typedef void (* RGFW_windowQuitfunc)(RGFW_window* win); +/*! @brief RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */ +typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus); +/*! @brief RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */ +typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, i32 x, i32 y, RGFW_bool status); +/*! @brief RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */ +typedef void (* RGFW_mousePosfunc)(RGFW_window* win, i32 x, i32 y, float vecX, float vecY); +/*! @brief RGFW_dataDrag, the window, the point of the drop on the windows */ +typedef void (* RGFW_dataDragfunc)(RGFW_window* win, i32 x, i32 y); +/*! @brief RGFW_windowRefresh, the window that needs to be refreshed */ +typedef void (* RGFW_windowRefreshfunc)(RGFW_window* win); +/*! @brief RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */ +typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 sym, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool pressed); +/*! @brief 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, RGFW_mouseButton button, RGFW_bool pressed); +/*! @brief RGFW_mouseScroll, the window that got the event, the x scroll value, the y scroll value */ +typedef void (* RGFW_mouseScrollfunc)(RGFW_window* win, float x, float y); +/*! @brief RGFW_dataDrop the window that had the drop, the drop data and the number of files dropped */ +typedef void (* RGFW_dataDropfunc)(RGFW_window* win, char** files, size_t count); +/*! @brief RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */ +typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY); + +/*! @brief function pointer equivalent of void* */ +typedef void (*RGFW_proc)(void); + +#ifndef RGFW_NO_MONITOR + +/*! @brief monitor mode data | can be changed by the user (with functions)*/ +typedef struct RGFW_monitorMode { + i32 w, h; /*!< monitor workarea size */ + u32 refreshRate; /*!< monitor refresh rate */ + u8 red, blue, green; +} RGFW_monitorMode; + +/*! @brief structure for monitor data */ +typedef struct RGFW_monitor { + i32 x, y; /*!< x - y of the monitor workarea */ + char name[128]; /*!< monitor name */ + float scaleX, scaleY; /*!< monitor content scale */ + float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */ + float physW, physH; /*!< monitor physical size in inches */ + RGFW_monitorMode mode; +} RGFW_monitor; + +/*! @brief what type of request you are making for the monitor */ +typedef RGFW_ENUM(u8, RGFW_modeRequest) { + RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */ + RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */ + RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */ + RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB +}; + +#endif + +#if defined(RGFW_OPENGL) + +/*! @brief abstract structure for interfacing with the underlying OpenGL API */ +typedef struct RGFW_glContext RGFW_glContext; + +/*! @brief abstract structure for interfacing with the underlying EGL API */ +typedef struct RGFW_eglContext RGFW_eglContext; + +/*! values for the releaseBehavior hint */ +typedef RGFW_ENUM(i32, RGFW_glReleaseBehavior) { + RGFW_glReleaseFlush = 0, /*!< flush the pipeline will be flushed when the context is release */ + RGFW_glReleaseNone /*!< do nothing on release */ +}; + +/*! values for the profile hint */ +typedef RGFW_ENUM(i32, RGFW_glProfile) { + RGFW_glCore = 0, /*!< the core OpenGL version, e.g. just support for that version */ + RGFW_glCompatibility, /*!< allow compatibility for older versions of RGFW as well as the requested version */ + RGFW_glES /*!< use OpenGL ES */ +}; + +/*! values for the renderer hint */ +typedef RGFW_ENUM(i32, RGFW_glRenderer) { + RGFW_glAccelerated = 0, /*!< hardware accelerated (GPU) */ + RGFW_glSoftware /*!< software rendered (CPU) */ +}; + +/*! OpenGL initalization hints */ +typedef struct RGFW_glHints { + i32 stencil; /*!< set stencil buffer bit size (0 by default) */ + i32 samples; /*!< set number of sample buffers (0 by default) */ + i32 stereo; /*!< hint the context to use stereoscopic frame buffers for 3D (false by default) */ + i32 auxBuffers; /*!< number of aux buffers (0 by default) */ + i32 doubleBuffer; /*!< request double buffering (true by default) */ + i32 red, green, blue, alpha; /*!< set color bit sizes (all 8 by default) */ + i32 depth; /*!< set depth buffer bit size (24 by default) */ + i32 accumRed, accumGreen, accumBlue, accumAlpha; /*!< set accumulated RGBA bit sizes (all 0 by default) */ + RGFW_bool sRGB; /*!< request sRGA format (false by default) */ + RGFW_bool robustness; /*!< request a "robust" (as in memory-safe) context (false by default). For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_robustness.txt */ + RGFW_bool debug; /*!< request OpenGL debugging (false by default). */ + RGFW_bool noError; /*!< request no OpenGL errors (false by default). This causes OpenGL errors to be undefined behavior. For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_no_error.txt */ + RGFW_glReleaseBehavior releaseBehavior; /*!< hint how the OpenGL driver should behave when changing contexts (RGFW_glReleaseNone by default). For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_context_flush_control.txt */ + RGFW_glProfile profile; /*!< set OpenGL API profile (RGFW_glCore by default) */ + i32 major, minor; /*!< set the OpenGL API profile version (by default RGFW_glMajor is 1, RGFW_glMinor is 0) */ + RGFW_glContext* share; /*!< Share this OpenGL context with newly created OpenGL contexts; defaults to NULL. */ + RGFW_eglContext* shareEGL; /*!< Share this EGL context with newly created OpenGL contexts; defaults to NULL. */ + RGFW_glRenderer renderer; /*!< renderer to use e.g. accelerated or software defaults to accelerated */ +} RGFW_glHints; + +#endif + +/**! + * @brief Allocates memory using the allocator defined by RGFW_ALLOC at compile time. + * @param size The size (in bytes) of the memory block to allocate. + * @return A pointer to the allocated memory block. +*/ +RGFWDEF void* RGFW_alloc(size_t size); + +/**! + * @brief Frees memory using the deallocator defined by RGFW_FREE at compile time. + * @param ptr A pointer to the memory block to free. +*/ +RGFWDEF void RGFW_free(void* ptr); + +/**! + * @brief Returns the size (in bytes) of the RGFW_window structure. + * @return The size of the RGFW_window structure. +*/ +RGFWDEF size_t RGFW_sizeofWindow(void); + +/**! + * @brief Returns the size (in bytes) of the RGFW_window_src structure. + * @return The size of the RGFW_window_src structure. +*/ +RGFWDEF size_t RGFW_sizeofWindowSrc(void); + +/**! + * @brief (Unix) Toggles the use of Wayland. + * This is enabled by default when compiled with `RGFW_WAYLAND`. + * If not using `RGFW_WAYLAND`, Wayland functions are not exposed. + * This function can be used to force the use of XWayland. + * @param wayland A boolean value indicating whether to use Wayland (true) or not (false). +*/ +RGFWDEF void RGFW_useWayland(RGFW_bool wayland); + +/**! + * @brief Checks if Wayland is currently being used. + * @return RGFW_TRUE if using Wayland, RGFW_FALSE otherwise. +*/ +RGFWDEF RGFW_bool RGFW_usingWayland(void); + +/**! + * @brief Retrieves the current Cocoa layer (macOS only). + * @return A pointer to the Cocoa layer, or NULL if the platform is not in use. +*/ +RGFWDEF void* RGFW_getLayer_OSX(void); + +/**! + * @brief Retrieves the current X11 display connection. + * @return A pointer to the X11 display, or NULL if the platform is not in use. +*/ +RGFWDEF void* RGFW_getDisplay_X11(void); + +/**! + * @brief Retrieves the current Wayland display connection. + * @return A pointer to the Wayland display (`struct wl_display*`), or NULL if the platform is not in use. +*/ +RGFWDEF struct wl_display* RGFW_getDisplay_Wayland(void); + +/**! + * @brief Sets the class name for X11 and WinAPI windows. + * Windows with the same class name will be grouped by the window manager. + * By default, the class name matches the root window’s name. + * @param name The class name to assign. +*/ +RGFWDEF void RGFW_setClassName(const char* name); + +/**! + * @brief Sets the X11 instance name. + * By default, the window name will be used as the instance name. + * @param name The X11 instance name to set. +*/ +RGFWDEF void RGFW_setXInstName(const char* name); + +/**! + * @brief (macOS only) Changes the current working directory to the application’s resource folder. +*/ +RGFWDEF void RGFW_moveToMacOSResourceDir(void); + +/*! copy image to another image, respecting each image's format */ +RGFWDEF void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format); + +/**! + * @brief Returns the size (in bytes) of the RGFW_nativeImage structure. + * @return The size of the RGFW_nativeImage structure. +*/ +RGFWDEF size_t RGFW_sizeofNativeImage(void); + +/**! + * @brief Returns the size (in bytes) of the RGFW_surface structure. + * @return The size of the RGFW_surface structure. +*/ +RGFWDEF size_t RGFW_sizeofSurface(void); + +/**! + * @brief Creates a new surface from raw pixel data. + * @param data A pointer to the pixel data buffer. + * @param w The width of the surface in pixels. + * @param h The height of the surface in pixels. + * @param format The pixel format of the data. + * @return A pointer to the newly created RGFW_surface. + * + * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual + * this means it may fail to render on any other window if the visual does not match + * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues + * Of course, you can also manually set the root window with RGFW_setRootWindow +*/ +RGFWDEF RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format); + +/**! + * @brief Creates a surface using a pre-allocated RGFW_surface structure. + * @param data A pointer to the pixel data buffer. + * @param w The width of the surface in pixels. + * @param h The height of the surface in pixels. + * @param format The pixel format of the data. + * @param surface A pointer to a pre-allocated RGFW_surface structure. + * @return RGFW_TRUE if successful, RGFW_FALSE otherwise. +*/ +RGFWDEF RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface); + +/**! + * @brief Retrieves the native image associated with a surface. + * @param surface A pointer to the RGFW_surface. + * @return A pointer to the native RGFW_nativeImage associated with the surface. +*/ +RGFWDEF RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface); + +/**! + * @brief Frees the surface pointer and any buffers used for software rendering. + * @param surface A pointer to the RGFW_surface to free. +*/ +RGFWDEF void RGFW_surface_free(RGFW_surface* surface); + +/**! + * @brief Frees only the internal buffers used for software rendering, leaving the surface struct intact. + * @param surface A pointer to the RGFW_surface whose buffers should be freed. +*/ +RGFWDEF void RGFW_surface_freePtr(RGFW_surface* surface); + + +/**! + * @brief Loads a mouse icon from bitmap data (similar to RGFW_window_setIcon). + * @param data A pointer to the bitmap pixel data. + * @param w The width of the mouse icon in pixels. + * @param h The height of the mouse icon in pixels. + * @param format The pixel format of the data. + * @return A pointer to the newly loaded RGFW_mouse structure. + * + * @note The icon is not resized by default. +*/ +RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format); + +/**! + * @brief Frees the data associated with an RGFW_mouse structure. + * @param mouse A pointer to the RGFW_mouse to free. +*/ +RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse); + +#ifndef RGFW_NO_MONITOR + +/**! + * @brief Retrieves an array of all available monitors. + * @param len [OUTPUT] A pointer to store the number of monitors found (maximum of 6). + * @return A pointer to an array of RGFW_monitor structures. +*/ +RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len); + +/**! + * @brief Retrieves the primary monitor. + * @return The RGFW_monitor structure representing the primary monitor. +*/ +RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); + +/**! + * @brief Requests a specific display mode for a monitor. + * @param mon The monitor to apply the mode change to. + * @param mode The desired RGFW_monitorMode. + * @param request The RGFW_modeRequest describing how to handle the mode change. + * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE. +*/ +RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); + +/**! + * @brief Compares two monitor modes to check if they are equivalent. + * @param mon The first monitor mode. + * @param mon2 The second monitor mode. + * @param request The RGFW_modeRequest that defines the comparison parameters. + * @return RGFW_TRUE if both modes are equivalent, otherwise RGFW_FALSE. +*/ +RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request); + +/**! + * @brief Scales a monitor’s mode to match a window’s size. + * @param mon The monitor to be scaled. + * @param win The window whose size should be used as a reference. + * @return RGFW_TRUE if the scaling was successful, otherwise RGFW_FALSE. +*/ +RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, struct RGFW_window* win); + +#endif + +/**! +* @brief sleep until RGFW gets an event or the timer ends (defined by OS) +* @param waitMS how long to wait for the next event (in miliseconds) +*/ +RGFWDEF void RGFW_waitForEvent(i32 waitMS); + +/**! +* @brief Set if events should be queued or not (enabled by default if the event queue is checked) +* @param queue boolean value if RGFW should queue events or not +*/ +RGFWDEF void RGFW_setQueueEvents(RGFW_bool queue); + +/**! +* @brief check all the events until there are none left and updates window structure attributes +*/ +RGFWDEF void RGFW_pollEvents(void); + +/**! +* @brief check all the events until there are none left and updates window structure attributes +* queues events if the queue is checked and/or requested +*/ +RGFWDEF void RGFW_stopCheckEvents(void); + +/** * @defgroup Input +* @{ */ + +/**! + * @brief returns true if the key is pressed during the current frame + * @param key the key code of the key you want to check + * @return The boolean value if the key is pressed or not +*/ +RGFWDEF RGFW_bool RGFW_isKeyPressed(RGFW_key key); + +/**! + * @brief returns true if the key was released during the current frame + * @param key the key code of the key you want to check + * @return The boolean value if the key is released or not +*/ +RGFWDEF RGFW_bool RGFW_isKeyReleased(RGFW_key key); + +/**! + * @brief returns true if the key is down + * @param key the key code of the key you want to check + * @return The boolean value if the key is down or not +*/ +RGFWDEF RGFW_bool RGFW_isKeyDown(RGFW_key key); + +/**! + * @brief returns true if the mouse button is pressed during the current frame + * @param button the mouse button code of the button you want to check + * @return The boolean value if the button is pressed or not +*/ +RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button); + +/**! + * @brief returns true if the mouse button is released during the current frame + * @param button the mouse button code of the button you want to check + * @return The boolean value if the button is released or not +*/ +RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button); + +/**! + * @brief returns true if the mouse button is down + * @param button the mouse button code of the button you want to check + * @return The boolean value if the button is down or not +*/ +RGFWDEF RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button); + +/**! + * @brief outputs the current x, y position of the mouse + * @param X [OUTPUT] a pointer for the output X value + * @param Y [OUTPUT] a pointer for the output Y value +*/ +RGFWDEF void RGFW_getMouseScroll(float* x, float* y); + +/**! + * @brief outputs the current x, y movement vector of the mouse + * @param X [OUTPUT] a pointer for the output X vector value + * @param Y [OUTPUT] a pointer for the output Y vector value +*/ +RGFWDEF void RGFW_getMouseVector(float* x, float* y); /** @} */ -#endif /* RGFW_HEADER */ -#if defined(RGFW_X11) || defined(RGFW_WAYLAND) - #define RGFW_OS_BASED_VALUE(l, w, m, h) l -#elif defined(RGFW_WINDOWS) - #define RGFW_OS_BASED_VALUE(l, w, m, h) w -#elif defined(RGFW_MACOS) - #define RGFW_OS_BASED_VALUE(l, w, m, h) m -#elif defined(RGFW_WASM) - #define RGFW_OS_BASED_VALUE(l, w, m, h) h +/**! + * @brief creates a new window + * @param name the requested title of the window + * @param x the requested x position of the window + * @param y the requested y position of the window + * @param w the requested width of the window + * @param h the requested height of the window + * @param flags extra arguments ((u32)0 means no flags used) + * @return A pointer to the newly created window structure + * + * NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window +*/ +RGFWDEF RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags); + +/**! + * @brief creates a new window using a pre-allocated window structure + * @param name the requested title of the window + * @param x the requested x position of the window + * @param y the requested y position of the window + * @param w the requested width of the window + * @param h the requested height of the window + * @param flags extra arguments ((u32)0 means no flags used) + * @param win a pointer the pre-allocated window structure + * @return A pointer to the newly created window structure +*/ +RGFWDEF RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win); + +/**! + * @brief creates a new surface structure + * @param win the source window of the surface + * @param data a pointer to the raw data of the structure (you allocate this) + * @param w the width the data + * @param h the height of the data + * @return A pointer to the newly created surface structure + * + * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual + * this means it may fail to render on any other window if the visual does not match + * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues + * Of course, you can also manually set the root window with RGFW_setRootWindow + */ +RGFWDEF RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format); + +/**! + * @brief creates a new surface structure using a pre-allocated surface structure + * @param win the source window of the surface + * @param data a pointer to the raw data of the structure (you allocate this) + * @param w the width the data + * @param h the height of the data + * @param a pointer to the pre-allocated surface structure + * @return a bool if the creation was successful or not +*/ +RGFWDEF RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface); + +/**! + * @brief blits a surface stucture to the window + * @param win a pointer the window to blit to + * @param surface a pointer to the surface +*/ +RGFWDEF void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface); + +/**! + * @brief gets the position of the window | with RGFW_window.x and window.y + * @param x [OUTPUT] the x position of the window + * @param y [OUTPUT] the y position of the window + * @return a bool if the function was successful +*/ +RGFWDEF RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y); /*!< */ + +/**! + * @brief gets the size of the window | with RGFW_window.w and window.h + * @param win a pointer to the window + * @param w [OUTPUT] the width of the window + * @param h [OUTPUT] the height of the window + * @return a bool if the function was successful +*/ +RGFWDEF RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h); + +/**! + * @brief gets the flags of the window | returns RGFW_window._flags + * @param win a pointer to the window + * @return the window flags +*/ +RGFWDEF u32 RGFW_window_getFlags(RGFW_window* win); + +/**! + * @brief returns the exit key assigned to the window + * @param win a pointer to the target window + * @return The key code assigned as the exit key +*/ +RGFWDEF RGFW_key RGFW_window_getExitKey(RGFW_window* win); + +/**! + * @brief sets the exit key for the window + * @param win a pointer to the target window + * @param key the key code to assign as the exit key +*/ +RGFWDEF void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key); + +/**! + * @brief sets the types of events you want the window to receive + * @param win a pointer to the target window + * @param events the event flags to enable (use RGFW_allEventFlags for all) +*/ +RGFWDEF void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events); + +/**! + * @brief gets the currently enabled events for the window + * @param win a pointer to the target window + * @return The enabled event flags for the window +*/ +RGFWDEF RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win); + +/**! + * @brief enables all events and disables selected ones + * @param win a pointer to the target window + * @param events the event flags to disable +*/ +RGFWDEF void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events); + +/**! + * @brief directly enables or disables a specific event or group of events + * @param win a pointer to the target window + * @param event the event flag or group of flags to modify + * @param state RGFW_TRUE to enable, RGFW_FALSE to disable +*/ +RGFWDEF void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state); + +/**! + * @brief gets the user pointer associated with the window + * @param win a pointer to the target window + * @return The user-defined pointer stored in the window +*/ +RGFWDEF void* RGFW_window_getUserPtr(RGFW_window* win); + +/**! + * @brief sets a user pointer for the window + * @param win a pointer to the target window + * @param ptr a pointer to associate with the window +*/ +RGFWDEF void RGFW_window_setUserPtr(RGFW_window* win, void* ptr); + +/**! + * @brief retrieves the platform-specific window source pointer + * @param win a pointer to the target window + * @return A pointer to the internal RGFW_window_src structure +*/ +RGFWDEF RGFW_window_src* RGFW_window_getSrc(RGFW_window* win); + +/**! + * @brief sets the macOS layer object associated with the window + * @param win a pointer to the target window + * @param layer a pointer to the macOS layer object + * @note Only available on macOS platforms +*/ +RGFWDEF void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer); + +/**! + * @brief retrieves the macOS view object associated with the window + * @param win a pointer to the target window + * @return A pointer to the macOS view object, or NULL if not on macOS +*/ +RGFWDEF void* RGFW_window_getView_OSX(RGFW_window* win); + +/**! + * @brief retrieves the macOS window object + * @param win a pointer to the target window + * @return A pointer to the macOS window object, or NULL if not on macOS +*/ +RGFWDEF void* RGFW_window_getWindow_OSX(RGFW_window* win); + +/**! + * @brief retrieves the HWND handle for the window + * @param win a pointer to the target window + * @return A pointer to the Windows HWND handle, or NULL if not on Windows +*/ +RGFWDEF void* RGFW_window_getHWND(RGFW_window* win); + +/**! + * @brief retrieves the HDC handle for the window + * @param win a pointer to the target window + * @return A pointer to the Windows HDC handle, or NULL if not on Windows +*/ +RGFWDEF void* RGFW_window_getHDC(RGFW_window* win); + +/**! + * @brief retrieves the X11 Window handle for the window + * @param win a pointer to the target window + * @return The X11 Window handle, or 0 if not on X11 +*/ +RGFWDEF u64 RGFW_window_getWindow_X11(RGFW_window* win); + +/**! + * @brief retrieves the Wayland surface handle for the window + * @param win a pointer to the target window + * @return A pointer to the Wayland wl_surface, or NULL if not on Wayland +*/ +RGFWDEF struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win); + +/** * @defgroup Window_management +* @{ */ + +/*! set the window flags (will undo flags if they don't match the old ones) */ +RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags); + +/**! + * @brief polls and pops the next event from the window's event queue + * @param win a pointer to the target window + * @param event [OUTPUT] a pointer to store the retrieved event + * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise + * + * NOTE: Using this function without a loop may cause event lag. + * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_window_checkQueuedEvent. + * + * Example: + * RGFW_event event; + * while (RGFW_window_checkEvent(win, &event)) { + * // handle event + * } +*/ +RGFWDEF RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event); + +/**! + * @brief pops the first queued event for the window + * @param win a pointer to the target window + * @param event [OUTPUT] a pointer to store the retrieved event + * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event); + +/**! + * @brief checks if a key was pressed while the window is in focus + * @param win a pointer to the target window + * @param key the key code to check + * @return RGFW_TRUE if the key was pressed, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key); + +/**! + * @brief checks if a key is currently being held down + * @param win a pointer to the target window + * @param key the key code to check + * @return RGFW_TRUE if the key is held down, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key); + +/**! + * @brief checks if a key was released + * @param win a pointer to the target window + * @param key the key code to check + * @return RGFW_TRUE if the key was released, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key); + +/**! + * @brief checks if a mouse button was pressed + * @param win a pointer to the target window + * @param button the mouse button code to check + * @return RGFW_TRUE if the mouse button was pressed, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button); + +/**! + * @brief checks if a mouse button is currently held down + * @param win a pointer to the target window + * @param button the mouse button code to check + * @return RGFW_TRUE if the mouse button is down, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button); + +/**! + * @brief checks if a mouse button was released + * @param win a pointer to the target window + * @param button the mouse button code to check + * @return RGFW_TRUE if the mouse button was released, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button); + +/**! + * @brief checks if the mouse left the window (true only for the first frame) + * @param win a pointer to the target window + * @return RGFW_TRUE if the mouse left, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win); + +/**! + * @brief checks if the mouse entered the window (true only for the first frame) + * @param win a pointer to the target window + * @return RGFW_TRUE if the mouse entered, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win); + +/**! + * @brief checks if the mouse is currently inside the window bounds + * @param win a pointer to the target window + * @return RGFW_TRUE if the mouse is inside, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isMouseInside(RGFW_window* win); + +/**! + * @brief checks if there is data being dragged into or within the window + * @param win a pointer to the target window + * @return RGFW_TRUE if data is being dragged, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isDataDragging(RGFW_window* win); + +/**! + * @brief gets the position of a data drag + * @param win a pointer to the target window + * @param x [OUTPUT] pointer to store the x position + * @param y [OUTPUT] pointer to store the y position + * @return RGFW_TRUE if there is an active drag, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y); + +/**! + * @brief checks if a data drop occurred in the window (first frame only) + * @param win a pointer to the target window + * @return RGFW_TRUE if data was dropped, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_didDataDrop(RGFW_window* win); + +/**! + * @brief retrieves files from a data drop (drag and drop) + * @param win a pointer to the target window + * @param files [OUTPUT] a pointer to the array of file paths + * @param count [OUTPUT] the number of dropped files + * @return RGFW_TRUE if a data drop occurred, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_getDataDrop(RGFW_window* win, const char*** files, size_t* count); + +/**! + * @brief closes the window and frees its associated structure + * @param win a pointer to the target window +*/ +RGFWDEF void RGFW_window_close(RGFW_window* win); + +/**! + * @brief closes the window without freeing its structure + * @param win a pointer to the target window +*/ +RGFWDEF void RGFW_window_closePtr(RGFW_window* win); + +/**! + * @brief moves the window to a new position on the screen + * @param win a pointer to the target window + * @param x the new x position + * @param y the new y position +*/ +RGFWDEF void RGFW_window_move(RGFW_window* win, i32 x, i32 y); + +#ifndef RGFW_NO_MONITOR +/**! + * @brief moves the window to a specific monitor + * @param win a pointer to the target window + * @param m the target monitor +*/ +RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m); #endif +/**! + * @brief resizes the window to the given dimensions + * @param win a pointer to the target window + * @param w the new width + * @param h the new height +*/ +RGFWDEF void RGFW_window_resize(RGFW_window* win, i32 w, i32 h); + +/**! + * @brief sets the aspect ratio of the window + * @param win a pointer to the target window + * @param w the width ratio + * @param h the height ratio +*/ +RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h); + +/**! + * @brief sets the minimum size of the window + * @param win a pointer to the target window + * @param w the minimum width + * @param h the minimum height +*/ +RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h); + +/**! + * @brief sets the maximum size of the window + * @param win a pointer to the target window + * @param w the maximum width + * @param h the maximum height +*/ +RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h); + +/**! + * @brief sets focus to the window + * @param win a pointer to the target window +*/ +RGFWDEF void RGFW_window_focus(RGFW_window* win); + +/**! + * @brief checks if the window is currently in focus + * @param win a pointer to the target window + * @return RGFW_TRUE if the window is in focus, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); + +/**! + * @brief raises the window to the top of the stack + * @param win a pointer to the target window +*/ +RGFWDEF void RGFW_window_raise(RGFW_window* win); + +/**! + * @brief maximizes the window + * @param win a pointer to the target window +*/ +RGFWDEF void RGFW_window_maximize(RGFW_window* win); + +/**! + * @brief toggles fullscreen mode for the window + * @param win a pointer to the target window + * @param fullscreen RGFW_TRUE to enable fullscreen, RGFW_FALSE to disable +*/ +RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); + +/**! + * @brief centers the window on the screen + * @param win a pointer to the target window +*/ +RGFWDEF void RGFW_window_center(RGFW_window* win); + +/**! + * @brief minimizes the window + * @param win a pointer to the target window +*/ +RGFWDEF void RGFW_window_minimize(RGFW_window* win); + +/**! + * @brief restores the window from minimized state + * @param win a pointer to the target window +*/ +RGFWDEF void RGFW_window_restore(RGFW_window* win); + +/**! + * @brief makes the window a floating window + * @param win a pointer to the target window + * @param floating RGFW_TRUE to float, RGFW_FALSE to disable +*/ +RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); + +/**! + * @brief sets the opacity level of the window + * @param win a pointer to the target window + * @param opacity the opacity level (0–255) +*/ +RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); + +/**! + * @brief toggles window borders + * @param win a pointer to the target window + * @param border RGFW_TRUE for bordered, RGFW_FALSE for borderless +*/ +RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border); + +/**! + * @brief checks if the window is borderless + * @param win a pointer to the target window + * @return RGFW_TRUE if borderless, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win); + +/**! + * @brief toggles drag-and-drop (DND) support for the window + * @param win a pointer to the target window + * @param allow RGFW_TRUE to allow DND, RGFW_FALSE to disable + * @note RGFW_windowAllowDND must still be passed when creating the window +*/ +RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow); + +/**! + * @brief checks if drag-and-drop (DND) is allowed + * @param win a pointer to the target window + * @return RGFW_TRUE if DND is enabled, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win); + +#ifndef RGFW_NO_PASSTHROUGH +/**! + * @brief toggles mouse passthrough for the window + * @param win a pointer to the target window + * @param passthrough RGFW_TRUE to enable passthrough, RGFW_FALSE to disable +*/ +RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough); +#endif + +/**! + * @brief renames the window + * @param win a pointer to the target window + * @param name the new title string for the window +*/ +RGFWDEF void RGFW_window_setName(RGFW_window* win, const char* name); + +/**! + * @brief sets the icon for the window and taskbar + * @param win a pointer to the target window + * @param data the image data + * @param w the width of the icon + * @param h the height of the icon + * @param format the image format + * @return RGFW_TRUE if successful, RGFW_FALSE otherwise + * + * NOTE: The image may be resized by default. +*/ +RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format); + +/**! + * @brief sets the icon for the window and/or taskbar + * @param win a pointer to the target window + * @param data the image data + * @param w the width of the icon + * @param h the height of the icon + * @param format the image format + * @param type the target icon type (taskbar, window, or both) + * @return RGFW_TRUE if successful, RGFW_FALSE otherwise +*/ +RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type); + +/**! + * @brief sets the mouse icon for the window using a loaded bitmap + * @param win a pointer to the target window + * @param mouse a pointer to the RGFW_mouse struct containing the icon +*/ +RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse); + +/**! + * @brief Sets the mouse to a standard system cursor. + * @param win The target window. + * @param mouse The standard cursor type (see RGFW_MOUSE enum). + * @return True if the standard cursor was successfully applied. +*/ +RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, RGFW_mouseIcons mouse); + +/**! + * @brief Sets the mouse to the default cursor icon. + * @param win The target window. + * @return True if the default cursor was successfully set. +*/ +RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); + +/**! + * @brief Locks the cursor to the center of the window. + * @param win The target window. + * + * While the cursor is held, X and Y report raw mouse movement data. + * Useful for 3D camera or first-person movement systems. +*/ +RGFWDEF void RGFW_window_holdMouse(RGFW_window* win); + +/**! + * @brief Returns true if the mouse is currently held by RGFW. + * @param win The target window. + * @return True if the mouse is being held. +*/ +RGFWDEF RGFW_bool RGFW_window_isHoldingMouse(RGFW_window* win); + +/**! + * @brief Releases the mouse so it can move freely again. + * @param win The target window. +*/ +RGFWDEF void RGFW_window_unholdMouse(RGFW_window* win); + +/**! + * @brief Hides the window from view. + * @param win The target window. +*/ +RGFWDEF void RGFW_window_hide(RGFW_window* win); + +/**! + * @brief Shows the window if it was hidden. + * @param win The target window. +*/ +RGFWDEF void RGFW_window_show(RGFW_window* win); + +/**! + * @brief Sets whether the window should close. + * @param win The target window. + * @param shouldClose True to signal the window should close, false to keep it open. + * + * This can override or trigger the `RGFW_window_shouldClose` state by modifying window flags. +*/ +RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose); + +/**! + * @brief Retrieves the current global mouse position. + * @param x [OUTPUT] Pointer to store the X position of the mouse on the screen. + * @param y [OUTPUT] Pointer to store the Y position of the mouse on the screen. + * @return True if the position was successfully retrieved. +*/ +RGFWDEF RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y); + +/**! + * @brief Retrieves the mouse position relative to the window. + * @param win The target window. + * @param x [OUTPUT] Pointer to store the X position within the window. + * @param y [OUTPUT] Pointer to store the Y position within the window. + * @return True if the position was successfully retrieved. +*/ +RGFWDEF RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y); + +/**! + * @brief Shows or hides the mouse cursor for the window. + * @param win The target window. + * @param show True to show the mouse, false to hide it. +*/ +RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show); + +/**! + * @brief Checks if the mouse is currently hidden in the window. + * @param win The target window. + * @return True if the mouse is hidden. +*/ +RGFWDEF RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win); + +/**! + * @brief Moves the mouse to the specified position within the window. + * @param win The target window. + * @param x The new X position. + * @param y The new Y position. +*/ +RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y); + +/**! + * @brief Checks if the window should close. + * @param win The target window. + * @return True if the window should close (for example, if ESC was pressed or a close event occurred). +*/ +RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win); + +/**! + * @brief Checks if the window is currently fullscreen. + * @param win The target window. + * @return True if the window is fullscreen. +*/ +RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win); + +/**! + * @brief Checks if the window is currently hidden. + * @param win The target window. + * @return True if the window is hidden. +*/ +RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win); + +/**! + * @brief Checks if the window is minimized. + * @param win The target window. + * @return True if the window is minimized. +*/ +RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win); + +/**! + * @brief Checks if the window is maximized. + * @param win The target window. + * @return True if the window is maximized. +*/ +RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win); + +/**! + * @brief Checks if the window is floating. + * @param win The target window. + * @return True if the window is floating. +*/ +RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win); +/** @} */ + +/** * @defgroup Monitor +* @{ */ + +#ifndef RGFW_NO_MONITOR +/**! + * @brief Scales the window to match its monitor’s resolution. + * @param win The target window. + * + * This function is automatically called when the flag `RGFW_scaleToMonitor` + * is used during window creation. +*/ +RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win); + +/**! + * @brief Retrieves the monitor structure associated with the window. + * @param win The target window. + * @return The monitor structure of the window. +*/ +RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); +#endif + +/** @} */ + +/** * @defgroup Clipboard +* @{ */ + +/**! + * @brief Reads clipboard data. + * @param size [OUTPUT] A pointer that will be filled with the size of the clipboard data. + * @return A pointer to the clipboard data as a string. +*/ +RGFWDEF const char* RGFW_readClipboard(size_t* size); + +/**! + * @brief Reads clipboard data into a provided buffer, or returns the required length if str is NULL. + * @param str [OUTPUT] A pointer to the buffer that will receive the clipboard data (or NULL to get required size). + * @param strCapacity The capacity of the provided buffer. + * @return The number of bytes read or required length of clipboard data. +*/ +RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity); + +/**! + * @brief Writes text to the clipboard. + * @param text The text to be written to the clipboard. + * @param textLen The length of the text being written. +*/ +RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); +/** @} */ + + + +/** * @defgroup error handling +* @{ */ +/**! + * @brief Sets the callback function to handle debug messages from RGFW. + * @param func The function pointer to be used as the debug callback. + * @return The previously set debug callback function. +*/ +RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func); + +/**! + * @brief Sends a debug message manually through the currently set debug callback. + * @param type The type of debug message being sent. + * @param err The associated error code. + * @param msg The debug message text. +*/ +RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char* msg); +/** @} */ + +/** + + + event callbacks. + These are completely optional, so you can use the normal + RGFW_checkEvent() method if you prefer that + +* @defgroup Callbacks +* @{ +*/ + +/**! + * @brief Sets the callback function for window move events. + * @param func The function to be called when the window is moved. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func); + +/**! + * @brief Sets the callback function for window resize events. + * @param func The function to be called when the window is resized. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func); + +/**! + * @brief Sets the callback function for window quit events. + * @param func The function to be called when the window receives a quit signal. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func); + +/**! + * @brief Sets the callback function for mouse move events. + * @param func The function to be called when the mouse moves within the window. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func); + +/**! + * @brief Sets the callback function for window refresh events. + * @param func The function to be called when the window needs to be refreshed. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func); + +/**! + * @brief Sets the callback function for focus change events. + * @param func The function to be called when the window gains or loses focus. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func); + +/**! + * @brief Sets the callback function for mouse notification events. + * @param func The function to be called when a mouse notification event occurs. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func); + +/**! + * @brief Sets the callback function for data drop events. + * @param func The function to be called when data is dropped into the window. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_dataDropfunc RGFW_setDataDropCallback(RGFW_dataDropfunc func); + +/**! + * @brief Sets the callback function for the start of a data drag event. + * @param func The function to be called when data dragging begins. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_dataDragfunc RGFW_setDataDragCallback(RGFW_dataDragfunc func); + +/**! + * @brief Sets the callback function for key press and release events. + * @param func The function to be called when a key is pressed or released. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func); + +/**! + * @brief Sets the callback function for mouse button press and release events. + * @param func The function to be called when a mouse button is pressed or released. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func); + +/**! + * @brief Sets the callback function for mouse scroll events. + * @param func The function to be called when the mouse wheel is scrolled. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_mouseScrollfunc RGFW_setMouseScrollCallback(RGFW_mouseScrollfunc func); + +/**! + * @brief Sets the callback function for window maximize events. + * @param func The function to be called when the window is maximized. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_windowMaximizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowMaximizedfunc func); + +/**! + * @brief Sets the callback function for window minimize events. + * @param func The function to be called when the window is minimized. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_windowMinimizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowMinimizedfunc func); + +/**! + * @brief Sets the callback function for window restore events. + * @param func The function to be called when the window is restored from a minimized or maximized state. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_windowRestoredfunc RGFW_setWindowRestoredCallback(RGFW_windowRestoredfunc func); + +/**! + * @brief Sets the callback function for DPI (scale) update events. + * @param func The function to be called when the window’s DPI or scale changes. + * @return The previously set callback function, if any. +*/ +RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func); +/** @} */ + +/** * @defgroup graphics_API +* @{ */ + +/*! native rendering API functions */ +#if defined(RGFW_OPENGL) +/* these are native opengl specific functions and will NOT work with EGL */ + +/*!< make the window the current OpenGL drawing context + + NOTE: + if you want to switch the graphics context's thread, + you have to run RGFW_window_makeCurrentContext_OpenGL(NULL); on the old thread + then RGFW_window_makeCurrentContext_OpenGL(valid_window) on the new thread +*/ + +/**! + * @brief Sets the global OpenGL hints to the specified pointer. + * @param hints A pointer to the RGFW_glHints structure containing the desired OpenGL settings. +*/ +RGFWDEF void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints); + +/**! + * @brief Resets the global OpenGL hints to their default values. +*/ +RGFWDEF void RGFW_resetGlobalHints_OpenGL(void); + +/**! + * @brief Gets the current global OpenGL hints pointer. + * @return A pointer to the currently active RGFW_glHints structure. +*/ +RGFWDEF RGFW_glHints* RGFW_getGlobalHints_OpenGL(void); + +/**! + * @brief Creates and allocates an OpenGL context for the specified window. + * @param win A pointer to the target RGFW_window. + * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. + * @return A pointer to the newly created RGFW_glContext. +*/ +RGFWDEF RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints); + +/**! + * @brief Creates an OpenGL context for the specified window using a preallocated context structure. + * @param win A pointer to the target RGFW_window. + * @param ctx A pointer to an already allocated RGFW_glContext structure. + * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. + * @return RGFW_TRUE on success, RGFW_FALSE on failure. +*/ +RGFWDEF RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints); + +/**! + * @brief Retrieves the OpenGL context associated with a window. + * @param win A pointer to the RGFW_window. + * @return A pointer to the associated RGFW_glContext, or NULL if none exists or if the context is EGL-based. +*/ +RGFWDEF RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win); + +/**! + * @brief Deletes and frees the OpenGL context. + * @param win A pointer to the RGFW_window. + * @param ctx A pointer to the RGFW_glContext to delete. + * + * @note This is automatically called by RGFW_window_close if the window’s context is not NULL. +*/ +RGFWDEF void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx); + +/**! + * @brief Deletes the OpenGL context without freeing its memory. + * @param win A pointer to the RGFW_window. + * @param ctx A pointer to the RGFW_glContext to delete. + * + * @note This is automatically called by RGFW_window_close if the window’s context is not NULL. +*/ +RGFWDEF void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx); + +/**! + * @brief Retrieves the native source context from an RGFW_glContext. + * @param ctx A pointer to the RGFW_glContext. + * @return A pointer to the native OpenGL context handle. +*/ +RGFWDEF void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx); + +/**! + * @brief Makes the specified window the current OpenGL rendering target. + * @param win A pointer to the RGFW_window to make current. + * + * @note This is typically called internally by RGFW_window_makeCurrent. +*/ +RGFWDEF void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win); + +/**! + * @brief Makes the OpenGL context of the specified window current. + * @param win A pointer to the RGFW_window whose context should be made current. + * + * @note To move a context between threads, call RGFW_window_makeCurrentContext_OpenGL(NULL) + * on the old thread before making it current on the new one. +*/ +RGFWDEF void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win); + +/**! + * @brief Swaps the OpenGL buffers for the specified window. + * @param win A pointer to the RGFW_window whose buffers should be swapped. + * + * @note Typically called by RGFW_window_swapInterval. +*/ +RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); + +/**! + * @brief Retrieves the current OpenGL context. + * @return A pointer to the currently active OpenGL context (GLX, WGL, Cocoa, or WebGL backend). +*/ +RGFWDEF void* RGFW_getCurrentContext_OpenGL(void); + +/**! + * @brief Retrieves the current OpenGL window. + * @return A pointer to the RGFW_window currently bound as the OpenGL context target. +*/ +RGFWDEF RGFW_window* RGFW_getCurrentWindow_OpenGL(void); + +/**! + * @brief Sets the OpenGL swap interval (vsync). + * @param win A pointer to the RGFW_window. + * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable). +*/ +RGFWDEF void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval); + +/**! + * @brief Retrieves the address of a native OpenGL procedure. + * @param procname The name of the OpenGL function to look up. + * @return A pointer to the function, or NULL if not found. +*/ +RGFWDEF RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname); + +/**! + * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported. + * @param extension The name of the extension to check. + * @param len The length of the extension string. + * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. +*/ +RGFWDEF RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len); + +/**! + * @brief Checks whether a specific platform-dependent OpenGL extension is supported. + * @param extension The name of the extension to check. + * @param len The length of the extension string. + * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. +*/ +RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len); + +/* these are EGL specific functions, they may fallback to OpenGL */ +#ifdef RGFW_EGL +/**! + * @brief Creates and allocates an OpenGL/EGL context for the specified window. + * @param win A pointer to the target RGFW_window. + * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. + * @return A pointer to the newly created RGFW_eglContext. +*/ +RGFWDEF RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints); + +/**! + * @brief Creates an OpenGL/EGL context for the specified window using a preallocated context structure. + * @param win A pointer to the target RGFW_window. + * @param ctx A pointer to an already allocated RGFW_eglContext structure. + * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. + * @return RGFW_TRUE on success, RGFW_FALSE on failure. +*/ +RGFWDEF RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints); + +/**! + * @brief Frees and deletes an OpenGL/EGL context. + * @param win A pointer to the RGFW_window. + * @param ctx A pointer to the RGFW_eglContext to delete. + * + * @note Automatically called by RGFW_window_close if RGFW owns the context. +*/ +RGFWDEF void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx); + +/**! + * @brief Deletes an OpenGL/EGL context without freeing its memory. + * @param win A pointer to the RGFW_window. + * @param ctx A pointer to the RGFW_eglContext to delete. + * + * @note Automatically called by RGFW_window_close if RGFW owns the context. +*/ +RGFWDEF void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx); + +/**! + * @brief Retrieves the OpenGL/EGL context associated with a window. + * @param win A pointer to the RGFW_window. + * @return A pointer to the associated RGFW_eglContext, or NULL if none exists or if the context is a native OpenGL context. +*/ +RGFWDEF RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win); + +/**! + * @brief Retrieves the EGL display handle. + * @return A pointer to the native EGLDisplay. +*/ +RGFWDEF void* RGFW_getDisplay_EGL(void); + +/**! + * @brief Retrieves the native source context from an RGFW_eglContext. + * @param ctx A pointer to the RGFW_eglContext. + * @return A pointer to the native EGLContext handle. +*/ +RGFWDEF void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx); + +/**! + * @brief Retrieves the EGL surface handle from an RGFW_eglContext. + * @param ctx A pointer to the RGFW_eglContext. + * @return A pointer to the EGLSurface associated with the context. +*/ +RGFWDEF void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx); + +/**! + * @brief Retrieves the Wayland EGL window handle from an RGFW_eglContext. + * @param ctx A pointer to the RGFW_eglContext. + * @return A pointer to the wl_egl_window associated with the EGL context. +*/ +RGFWDEF struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx); + +/**! + * @brief Swaps the EGL buffers for the specified window. + * @param win A pointer to the RGFW_window whose buffers should be swapped. + * + * @note Typically called by RGFW_window_swapInterval. +*/ +RGFWDEF void RGFW_window_swapBuffers_EGL(RGFW_window* win); + +/**! + * @brief Makes the specified window the current EGL rendering target. + * @param win A pointer to the RGFW_window to make current. + * + * @note This is typically called internally by RGFW_window_makeCurrent. +*/ +RGFWDEF void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win); + +/**! + * @brief Makes the EGL context of the specified window current. + * @param win A pointer to the RGFW_window whose context should be made current. + * + * @note To move a context between threads, call RGFW_window_makeCurrentContext_EGL(NULL) + * on the old thread before making it current on the new one. +*/ +RGFWDEF void RGFW_window_makeCurrentContext_EGL(RGFW_window* win); + +/**! + * @brief Retrieves the current EGL context. + * @return A pointer to the currently active EGLContext. +*/ +RGFWDEF void* RGFW_getCurrentContext_EGL(void); + +/**! + * @brief Retrieves the current EGL window. + * @return A pointer to the RGFW_window currently bound as the EGL context target. +*/ +RGFWDEF RGFW_window* RGFW_getCurrentWindow_EGL(void); + +/**! + * @brief Sets the EGL swap interval (vsync). + * @param win A pointer to the RGFW_window. + * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable). +*/ +RGFWDEF void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval); + +/**! + * @brief Retrieves the address of a native OpenGL or OpenGL ES procedure in an EGL context. + * @param procname The name of the OpenGL function to look up. + * @return A pointer to the function, or NULL if not found. +*/ +RGFWDEF RGFW_proc RGFW_getProcAddress_EGL(const char* procname); + +/**! + * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported in the current EGL context. + * @param extension The name of the extension to check. + * @param len The length of the extension string. + * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. +*/ +RGFWDEF RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len); + +/**! + * @brief Checks whether a specific platform-dependent EGL extension is supported in the current context. + * @param extension The name of the extension to check. + * @param len The length of the extension string. + * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. +*/ +RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len); +#endif +#endif + +#ifdef RGFW_VULKAN +#include + +/* if you don't want to use the above macros */ + +/**! + * @brief Retrieves the Vulkan instance extensions required by RGFW. + * @param count [OUTPUT] A pointer that will receive the number of required extensions (typically 2). + * @return A pointer to a static array of required Vulkan instance extension names. +*/ +RGFWDEF const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count); + +/**! + * @brief Creates a Vulkan surface for the specified window. + * @param win A pointer to the RGFW_window for which to create the Vulkan surface. + * @param instance The Vulkan instance used to create the surface. + * @param surface [OUTPUT] A pointer to a VkSurfaceKHR handle that will receive the created surface. + * @return A VkResult indicating success or failure. +*/ +RGFWDEF VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface); + +/**! + * @brief Checks whether the specified Vulkan physical device and queue family support presentation for RGFW. + * @param instance The Vulkan instance. + * @param physicalDevice The Vulkan physical device to check. + * @param queueFamilyIndex The index of the queue family to query for presentation support. + * @return RGFW_TRUE if presentation is supported, RGFW_FALSE otherwise. +*/ +RGFWDEF RGFW_bool RGFW_getPresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex); +#endif + +#ifdef RGFW_DIRECTX +#ifndef RGFW_WINDOWS + #undef RGFW_DIRECTX +#else + #define OEMRESOURCE + #include + + #ifndef __cplusplus + #define __uuidof(T) IID_##T + #endif +/**! + * @brief Creates a DirectX swap chain for the specified RGFW window. + * @param win A pointer to the RGFW_window for which to create the swap chain. + * @param pFactory A pointer to the IDXGIFactory used to create the swap chain. + * @param pDevice A pointer to the DirectX device (e.g., ID3D11Device or ID3D12Device). + * @param swapchain [OUTPUT] A pointer to an IDXGISwapChain pointer that will receive the created swap chain. + * @return An integer result code (0 on success, or a DirectX error code on failure). +*/ +RGFWDEF int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain); +#endif +#endif + +#ifdef RGFW_WEBGPU + #include + /**! + * @brief Creates a WebGPU surface for the specified RGFW window. + * @param window A pointer to the RGFW_window for which to create the surface. + * @param instance The WebGPU instance used to create the surface. + * @return The created WGPUSurface handle. + */ + RGFWDEF WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance); +#endif + +/** @} */ + +/** * @defgroup Supporting +* @{ */ + +/**! + * @brief Sets the root (main) RGFW window. + * @param win A pointer to the RGFW_window to set as the root window. +*/ +RGFWDEF void RGFW_setRootWindow(RGFW_window* win); + +/**! + * @brief Retrieves the current root RGFW window. + * @return A pointer to the current root RGFW_window. +*/ +RGFWDEF RGFW_window* RGFW_getRootWindow(void); + +/**! + * @brief Pushes an event into the standard RGFW event queue. + * @param event A pointer to the RGFW_event to be added to the queue. +*/ +RGFWDEF void RGFW_eventQueuePush(const RGFW_event* event); + +/**! + * @brief Clears all events from the RGFW event queue without processing them. +*/ +RGFWDEF void RGFW_eventQueueFlush(void); + +/**! + * @brief Pops the next event from the RGFW event queue for the specified window. + * @param win A pointer to the RGFW_window to retrieve an event for. + * @return A pointer to the popped RGFW_event, or NULL if the queue is empty. +*/ +RGFWDEF RGFW_event* RGFW_eventQueuePop(RGFW_window* win); + +/**! + * @brief Converts an API keycode to the RGFW unmapped (physical) key. + * @param keycode The platform-specific keycode. + * @return The corresponding RGFW keycode. +*/ +RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode); + +/**! + * @brief Converts an RGFW keycode to the unmapped (physical) API key. + * @param keycode The RGFW keycode. + * @return The corresponding platform-specific keycode. +*/ +RGFWDEF u32 RGFW_rgfwToApiKey(u32 keycode); + +/**! + * @brief Converts an RGFW keycode to the mapped character representation. + * @param keycode The RGFW keycode. + * @return The corresponding key character. +*/ +RGFWDEF u8 RGFW_rgfwToKeyChar(u32 keycode); + +/**! + * @brief Retrieves the size of the RGFW_info structure. + * @return The size (in bytes) of RGFW_info. +*/ +RGFWDEF size_t RGFW_sizeofInfo(void); + +/**! + * @brief Initializes the RGFW library. + * @return 0 on success, or a negative error code on failure. + * @note This is automatically called when the first window is created. +*/ +RGFWDEF i32 RGFW_init(void); + +/**! + * @brief Deinitializes the RGFW library. + * @note This is automatically called when the last open window is closed. +*/ +RGFWDEF void RGFW_deinit(void); + +/**! + * @brief Initializes RGFW using a user-provided RGFW_info structure. + * @param info A pointer to an RGFW_info structure to be used for initialization. + * @return 0 on success, or a negative error code on failure. +*/ +RGFWDEF i32 RGFW_init_ptr(RGFW_info* info); + +/**! + * @brief Deinitializes a specific RGFW instance stored in the provided RGFW_info pointer. + * @param info A pointer to the RGFW_info structure representing the instance to deinitialize. +*/ +RGFWDEF void RGFW_deinit_ptr(RGFW_info* info); + +/**! + * @brief Sets the global RGFW_info structure pointer. + * @param info A pointer to the RGFW_info structure to set. +*/ +RGFWDEF void RGFW_setInfo(RGFW_info* info); + +/**! + * @brief Retrieves the global RGFW_info structure pointer. + * @return A pointer to the current RGFW_info structure. +*/ +RGFWDEF RGFW_info* RGFW_getInfo(void); + +/** @} */ +#endif /* RGFW_HEADER */ + +#if !defined(RGFW_NATIVE_HEADER) && (defined(RGFW_NATIVE) || defined(RGFW_IMPLEMENTATION)) +#define RGFW_NATIVE_HEADER + #if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER) + #pragma comment(lib, "opengl32") + #endif + + #ifdef RGFW_OPENGL + struct RGFW_eglContext { + void* ctx; + void* surface; + struct wl_egl_window* eglWindow; + }; + + typedef union RGFW_gfxContext { + RGFW_glContext* native; + RGFW_eglContext* egl; + } RGFW_gfxContext; + + typedef RGFW_ENUM(u32, RGFW_gfxContextType) { + RGFW_gfxNativeOpenGL = RGFW_BIT(0), + RGFW_gfxEGL = RGFW_BIT(1), + RGFW_gfxOwnedByRGFW = RGFW_BIT(2) + }; + #endif + + /*! source data for the window (used by the APIs) */ + #ifdef RGFW_WINDOWS + + #define WIN32_LEAN_AND_MEAN + #define OEMRESOURCE + #include + + struct RGFW_nativeImage { + HBITMAP bitmap; + u8* bitmapBits; + RGFW_format format; + HDC hdcMem; + }; + + #ifdef RGFW_OPENGL + struct RGFW_glContext { HGLRC ctx; }; + #endif + + struct RGFW_window_src { + HWND window; /*!< source window */ + HDC hdc; /*!< source HDC */ + i32 offsetW, offsetH; /*!< width and height offset for window */ + HICON hIconSmall, hIconBig; /*!< source window icons */ + i32 maxSizeW, maxSizeH, minSizeW, minSizeH, aspectRatioW, aspectRatioH; /*!< for setting max/min resize (RGFW_WINDOWS) */ + #ifdef RGFW_OPENGL + RGFW_gfxContext ctx; + RGFW_gfxContextType gfxType; + #endif + }; + +#elif defined(RGFW_UNIX) + #ifdef RGFW_X11 + #include + #include + #endif + + #ifdef RGFW_WAYLAND + #ifdef RGFW_LIBDECOR + #include + #endif + + #include + #include + #endif + + struct RGFW_nativeImage { + #ifdef RGFW_X11 + XImage* bitmap; + #endif + #ifdef RGFW_WAYLAND + struct wl_buffer* wl_buffer; + #endif + u8* buffer; + RGFW_format format; + }; + + #ifdef RGFW_OPENGL + struct RGFW_glContext { + #ifdef RGFW_X11 + struct __GLXcontextRec* ctx; /*!< source graphics context */ + Window window; + #endif + #ifdef RGFW_WAYLAND + RGFW_eglContext egl; + #endif + }; + #endif + + struct RGFW_window_src { + i32 x, y, w, h; + #ifdef RGFW_OPENGL + RGFW_gfxContext ctx; + RGFW_gfxContextType gfxType; + #endif +#ifdef RGFW_X11 + Window window; /*!< source window */ + Window parent; /*!< parent window */ + GC gc; + #ifdef RGFW_ADVANCED_SMOOTH_RESIZE + i64 counter_value; + XID counter; + #endif +#endif /* RGFW_X11 */ + +#if defined(RGFW_WAYLAND) + struct wl_surface* surface; + struct xdg_surface* xdg_surface; + struct xdg_toplevel* xdg_toplevel; + struct zxdg_toplevel_decoration_v1* decoration; + struct zwp_locked_pointer_v1 *locked_pointer; + struct xdg_toplevel_icon_v1 *icon; + u32 decoration_mode; + /* State flags to configure the window */ + RGFW_bool pending_activated; + RGFW_bool activated; + RGFW_bool resizing; + RGFW_bool pending_maximized; + RGFW_bool maximized; + RGFW_bool minimized; + + RGFW_bool using_custom_cursor; + struct wl_surface* custom_cursor_surface; + + RGFW_monitor active_monitor; + + struct wl_data_source *data_source; // offer data to other clients + + #ifdef RGFW_LIBDECOR + struct libdecor* decorContext; + #endif +#endif /* RGFW_WAYLAND */ + }; + +#elif defined(RGFW_MACOS) + + struct RGFW_nativeImage { + RGFW_format format; + }; + + #ifdef RGFW_OPENGL + struct RGFW_glContext { void* ctx; }; + #endif + + struct RGFW_window_src { + void* window; + void* view; /* apple viewpoint thingy */ + void* mouse; + #ifdef RGFW_OPENGL + RGFW_gfxContext ctx; + RGFW_gfxContextType gfxType; + #endif + }; + +#elif defined(RGFW_WASM) + + #include + #include + + struct RGFW_nativeImage { + RGFW_format format; + }; + + #ifdef RGFW_OPENGL + struct RGFW_glContext { + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; + }; + #endif + + struct RGFW_window_src { + #ifdef RGFW_OPENGL + RGFW_gfxContext ctx; + RGFW_gfxContextType gfxType; + #endif + }; + +#endif + +struct RGFW_surface { + u8* data; + i32 w, h; + RGFW_format format; + RGFW_nativeImage native; +}; + +/*! internal window data that is not specific to the OS */ +typedef struct RGFW_windowInternal { + /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */ + RGFW_key exitKey; + i32 lastMouseX, lastMouseY; /*!< last cusor point (for raw mouse data) */ + + RGFW_bool shouldClose; + RGFW_bool holdMouse; + RGFW_bool inFocus; + RGFW_bool mouseInside; + RGFW_keymod mod; + RGFW_eventFlag enabledEvents; + u32 flags; /*!< windows flags (for RGFW to check and modify) */ + i32 oldX, oldY, oldW, oldH; +} RGFW_windowInternal; + +struct RGFW_window { + RGFW_window_src src; /*!< src window data */ + RGFW_windowInternal internal; /*!< internal window data that is not specific to the OS */ + void* userPtr; /* ptr for usr data */ + i32 x, y, w, h; /*!< position and size of the window */ +}; /*!< window structure for the window */ + +typedef struct RGFW_windowState { + RGFW_bool mouseEnter; + RGFW_bool dataDragging; + RGFW_bool dataDrop; + size_t filesCount; + i32 dropX, dropY; + RGFW_window* win; /*!< it's not possible for one of these events to happen in the frame that the other event happened */ + + RGFW_bool mouseLeave; + RGFW_window* winLeave; /*!< if a mouse leaves one widow and enters the next */ +} RGFW_windowState; + +typedef struct { + RGFW_bool current; + RGFW_bool prev; +} RGFW_keyState; + +#ifndef RGFW_NO_MONITOR + typedef struct RGFW_monitorNode { + RGFW_monitor mon; + struct RGFW_monitorNode* next; +#ifdef RGFW_WAYLAND + u32 id; /* Add id so wl_outputs can be removed */ + struct wl_output *output; + struct zxdg_output_v1 *xdg_output; +#endif + } RGFW_monitorNode; + + typedef struct RGFW_monitorList { + RGFW_monitorNode* head; + RGFW_monitorNode* cur; + } RGFW_monitorList; + + typedef struct RGFW_monitors { + RGFW_monitorList list; + RGFW_monitorList freeList; + size_t count; + RGFW_monitorNode data[RGFW_MAX_MONITORS]; + } RGFW_monitors; + + RGFWDEF RGFW_monitorNode* RGFW_monitors_add(RGFW_monitor mon); + RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev); +#endif + +struct RGFW_info { + RGFW_window* root; + i32 windowCount; + + RGFW_mouse* hiddenMouse; + + RGFW_event events[RGFW_MAX_EVENTS]; /* A circular buffer (FIFO), using eventBottom/Len */ + + i32 eventBottom; + i32 eventLen; + RGFW_bool queueEvents; + RGFW_bool polledEvents; + + u32 apiKeycodes[RGFW_keyLast]; + #if defined(RGFW_X11) || defined(RGFW_WAYLAND) + u8 keycodes[256]; + #elif defined(RGFW_WINDOWS) + u8 keycodes[512]; + #elif defined(RGFW_MACOS) + u8 keycodes[128]; + #elif defined(RGFW_WASM) + u8 keycodes[256]; + #endif + + const char* className; + RGFW_bool useWaylandBool; + RGFW_bool stopCheckEvents_bool ; + u64 timerOffset; + + char* clipboard_data; + char* clipboard; /* for writing to the clipboard selection */ + size_t clipboard_len; + char filesSrc[RGFW_MAX_PATH * RGFW_MAX_DROPS]; + char** files; + #ifdef RGFW_X11 + Display* display; + XContext context; + Window helperWindow; + const char* instName; + XErrorEvent* x11Error; + #endif + #ifdef RGFW_WAYLAND + struct wl_display* wl_display; + struct xkb_context *xkb_context; + struct xkb_keymap *keymap; + struct xkb_state *xkb_state; + struct zxdg_decoration_manager_v1 *decoration_manager; + struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; + struct zwp_relative_pointer_v1 *relative_pointer; + struct zwp_pointer_constraints_v1 *constraint_manager; + struct xdg_toplevel_icon_manager_v1 *icon_manager; + + struct zxdg_output_manager_v1 *xdg_output_manager; + + struct wl_data_device_manager *data_device_manager; + struct wl_data_device *data_device; // supports clipboard and DND + + struct wl_keyboard* wl_keyboard; + struct wl_pointer* wl_pointer; + struct wl_compositor* compositor; + struct xdg_wm_base* xdg_wm_base; + struct wl_shm* shm; + struct wl_seat *seat; + struct wl_registry *registry; + u32 mouse_enter_serial; + struct wl_cursor_theme* wl_cursor_theme; + struct wl_surface* cursor_surface; + + RGFW_window* kbOwner; + + #endif + + RGFW_monitors monitors; + + #ifdef RGFW_UNIX + int eventWait_forceStop[3]; + #endif + + #ifdef RGFW_MACOS + void* NSApp; + void* customViewClasses[2]; /* NSView and NSOpenGLView */ + void* customWindowDelegateClass; + #endif + + #ifdef RGFW_OPENGL + RGFW_window* current; + #endif + #ifdef RGFW_EGL + void* EGL_display; + #endif + + RGFW_window* mouseOwner; + RGFW_windowState windowState; /*! for checking window state events */ + + RGFW_keyState mouseButtons[RGFW_mouseFinal]; + RGFW_keyState keyboard[RGFW_keyLast]; + float scrollX, scrollY; + float vectorX, vectorY; +}; +#endif /* RGFW_NATIVE_HEADER */ #ifdef RGFW_IMPLEMENTATION -RGFW_bool RGFW_useWaylandBool = 1; -void RGFW_useWayland(RGFW_bool wayland) { RGFW_useWaylandBool = wayland; } -RGFW_bool RGFW_usingWayland(void) { return RGFW_useWaylandBool; } -#if !defined(RGFW_NO_X11) && defined(RGFW_WAYLAND) -#define RGFW_GOTO_WAYLAND(fallback) if (RGFW_useWaylandBool && fallback == 0) goto wayland -#define RGFW_WAYLAND_LABEL wayland:; -#else -#define RGFW_GOTO_WAYLAND(fallback) -#define RGFW_WAYLAND_LABEL +/* global private API */ + +/* for C++ / C89 */ +#define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(&e); } + +RGFWDEF RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win); +RGFWDEF void RGFW_window_closePlatform(RGFW_window* win); + +RGFWDEF void RGFW_window_focusLost(RGFW_window* win); +RGFWDEF void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags); + +RGFWDEF void RGFW_initKeycodes(void); +RGFWDEF void RGFW_initKeycodesPlatform(void); +RGFWDEF void RGFW_resetPrevState(void); +RGFWDEF void RGFW_resetKey(void); +RGFWDEF void RGFW_unloadEGL(void); +RGFWDEF void RGFW_updateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll); +RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll); +RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show); +RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value); + +RGFWDEF void RGFW_setBit(u32* var, u32 mask, RGFW_bool set); +RGFWDEF void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode); + +RGFWDEF void RGFW_captureCursor(RGFW_window* win); +RGFWDEF void RGFW_releaseCursor(RGFW_window* win); + +RGFWDEF void RGFW_copyImageData64(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, + u8* src_data, RGFW_format src_format, RGFW_bool is64bit); + +RGFWDEF RGFW_bool RGFW_loadEGL(void); + +#ifdef RGFW_OPENGL +typedef struct RGFW_attribStack { + i32* attribs; + size_t count; + size_t max; +} RGFW_attribStack; +RGFWDEF void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max); +RGFWDEF void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib); +RGFWDEF void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2); + +RGFWDEF RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len); #endif -char* RGFW_clipboard_data; +typedef struct RGFW_colorLayout { i32 r, g, b, a; } RGFW_colorLayout; + +#ifdef RGFW_X11 +RGFWDEF void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win); +#endif +#ifdef RGFW_MACOS +RGFWDEF void RGFW_osx_initView(RGFW_window* win); +#endif +/* end of global private API defs */ + +RGFW_info* _RGFW = NULL; +void RGFW_setInfo(RGFW_info* info) { _RGFW = info; } +RGFW_info* RGFW_getInfo(void) { return _RGFW; } + + +void* RGFW_alloc(size_t size) { return RGFW_ALLOC(size); } +void RGFW_free(void* ptr) { RGFW_FREE(ptr); } + +void RGFW_useWayland(RGFW_bool wayland) { RGFW_init(); _RGFW->useWaylandBool = RGFW_BOOL(wayland); } +RGFW_bool RGFW_usingWayland(void) { return _RGFW->useWaylandBool; } + void RGFW_clipboard_switch(char* newstr); void RGFW_clipboard_switch(char* newstr) { - if (RGFW_clipboard_data != NULL) - RGFW_FREE(RGFW_clipboard_data); - RGFW_clipboard_data = newstr; + if (_RGFW->clipboard_data != NULL) + RGFW_FREE(_RGFW->clipboard_data); + _RGFW->clipboard_data = newstr; } #define RGFW_CHECK_CLIPBOARD() \ - if (size <= 0 && RGFW_clipboard_data != NULL) \ - return (const char*)RGFW_clipboard_data; \ + if (size <= 0 && _RGFW->clipboard_data != NULL) \ + return (const char*)_RGFW->clipboard_data; \ else if (size <= 0) \ return "\0"; @@ -1589,52 +3036,6 @@ const char* RGFW_readClipboard(size_t* len) { return (const char*)str; } -RGFW_debugfunc RGFW_debugCallback = NULL; -RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func) { - RGFW_debugfunc RGFW_debugCallbackPrev = RGFW_debugCallback; - RGFW_debugCallback = func; - return RGFW_debugCallbackPrev; -} - -#ifdef RGFW_DEBUG -#include -#endif - -void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg) { - if (RGFW_debugCallback) RGFW_debugCallback(type, err, ctx, msg); - #ifdef RGFW_DEBUG - switch (type) { - case RGFW_typeInfo: printf("RGFW INFO (%i %i): %s", type, err, msg); break; - case RGFW_typeError: printf("RGFW DEBUG (%i %i): %s", type, err, msg); break; - case RGFW_typeWarning: printf("RGFW WARNING (%i %i): %s", type, err, msg); break; - default: break; - } - - switch (err) { - #ifdef RGFW_BUFFER - case RGFW_errBuffer: case RGFW_infoBuffer: printf(" buffer size: %i %i\n", ctx.win->bufferSize.w, ctx.win->bufferSize.h); break; - #endif - case RGFW_infoMonitor: printf(": scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", ctx.monitor->name, ctx.monitor->x, ctx.monitor->y, ctx.monitor->mode.area.w, ctx.monitor->mode.area.h, ctx.monitor->physW, ctx.monitor->physH, ctx.monitor->scaleX, ctx.monitor->scaleY, ctx.monitor->pixelRatio, ctx.monitor->mode.refreshRate, ctx.monitor->mode.red + ctx.monitor->mode.green + ctx.monitor->mode.blue); break; - case RGFW_infoWindow: printf(" with rect of {%i, %i, %i, %i} \n", ctx.win->r.x, ctx.win->r.y,ctx. win->r.w, ctx.win->r.h); break; - case RGFW_errDirectXContext: printf(" srcError %i\n", ctx.srcError); break; - default: printf("\n"); - } - #endif -} - -u64 RGFW_timerOffset = 0; -void RGFW_setTime(double time) { - RGFW_timerOffset = RGFW_getTimerValue() - (u64)(time * (double)RGFW_getTimerFreq()); -} - -double RGFW_getTime(void) { - return (double) ((double)(RGFW_getTimerValue() - RGFW_timerOffset) / (double)RGFW_getTimerFreq()); -} - -u64 RGFW_getTimeNS(void) { - return (u64)(((double)((RGFW_getTimerValue() - RGFW_timerOffset)) * 1e9) / (double)RGFW_getTimerFreq()); -} - /* RGFW_IMPLEMENTATION starts with generic RGFW defines @@ -1643,205 +3044,44 @@ This is the start of keycode data -/* - the c++ compiler doesn't support setting up an array like, - we'll have to do it during runtime using a function & this messy setup -*/ - -#ifndef RGFW_CUSTOM_BACKEND - -#if !defined(__cplusplus) && !defined(RGFW_C89) -#define RGFW_NEXT , -#define RGFW_MAP -#else -#define RGFW_NEXT ; -#define RGFW_MAP RGFW_keycodes -#endif - -u32 RGFW_apiKeycodes[RGFW_keyLast] = { 0 }; - -u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(256, 512, 128, 256)] = { -#if defined(__cplusplus) || defined(RGFW_C89) - 0 -}; -void RGFW_init_keys(void); -void RGFW_init_keys(void) { -#endif - RGFW_MAP [RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] = RGFW_backtick RGFW_NEXT - - RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x00B, 29, DOM_VK_0)] = RGFW_0 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x002, 18, DOM_VK_1)] = RGFW_1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x003, 19, DOM_VK_2)] = RGFW_2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x004, 20, DOM_VK_3)] = RGFW_3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x005, 21, DOM_VK_4)] = RGFW_4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x006, 23, DOM_VK_5)] = RGFW_5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x007, 22, DOM_VK_6)] = RGFW_6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x008, 26, DOM_VK_7)] = RGFW_7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x009, 28, DOM_VK_8)] = RGFW_8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x00A, 25, DOM_VK_9)] = RGFW_9, - RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x039, 49, DOM_VK_SPACE)] = RGFW_space, - RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x01E, 0, DOM_VK_A)] = RGFW_a RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x030, 11, DOM_VK_B)] = RGFW_b RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x02E, 8, DOM_VK_C)] = RGFW_c RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x020, 2, DOM_VK_D)] = RGFW_d RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x012, 14, DOM_VK_E)] = RGFW_e RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x021, 3, DOM_VK_F)] = RGFW_f RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x022, 5, DOM_VK_G)] = RGFW_g RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x023, 4, DOM_VK_H)] = RGFW_h RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x017, 34, DOM_VK_I)] = RGFW_i RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x024, 38, DOM_VK_J)] = RGFW_j RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x025, 40, DOM_VK_K)] = RGFW_k RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x026, 37, DOM_VK_L)] = RGFW_l RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x032, 46, DOM_VK_M)] = RGFW_m RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x031, 45, DOM_VK_N)] = RGFW_n RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x018, 31, DOM_VK_O)] = RGFW_o RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x019, 35, DOM_VK_P)] = RGFW_p RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x010, 12, DOM_VK_Q)] = RGFW_q RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x013, 15, DOM_VK_R)] = RGFW_r RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x01F, 1, DOM_VK_S)] = RGFW_s RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x014, 17, DOM_VK_T)] = RGFW_t RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x016, 32, DOM_VK_U)] = RGFW_u RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x02F, 9, DOM_VK_V)] = RGFW_v RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x011, 13, DOM_VK_W)] = RGFW_w RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x02D, 7, DOM_VK_X)] = RGFW_x RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x015, 16, DOM_VK_Y)] = RGFW_y RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x02C, 6, DOM_VK_Z)] = RGFW_z, - RGFW_MAP [RGFW_OS_BASED_VALUE(60, 0x034, 47, DOM_VK_PERIOD)] = RGFW_period RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(59, 0x033, 43, DOM_VK_COMMA)] = RGFW_comma RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(61, 0x035, 44, DOM_VK_SLASH)] = RGFW_slash RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(34, 0x01A, 33, DOM_VK_OPEN_BRACKET)] = RGFW_bracket RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(35, 0x01B, 30, DOM_VK_CLOSE_BRACKET)] = RGFW_closeBracket RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(47, 0x027, 41, DOM_VK_SEMICOLON)] = RGFW_semicolon RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(48, 0x028, 39, DOM_VK_QUOTE)] = RGFW_apostrophe RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(51, 0x02B, 42, DOM_VK_BACK_SLASH)] = RGFW_backSlash, - RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x01C, 36, DOM_VK_RETURN)] = RGFW_return RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x153, 118, DOM_VK_DELETE)] = RGFW_delete RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x145, 72, DOM_VK_NUM_LOCK)] = RGFW_numLock RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x135, 82, DOM_VK_DIVIDE)] = RGFW_KP_Slash RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x037, 76, DOM_VK_MULTIPLY)] = RGFW_multiply RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x04A, 67, DOM_VK_SUBTRACT)] = RGFW_KP_Minus RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x04F, 84, DOM_VK_NUMPAD1)] = RGFW_KP_1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x050, 85, DOM_VK_NUMPAD2)] = RGFW_KP_2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x051, 86, DOM_VK_NUMPAD3)] = RGFW_KP_3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x04B, 87, DOM_VK_NUMPAD4)] = RGFW_KP_4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x04C, 88, DOM_VK_NUMPAD5)] = RGFW_KP_5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x04D, 89, DOM_VK_NUMPAD6)] = RGFW_KP_6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x047, 90, DOM_VK_NUMPAD7)] = RGFW_KP_7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x048, 92, DOM_VK_NUMPAD8)] = RGFW_KP_8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x049, 93, DOM_VK_NUMPAD9)] = RGFW_KP_9 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x052, 83, DOM_VK_NUMPAD0)] = RGFW_KP_0 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x053, 65, DOM_VK_DECIMAL)] = RGFW_KP_Period RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x11C, 77, 0)] = RGFW_KP_Return, - RGFW_MAP [RGFW_OS_BASED_VALUE(20, 0x00C, 27, DOM_VK_HYPHEN_MINUS)] = RGFW_minus RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(21, 0x00D, 24, DOM_VK_EQUALS)] = RGFW_equals RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(22, 0x00E, 51, DOM_VK_BACK_SPACE)] = RGFW_backSpace RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x00F, 48, DOM_VK_TAB)] = RGFW_tab RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(66, 0x03A, 57, DOM_VK_CAPS_LOCK)] = RGFW_capsLock RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x02A, 56, DOM_VK_SHIFT)] = RGFW_shiftL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL)] = RGFW_controlL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT)] = RGFW_altL RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN)] = RGFW_superL, - #if !defined(RGFW_MACOS) && !defined(RGFW_WASM) - RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0)] = RGFW_controlR RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(134, 0x15C, 55, 0)] = RGFW_superR, - RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0)] = RGFW_shiftR RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(108, 0x138, 58, 0)] = RGFW_altR, - #endif - RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x03B, 127, DOM_VK_F1)] = RGFW_F1 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x03C, 121, DOM_VK_F2)] = RGFW_F2 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x03D, 100, DOM_VK_F3)] = RGFW_F3 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x03E, 119, DOM_VK_F4)] = RGFW_F4 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x03F, 97, DOM_VK_F5)] = RGFW_F5 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x040, 98, DOM_VK_F6)] = RGFW_F6 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x041, 99, DOM_VK_F7)] = RGFW_F7 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x042, 101, DOM_VK_F8)] = RGFW_F8 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x043, 102, DOM_VK_F9)] = RGFW_F9 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x044, 110, DOM_VK_F10)] = RGFW_F10 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x057, 104, DOM_VK_F11)] = RGFW_F11 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x058, 111, DOM_VK_F12)] = RGFW_F12 RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x148, 126, DOM_VK_UP)] = RGFW_up RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x150, 125, DOM_VK_DOWN)] = RGFW_down RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x14B, 123, DOM_VK_LEFT)] = RGFW_left RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x14D, 124, DOM_VK_RIGHT)] = RGFW_right RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x152, 115, DOM_VK_INSERT)] = RGFW_insert RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x14F, 120, DOM_VK_END)] = RGFW_end RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(112, 0x149, 117, DOM_VK_PAGE_UP)] = RGFW_pageUp RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN)] = RGFW_pageDown RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE)] = RGFW_escape RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME)] = RGFW_home RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(78, 0x046, 107, DOM_VK_SCROLL_LOCK)] = RGFW_scrollLock RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(107, 0x137, 105, DOM_VK_PRINTSCREEN)] = RGFW_printScreen RGFW_NEXT - RGFW_MAP [RGFW_OS_BASED_VALUE(128, 0x045, 113, DOM_VK_PAUSE)] = RGFW_pause RGFW_NEXT -#if defined(__cplusplus) || defined(RGFW_C89) -} -#else -}; -#endif - -#undef RGFW_NEXT -#undef RGFW_MAP - -u32 RGFW_apiKeyToRGFW(u32 keycode) { - #if defined(__cplusplus) || defined(RGFW_C89) - if (RGFW_keycodes[RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] != RGFW_backtick) { - RGFW_init_keys(); - } - #endif - - /* make sure the key isn't out of bounds */ - if (keycode > sizeof(RGFW_keycodes) / sizeof(u8)) - return 0; - - return RGFW_keycodes[keycode]; -} - -u32 RGFW_rgfwToApiKey(u32 keycode) { - if (RGFW_apiKeycodes[RGFW_backtick] != RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)) { - for (u32 i = 0; i < RGFW_keyLast; i++) { - for (u32 y = 0; y < sizeof(RGFW_keycodes); y++) { - if (RGFW_keycodes[y] == i) { - RGFW_apiKeycodes[i] = y; - break; - } +void RGFW_initKeycodes(void) { + RGFW_MEMSET(_RGFW->keycodes, 0, sizeof(_RGFW->keycodes)); + RGFW_initKeycodesPlatform(); + u32 i, y; + for (i = 0; i < RGFW_keyLast; i++) { + for (y = 0; y < sizeof(_RGFW->keycodes); y++) { + if (_RGFW->keycodes[y] == i) { + _RGFW->apiKeycodes[i] = y; + break; } } } - /* make sure the key isn't out of bounds */ - if (keycode > sizeof(RGFW_apiKeycodes) / sizeof(u32)) + + RGFW_resetKey(); +} + +u32 RGFW_apiKeyToRGFW(u32 keycode) { + /* make sure the key isn't out of bounds */ + if (keycode > sizeof(_RGFW->keycodes) / sizeof(u8)) return 0; - return RGFW_apiKeycodes[keycode]; + return _RGFW->keycodes[keycode]; } -#endif /* RGFW_CUSTOM_BACKEND */ -typedef struct { - RGFW_bool current : 1; - RGFW_bool prev : 1; -} RGFW_keyState; +u32 RGFW_rgfwToApiKey(u32 keycode) { + /* make sure the key isn't out of bounds */ + if (keycode > sizeof(_RGFW->apiKeycodes) / sizeof(u32)) + return 0; -RGFW_keyState RGFW_keyboard[RGFW_keyLast] = { {0, 0} }; - -RGFWDEF void RGFW_resetKeyPrev(void); -void RGFW_resetKeyPrev(void) { - size_t i; /*!< reset each previous state */ - for (i = 0; i < RGFW_keyLast; i++) RGFW_keyboard[i].prev = 0; + return _RGFW->apiKeycodes[keycode]; } -RGFWDEF void RGFW_resetKey(void); -void RGFW_resetKey(void) { RGFW_MEMSET(RGFW_keyboard, 0, sizeof(RGFW_keyboard)); } + +void RGFW_resetKey(void) { RGFW_MEMSET(_RGFW->keyboard, 0, sizeof(_RGFW->keyboard)); } /* this is the end of keycode data */ -/* gamepad data */ -RGFW_keyState RGFW_gamepadPressed[4][32]; /*!< if a key is currently pressed or not (per gamepad) */ -RGFW_point RGFW_gamepadAxes[4][4]; /*!< if a key is currently pressed or not (per gamepad) */ - -RGFW_gamepadType RGFW_gamepads_type[4]; /*!< if a key is currently pressed or not (per gamepad) */ -i32 RGFW_gamepads[4] = {0, 0, 0, 0}; /*!< limit of 4 gamepads at a time */ -char RGFW_gamepads_name[4][128]; /*!< gamepad names */ -u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */ - /* event callback defines start here */ @@ -1854,79 +3094,101 @@ u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */ RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning */ -static void RGFW_windowMovedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowResizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowRestoredfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowMinimizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowMaximizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } -static void RGFW_windowQuitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); } -static void RGFW_focusfuncEMPTY(RGFW_window* win, RGFW_bool inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);} -static void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_bool status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);} -static void RGFW_mousePosfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_point vector) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(vector);} -static void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} -static void RGFW_windowRefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); } -static void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);} -static void RGFW_mouseButtonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);} -static void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); } -static void RGFW_gamepadAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); RGFW_UNUSED(whichAxis); } -static void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_bool connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);} -static void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} -static void RGFW_scaleUpdatedfuncEMPTY(RGFW_window* win, float scaleX, float scaleY) {RGFW_UNUSED(win); RGFW_UNUSED(scaleX); RGFW_UNUSED(scaleY); } - #define RGFW_CALLBACK_DEFINE(x, x2) \ -RGFW_##x##func RGFW_##x##Callback = RGFW_##x##funcEMPTY; \ +RGFW_##x##func RGFW_##x##CallbackSrc = NULL; \ RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \ - RGFW_##x##func prev = RGFW_##x##Callback; \ - RGFW_##x##Callback = func; \ + RGFW_##x##func prev = RGFW_##x##CallbackSrc; \ + RGFW_##x##CallbackSrc = func; \ return prev; \ } + RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized) +#define RGFW_windowMaximizedCallback(win, x, y, w, h) if (RGFW_windowMaximizedCallbackSrc) RGFW_windowMaximizedCallbackSrc(win, x, y, w, h); + RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized) +#define RGFW_windowMinimizedCallback(w) if (RGFW_windowMinimizedCallbackSrc) RGFW_windowMinimizedCallbackSrc(w); + RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored) +#define RGFW_windowRestoredCallback(win, x, y, w, h) if (RGFW_windowRestoredCallbackSrc) RGFW_windowRestoredCallbackSrc(win, x, y, w, h); + RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved) +#define RGFW_windowMovedCallback(w, x, y) if (RGFW_windowMovedCallbackSrc) RGFW_windowMovedCallbackSrc(w, x, y); + RGFW_CALLBACK_DEFINE(windowResized, WindowResized) +#define RGFW_windowResizedCallback(win, w, h) if (RGFW_windowResizedCallbackSrc) RGFW_windowResizedCallbackSrc(win, w, h); + RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit) +#define RGFW_windowQuitCallback(w) if (RGFW_windowQuitCallbackSrc) RGFW_windowQuitCallbackSrc(w); + RGFW_CALLBACK_DEFINE(mousePos, MousePos) +#define RGFW_mousePosCallback(w, x, y, vecX, vecY) if (RGFW_mousePosCallbackSrc) RGFW_mousePosCallbackSrc(w, x, y, vecX, vecY); + RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh) +#define RGFW_windowRefreshCallback(w) if (RGFW_windowRefreshCallbackSrc) RGFW_windowRefreshCallbackSrc(w); + RGFW_CALLBACK_DEFINE(focus, Focus) +#define RGFW_focusCallback(w, inFocus) if (RGFW_focusCallbackSrc) RGFW_focusCallbackSrc(w, inFocus); + RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify) -RGFW_CALLBACK_DEFINE(dnd, Dnd) -RGFW_CALLBACK_DEFINE(dndInit, DndInit) +#define RGFW_mouseNotifyCallback(w, x, y, status) if (RGFW_mouseNotifyCallbackSrc) RGFW_mouseNotifyCallbackSrc(w, x, y, status); + +RGFW_CALLBACK_DEFINE(dataDrop, DataDrop) +#define RGFW_dataDropCallback(w, files, count) if (RGFW_dataDropCallbackSrc) RGFW_dataDropCallbackSrc(w, files, count); + +RGFW_CALLBACK_DEFINE(dataDrag, DataDrag) +#define RGFW_dataDragCallback(w, x, y) if (RGFW_dataDragCallbackSrc) RGFW_dataDragCallbackSrc(w, x, y); + RGFW_CALLBACK_DEFINE(key, Key) +#define RGFW_keyCallback(w, key, sym, mod, repeat, press) if (RGFW_keyCallbackSrc) RGFW_keyCallbackSrc(w, key, sym, mod, repeat, press); + RGFW_CALLBACK_DEFINE(mouseButton, MouseButton) -RGFW_CALLBACK_DEFINE(gamepadButton, GamepadButton) -RGFW_CALLBACK_DEFINE(gamepadAxis, GamepadAxis) -RGFW_CALLBACK_DEFINE(gamepad, Gamepad) +#define RGFW_mouseButtonCallback(w, button, press) if (RGFW_mouseButtonCallbackSrc) RGFW_mouseButtonCallbackSrc(w, button, press); + +RGFW_CALLBACK_DEFINE(mouseScroll, MouseScroll) +#define RGFW_mouseScrollCallback(w, x, y) if (RGFW_mouseScrollCallbackSrc) RGFW_mouseScrollCallbackSrc(w, x, y); + RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated) +#define RGFW_scaleUpdatedCallback(w, scaleX, scaleY) if (RGFW_scaleUpdatedCallbackSrc) RGFW_scaleUpdatedCallbackSrc(w, scaleX, scaleY); + +RGFW_CALLBACK_DEFINE(debug, Debug) +#define RGFW_debugCallback(type, err, msg) if (RGFW_debugCallbackSrc) RGFW_debugCallbackSrc(type, err, msg); #undef RGFW_CALLBACK_DEFINE -void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) { - RGFW_window_eventWait(win, waitMS); +#ifdef RGFW_DEBUG +#include +#endif - while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) { - if (win->event.type == RGFW_quit) return; +void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char* msg) { + RGFW_debugCallback(type, err, msg); + + #ifdef RGFW_DEBUG + switch (type) { + case RGFW_typeInfo: RGFW_PRINTF("RGFW INFO (%i %i): %s", type, err, msg); break; + case RGFW_typeError: RGFW_PRINTF("RGFW DEBUG (%i %i): %s", type, err, msg); break; + case RGFW_typeWarning: RGFW_PRINTF("RGFW WARNING (%i %i): %s", type, err, msg); break; + default: break; } - #ifdef RGFW_WASM /* WASM needs to run the sleep function for asyncify */ - RGFW_sleep(0); + RGFW_PRINTF("\n"); #endif } void RGFW_window_checkMode(RGFW_window* win); void RGFW_window_checkMode(RGFW_window* win) { - if (RGFW_window_isMinimized(win)) { - win->_flags |= RGFW_windowMinimize; - RGFW_windowMinimizedCallback(win, win->r); - } else if (RGFW_window_isMaximized(win)) { - win->_flags |= RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win); - RGFW_windowMaximizedCallback(win, win->r); - } else if (((win->_flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) || - (win->_flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) { - win->_flags &= ~(u32)RGFW_windowMinimize; - if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->_flags &= ~(u32)RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); - RGFW_windowRestoredCallback(win, win->r); + if (RGFW_window_isMinimized(win) && (win->internal.enabledEvents & RGFW_windowMinimizedFlag)) { + win->internal.flags |= RGFW_windowMinimize; + RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); + RGFW_windowMinimizedCallback(win); + } else if (RGFW_window_isMaximized(win) && (win->internal.enabledEvents & RGFW_windowMaximizedFlag)) { + win->internal.flags |= RGFW_windowMaximize; + RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); + RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h); + } else if ((((win->internal.flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) || + (win->internal.flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) && (win->internal.enabledEvents & RGFW_windowRestoredFlag)) { + win->internal.flags &= ~(u32)RGFW_windowMinimize; + if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->internal.flags &= ~(u32)RGFW_windowMaximize; + RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); + RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); } } @@ -1934,173 +3196,359 @@ void RGFW_window_checkMode(RGFW_window* win) { no more event call back defines */ -#define SET_ATTRIB(a, v) { \ - RGFW_ASSERT(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ - attribs[index++] = a; \ - attribs[index++] = v; \ -} +size_t RGFW_sizeofInfo(void) { return sizeof(RGFW_info); } +size_t RGFW_sizeofNativeImage(void) { return sizeof(RGFW_nativeImage); } +size_t RGFW_sizeofSurface(void) { return sizeof(RGFW_surface); } +size_t RGFW_sizeofWindow(void) { return sizeof(RGFW_window); } +size_t RGFW_sizeofWindowSrc(void) { return sizeof(RGFW_window_src); } -#define RGFW_EVENT_PASSED RGFW_BIT(24) /* if a queued event was passed */ -#define RGFW_EVENT_QUIT RGFW_BIT(25) /* the window close button was pressed */ -#define RGFW_HOLD_MOUSE RGFW_BIT(26) /*!< hold the moues still */ -#define RGFW_MOUSE_LEFT RGFW_BIT(27) /* if mouse left the window */ -#define RGFW_WINDOW_ALLOC RGFW_BIT(28) /* if window was allocated by RGFW */ -#define RGFW_BUFFER_ALLOC RGFW_BIT(29) /* if window.buffer was allocated by RGFW */ -#define RGFW_WINDOW_INIT RGFW_BIT(30) /* if window.buffer was allocated by RGFW */ -#define RGFW_INTERNAL_FLAGS (RGFW_EVENT_QUIT | RGFW_EVENT_PASSED | RGFW_HOLD_MOUSE | RGFW_MOUSE_LEFT | RGFW_WINDOW_ALLOC | RGFW_BUFFER_ALLOC | RGFW_windowFocus) +RGFW_window_src* RGFW_window_getSrc(RGFW_window* win) { return &win->src; } +RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y) { if (x) *x = win->x; if (y) *y = win->y; return RGFW_TRUE; } +RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h) { if (w) *w = win->w; if (h) *h = win->h; return RGFW_TRUE; } +u32 RGFW_window_getFlags(RGFW_window* win) { return win->internal.flags; } +RGFW_key RGFW_window_getExitKey(RGFW_window* win) { return win->internal.exitKey; } +void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key) { win->internal.exitKey = key; } +void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events) { win->internal.enabledEvents = events; } +RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win) { return win->internal.enabledEvents; } +void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events) { RGFW_window_setEnabledEvents(win, (RGFW_allEventFlags) & ~(u32)events); } +void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state) { RGFW_setBit(&win->internal.enabledEvents, event, state); } +void* RGFW_window_getUserPtr(RGFW_window* win) { return win->userPtr; } +void RGFW_window_setUserPtr(RGFW_window* win, void* ptr) { win->userPtr = ptr; } -RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlags flags) { - RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window)); - RGFW_ASSERT(win != NULL); - win->_flags = RGFW_WINDOW_ALLOC; - return RGFW_createWindowPtr(name, rect, flags, win); -} #if defined(RGFW_USE_XDL) && defined(RGFW_X11) #define XDL_IMPLEMENTATION #include "XDL.h" #endif -#define RGFW_MAX_EVENTS 32 -typedef struct RGFW_globalStruct { - RGFW_window* root; - RGFW_window* current; - i32 windowCount; - i32 eventLen; - i32 eventIndex; - - #ifdef RGFW_X11 - Display* display; - Window helperWindow; - char* clipboard; /* for writing to the clipboard selection */ - size_t clipboard_len; - #endif - #ifdef RGFW_WAYLAND - struct wl_display* wl_display; - #endif - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) || defined(RGFW_WAYLAND) - RGFW_mouse* hiddenMouse; - #endif - RGFW_event events[RGFW_MAX_EVENTS]; - -} RGFW_globalStruct; -#if !defined(RGFW_C89) && !defined(__cplusplus) -RGFW_globalStruct _RGFW = {.root = NULL, .current = NULL, .windowCount = -1, .eventLen = 0, .eventIndex = 0}; -#define _RGFW_init RGFW_TRUE -#else -RGFW_bool _RGFW_init = RGFW_FALSE; -RGFW_globalStruct _RGFW; +#ifndef RGFW_FORCE_INIT +RGFW_info _rgfwGlobal; #endif -void RGFW_eventQueuePush(RGFW_event event) { - if (_RGFW.eventLen >= RGFW_MAX_EVENTS) return; - _RGFW.events[_RGFW.eventLen] = event; - _RGFW.eventLen++; +i32 RGFW_init(void) { return RGFW_init_ptr(&_rgfwGlobal); } +void RGFW_deinit(void) { RGFW_deinit_ptr(&_rgfwGlobal); } + +i32 RGFW_initPlatform(void); +void RGFW_deinitPlatform(void); + +i32 RGFW_init_ptr(RGFW_info* info) { + if (info == _RGFW || info == NULL) return 1; + + RGFW_setInfo(info); + RGFW_MEMSET(_RGFW, 0, sizeof(RGFW_info)); + _RGFW->queueEvents = RGFW_FALSE; + _RGFW->polledEvents = RGFW_FALSE; +#ifdef RGFW_WAYLAND + _RGFW->useWaylandBool = RGFW_TRUE; +#endif + + _RGFW->files = (char**)(void*)_RGFW->filesSrc; + u32 i; + for (i = 0; i < RGFW_MAX_DROPS; i++) + _RGFW->files[i] = (char*)(_RGFW->filesSrc + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH)); + + _RGFW->monitors.freeList.head = &_RGFW->monitors.data[0]; + _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head; + + for (i = 1; i < RGFW_MAX_MONITORS; i++) { + RGFW_monitorNode* newNode = &_RGFW->monitors.data[i]; + _RGFW->monitors.freeList.cur->next = newNode; + _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next; + } + + RGFW_initKeycodes(); + i32 out = RGFW_initPlatform(); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context initialized"); + + return out; +} + +#ifndef RGFW_EGL +void RGFW_unloadEGL(void) { } +#endif + +void RGFW_deinit_ptr(RGFW_info* info) { + if (info == NULL) return; + + RGFW_setInfo(info); + RGFW_unloadEGL(); + RGFW_deinitPlatform(); + + _RGFW->root = NULL; + _RGFW->windowCount = 0; + RGFW_setInfo(NULL); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized"); +} + +RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags) { + RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window)); + RGFW_ASSERT(win != NULL); + return RGFW_createWindowPtr(name, x, y, w, h, flags, win); +} + +void RGFW_window_close(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_window_closePtr(win); + RGFW_FREE(win); +} + +RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_MEMSET(win, 0, sizeof(RGFW_window)); + if (_RGFW == NULL) RGFW_init(); + _RGFW->windowCount++; + + /* rect based the requested flags */ + if (_RGFW->root == NULL) { + RGFW_setRootWindow(win); + } + + /* set and init the new window's data */ + win->x = x; + win->y = y; + win->w = w; + win->h = h; + win->internal.flags = flags; + win->internal.enabledEvents = RGFW_allEventFlags; + + RGFW_window* ret = RGFW_createWindowPlatform(name, flags, win); + +#ifndef RGFW_X11 + RGFW_window_setFlagsInternal(win, flags, 0); +#endif + +#ifdef RGFW_OPENGL + win->src.gfxType = 0; + if (flags & RGFW_windowOpenGL) + RGFW_window_createContext_OpenGL(win, RGFW_getGlobalHints_OpenGL()); +#endif + +#ifdef RGFW_EGL + if (flags & RGFW_windowEGL) + RGFW_window_createContext_EGL(win, RGFW_getGlobalHints_OpenGL()); +#endif + + /* X11 creates the window after the OpenGL context is created (because of visual garbage), + * so we have to wait to set the flags + * This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used + * if a window is crated, CreateContext will delete the window and create a new one + * */ +#ifdef RGFW_X11 + RGFW_window_setFlagsInternal(win, flags, 0); +#endif + +#ifdef RGFW_MACOS + /*NOTE: another OpenGL/setFlags related hack, this because OSX the 'view' class must be setup after the NSOpenGL view is made AND after setFlags happens */ + RGFW_osx_initView(win); +#endif + +#ifdef RGFW_WAYLAND + /* recieve all events needed to configure the surface */ + /* also gets the wl_outputs */ + if (RGFW_usingWayland()) { + wl_display_roundtrip(_RGFW->wl_display); + /* NOTE: this is a hack so that way wayland spawns a window, even if nothing is drawn */ + if (!(flags & RGFW_windowOpenGL) && !(flags & RGFW_windowEGL)) { + u8* data = (u8*)RGFW_ALLOC((u32)(win->w * win->h * 3)); + RGFW_MEMSET(data, 0, (u32)(win->w * win->h * 3) * sizeof(u8)); + RGFW_surface* surface = RGFW_createSurface(data, win->w, win->h, RGFW_formatBGR8); + RGFW_window_blitSurface(win, surface); + RGFW_FREE(data); + RGFW_surface_free(surface); + } + } +#endif + + RGFW_window_setMouseDefault(win); + RGFW_window_setName(win, name); + if (!(flags & RGFW_windowHide)) { + RGFW_window_show(win); + } + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a new window was created"); + + + return ret; +} + +void RGFW_window_closePtr(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + + #ifdef RGFW_EGL + if ((win->src.gfxType & RGFW_gfxEGL) && win->src.ctx.egl) { + RGFW_window_deleteContext_EGL(win, win->src.ctx.egl); + win->src.ctx.egl = NULL; + } + #endif + + #ifdef RGFW_OPENGL + if ((win->src.gfxType & RGFW_gfxNativeOpenGL) && win->src.ctx.native) { + RGFW_window_deleteContext_OpenGL(win, win->src.ctx.native); + win->src.ctx.native = NULL; + } + #endif + + RGFW_window_closePlatform(win); + + RGFW_clipboard_switch(NULL); + _RGFW->windowCount--; + if (_RGFW->windowCount == 0) RGFW_deinit(); + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed"); +} + +void RGFW_setQueueEvents(RGFW_bool queue) { _RGFW->queueEvents = RGFW_BOOL(queue); } + +void RGFW_eventQueueFlush(void) { _RGFW->eventLen = 0; } + +void RGFW_eventQueuePush(const RGFW_event* event) { + if (_RGFW->queueEvents == RGFW_FALSE) return; + RGFW_ASSERT(_RGFW->eventLen >= 0); + + if (_RGFW->eventLen >= RGFW_MAX_EVENTS) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEventQueue, "Event queue limit 'RGFW_MAX_EVENTS' has been reached automatically flushing queue."); + RGFW_eventQueueFlush(); + return; + } + + i32 eventTop = (_RGFW->eventBottom + _RGFW->eventLen) % RGFW_MAX_EVENTS; + _RGFW->eventLen += 1; + _RGFW->events[eventTop] = *event; } RGFW_event* RGFW_eventQueuePop(RGFW_window* win) { - RGFW_event* ev; - if (_RGFW.eventLen == 0) return NULL; + RGFW_ASSERT(_RGFW->eventLen >= 0 && _RGFW->eventLen <= RGFW_MAX_EVENTS); + RGFW_event* ev; - ev = (RGFW_event*)&_RGFW.events[_RGFW.eventIndex]; - - _RGFW.eventLen--; - if (_RGFW.eventLen >= 0 && _RGFW.eventIndex < _RGFW.eventLen) { - _RGFW.eventIndex++; - } else if (_RGFW.eventLen == 0) { - _RGFW.eventIndex = 0; - } - - if (ev->_win != win && ev->_win != NULL) { - RGFW_eventQueuePush(*ev); - return NULL; + if (_RGFW->eventLen == 0) { + return NULL; + } + + ev = &_RGFW->events[_RGFW->eventBottom]; + _RGFW->eventLen -= 1; + _RGFW->eventBottom = (_RGFW->eventBottom + 1) % RGFW_MAX_EVENTS; + + if (ev->common.win != win && ev->common.win != NULL) { + RGFW_eventQueuePush(ev); + return NULL; } - ev->droppedFilesCount = win->event.droppedFilesCount; - ev->droppedFiles = win->event.droppedFiles; return ev; } -RGFW_event* RGFW_window_checkEventCore(RGFW_window* win); -RGFW_event* RGFW_window_checkEventCore(RGFW_window* win) { +void RGFW_resetPrevState(void) { + size_t i; /*!< reset each previous state */ + for (i = 0; i < RGFW_keyLast; i++) _RGFW->keyboard[i].prev = _RGFW->keyboard[i].current; + for (i = 0; i < RGFW_mouseFinal; i++) _RGFW->mouseButtons[i].prev = _RGFW->mouseButtons[i].current; + _RGFW->scrollX = 0.0f; + _RGFW->scrollY = 0.0f; + _RGFW->vectorX = (float)0.0f; + _RGFW->vectorY = (float)0.0f; + RGFW_MEMSET(&_RGFW->windowState, 0, sizeof(_RGFW->windowState)); +} + +RGFW_bool RGFW_isKeyPressed(RGFW_key key) { + return _RGFW != NULL && _RGFW->keyboard[key].current && !_RGFW->keyboard[key].prev; +} + +RGFW_bool RGFW_isKeyDown(RGFW_key key) { + return _RGFW != NULL && _RGFW->keyboard[key].current; +} + +RGFW_bool RGFW_isKeyReleased(RGFW_key key) { + return _RGFW != NULL && !_RGFW->keyboard[key].current && _RGFW->keyboard[key].prev; +} + + +RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button) { + return _RGFW != NULL && _RGFW->mouseButtons[button].current && !_RGFW->mouseButtons[button].prev; +} +RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button) { + return _RGFW != NULL && _RGFW->mouseButtons[button].current; +} +RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button) { + return _RGFW != NULL && !_RGFW->mouseButtons[button].current && _RGFW->mouseButtons[button].prev; +} + +void RGFW_getMouseScroll(float* x, float* y) { + RGFW_ASSERT(_RGFW != NULL); + if (x) *x = _RGFW->scrollX; + if (y) *y = _RGFW->scrollY; +} + +void RGFW_getMouseVector(float* x, float* y) { + RGFW_ASSERT(_RGFW != NULL); + if (x) *x = _RGFW->vectorX; + if (y) *y = _RGFW->vectorY; +} + +RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win) { return _RGFW->windowState.winLeave == win && _RGFW->windowState.mouseLeave; } +RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win) { return _RGFW->windowState.win == win && _RGFW->windowState.mouseEnter; } +RGFW_bool RGFW_window_isMouseInside(RGFW_window* win) { return win->internal.mouseInside; } + +RGFW_bool RGFW_window_isDataDragging(RGFW_window* win) { return RGFW_window_getDataDrag(win, (i32*)NULL, (i32*)NULL); } +RGFW_bool RGFW_window_didDataDrop(RGFW_window* win) { return RGFW_window_getDataDrop(win, (const char***)NULL, (size_t*)NULL);} + + +RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y) { + if (_RGFW->windowState.win != win || _RGFW->windowState.dataDragging == RGFW_FALSE) return RGFW_FALSE; + if (x) *x = _RGFW->windowState.dropX; + if (y) *y = _RGFW->windowState.dropY; + return RGFW_TRUE; +} +RGFW_bool RGFW_window_getDataDrop(RGFW_window* win, const char*** files, size_t* count) { + if (_RGFW->windowState.win != win || _RGFW->windowState.dataDrop == RGFW_FALSE) return RGFW_FALSE; + if (files) *files = (const char**)_RGFW->files; + if (count) *count = _RGFW->windowState.filesCount; + return RGFW_TRUE; +} + +RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event) { + if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) { + _RGFW->queueEvents = RGFW_TRUE; + RGFW_pollEvents(); + _RGFW->polledEvents = RGFW_TRUE; + } + + if (RGFW_window_checkQueuedEvent(win, event) == RGFW_FALSE) { + _RGFW->polledEvents = RGFW_FALSE; + return RGFW_FALSE; + } + + return RGFW_TRUE; +} + +RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event) { RGFW_event* ev; - RGFW_ASSERT(win != NULL); - if (win->event.type == 0 && _RGFW.eventLen == 0) - RGFW_resetKeyPrev(); - - if (win->event.type == RGFW_quit && win->_flags & RGFW_windowFreeOnClose) { - static RGFW_event event; - event = win->event; - RGFW_window_close(win); - return &event; - } - - if (win->event.type != RGFW_DNDInit) win->event.type = 0; - + RGFW_ASSERT(win != NULL); + _RGFW->queueEvents = RGFW_TRUE; /* check queued events */ ev = RGFW_eventQueuePop(win); if (ev != NULL) { if (ev->type == RGFW_quit) RGFW_window_setShouldClose(win, RGFW_TRUE); - win->event = *ev; + *event = *ev; + return RGFW_TRUE; } - else return NULL; - return &win->event; + return RGFW_FALSE; } +void RGFW_setRootWindow(RGFW_window* win) { _RGFW->root = win; } +RGFW_window* RGFW_getRootWindow(void) { return _RGFW->root; } -RGFWDEF void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags); -void RGFW_setRootWindow(RGFW_window* win) { _RGFW.root = win; } -RGFW_window* RGFW_getRootWindow(void) { return _RGFW.root; } - -/* do a basic initialization for RGFW_window, this is to standard it for each OS */ -void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags) { - RGFW_UNUSED(flags); - if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init(); - _RGFW.windowCount++; - - /* rect based the requested flags */ - if (_RGFW.root == NULL) { - RGFW_setRootWindow(win); - RGFW_setTime(0); - } - - if (!(win->_flags & RGFW_WINDOW_ALLOC)) win->_flags = 0; - - /* set and init the new window's data */ - win->r = rect; - win->exitKey = RGFW_escape; - win->event.droppedFilesCount = 0; - - win->_flags = 0 | (win->_flags & RGFW_WINDOW_ALLOC); - win->_flags |= flags; - win->event.keyMod = 0; - win->_lastMousePoint.x = 0; - win->_lastMousePoint.y = 0; - - win->event.droppedFiles = (char**)RGFW_ALLOC(RGFW_MAX_PATH * RGFW_MAX_DROPS); - RGFW_ASSERT(win->event.droppedFiles != NULL); - - { - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) - win->event.droppedFiles[i] = (char*)(win->event.droppedFiles + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH)); - } -} - -void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { - RGFW_windowFlags cmpFlags = win->_flags; - if (win->_flags & RGFW_WINDOW_INIT) cmpFlags = 0; +#ifndef RGFW_EGL +RGFW_bool RGFW_loadEGL(void) { return RGFW_FALSE; } +#endif +void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags) { #ifndef RGFW_NO_MONITOR if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); #endif if (flags & RGFW_windowCenter) RGFW_window_center(win); - if (flags & RGFW_windowCenterCursor) - RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); + if (flags & RGFW_windowCenterCursor) RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0); - else RGFW_window_setBorder(win, 1); + else if (cmpFlags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 1); if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE); else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0); if (flags & RGFW_windowMaximize) RGFW_window_maximize(win); @@ -2111,153 +3559,97 @@ void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1); if (flags & RGFW_windowHide) RGFW_window_hide(win); else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win); - if (flags & RGFW_windowCocoaCHDirToRes) RGFW_moveToMacOSResourceDir(); if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1); else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0); if (flags & RGFW_windowFocus) RGFW_window_focus(win); if (flags & RGFW_windowNoResize) { - RGFW_window_setMaxSize(win, RGFW_AREA(win->r.w, win->r.h)); - RGFW_window_setMinSize(win, RGFW_AREA(win->r.w, win->r.h)); + RGFW_window_setMaxSize(win, win->w, win->h); + RGFW_window_setMinSize(win, win->w, win->h); } else if (cmpFlags & RGFW_windowNoResize) { - RGFW_window_setMaxSize(win, RGFW_AREA(0, 0)); - RGFW_window_setMinSize(win, RGFW_AREA(0, 0)); + RGFW_window_setMaxSize(win, 0, 0); + RGFW_window_setMinSize(win, 0, 0); } - win->_flags = flags | (win->_flags & RGFW_INTERNAL_FLAGS); + win->internal.flags = flags; } -RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win) { - return RGFW_BOOL(win->_flags |= RGFW_windowOpenglSoftware); -} + +void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { RGFW_window_setFlagsInternal(win, flags, win->internal.flags); } RGFW_bool RGFW_window_isInFocus(RGFW_window* win) { #ifdef RGFW_WASM return RGFW_TRUE; #else - return RGFW_BOOL(win->_flags & RGFW_windowFocus); + return RGFW_BOOL(win->internal.inFocus); #endif } -void RGFW_window_initBuffer(RGFW_window* win) { - RGFW_area area = RGFW_getScreenSize(); - if ((win->_flags & RGFW_windowNoResize)) - area = RGFW_AREA(win->r.w, win->r.h); - - RGFW_window_initBufferSize(win, area); -} - -void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area) { -#if defined(RGFW_BUFFER) || defined(RGFW_OSMESA) - win->_flags |= RGFW_BUFFER_ALLOC; - #ifndef RGFW_WINDOWS - u8* buffer = (u8*)RGFW_ALLOC(area.w * area.h * 4); - RGFW_ASSERT(buffer != NULL); - - RGFW_window_initBufferPtr(win, buffer, area); - #else /* windows's bitmap allocs memory for us */ - RGFW_window_initBufferPtr(win, (u8*)NULL, area); - #endif -#else - RGFW_UNUSED(win); RGFW_UNUSED(area); -#endif -} - -#ifdef RGFW_MACOS -RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer); -RGFWDEF void* RGFW_cocoaGetLayer(void); -#endif - -const char* RGFW_className = NULL; -void RGFW_setClassName(const char* name) { RGFW_className = name; } +void RGFW_setClassName(const char* name) { RGFW_init(); _RGFW->className = name; } #ifndef RGFW_X11 void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); } #endif -RGFW_keyState RGFW_mouseButtons[RGFW_mouseFinal] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }; - -RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { - return RGFW_mouseButtons[button].current && (win == NULL || RGFW_window_isInFocus(win)); -} -RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) { - return RGFW_mouseButtons[button].prev && (win != NULL || RGFW_window_isInFocus(win)); -} -RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) { - return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); -} -RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { - return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); -} - -RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { +RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y) { RGFW_ASSERT(win != NULL); - return win->_lastMousePoint; + if (x) *x = win->internal.lastMouseX; + if (y) *y = win->internal.lastMouseY; + return RGFW_TRUE; } -RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key) { - return RGFW_keyboard[key].current && (win == NULL || RGFW_window_isInFocus(win)); -} +RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key) { return RGFW_isKeyPressed(key) && RGFW_window_isInFocus(win); } +RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key) { return RGFW_isKeyDown(key) && RGFW_window_isInFocus(win); } +RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key) { return RGFW_isKeyReleased(key) && RGFW_window_isInFocus(win); } -RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key) { - return RGFW_keyboard[key].prev && (win == NULL || RGFW_window_isInFocus(win)); -} +RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMousePressed(button) && RGFW_window_isInFocus(win); } +RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseDown(button) && RGFW_window_isInFocus(win); } +RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseReleased(button) && RGFW_window_isInFocus(win); } -RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key) { - return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); -} -RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key) { - return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key)); -} -RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key) { - return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); -} - -void RGFW_window_makeCurrent(RGFW_window* win) { - _RGFW.current = win; -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) - RGFW_window_makeCurrent_OpenGL(win); +#ifndef RGFW_X11 +void* RGFW_getDisplay_X11(void) { return NULL; } +u64 RGFW_window_getWindow_X11(RGFW_window* win) { RGFW_UNUSED(win); return 0; } #endif -} -RGFW_window* RGFW_getCurrent(void) { - return _RGFW.current; -} - -void RGFW_window_swapBuffers(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_window_swapBuffers_software(win); -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) - RGFW_window_swapBuffers_OpenGL(win); +#ifndef RGFW_WAYLAND +struct wl_display* RGFW_getDisplay_Wayland(void) { return NULL; } +struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } #endif -} -RGFWDEF void RGFW_setBit(u32* data, u32 bit, RGFW_bool value); -void RGFW_setBit(u32* data, u32 bit, RGFW_bool value) { - if (value) - *data |= bit; - else if (!value && (*(data) & bit)) - *data ^= bit; +#ifndef RGFW_WINDOWS +void* RGFW_window_getHWND(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } +void* RGFW_window_getHDC(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } +#endif + +#ifndef RGFW_MACOS +void* RGFW_window_getView_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } +void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) { RGFW_UNUSED(win); RGFW_UNUSED(layer); } +void* RGFW_getLayer_OSX(void) { return NULL; } +void* RGFW_window_getWindow_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } +#endif + +void RGFW_setBit(u32* var, u32 mask, RGFW_bool set) { + if (set) *var |= mask; + else *var &= ~mask; } void RGFW_window_center(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_area screenR = RGFW_getScreenSize(); - RGFW_window_move(win, RGFW_POINT((i32)(screenR.w - (u32)win->r.w) / 2, (screenR.h - (u32)win->r.h) / 2)); + RGFW_monitor mon = RGFW_window_getMonitor(win); + RGFW_window_move(win, (i32)(mon.mode.w - win->w) / 2, (mon.mode.h - win->h) / 2); } RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win) { RGFW_monitorMode mode; RGFW_ASSERT(win != NULL); - mode.area.w = (u32)win->r.w; - mode.area.h = (u32)win->r.h; + mode.w = win->w; + mode.h = win->h; return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale); } -void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode); void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) { if (bpp == 32) bpp = 24; mode->red = mode->green = mode->blue = (u8)(bpp / 3); @@ -2268,21 +3660,21 @@ void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) { } RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) { - return (((mon.area.w == mon2.area.w && mon.area.h == mon2.area.h) || !(request & RGFW_monitorScale)) && + return (((mon.w == mon2.w && mon.h == mon2.h) || !(request & RGFW_monitorScale)) && ((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) && ((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB))); } RGFW_bool RGFW_window_shouldClose(RGFW_window* win) { - return (win == NULL || (win->_flags & RGFW_EVENT_QUIT)|| (win->exitKey && RGFW_isPressed(win, win->exitKey))); + return (win == NULL || win->internal.shouldClose || (win->internal.exitKey && RGFW_window_isKeyPressed(win, win->internal.exitKey))); } void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) { if (shouldClose) { - win->_flags |= RGFW_EVENT_QUIT; + win->internal.shouldClose = RGFW_TRUE; RGFW_windowQuitCallback(win); } else { - win->_flags &= ~(u32)RGFW_EVENT_QUIT; + win->internal.shouldClose = RGFW_FALSE; } } @@ -2292,123 +3684,169 @@ void RGFW_window_scaleToMonitor(RGFW_window* win) { if (monitor.scaleX == 0 && monitor.scaleY == 0) return; - RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleY * (float)win->r.h))); + RGFW_window_resize(win, (i32)(monitor.scaleX * (float)win->w), (i32)(monitor.scaleY * (float)win->h)); } void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) { - RGFW_window_move(win, RGFW_POINT(m.x + win->r.x, m.y + win->r.y)); + RGFW_window_move(win, m.x + win->x, m.y + win->y); } #endif -RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { - return RGFW_window_setIconEx(win, icon, a, channels, RGFW_iconBoth); +RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format) { + RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface)); + RGFW_MEMSET(surface, 0, sizeof(RGFW_surface)); + RGFW_createSurfacePtr(data, w, h, format, surface); + return surface; } -RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect); -RGFWDEF void RGFW_releaseCursor(RGFW_window* win); - - -RGFW_bool RGFW_window_mouseHeld(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_HOLD_MOUSE); } - -void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) { - if (!area.w && !area.h) - area = RGFW_AREA(win->r.w / 2, win->r.h / 2); - - win->_flags |= RGFW_HOLD_MOUSE; - RGFW_captureCursor(win, win->r); - RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); +void RGFW_surface_free(RGFW_surface* surface) { + RGFW_surface_freePtr(surface); + RGFW_FREE(surface); } -void RGFW_window_mouseUnhold(RGFW_window* win) { - win->_flags &= ~(u32)RGFW_HOLD_MOUSE; +RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface) { + return &surface->native; +} + +RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) { + RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface)); + RGFW_MEMSET(surface, 0, sizeof(RGFW_surface)); + RGFW_window_createSurfacePtr(win, data, w, h, format, surface); + return surface; +} +#ifndef RGFW_X11 +RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { + RGFW_UNUSED(win); + return RGFW_createSurfacePtr(data, w, h, format, surface); +} +#endif + +const RGFW_colorLayout RGFW_layouts[RGFW_formatCount] = { + { 0, 1, 2, 3 }, /* RGFW_formatRGB8 */ + { 2, 1, 0, 3 }, /* RGFW_formatBGR8 */ + { 0, 1, 2, 3 }, /* RGFW_formatRGBA8 */ + { 1, 2, 3, 0 }, /* RGFW_formatARGB8 */ + { 2, 1, 0, 3 }, /* RGFW_formatBGRA8 */ + { 3, 2, 1, 0 }, /* RGFW_formatABGR8 */ +}; + + +void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format) { + RGFW_copyImageData64(dest_data, w, h, dest_format, src_data, src_format, RGFW_FALSE); +} + +void RGFW_copyImageData64(u8* dest_data, i32 dest_w, i32 dest_h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_bool is64bit) { + RGFW_ASSERT(dest_data && src_data); + + u32 src_channels = (src_format >= RGFW_formatRGBA8) ? 4 : 3; + u32 dest_channels = (dest_format >= RGFW_formatRGBA8) ? 4 : 3; + + u32 pixel_count = (u32)(dest_w * dest_h); + + if (src_format == dest_format) { + RGFW_MEMCPY(dest_data, src_data, pixel_count * dest_channels); + return; + } + + const RGFW_colorLayout* src_layout = &RGFW_layouts[src_format]; + const RGFW_colorLayout* dest_layout = &RGFW_layouts[dest_format]; + + u32 i, i2 = 0; + for (i = 0; i < pixel_count; i++) { + const u8* src_px = &src_data[i * src_channels]; + u8* dst_px = &dest_data[i2 * dest_channels]; + u8 rgba[4] = {0}; + rgba[0] = src_px[src_layout->r]; + rgba[1] = src_px[src_layout->g]; + rgba[2] = src_px[src_layout->b]; + rgba[3] = 255; + if (src_channels == 4) + rgba[3] = src_px[src_layout->a]; + + dst_px[dest_layout->r] = rgba[0]; + dst_px[dest_layout->g] = rgba[1]; + dst_px[dest_layout->b] = rgba[2]; + if (dest_channels == 4) + dst_px[dest_layout->a] = rgba[3]; + + i2 += 1 + is64bit; + } +} + +RGFW_monitorNode* RGFW_monitors_add(RGFW_monitor mon) { + RGFW_monitorNode* node = NULL; + if (_RGFW->monitors.freeList.head == NULL) return node; + + node = _RGFW->monitors.freeList.head; + mon = node->mon; + + _RGFW->monitors.freeList.head = node->next; + if (_RGFW->monitors.freeList.head == NULL) { + _RGFW->monitors.freeList.cur = NULL; + } + + node->next = NULL; + + if (_RGFW->monitors.list.head == NULL) { + _RGFW->monitors.list.head = node; + } else { + _RGFW->monitors.list.cur->next = node; + } + + _RGFW->monitors.list.cur = node; + + node->mon = mon; + _RGFW->monitors.count += 1; + return node; +} + +void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev) { + _RGFW->monitors.count -= 1; + + /* remove node from the list */ + if (prev != node) { + prev->next = node->next; + } else { /* node is the head */ + _RGFW->monitors.list.head = NULL; + } + + node->next = NULL; + + /* move node to the free list */ + if (_RGFW->monitors.freeList.head == NULL) { + _RGFW->monitors.freeList.head = node; + } else { + _RGFW->monitors.freeList.cur->next = node; + } + + _RGFW->monitors.freeList.cur = node; +} + +RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) { + return RGFW_window_setIconEx(win, data, w, h, format, RGFW_iconBoth); +} + +void RGFW_window_holdMouse(RGFW_window* win) { + win->internal.holdMouse = RGFW_TRUE; + _RGFW->mouseOwner = win; + RGFW_captureCursor(win); + RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); +} + +RGFW_bool RGFW_window_isHoldingMouse(RGFW_window* win) { return RGFW_BOOL(win->internal.holdMouse); } + +void RGFW_window_unholdMouse(RGFW_window* win) { + win->internal.holdMouse = RGFW_FALSE; + _RGFW->mouseOwner = NULL; RGFW_releaseCursor(win); } -u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap) { - double deltaTime = RGFW_getTime() - startTime; - if (deltaTime == 0) return 0; - - double fps = (frameCount / deltaTime); /* the numer of frames over the time it took for them to render */ - if (fpsCap && fps > fpsCap) { - double frameTime = (double)frameCount / (double)fpsCap; /* how long it should take to finish the frames */ - double sleepTime = frameTime - deltaTime; /* subtract how long it should have taken with how long it did take */ - - if (sleepTime > 0) RGFW_sleep((u32)(sleepTime * 1000)); - } - - return (u32) fps; -} - -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) -void RGFW_RGB_to_BGR(RGFW_window* win, u8* data) { - #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA) - u32 x, y; - for (y = 0; y < (u32)win->r.h; y++) { - for (x = 0; x < (u32)win->r.w; x++) { - u32 index = (y * 4 * win->bufferSize.w) + x * 4; - - u8 red = data[index]; - data[index] = win->buffer[index + 2]; - data[index + 2] = red; - } - } - #elif defined(RGFW_OSMESA) - u32 y; - for(y = 0; y < (u32)win->r.h; y++){ - u32 index_from = (y + (win->bufferSize.h - win->r.h)) * 4 * win->bufferSize.w; - u32 index_to = y * 4 * win->bufferSize.w; - memcpy(&data[index_to], &data[index_from], 4 * win->bufferSize.w); - } - #else - RGFW_UNUSED(win); RGFW_UNUSED(data); - #endif -} -#endif - -u32 RGFW_isPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) { - RGFW_UNUSED(win); - return RGFW_gamepadPressed[c][button].current; -} -u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) { - RGFW_UNUSED(win); - return RGFW_gamepadPressed[c][button].prev; -} -u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) { - RGFW_UNUSED(win); - return !RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button); -} -u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) { - RGFW_UNUSED(win); - return RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button); -} - -RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis) { - RGFW_UNUSED(win); - return RGFW_gamepadAxes[controller][whichAxis]; -} -const char* RGFW_getGamepadName(RGFW_window* win, u16 controller) { - RGFW_UNUSED(win); - return (const char*)RGFW_gamepads_name[controller]; -} - -size_t RGFW_getGamepadCount(RGFW_window* win) { - RGFW_UNUSED(win); - return RGFW_gamepadCount; -} - -RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller) { - RGFW_UNUSED(win); - return RGFW_gamepads_type[controller]; -} - -RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value); void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) { - if (value) win->event.keyMod |= mod; - else win->event.keyMod &= ~mod; + if (value) win->internal.mod |= mod; + else win->internal.mod &= ~mod; } -RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll); -void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { +void RGFW_updateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { RGFW_updateKeyMod(win, RGFW_modCapsLock, capital); RGFW_updateKeyMod(win, RGFW_modNumLock, numlock); RGFW_updateKeyMod(win, RGFW_modControl, control); @@ -2418,60 +3856,63 @@ void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numloc RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll); } -RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll); void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) { - RGFW_updateKeyModsPro(win, capital, numlock, - RGFW_isPressed(win, RGFW_controlL) || RGFW_isPressed(win, RGFW_controlR), - RGFW_isPressed(win, RGFW_altL) || RGFW_isPressed(win, RGFW_altR), - RGFW_isPressed(win, RGFW_shiftL) || RGFW_isPressed(win, RGFW_shiftR), - RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR), + RGFW_updateKeyModsEx(win, capital, numlock, + RGFW_window_isKeyDown(win, RGFW_controlL) || RGFW_window_isKeyDown(win, RGFW_controlR), + RGFW_window_isKeyDown(win, RGFW_altL) || RGFW_window_isKeyDown(win, RGFW_altR), + RGFW_window_isKeyDown(win, RGFW_shiftL) || RGFW_window_isKeyDown(win, RGFW_shiftR), + RGFW_window_isKeyDown(win, RGFW_superL) || RGFW_window_isKeyDown(win, RGFW_superR), scroll); } -RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show); void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) { - if (show && (win->_flags & RGFW_windowHideMouse)) - win->_flags ^= RGFW_windowHideMouse; - else if (!show && !(win->_flags & RGFW_windowHideMouse)) - win->_flags |= RGFW_windowHideMouse; + if (show && (win->internal.flags & RGFW_windowHideMouse)) + win->internal.flags ^= RGFW_windowHideMouse; + else if (!show && !(win->internal.flags & RGFW_windowHideMouse)) + win->internal.flags |= RGFW_windowHideMouse; } -RGFW_bool RGFW_window_mouseHidden(RGFW_window* win) { - return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowHideMouse); +RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win) { + return (RGFW_bool)RGFW_BOOL(((RGFW_window*)win)->internal.flags & RGFW_windowHideMouse); } RGFW_bool RGFW_window_borderless(RGFW_window* win) { - return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowNoBorder); + return (RGFW_bool)RGFW_BOOL(win->internal.flags & RGFW_windowNoBorder); } -RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->_flags & RGFW_windowFullscreen); } -RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_windowAllowDND); } +RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->internal.flags & RGFW_windowFullscreen); } +RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->internal.flags & RGFW_windowAllowDND); } void RGFW_window_focusLost(RGFW_window* win) { /* standard routines for when a window looses focus */ - _RGFW.root->_flags &= ~(u32)RGFW_windowFocus; - if ((win->_flags & RGFW_windowFullscreen)) + win->internal.inFocus = RGFW_FALSE; + if ((win->internal.flags & RGFW_windowFullscreen)) RGFW_window_minimize(win); - for (size_t key = 0; key < RGFW_keyLast; key++) { - if (RGFW_isPressed(NULL, (u8)key) == RGFW_FALSE) continue; - RGFW_keyboard[key].current = RGFW_FALSE; - u8 keyChar = RGFW_rgfwToKeyChar((u32)key); - RGFW_keyCallback(win, (u8)key, keyChar, win->event.keyMod, RGFW_FALSE); - RGFW_eventQueuePushEx(e.type = RGFW_keyReleased; - e.key = (u8)key; - e.keyChar = keyChar; - e.repeat = RGFW_FALSE; - e.keyMod = win->event.keyMod; - e._win = win); + size_t key; + for (key = 0; key < RGFW_keyLast; key++) { + if (RGFW_isKeyDown((u8)key) == RGFW_FALSE) continue; + + _RGFW->keyboard[key].current = RGFW_FALSE; + u8 sym = RGFW_rgfwToKeyChar((u32)key); + + if ((win->internal.enabledEvents & RGFW_BIT(RGFW_keyReleased))) { + RGFW_keyCallback(win, (u8)key, sym, win->internal.mod, RGFW_FALSE, RGFW_FALSE); + RGFW_eventQueuePushEx(e.type = RGFW_keyReleased; + e.key.value = (u8)key; + e.key.sym = sym; + e.key.repeat = RGFW_FALSE; + e.key.mod = win->internal.mod; + e.common.win = win); + } } - + RGFW_resetKey(); } #ifndef RGFW_WINDOWS void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { - RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow); + RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow); } #endif @@ -2486,8 +3927,8 @@ struct timespec; #if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS) void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { RGFW_window_showMouseFlags(win, show); - if (show == 0) - RGFW_window_setMouse(win, _RGFW.hiddenMouse); + if (show == RGFW_FALSE) + RGFW_window_setMouse(win, _RGFW->hiddenMouse); else RGFW_window_setMouseDefault(win); } @@ -2507,50 +3948,109 @@ void RGFW_moveToMacOSResourceDir(void) { } OpenGL defines start here (Normal, EGL, OSMesa) */ -#if defined(RGFW_OPENGL) || defined(RGFW_EGL) +#if defined(RGFW_OPENGL) +/* EGL, OpenGL */ +#define RGFW_DEFAULT_GL_HINTS { \ + /* Stencil */ 0, \ + /* Samples */ 0, \ + /* Stereo */ RGFW_FALSE, \ + /* AuxBuffers */ 0, \ + /* DoubleBuffer */ RGFW_TRUE, \ + /* Red */ 8, \ + /* Green */ 8, \ + /* Blue */ 8, \ + /* Alpha */ 8, \ + /* Depth */ 24, \ + /* AccumRed */ 0, \ + /* AccumGreen */ 0, \ + /* AccumBlue */ 0, \ + /* AccumAlpha */ 0, \ + /* SRGB */ RGFW_FALSE, \ + /* Robustness */ RGFW_FALSE, \ + /* Debug */ RGFW_FALSE, \ + /* NoError */ RGFW_FALSE, \ + /* ReleaseBehavior */ RGFW_glReleaseNone, \ + /* Profile */ RGFW_glCore, \ + /* Major */ 1, \ + /* Minor */ 0, \ + /* Share */ NULL, \ + /* Share_EGL */ NULL, \ + /* renderer */ RGFW_glAccelerated \ +} -#ifdef RGFW_WINDOWS - #define WIN32_LEAN_AND_MEAN - #define OEMRESOURCE - #include -#endif +RGFW_glHints RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS; +RGFW_glHints* RGFW_globalHints_OpenGL = &RGFW_globalHints_OpenGL_SRC; -#if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER) - #include -#elif defined(__APPLE__) - #ifndef GL_SILENCE_DEPRECATION - #define GL_SILENCE_DEPRECATION - #endif - #include - #include -#endif - -/* EGL, normal OpenGL only */ -#ifndef RGFW_EGL -i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {8, +void RGFW_resetGlobalHints_OpenGL(void) { +#if !defined(__cplusplus) || defined(RGFW_MACOS) + RGFW_globalHints_OpenGL_SRC = (RGFW_glHints)RGFW_DEFAULT_GL_HINTS; #else -i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {0, + RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS; #endif - 0, 0, 0, 1, 8, 8, 8, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, RGFW_glReleaseNone, RGFW_glCore, 0, 0}; +} +void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints) { RGFW_globalHints_OpenGL = hints; } +RGFW_glHints* RGFW_getGlobalHints_OpenGL(void) { RGFW_init(); return RGFW_globalHints_OpenGL; } -void RGFW_setGLHint(RGFW_glHints hint, i32 value) { - if (hint < RGFW_glFinalHint && hint) RGFW_GL_HINTS[hint] = value; + +void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx) { + RGFW_UNUSED(ctx); + +#ifdef RGFW_WAYLAND + if (RGFW_usingWayland()) return (void*)ctx->egl.ctx; +#endif + +#if defined(RGFW_X11) + return (void*)ctx->ctx; +#else + return NULL; +#endif +} + +RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints) { + #ifdef RGFW_WAYLAND + if (RGFW_usingWayland()) { + return (RGFW_glContext*)RGFW_window_createContext_EGL(win, hints); + } + #endif + RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext)); + if (RGFW_window_createContextPtr_OpenGL(win, ctx, hints) == RGFW_FALSE) { + RGFW_FREE(ctx); + win->src.ctx.native = NULL; + return NULL; + } + win->src.gfxType |= RGFW_gfxOwnedByRGFW; + return ctx; +} + +RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win) { + if (win->src.gfxType & RGFW_windowEGL) return NULL; + return win->src.ctx.native; +} + +void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { + RGFW_window_deleteContextPtr_OpenGL(win, ctx); + if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx); } RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) { const char *start = extensions; - const char *where; + const char *where; const char* terminator; - if (extensions == NULL || ext == NULL) + if (extensions == NULL || ext == NULL) { return RGFW_FALSE; + } - where = strstr(extensions, ext); + while (ext[len - 1] == '\0' && len > 3) { + len--; + } + + where = RGFW_STRSTR(extensions, ext); while (where) { - terminator = where + len; + terminator = where + len; if ((where == start || *(where - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) { - return RGFW_TRUE; + return RGFW_TRUE; } where = RGFW_STRSTR(terminator, ext); } @@ -2558,457 +4058,523 @@ RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, si return RGFW_FALSE; } -RGFW_bool RGFW_extensionSupported(const char* extension, size_t len) { +RGFWDEF RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len); +RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len) { #ifdef GL_NUM_EXTENSIONS - if (RGFW_GL_HINTS[RGFW_glMajor] >= 3) { + if (RGFW_globalHints_OpenGL->major >= 3) { i32 i; + GLint count = 0; - RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress("glGetStringi"); - RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress("RGFW_glGetIntegerv"); - if (RGFW_glGetIntegerv) + RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress_OpenGL("glGetStringi"); + RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress_OpenGL("glGetIntegerv"); + if (RGFW_glGetIntegerv) ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count); for (i = 0; RGFW_glGetStringi && i < count; i++) { const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i); - if (en && RGFW_STRNCMP(en, extension, len) == 0) - return RGFW_TRUE; + if (en && RGFW_STRNCMP(en, extension, len) == 0) { + return RGFW_TRUE; + } } - } else + } else #endif { - RGFW_proc RGFW_glGetString = RGFW_getProcAddress("glGetString"); - + RGFW_proc RGFW_glGetString = RGFW_getProcAddress_OpenGL("glGetString"); + #define RGFW_GL_EXTENSIONS 0x1F03 if (RGFW_glGetString) { - const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(GL_EXTENSIONS); - if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) - return RGFW_TRUE; + const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(RGFW_GL_EXTENSIONS); + + if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) { + return RGFW_TRUE; + } } } - - return RGFW_extensionSupportedPlatform(extension, len); + return RGFW_FALSE; } -/* OPENGL normal only (no EGL / OSMesa) */ -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) && !defined(RGFW_CUSTOM_BACKEND) && !defined(RGFW_WASM) - -#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0) - #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0) - #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0) - #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0) - #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0) - #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0) - #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0) - #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0) - -#if defined(RGFW_X11) || defined(RGFW_WINDOWS) - #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0) - #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0) - #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0) - #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0) - #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0) - #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0) - #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0) - #define RGFW_GL_ACCUM_RED_SIZE RGFW_OS_BASED_VALUE(14, 0x201E, 0, 0) - #define RGFW_GL_ACCUM_GREEN_SIZE RGFW_OS_BASED_VALUE(15, 0x201F, 0, 0) - #define RGFW_GL_ACCUM_BLUE_SIZE RGFW_OS_BASED_VALUE(16, 0x2020, 0, 0) - #define RGFW_GL_ACCUM_ALPHA_SIZE RGFW_OS_BASED_VALUE(17, 0x2021, 0, 0) - #define RGFW_GL_SRGB RGFW_OS_BASED_VALUE(0x20b2, 0x3089, 0, 0) - #define RGFW_GL_NOERROR RGFW_OS_BASED_VALUE(0x31b3, 0x31b3, 0, 0) - #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) - #define RGFW_GL_RELEASE_BEHAVIOR RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 0x2097 , 0, 0) - #define RGFW_GL_CONTEXT_RELEASE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB, 0x2098, 0, 0) - #define RGFW_GL_CONTEXT_NONE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB, 0x0000, 0, 0) - #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) - #define RGFW_GL_DEBUG_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) - #define RGFW_GL_ROBUST_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB, 0x00000004, 0, 0) -#endif - -#ifdef RGFW_WINDOWS - #define WGL_SUPPORT_OPENGL_ARB 0x2010 - #define WGL_COLOR_BITS_ARB 0x2014 - #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 - #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 - #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 - #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 - #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 - #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 - #define WGL_SAMPLE_BUFFERS_ARB 0x2041 - #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 - #define WGL_PIXEL_TYPE_ARB 0x2013 - #define WGL_TYPE_RGBA_ARB 0x202B - - #define WGL_TRANSPARENT_ARB 0x200A -#endif - -/* The window'ing api needs to know how to render the data we (or opengl) give it - 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 */ -i32* RGFW_initFormatAttribs(void); -i32* RGFW_initFormatAttribs(void) { - static i32 attribs[] = { - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) - RGFW_GL_RENDER_TYPE, - RGFW_GL_FULL_FORMAT, - RGFW_GL_DRAW, 1, - RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA, - #endif - - #ifdef RGFW_X11 - GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, - #endif - - #ifdef RGFW_MACOS - 72, - 8, 24, - #endif - - #ifdef RGFW_WINDOWS - WGL_SUPPORT_OPENGL_ARB, 1, - WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, - WGL_COLOR_BITS_ARB, 32, - #endif - 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, 0, 0 - }; - - size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 27; - - #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ - if (attVal) { \ - attribs[index] = attrib;\ - attribs[index + 1] = attVal;\ - index += 2;\ - } - - #if defined(RGFW_MACOS) && defined(RGFW_COCOA_GRAPHICS_SWITCHING) - RGFW_GL_ADD_ATTRIB(96, kCGLPFASupportsAutomaticGraphicsSwitching); - #endif - - RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1); - - RGFW_GL_ADD_ATTRIB(RGFW_GL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_GL_HINTS[RGFW_glStereo]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_GL_HINTS[RGFW_glAuxBuffers]); - - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) - RGFW_GL_ADD_ATTRIB(RGFW_GL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]); - #endif - - #if defined(RGFW_X11) || defined(RGFW_WINDOWS) - RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_RED_SIZE, RGFW_GL_HINTS[RGFW_glAccumRed]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glAccumBlue]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glAccumGreen]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAccumAlpha]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_SRGB, RGFW_GL_HINTS[RGFW_glSRGB]); - RGFW_GL_ADD_ATTRIB(RGFW_GL_NOERROR, RGFW_GL_HINTS[RGFW_glNoError]); - - if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) { - RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_RELEASE); - } else if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_glReleaseNone) { - RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_NONE); - } - - i32 flags = 0; - if (RGFW_GL_HINTS[RGFW_glDebug]) flags |= RGFW_GL_DEBUG_BIT; - if (RGFW_GL_HINTS[RGFW_glRobustness]) flags |= RGFW_GL_ROBUST_BIT; - RGFW_GL_ADD_ATTRIB(RGFW_GL_FLAGS, flags); - #else - i32 accumSize = (i32)(RGFW_GL_HINTS[RGFW_glAccumRed] + RGFW_GL_HINTS[RGFW_glAccumGreen] + RGFW_GL_HINTS[RGFW_glAccumBlue] + RGFW_GL_HINTS[RGFW_glAccumAlpha]) / 4; - RGFW_GL_ADD_ATTRIB(14, accumSize); - #endif - - #ifndef RGFW_X11 - RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]); - #endif - - #ifdef RGFW_MACOS - if (_RGFW.root->_flags & RGFW_windowOpenglSoftware) { - RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID); - } else { - attribs[index] = RGFW_GL_RENDER_TYPE; - index += 1; - } - #endif - - #ifdef RGFW_MACOS - /* macOS has the surface attribs and the opengl attribs connected for some reason - maybe this is to give macOS more control to limit openGL/the opengl version? */ - - attribs[index] = 99; - attribs[index + 1] = 0x1000; - - - if (RGFW_GL_HINTS[RGFW_glMajor] >= 4 || RGFW_GL_HINTS[RGFW_glMajor] >= 3) { - attribs[index + 1] = (i32) ((RGFW_GL_HINTS[RGFW_glMajor] >= 4) ? 0x4100 : 0x3200); - } - #endif - - RGFW_GL_ADD_ATTRIB(0, 0); - - return attribs; +RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len) { + if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE; + return RGFW_extensionSupportedPlatform_OpenGL(extension, len); } -/* EGL only (no OSMesa nor normal OPENGL) */ -#elif defined(RGFW_EGL) +void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win) { + if (win) { + _RGFW->current = win; + } + RGFW_window_makeCurrentContext_OpenGL(win); +} + +RGFW_window* RGFW_getCurrentWindow_OpenGL(void) { return _RGFW->current; } +void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max) { stack->attribs = attribs; stack->count = 0; stack->max = max; } +void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib) { + RGFW_ASSERT(stack->count < stack->max); + stack->attribs[stack->count] = attrib; + stack->count += 1; +} +void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2) { + RGFW_attribStack_pushAttrib(stack, attrib1); + RGFW_attribStack_pushAttrib(stack, attrib2); +} + +/* EGL */ +#ifdef RGFW_EGL #include -#if defined(RGFW_LINK_EGL) - typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*); - - PFNEGLINITIALIZEPROC eglInitializeSource; - PFNEGLGETCONFIGSPROC eglGetConfigsSource; - PFNEGLCHOOSECONFIgamepadROC eglChooseConfigSource; - PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource; - PFNEGLCREATECONTEXTPROC eglCreateContextSource; - PFNEGLMAKECURRENTPROC eglMakeCurrentSource; - PFNEGLGETDISPLAYPROC eglGetDisplaySource; - PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource; - PFNEGLSWAPINTERVALPROC eglSwapIntervalSource; - PFNEGLBINDAPIPROC eglBindAPISource; - PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource; - PFNEGLTERMINATEPROC eglTerminateSource; - PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource; - - #define eglInitialize eglInitializeSource - #define eglGetConfigs eglGetConfigsSource - #define eglChooseConfig eglChooseConfigSource - #define eglCreateWindowSurface eglCreateWindowSurfaceSource - #define eglCreateContext eglCreateContextSource - #define eglMakeCurrent eglMakeCurrentSource - #define eglGetDisplay eglGetDisplaySource - #define eglSwapBuffers eglSwapBuffersSource - #define eglSwapInterval eglSwapIntervalSource - #define eglBindAPI eglBindAPISource - #define eglDestroyContext eglDestroyContextSource - #define eglTerminate eglTerminateSource - #define eglDestroySurface eglDestroySurfaceSource; -#endif - +PFNEGLINITIALIZEPROC RGFW_eglInitialize; +PFNEGLGETCONFIGSPROC RGFW_eglGetConfigs; +PFNEGLCHOOSECONFIGPROC RGFW_eglChooseConfig; +PFNEGLCREATEWINDOWSURFACEPROC RGFW_eglCreateWindowSurface; +PFNEGLCREATECONTEXTPROC RGFW_eglCreateContext; +PFNEGLMAKECURRENTPROC RGFW_eglMakeCurrent; +PFNEGLGETDISPLAYPROC RGFW_eglGetDisplay; +PFNEGLSWAPBUFFERSPROC RGFW_eglSwapBuffers; +PFNEGLSWAPINTERVALPROC RGFW_eglSwapInterval; +PFNEGLBINDAPIPROC RGFW_eglBindAPI; +PFNEGLDESTROYCONTEXTPROC RGFW_eglDestroyContext; +PFNEGLTERMINATEPROC RGFW_eglTerminate; +PFNEGLDESTROYSURFACEPROC RGFW_eglDestroySurface; +PFNEGLGETCURRENTCONTEXTPROC RGFW_eglGetCurrentContext; +PFNEGLGETPROCADDRESSPROC RGFW_eglGetProcAddress = NULL; +PFNEGLQUERYSTRINGPROC RGFW_eglQueryString; +PFNEGLGETCONFIGATTRIBPROC RGFW_eglGetConfigAttrib; #define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098 #define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb -#ifndef RGFW_GL_ADD_ATTRIB -#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ - if (attVal) { \ - attribs[index] = attrib;\ - attribs[index + 1] = attVal;\ - index += 2;\ - } +#ifdef RGFW_WINDOWS + #include +#elif defined(RGFW_MACOS) || defined(RGFW_UNIX) + #include #endif - -void RGFW_window_initOpenGL(RGFW_window* win) { -#if defined(RGFW_LINK_EGL) - eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize"); - eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs"); - eglChooseConfigSource = (PFNEGLCHOOSECONFIgamepadROC) eglGetProcAddress("eglChooseConfig"); - eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface"); - eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext"); - eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent"); - eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay"); - eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers"); - eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval"); - eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI"); - eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext"); - eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate"); - eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface"); - - RGFW_ASSERT(eglInitializeSource != NULL && - eglGetConfigsSource != NULL && - eglChooseConfigSource != NULL && - eglCreateWindowSurfaceSource != NULL && - eglCreateContextSource != NULL && - eglMakeCurrentSource != NULL && - eglGetDisplaySource != NULL && - eglSwapBuffersSource != NULL && - eglSwapIntervalsSource != NULL && - eglBindAPISource != NULL && - eglDestroyContextSource != NULL && - eglTerminateSource != NULL && - eglDestroySurfaceSource != NULL); -#endif /* RGFW_LINK_EGL */ - #ifdef RGFW_WAYLAND - if (RGFW_useWaylandBool) - win->src.eglWindow = wl_egl_window_create(win->src.surface, win->r.w, win->r.h); +#include #endif +void* RGFW_eglLibHandle = NULL; + +void* RGFW_getDisplay_EGL(void) { return _RGFW->EGL_display; } +void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx) { return ctx->ctx; } +void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx) { return ctx->surface; } +struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx) { return ctx->eglWindow; } + +RGFW_bool RGFW_loadEGL(void) { + RGFW_init(); + if (RGFW_eglGetProcAddress != NULL) { + return RGFW_TRUE; + } + +#ifndef RGFW_WASM #ifdef RGFW_WINDOWS - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc); - #elif defined(RGFW_MACOS) - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0); - #elif defined(RGFW_WAYLAND) - if (RGFW_useWaylandBool) - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.wl_display); - else - #endif - #ifdef RGFW_X11 - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display); - #else - {} - #endif - #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11) - win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display); + const char* libNames[] = { "libEGL.dll", "EGL.dll" }; + #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) + /* Linux and macOS */ + const char* libNames[] = { + "libEGL.so.1", /* most common */ + "libEGL.so", /* fallback */ + "/System/Library/Frameworks/OpenGL.framework/OpenGL" /* fallback for older macOS EGL-like systems */ + }; #endif - EGLint major, minor; + for (size_t i = 0; i < sizeof(libNames) / sizeof(libNames[0]); ++i) { + #ifdef RGFW_WINDOWS + RGFW_eglLibHandle = (void*)LoadLibraryA(libNames[i]); + if (RGFW_eglLibHandle) { + RGFW_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC)(RGFW_proc)GetProcAddress((HMODULE)RGFW_eglLibHandle, "eglGetProcAddress"); + break; + } + #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) + RGFW_eglLibHandle = dlopen(libNames[i], RTLD_LAZY | RTLD_GLOBAL); + if (RGFW_eglLibHandle) { + void* lib = dlsym(RGFW_eglLibHandle, "eglGetProcAddress"); + if (lib != NULL) RGFW_MEMCPY(&RGFW_eglGetProcAddress, &lib, sizeof(PFNEGLGETPROCADDRESSPROC)); + break; + } + #endif + } - eglInitialize(win->src.EGL_display, &major, &minor); + if (!RGFW_eglLibHandle || !RGFW_eglGetProcAddress) { + return RGFW_FALSE; + } + + RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) RGFW_eglGetProcAddress("eglInitialize"); + RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) RGFW_eglGetProcAddress("eglGetConfigs"); + RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) RGFW_eglGetProcAddress("eglChooseConfig"); + RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) RGFW_eglGetProcAddress("eglCreateWindowSurface"); + RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) RGFW_eglGetProcAddress("eglCreateContext"); + RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) RGFW_eglGetProcAddress("eglMakeCurrent"); + RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) RGFW_eglGetProcAddress("eglGetDisplay"); + RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) RGFW_eglGetProcAddress("eglSwapBuffers"); + RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) RGFW_eglGetProcAddress("eglSwapInterval"); + RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) RGFW_eglGetProcAddress("eglBindAPI"); + RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) RGFW_eglGetProcAddress("eglDestroyContext"); + RGFW_eglTerminate = (PFNEGLTERMINATEPROC) RGFW_eglGetProcAddress("eglTerminate"); + RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) RGFW_eglGetProcAddress("eglDestroySurface"); + RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) RGFW_eglGetProcAddress("eglQueryString"); + RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) RGFW_eglGetProcAddress("eglGetCurrentContext"); + RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) RGFW_eglGetProcAddress("eglGetConfigAttrib"); + +#else + RGFW_eglGetProcAddress = eglGetProcAddress; + RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) eglInitialize; + RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) eglGetConfigs; + RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) eglChooseConfig; + RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) eglCreateWindowSurface; + RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) eglCreateContext; + RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) eglMakeCurrent; + RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) eglGetDisplay; + RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) eglSwapBuffers; + RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) eglSwapInterval; + RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) eglBindAPI; + RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) eglDestroyContext; + RGFW_eglTerminate = (PFNEGLTERMINATEPROC) eglTerminate; + RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) eglDestroySurface; + RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) eglQueryString; + RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) eglGetCurrentContext; + RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)eglGetConfigAttrib; +#endif + + RGFW_bool out = RGFW_BOOL(RGFW_eglInitialize!= NULL && + RGFW_eglGetConfigs!= NULL && + RGFW_eglChooseConfig!= NULL && + RGFW_eglCreateWindowSurface!= NULL && + RGFW_eglCreateContext!= NULL && + RGFW_eglMakeCurrent!= NULL && + RGFW_eglGetDisplay!= NULL && + RGFW_eglSwapBuffers!= NULL && + RGFW_eglSwapInterval != NULL && + RGFW_eglBindAPI!= NULL && + RGFW_eglDestroyContext!= NULL && + RGFW_eglTerminate!= NULL && + RGFW_eglDestroySurface!= NULL && + RGFW_eglQueryString != NULL && + RGFW_eglGetCurrentContext != NULL && + RGFW_eglGetConfigAttrib != NULL); + + if (out) { + #ifdef RGFW_WINDOWS + HDC dc = GetDC(NULL); + _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) dc); + ReleaseDC(NULL, dc); + #elif defined(RGFW_WAYLAND) + if (_RGFW->useWaylandBool) + _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->wl_display); + else + #endif + #ifdef RGFW_X11 + _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->display); + #else + {} + #endif + #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11) + _RGFW->EGL_display = RGFW_eglGetDisplay(EGL_DEFAULT_DISPLAY); + #endif + } + + RGFW_eglInitialize(_RGFW->EGL_display, NULL, NULL); + return out; +} + + +void RGFW_unloadEGL(void) { + if (!RGFW_eglLibHandle) return; + RGFW_eglTerminate(_RGFW->EGL_display); + #ifdef RGFW_WINDOWS + FreeLibrary((HMODULE)RGFW_eglLibHandle); + #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) + dlclose(RGFW_eglLibHandle); + #endif + + RGFW_eglLibHandle = NULL; + RGFW_eglGetProcAddress = NULL; +} + +RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints) { + if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE; + win->src.ctx.egl = ctx; + win->src.gfxType = RGFW_gfxEGL; + +#ifdef RGFW_WAYLAND + if (_RGFW->useWaylandBool) + win->src.ctx.egl->eglWindow = wl_egl_window_create(win->src.surface, win->w, win->h); +#endif #ifndef EGL_OPENGL_ES1_BIT #define EGL_OPENGL_ES1_BIT 0x1 #endif - EGLint egl_config[24] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, - #ifdef RGFW_OPENGL_ES1 - EGL_OPENGL_ES1_BIT, - #elif defined(RGFW_OPENGL_ES3) - EGL_OPENGL_ES3_BIT, - #elif defined(RGFW_OPENGL_ES2) - EGL_OPENGL_ES2_BIT, - #else - EGL_OPENGL_BIT, - #endif - EGL_NONE, EGL_NONE - }; + EGLint egl_config[24]; { - size_t index = 7; - EGLint* attribs = egl_config; + RGFW_attribStack stack; + RGFW_attribStack_init(&stack, egl_config, 24); - RGFW_GL_ADD_ATTRIB(EGL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]); - RGFW_GL_ADD_ATTRIB(EGL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]); - RGFW_GL_ADD_ATTRIB(EGL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]); - RGFW_GL_ADD_ATTRIB(EGL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]); - RGFW_GL_ADD_ATTRIB(EGL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]); + RGFW_attribStack_pushAttribs(&stack, EGL_SURFACE_TYPE, EGL_WINDOW_BIT); + RGFW_attribStack_pushAttrib(&stack, EGL_RENDERABLE_TYPE); - if (RGFW_GL_HINTS[RGFW_glSRGB]) - RGFW_GL_ADD_ATTRIB(0x3089, RGFW_GL_HINTS[RGFW_glSRGB]); + if (hints->profile == RGFW_glES) { + switch (hints->major) { + case 1: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES1_BIT); break; + case 2: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES2_BIT); break; + case 3: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES3_BIT); break; + default: break; + } + } else { + RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_BIT); + } - RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE); + RGFW_attribStack_pushAttribs(&stack, EGL_RED_SIZE, hints->red); + RGFW_attribStack_pushAttribs(&stack, EGL_GREEN_SIZE, hints->green); + RGFW_attribStack_pushAttribs(&stack, EGL_BLUE_SIZE, hints->blue); + RGFW_attribStack_pushAttribs(&stack, EGL_ALPHA_SIZE, hints->alpha); + RGFW_attribStack_pushAttribs(&stack, EGL_DEPTH_SIZE, hints->depth); + + RGFW_attribStack_pushAttribs(&stack, EGL_STENCIL_SIZE, hints->stencil); + if (hints->samples) { + RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLE_BUFFERS, 1); + RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLES, hints->samples); + } + + RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); } - EGLConfig config; - EGLint numConfigs; - eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs); + EGLint numConfigs, best_config = -1, best_samples = 0; + RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, NULL, 0, &numConfigs); + EGLConfig* configs = (EGLConfig*)RGFW_ALLOC(sizeof(EGLConfig) * (u32)numConfigs); + + RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, configs, numConfigs, &numConfigs); + +#ifdef RGFW_X11 + RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent); + EGLint best_depth = 0; +#endif + + for (EGLint i = 0; i < numConfigs; i++) { + EGLint visual_id = 0; + EGLint samples = 0; + + RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_NATIVE_VISUAL_ID, &visual_id); + RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_SAMPLES, &samples); + + if (best_config == -1) best_config = i; + +#ifdef RGFW_X11 + if (_RGFW->useWaylandBool == RGFW_FALSE) { + XVisualInfo vinfo_template; + vinfo_template.visualid = (VisualID)visual_id; + + int num_visuals = 0; + XVisualInfo* vi = XGetVisualInfo(_RGFW->display, VisualIDMask, &vinfo_template, &num_visuals); + if (!vi) continue; + if ((!transparent || vi->depth == 32) && best_depth == 0) { + best_config = i; + best_depth = vi->depth; + } + + if ((!(transparent) || vi->depth == 32) && (samples <= hints->samples && samples > best_samples)) { + best_depth = vi->depth; + best_config = i; + best_samples = samples; + XFree(vi); + continue; + } + } +#endif + + if (samples <= hints->samples && samples > best_samples) { + best_config = i; + best_samples = samples; + } + } + + EGLConfig config = configs[best_config]; + RGFW_FREE(configs); +#ifdef RGFW_X11 + if (_RGFW->useWaylandBool == RGFW_FALSE) { + /* This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */ + XVisualInfo* result; + XVisualInfo desired; + EGLint visualID = 0, count = 0; + + RGFW_eglGetConfigAttrib(_RGFW->EGL_display, config, EGL_NATIVE_VISUAL_ID, &visualID); + if (visualID) { + desired.visualid = (VisualID)visualID; + result = XGetVisualInfo(_RGFW->display, VisualIDMask, &desired, &count); + } else RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to fetch a valid EGL VisualID"); + + if (result == NULL || count == 0) { + if (win->src.window == 0) { + /* try to create a EGL context anyway (this will work if you're not using a NVidia driver) */ + win->internal.flags &= ~(u32)RGFW_windowEGL; + RGFW_createWindowPlatform("", win->internal.flags, win); + } + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to find a valid visual for the EGL config"); + } else { + if (win->src.window) RGFW_window_closePlatform(win); + RGFW_XCreateWindow(*result, "", win->internal.flags, win); + XFree(result); + } + } +#endif + + EGLint surf_attribs[9]; + + { + RGFW_attribStack stack; + RGFW_attribStack_init(&stack, surf_attribs, 9); + + const char present_opaque_str[] = "EGL_EXT_present_opaque"; + RGFW_bool opaque_extension_Found = RGFW_extensionSupportedPlatform_EGL(present_opaque_str, sizeof(present_opaque_str)); + + #ifndef EGL_PRESENT_OPAQUE_EXT + #define EGL_PRESENT_OPAQUE_EXT 0x31df + #endif + + #ifndef EGL_GL_COLORSPACE_KHR + #define EGL_GL_COLORSPACE_KHR 0x309D + #ifndef EGL_GL_COLORSPACE_SRGB_KHR + #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 + #endif + #endif + + const char gl_colorspace_str[] = "EGL_KHR_gl_colorspace"; + RGFW_bool gl_colorspace_Found = RGFW_extensionSupportedPlatform_EGL(gl_colorspace_str, sizeof(gl_colorspace_str)); + + if (hints->sRGB && gl_colorspace_Found) { + RGFW_attribStack_pushAttribs(&stack, EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); + } + + if (!(win->internal.flags & RGFW_windowTransparent) && opaque_extension_Found) + RGFW_attribStack_pushAttribs(&stack, EGL_PRESENT_OPAQUE_EXT, EGL_TRUE); + + if (hints->doubleBuffer == 0) { + RGFW_attribStack_pushAttribs(&stack, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); + } + + RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); + } #if defined(RGFW_MACOS) - void* layer = RGFW_cocoaGetLayer(); + void* layer = RGFW_getLayer_OSX(); - RGFW_window_cocoaSetLayer(win, layer); + RGFW_window_setLayer_OSX(win, layer); - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL); + win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) layer, surf_attribs); #elif defined(RGFW_WINDOWS) - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); + win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs); #elif defined(RGFW_WAYLAND) - if (RGFW_useWaylandBool) - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.eglWindow, NULL); + if (_RGFW->useWaylandBool) + win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.ctx.egl->eglWindow, surf_attribs); else #endif #ifdef RGFW_X11 - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); + win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs); #else {} #endif - #if !defined(RGFW_X11) && !defined(RGFW_WAYLAND) && !defined(RGFW_MACOS) - win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); + #ifdef RGFW_WASM + win->src.ctx.egl->surface = eglCreateWindowSurface(_RGFW->EGL_display, config, 0, 0); #endif - EGLint attribs[12]; - size_t index = 0; - -#ifdef RGFW_OPENGL_ES1 - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 1); -#elif defined(RGFW_OPENGL_ES2) - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 2); -#elif defined(RGFW_OPENGL_ES3) - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 3); -#endif - - RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]); - RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]); - - if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0) - RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); - - if (RGFW_GL_HINTS[RGFW_glMajor]) { - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_GL_HINTS[RGFW_glMajor]); - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_GL_HINTS[RGFW_glMinor]); - - if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) { - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); - } - else { - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); - } + if (win->src.ctx.egl->surface == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL surface."); + return RGFW_FALSE; } - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, RGFW_GL_HINTS[RGFW_glRobustness]); - RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_DEBUG, RGFW_GL_HINTS[RGFW_glDebug]); - if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) { - RGFW_GL_ADD_ATTRIB(0x2097, 0x2098); - } else { - RGFW_GL_ADD_ATTRIB(0x2096, 0x0000); + EGLint attribs[20]; + { + RGFW_attribStack stack; + RGFW_attribStack_init(&stack, attribs, 20); + + if (hints->major || hints->minor) { + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MAJOR_VERSION, hints->major); + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MINOR_VERSION, hints->minor); + } + + if (hints->profile == RGFW_glCore) { + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); + } else if (hints->profile == RGFW_glCompatibility) { + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); + } + + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_ROBUST_ACCESS, hints->robustness); + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_DEBUG, hints->debug); + + #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_KHR + #define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 + #endif + + #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR + #define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 + #endif + + if (hints->releaseBehavior == RGFW_glReleaseFlush) { + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); + } else { + RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, 0x0000); + } + + RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); } - RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE); + if (hints->profile == RGFW_glES) + RGFW_eglBindAPI(EGL_OPENGL_ES_API); + else + RGFW_eglBindAPI(EGL_OPENGL_API); - #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3) - eglBindAPI(EGL_OPENGL_ES_API); - #else - eglBindAPI(EGL_OPENGL_API); + win->src.ctx.egl->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs); + + if (win->src.ctx.egl->ctx == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL context."); + return RGFW_FALSE; + } + + RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx); + RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context initalized."); + return RGFW_TRUE; +} + +RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win) { + if (win->src.gfxType == RGFW_windowOpenGL) return NULL; + return win->src.ctx.egl; +} + +void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx) { + if (_RGFW->EGL_display == NULL) return; + + RGFW_eglDestroySurface(_RGFW->EGL_display, ctx->surface); + RGFW_eglDestroyContext(_RGFW->EGL_display, ctx->ctx); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context freed"); + #ifdef RGFW_WAYLAND + if (_RGFW->useWaylandBool == RGFW_FALSE) return; + wl_egl_window_destroy(win->src.ctx.egl->eglWindow); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL window context freed"); #endif - - win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs); - - if (win->src.EGL_context == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, RGFW_DEBUG_CTX(win, 0), "failed to create an EGL opengl context"); - return; - } - - eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); - eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context initalized"); + win->src.ctx.egl = NULL; } -void RGFW_window_freeOpenGL(RGFW_window* win) { - if (win->src.EGL_display == NULL) return; - - eglDestroySurface(win->src.EGL_display, win->src.EGL_surface); - eglDestroyContext(win->src.EGL_display, win->src.EGL_context); - eglTerminate(win->src.EGL_display); - win->src.EGL_display = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context freed"); -} - -void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { - if (win == NULL) - eglMakeCurrent(_RGFW.root->src.EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +void RGFW_window_makeCurrentContext_EGL(RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.egl); + if (win == NULL) + RGFW_eglMakeCurrent(_RGFW->EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); else { - eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); + RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx); } } -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); } +void RGFW_window_swapBuffers_EGL(RGFW_window* win) { + if (RGFW_eglSwapBuffers) + RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface); + else RGFW_window_swapBuffers_OpenGL(win); +} -void* RGFW_getCurrent_OpenGL(void) { return eglGetCurrentContext(); } +void* RGFW_getCurrentContext_EGL(void) { + return RGFW_eglGetCurrentContext(); +} -#ifdef RGFW_APPLE -void* RGFWnsglFramework = NULL; -#elif defined(RGFW_WINDOWS) -HMODULE RGFW_wgl_dll = NULL; -#endif - -RGFW_proc RGFW_getProcAddress(const char* procname) { +RGFW_proc RGFW_getProcAddress_EGL(const char* procname) { #if defined(RGFW_WINDOWS) RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); @@ -3016,19 +4582,46 @@ RGFW_proc RGFW_getProcAddress(const char* procname) { return proc; #endif - return (RGFW_proc) eglGetProcAddress(procname); + return (RGFW_proc) RGFW_eglGetProcAddress(procname); } -RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) { - const char* extensions = eglQueryString(_RGFW.root->src.EGL_display, EGL_EXTENSIONS); - return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); +RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len) { + if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE; + const char* extensions = RGFW_eglQueryString(_RGFW->EGL_display, EGL_EXTENSIONS); + return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); } -void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { +void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval) { RGFW_ASSERT(win != NULL); + RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval); +} - eglSwapInterval(win->src.EGL_display, swapInterval); +RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len) { + if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE; + return RGFW_extensionSupportedPlatform_EGL(extension, len); +} +void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win) { + _RGFW->current = win; + RGFW_window_makeCurrentContext_EGL(win); +} + +RGFW_window* RGFW_getCurrentWindow_EGL(void) { return _RGFW->current; } + +RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints) { + RGFW_eglContext* ctx = (RGFW_eglContext*)RGFW_ALLOC(sizeof(RGFW_eglContext)); + if (RGFW_window_createContextPtr_EGL(win, ctx, hints) == RGFW_FALSE) { + RGFW_FREE(ctx); + win->src.ctx.egl = NULL; + return NULL; + } + win->src.gfxType |= RGFW_gfxOwnedByRGFW; + return ctx; +} + +void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) { + RGFW_window_deleteContextPtr_EGL(win, ctx); + if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx); } #endif /* RGFW_EGL */ @@ -3046,7 +4639,7 @@ void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { #include #endif -const char** RGFW_getVKRequiredInstanceExtensions(size_t* count) { +const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count) { static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME}; arr[1] = RGFW_VK_SURFACE; if (count != NULL) *count = 2; @@ -3054,20 +4647,20 @@ const char** RGFW_getVKRequiredInstanceExtensions(size_t* count) { return (const char**)arr; } -VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) { +VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) { RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance); RGFW_ASSERT(surface != NULL); *surface = VK_NULL_HANDLE; #ifdef RGFW_X11 - RGFW_GOTO_WAYLAND(0); - VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window }; + + VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) _RGFW->display, (Window) win->src.window }; return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface); #endif #if defined(RGFW_WAYLAND) -RGFW_WAYLAND_LABEL - VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) win->src.wl_display, (struct wl_surface*) win->src.surface }; + + VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) _RGFW->wl_display, (struct wl_surface*) win->src.surface }; return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface); #elif defined(RGFW_WINDOWS) VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window }; @@ -3075,28 +4668,24 @@ RGFW_WAYLAND_LABEL return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface); #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) void* contentView = ((void* (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView")); - VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, win->src.display, (void*)contentView }; - + VkMacOSSurfaceCreateSurfaceMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, 0, (void*)contentView }; return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface); #endif } -RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { +RGFW_bool RGFW_getPresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { RGFW_ASSERT(instance); - if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init(); + if (_RGFW == NULL) RGFW_init(); #ifdef RGFW_X11 - RGFW_GOTO_WAYLAND(0); - Visual* visual = DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)); - if (_RGFW.root) - visual = _RGFW.root->src.visual.visual; - RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.display, XVisualIDFromVisual(visual)); + Visual* visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)); + RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->display, XVisualIDFromVisual(visual)); return out; #endif #if defined(RGFW_WAYLAND) -RGFW_WAYLAND_LABEL - RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.wl_display); + + RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->wl_display); return wlout; #elif defined(RGFW_WINDOWS) #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) @@ -3109,1341 +4698,138 @@ RGFW_WAYLAND_LABEL This is where OS specific stuff starts */ - -#if (defined(RGFW_WAYLAND) || defined(RGFW_X11)) && !defined(RGFW_NO_LINUX) - int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */ - - #if defined(__linux__) - #include - #include - #include - #include - - u32 RGFW_linux_updateGamepad(RGFW_window* win); - u32 RGFW_linux_updateGamepad(RGFW_window* win) { - /* check for new gamepads */ - static const char* str[] = {"/dev/input/js0", "/dev/input/js1", "/dev/input/js2", "/dev/input/js3", "/dev/input/js4", "/dev/input/js5"}; - static u8 RGFW_rawGamepads[6]; - { - u16 i; - for (i = 0; i < 6; i++) { - u16 index = RGFW_gamepadCount; - if (RGFW_rawGamepads[i]) { - struct input_id device_info; - if (ioctl(RGFW_rawGamepads[i], EVIOCGID, &device_info) == -2) { - if (errno == ENODEV) { - RGFW_rawGamepads[i] = 0; - } - } - continue; - } - - i32 js = open(str[i], O_RDONLY); - - if (js <= 0) - break; - - if (RGFW_gamepadCount >= 4) { - close(js); - break; - } - - RGFW_rawGamepads[i] = 1; - - int axes, buttons; - if (ioctl(js, JSIOCGAXES, &axes) < 0 || ioctl(js, JSIOCGBUTTONS, &buttons) < 0) { - close(js); - continue; - } - - if (buttons <= 5 || buttons >= 30) { - close(js); - continue; - } - - RGFW_gamepadCount++; - - RGFW_gamepads[index] = js; - - ioctl(js, JSIOCGNAME(sizeof(RGFW_gamepads_name[index])), RGFW_gamepads_name[index]); - RGFW_gamepads_name[index][sizeof(RGFW_gamepads_name[index]) - 1] = 0; - - u8 j; - for (j = 0; j < 16; j++) { - RGFW_gamepadPressed[index][j].prev = 0; - RGFW_gamepadPressed[index][j].current = 0; - } - - win->event.type = RGFW_gamepadConnected; - - RGFW_gamepads_type[index] = RGFW_gamepadUnknown; - if (RGFW_STRSTR(RGFW_gamepads_name[index], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[index], "X-Box")) - RGFW_gamepads_type[index] = RGFW_gamepadMicrosoft; - else if (RGFW_STRSTR(RGFW_gamepads_name[index], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS5")) - RGFW_gamepads_type[index] = RGFW_gamepadSony; - else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Nintendo")) - RGFW_gamepads_type[index] = RGFW_gamepadNintendo; - else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Logitech")) - RGFW_gamepads_type[index] = RGFW_gamepadLogitech; - - win->event.gamepad = index; - RGFW_gamepadCallback(win, index, 1); - return 1; - } - } - /* check gamepad events */ - u8 i; - - for (i = 0; i < RGFW_gamepadCount; i++) { - struct js_event e; - if (RGFW_gamepads[i] == 0) - continue; - - i32 flags = fcntl(RGFW_gamepads[i], F_GETFL, 0); - fcntl(RGFW_gamepads[i], F_SETFL, flags | O_NONBLOCK); - - ssize_t bytes; - while ((bytes = read(RGFW_gamepads[i], &e, sizeof(e))) > 0) { - switch (e.type) { - case JS_EVENT_BUTTON: { - size_t typeIndex = 0; - if (RGFW_gamepads_type[i] == RGFW_gamepadMicrosoft) typeIndex = 1; - else if (RGFW_gamepads_type[i] == RGFW_gamepadLogitech) typeIndex = 2; - - win->event.type = e.value ? RGFW_gamepadButtonPressed : RGFW_gamepadButtonReleased; - u8 RGFW_linux2RGFW[3][RGFW_gamepadR3 + 8] = {{ /* ps */ - RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadY, RGFW_gamepadX, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, - RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, - },{ /* xbox */ - RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadSelect, RGFW_gamepadStart, - RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, 255, 255, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight - },{ /* Logitech */ - RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, - RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight - } - }; - - win->event.button = RGFW_linux2RGFW[typeIndex][e.number]; - win->event.gamepad = i; - if (win->event.button == 255) break; - - RGFW_gamepadPressed[i][win->event.button].prev = RGFW_gamepadPressed[i][win->event.button].current; - RGFW_gamepadPressed[i][win->event.button].current = RGFW_BOOL(e.value); - RGFW_gamepadButtonCallback(win, i, win->event.button, RGFW_BOOL(e.value)); - - return 1; - } - case JS_EVENT_AXIS: { - size_t axis = e.number / 2; - if (axis == 2) axis = 1; - - ioctl(RGFW_gamepads[i], JSIOCGAXES, &win->event.axisesCount); - win->event.axisesCount = 2; - - if (axis < 3) { - if (e.number == 0 || e.number == 3) - RGFW_gamepadAxes[i][axis].x = (i32)((e.value / 32767.0f) * 100); - else if (e.number == 1 || e.number == 4) { - RGFW_gamepadAxes[i][axis].y = (i32)((e.value / 32767.0f) * 100); - } - } - - win->event.axis[axis] = RGFW_gamepadAxes[i][axis]; - win->event.type = RGFW_gamepadAxisMove; - win->event.gamepad = i; - win->event.whichAxis = (u8)axis; - RGFW_gamepadAxisCallback(win, i, win->event.axis, win->event.axisesCount, win->event.whichAxis); - return 1; - } - default: break; - } - } - if (bytes == -1 && errno == ENODEV) { - RGFW_gamepadCount--; - close(RGFW_gamepads[i]); - RGFW_gamepads[i] = 0; - - win->event.type = RGFW_gamepadDisconnected; - win->event.gamepad = i; - RGFW_gamepadCallback(win, i, 0); - return 1; - } - } - return 0; - } - - #endif -#endif - - - -/* - - Start of Wayland defines - - -*/ - -#ifdef RGFW_WAYLAND -/* -Wayland TODO: (out of date) -- fix RGFW_keyPressed lock state - - RGFW_windowMoved, the window was moved (by the user) - RGFW_windowResized the window was resized (by the user), [on WASM this means the browser was resized] - RGFW_windowRefresh The window content needs to be refreshed - - RGFW_DND a file has been dropped into the window - RGFW_DNDInit - -- window args: - #define RGFW_windowNoResize the window cannot be resized by the user - #define RGFW_windowAllowDND the window supports drag and drop - #define RGFW_scaleToMonitor scale the window to the screen - -- other missing functions functions ("TODO wayland") (~30 functions) -- fix buffer rendering weird behavior -*/ -#include -#include -#include -#include -#include -#include -#include -#include - -RGFW_window* RGFW_key_win = NULL; - -/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */ -#include "xdg-shell.h" -#include "xdg-decoration-unstable-v1.h" - -struct xkb_context *xkb_context; -struct xkb_keymap *keymap = NULL; -struct xkb_state *xkb_state = NULL; -enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode; -struct zxdg_decoration_manager_v1 *decoration_manager = NULL; - -struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL; -struct wl_surface* RGFW_cursor_surface = NULL; -struct wl_cursor_image* RGFW_cursor_image = NULL; - -void xdg_wm_base_ping_handler(void *data, - struct xdg_wm_base *wm_base, uint32_t serial) -{ - RGFW_UNUSED(data); - xdg_wm_base_pong(wm_base, serial); -} - -const struct xdg_wm_base_listener xdg_wm_base_listener = { - .ping = xdg_wm_base_ping_handler, -}; - -RGFW_bool RGFW_wl_configured = 0; - -void xdg_surface_configure_handler(void *data, - struct xdg_surface *xdg_surface, uint32_t serial) -{ - RGFW_UNUSED(data); - xdg_surface_ack_configure(xdg_surface, serial); - RGFW_wl_configured = 1; -} - -const struct xdg_surface_listener xdg_surface_listener = { - .configure = xdg_surface_configure_handler, -}; - -void xdg_toplevel_configure_handler(void *data, - struct xdg_toplevel *toplevel, int32_t width, int32_t height, - struct wl_array *states) -{ - RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states); - RGFW_UNUSED(width); RGFW_UNUSED(height); -} - -void xdg_toplevel_close_handler(void *data, - struct xdg_toplevel *toplevel) -{ - RGFW_UNUSED(data); - RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel); - if (win == NULL) - win = RGFW_key_win; - - RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); - RGFW_windowQuitCallback(win); -} - -void shm_format_handler(void *data, - struct wl_shm *shm, uint32_t format) -{ - RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format); -} - -const struct wl_shm_listener shm_listener = { - .format = shm_format_handler, -}; - -const struct xdg_toplevel_listener xdg_toplevel_listener = { - .configure = xdg_toplevel_configure_handler, - .close = xdg_toplevel_close_handler, -}; - -RGFW_window* RGFW_mouse_win = NULL; - -void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y); - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - RGFW_mouse_win = win; - - RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter; - e.point = RGFW_POINT(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)); - e._win = win); - - RGFW_mouseNotifyCallback(win, win->event.point, RGFW_TRUE); -} -void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface); - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - if (RGFW_mouse_win == win) - RGFW_mouse_win = NULL; - - RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave; - e.point = win->event.point; - e._win = win); - - RGFW_mouseNotifyCallback(win, win->event.point, RGFW_FALSE); -} -void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y); - - RGFW_ASSERT(RGFW_mouse_win != NULL); - RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)); - e._win = RGFW_mouse_win); - - RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)), RGFW_mouse_win->event.vector); -} -void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); - RGFW_ASSERT(RGFW_mouse_win != NULL); - - u32 b = (button - 0x110); - - /* flip right and middle button codes */ - if (b == 1) b = 2; - else if (b == 2) b = 1; - - RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current; - RGFW_mouseButtons[b].current = RGFW_BOOL(state); - - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased - RGFW_BOOL(state); - e.point = RGFW_mouse_win->event.point; - e.button = (u8)b; - e._win = RGFW_mouse_win); - RGFW_mouseButtonCallback(RGFW_mouse_win, (u8)b, 0, RGFW_BOOL(state)); -} -void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { - RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis); - RGFW_ASSERT(RGFW_mouse_win != NULL); - - double scroll = - wl_fixed_to_double(value); - - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.point = RGFW_mouse_win->event.point; - e.button = RGFW_mouseScrollUp + (scroll < 0); - e.scroll = scroll; - e._win = RGFW_mouse_win); - - RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1); -} - -void RGFW_doNothing(void) { } - -void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format); - - char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); - xkb_keymap_unref (keymap); - keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - - munmap (keymap_string, size); - close (fd); - xkb_state_unref (xkb_state); - xkb_state = xkb_state_new (keymap); -} -void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys); - - RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface); - - RGFW_key_win->_flags |= RGFW_windowFocus; - RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = RGFW_key_win); - RGFW_focusCallback(RGFW_key_win, RGFW_TRUE); - - if ((RGFW_key_win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(RGFW_key_win, RGFW_AREA(RGFW_key_win->r.w, RGFW_key_win->r.h)); -} -void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); - - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - if (RGFW_key_win == win) - RGFW_key_win = NULL; - - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win); - RGFW_focusCallback(win, RGFW_FALSE); - RGFW_window_focusLost(win); -} -void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); - - if (RGFW_key_win == NULL) return; - - xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8); - - u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8); - RGFW_keyboard[RGFWkey].prev = RGFW_keyboard[RGFWkey].current; - RGFW_keyboard[RGFWkey].current = RGFW_BOOL(state); - - RGFW_eventQueuePushEx(e.type = (u8)(RGFW_keyPressed + state); - e.key = (u8)RGFWkey; - e.keyChar = (u8)keysym; - e.repeat = RGFW_isHeld(RGFW_key_win, (u8)RGFWkey); - e._win = RGFW_key_win); - - RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "ScrollLock"))); - RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->event.keyMod, RGFW_BOOL(state)); -} -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); - xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); -} -struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void (*)(void *, struct wl_keyboard *, -int, int))&RGFW_doNothing}; - -void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) { - RGFW_UNUSED(data); - static struct wl_pointer_listener pointer_listener = {&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void (*)(void *, struct wl_pointer *))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void*, struct wl_pointer*, uint32_t, uint32_t))&RGFW_doNothing}; - - if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - struct wl_pointer *pointer = wl_seat_get_pointer (seat); - wl_pointer_add_listener (pointer, &pointer_listener, NULL); - } - if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat); - wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL); - } -} -struct wl_seat_listener seat_listener = {&seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing}; - -void wl_global_registry_handler(void *data, - struct wl_registry *registry, uint32_t id, const char *interface, - uint32_t version) -{ - RGFW_window* win = (RGFW_window*)data; - RGFW_UNUSED(version); - if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) { - win->src.compositor = wl_registry_bind(registry, - id, &wl_compositor_interface, 4); - } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) { - win->src.xdg_wm_base = wl_registry_bind(registry, - id, &xdg_wm_base_interface, 1); - } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) { - decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); - } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) { - win->src.shm = wl_registry_bind(registry, - id, &wl_shm_interface, 1); - wl_shm_add_listener(win->src.shm, &shm_listener, NULL); - } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) { - win->src.seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); - wl_seat_add_listener(win->src.seat, &seat_listener, NULL); - } -} - -void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); } -const struct wl_registry_listener registry_listener = { - .global = wl_global_registry_handler, - .global_remove = wl_global_registry_remove, -}; - -void decoration_handle_configure(void *data, - struct zxdg_toplevel_decoration_v1 *decoration, - enum zxdg_toplevel_decoration_v1_mode mode) { - RGFW_UNUSED(data); RGFW_UNUSED(decoration); - RGFW_current_mode = mode; -} - -const struct zxdg_toplevel_decoration_v1_listener decoration_listener = { - .configure = decoration_handle_configure, -}; - -void randname(char *buf) { - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - long r = ts.tv_nsec; - - int i; - for (i = 0; i < 6; ++i) { - buf[i] = (char)('A'+(r&15)+(r&16)*2); - r >>= 5; - } -} - -size_t wl_stringlen(char* name) { - size_t i = 0; - while (name[i]) { i++; } - return i; -} - -int anonymous_shm_open(void) { - char name[] = "/RGFW-wayland-XXXXXX"; - int retries = 100; - - do { - randname(name + wl_stringlen(name) - 6); - - --retries; - /* shm_open guarantees that O_CLOEXEC is set */ - int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) { - shm_unlink(name); - return fd; - } - } while (retries > 0 && errno == EEXIST); - - return -1; -} - -int create_shm_file(off_t size) { - int fd = anonymous_shm_open(); - if (fd < 0) { - return fd; - } - - if (ftruncate(fd, size) < 0) { - close(fd); - return -1; - } - - return fd; -} - -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; - wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); - wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h); - wl_surface_commit(win->src.surface); - #endif -} - -const struct wl_callback_listener wl_surface_frame_listener = { - .done = wl_surface_frame_done, -}; -#endif /* RGFW_WAYLAND */ -/* - End of Wayland defines -*/ - -/* - - -Start of Linux / Unix defines - - -*/ +/* start of unix (wayland or X11 (unix) ) defines */ #ifdef RGFW_UNIX -#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11) -#include -#endif - -#include - -#ifndef RGFW_NO_DPI -#include -#include -#endif - -#include -#include -#include +#include +#include #include -#include /* for converting keycode to string */ -#include /* for hiding */ -#include -#include -#include +void RGFW_stopCheckEvents(void) { -#include /* for data limits (mainly used in drag and drop functions) */ -#include - -/* atoms needed for drag and drop */ -Atom XdndAware, XtextPlain, XtextUriList; -Atom RGFW_XUTF8_STRING = 0; - -Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0; - -#if defined(RGFW_X11) && !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) - typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int); - typedef void (*PFN_XcursorImageDestroy)(XcursorImage*); - typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*); -#endif -#if defined(RGFW_OPENGL) && defined(RGFW_X11) - typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); -#endif - -#if !defined(RGFW_NO_X11_XI_PRELOAD) && defined(RGFW_X11) - typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); - PFN_XISelectEvents XISelectEventsSRC = NULL; - #define XISelectEvents XISelectEventsSRC - - void* X11Xihandle = NULL; -#endif - -#if !defined(RGFW_NO_X11_EXT_PRELOAD) && defined(RGFW_X11) - typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int); - PFN_XSyncIntToValue XSyncIntToValueSRC = NULL; - #define XSyncIntToValue XSyncIntToValueSRC - - typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue); - PFN_XSyncSetCounter XSyncSetCounterSRC = NULL; - #define XSyncSetCounter XSyncSetCounterSRC - - typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue); - PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL; - #define XSyncCreateCounter XSyncCreateCounterSRC - - typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); - PFN_XShapeCombineMask XShapeCombineMaskSRC; - #define XShapeCombineMask XShapeCombineMaskSRC - - typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); - PFN_XShapeCombineRegion XShapeCombineRegionSRC; - #define XShapeCombineRegion XShapeCombineRegionSRC - void* X11XEXThandle = NULL; -#endif - -#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) && defined(RGFW_X11) - PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL; - PFN_XcursorImageCreate XcursorImageCreateSRC = NULL; - PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL; - - #define XcursorImageLoadCursor XcursorImageLoadCursorSRC - #define XcursorImageCreate XcursorImageCreateSRC - #define XcursorImageDestroy XcursorImageDestroySRC - - void* X11Cursorhandle = NULL; -#endif - -#ifdef RGFW_X11 -const char* RGFW_instName = NULL; -void RGFW_setXInstName(const char* name) { RGFW_instName = name; } -#endif - -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) -RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { - const char* extensions = glXQueryExtensionsString(_RGFW.display, XDefaultScreen(_RGFW.display)); - return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len); -} -RGFW_proc RGFW_getProcAddress(const char* procname) { return (RGFW_proc) glXGetProcAddress((GLubyte*) procname); } -#endif - -void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) { - RGFW_GOTO_WAYLAND(0); - -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - win->buffer = (u8*)buffer; - win->bufferSize = area; - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, RGFW_DEBUG_CTX(win, 0), "createing a 4 channel buffer"); - #ifdef RGFW_X11 - #ifdef RGFW_OSMESA - win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - - win->src.bitmap = XCreateImage( - win->src.display, win->src.visual.visual, (u32)win->src.visual.depth, - ZPixmap, 0, NULL, area.w, area.h, 32, 0 - ); - #endif - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL {} - u32 size = (u32)(win->r.w * win->r.h * 4); - int fd = create_shm_file(size); - if (fd < 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, (u32)fd),"Failed to create a buffer."); - exit(1); - } - - win->src.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (win->src.buffer == MAP_FAILED) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, 0), "mmap failed!"); - close(fd); - exit(1); - } - - win->_flags |= RGFW_BUFFER_ALLOC; - - struct wl_shm_pool* pool = wl_shm_create_pool(win->src.shm, fd, (i32)size); - win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4, - WL_SHM_FORMAT_ARGB8888); - wl_shm_pool_destroy(pool); - - close(fd); - - wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); - wl_surface_commit(win->src.surface); - - u8 color[] = {0x00, 0x00, 0x00, 0xFF}; - - size_t i; - for (i = 0; i < area.w * area.h * 4; i += 4) { - RGFW_MEMCPY(&win->buffer[i], color, 4); - } - - RGFW_MEMCPY(win->src.buffer, win->buffer, (size_t)(win->r.w * win->r.h * 4)); - - #if defined(RGFW_OSMESA) - win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - #endif -#else - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL{} - #endif - - RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); -#endif + _RGFW->eventWait_forceStop[2] = 1; + while (1) { + const char byte = 0; + const ssize_t result = write(_RGFW->eventWait_forceStop[1], &byte, 1); + if (result == 1 || result == -1) + break; + } } -#define RGFW_LOAD_ATOM(name) \ - static Atom name = 0; \ - if (name == 0) name = XInternAtom(_RGFW.display, #name, False); +RGFWDEF u64 RGFW_linux_getTimeNS(i32 clock); +u64 RGFW_linux_getTimeNS(i32 clock) { + struct timespec ts; + const u64 scale_factor = 1000000000; + clock_gettime(clock, &ts); + return (u64)ts.tv_sec * scale_factor + (u64)ts.tv_nsec; +} -void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { - RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); +void RGFW_waitForEvent(i32 waitMS) { + if (waitMS == 0) return; - RGFW_GOTO_WAYLAND(0); - #ifdef RGFW_X11 - RGFW_LOAD_ATOM(_MOTIF_WM_HINTS); - - struct __x11WindowHints { - unsigned long flags, functions, decorations, status; - long input_mode; - } hints; - hints.flags = 2; - hints.decorations = border; - - XChangeProperty(win->src.display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, - PropModeReplace, (u8*)&hints, 5 - ); - - if (RGFW_window_isHidden(win) == 0) { - RGFW_window_hide(win); - RGFW_window_show(win); + if (_RGFW->eventWait_forceStop[0] == 0 || _RGFW->eventWait_forceStop[1] == 0) { + if (pipe(_RGFW->eventWait_forceStop) != -1) { + fcntl(_RGFW->eventWait_forceStop[0], F_GETFL, 0); + fcntl(_RGFW->eventWait_forceStop[0], F_GETFD, 0); + fcntl(_RGFW->eventWait_forceStop[1], F_GETFL, 0); + fcntl(_RGFW->eventWait_forceStop[1], F_GETFD, 0); + } } - #endif - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_UNUSED(win); RGFW_UNUSED(border); - #endif -} + struct pollfd fds[2]; + fds[0].fd = 0; + fds[0].events = POLLIN; + fds[0].revents = 0; + fds[1].fd = _RGFW->eventWait_forceStop[0]; + fds[1].events = POLLIN; + fds[1].revents = 0; -void RGFW_releaseCursor(RGFW_window* win) { -RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XUngrabPointer(win->src.display, CurrentTime); - /* disable raw input */ - unsigned char mask[] = { 0 }; - XIEventMask em; - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; + if (RGFW_usingWayland()) { + #ifdef RGFW_WAYLAND + fds[0].fd = wl_display_get_fd(_RGFW->wl_display); - XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_UNUSED(win); -#endif -} - -void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { -RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - /* enable raw input */ - unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; - XISetMask(mask, XI_RawMotion); - - XIEventMask em; - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - - 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))); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_UNUSED(win); RGFW_UNUSED(r); -#endif -} - -#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL) -#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \ - void* ptr = dlsym(proc, #name); \ - if (ptr != NULL) memcpy(&name##SRC, &ptr, sizeof(PFN_##name)); \ -} - -#ifdef RGFW_X11 -void RGFW_window_getVisual(RGFW_window* win) { -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) - i32* visual_attribs = RGFW_initFormatAttribs(); - i32 fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(win->src.display, DefaultScreen(win->src.display), visual_attribs, &fbcount); - - i32 best_fbc = -1; - i32 best_depth = 0; - i32 best_samples = 0; - - if (fbcount == 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to find any valid GLX visual configs"); - return; - } - - i32 i; - for (i = 0; i < fbcount; i++) { - XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, fbc[i]); - if (vi == NULL) - continue; - - i32 samp_buf, samples; - glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); - glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLES, &samples); - - if (best_fbc == -1) best_fbc = i; - if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && best_depth == 0) { - best_fbc = i; - best_depth = vi->depth; + /* empty the queue */ + while (wl_display_prepare_read(_RGFW->wl_display) != 0) { + /* error occured when dispatching the queue */ + if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { + return; } - if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && samples <= RGFW_GL_HINTS[RGFW_glSamples] && samples > best_samples) { - best_fbc = i; - best_depth = vi->depth; - best_samples = samples; + } + + /* send any pending requests to the compositor */ + while (wl_display_flush(_RGFW->wl_display) == -1) { + + /* queue is full dispatch them */ + if (errno == EAGAIN) { + if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { + return; + } + } else { + return; } - XFree(vi); } - - if (best_fbc == -1) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to get a valid GLX visual"); - return; - } - - win->src.bestFbc = fbc[best_fbc]; - XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, win->src.bestFbc); - if (vi->depth != 32 && (win->_flags & RGFW_windowTransparent)) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to to find a matching visual with a 32-bit depth"); - - if (best_samples < RGFW_GL_HINTS[RGFW_glSamples]) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load matching sampiling"); - - int configCaveat; - if (glXGetFBConfigAttrib(win->src.display, win->src.bestFbc, GLX_CONFIG_CAVEAT, &configCaveat) == Success && - configCaveat == GLX_SLOW_CONFIG) { - win->_flags |= RGFW_windowOpenglSoftware; - } - - XFree(fbc); - win->src.visual = *vi; - XFree(vi); -#else - win->src.visual.visual = DefaultVisual(win->src.display, DefaultScreen(win->src.display)); - win->src.visual.depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display)); - if (win->_flags & RGFW_windowTransparent) { - XMatchVisualInfo(win->src.display, DefaultScreen(win->src.display), 32, TrueColor, &win->src.visual); /*!< for RGBA backgrounds */ - if (win->src.visual.depth != 32) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load a 32-bit depth"); - } -#endif -} -#endif -#ifndef RGFW_EGL -void RGFW_window_initOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 }; - context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB; - if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) - context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - else - context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - - if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) { - context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB; - context_attribs[3] = RGFW_GL_HINTS[RGFW_glMajor]; - context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB; - context_attribs[5] = RGFW_GL_HINTS[RGFW_glMinor]; - } - - glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) - glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB"); - - GLXContext ctx = NULL; - if (_RGFW.root != NULL && _RGFW.root != win) { - ctx = _RGFW.root->src.ctx; - RGFW_window_makeCurrent_OpenGL(_RGFW.root); - } - - if (glXCreateContextAttribsARB == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to load proc address 'glXCreateContextAttribsARB', loading a generic opengl context"); - win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True); - } - else { - win->src.ctx = glXCreateContextAttribsARB(win->src.display, win->src.bestFbc, ctx, True, context_attribs); - XSync(win->src.display, False); - if (win->src.ctx == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to create an opengl context with AttribsARB, loading a generic opengl context"); - win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True); - } - } - - glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); -#else - RGFW_UNUSED(win); -#endif -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - if (win->src.ctx == NULL) return; - glXDestroyContext(win->src.display, win->src.ctx); - win->src.ctx = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); -#else -RGFW_UNUSED(win); -#endif -} -#endif - - -i32 RGFW_init(void) { - RGFW_GOTO_WAYLAND(1); -#if defined(RGFW_C89) || defined(__cplusplus) - if (_RGFW_init) return 0; - _RGFW_init = RGFW_TRUE; - _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; -#endif - -#ifdef RGFW_X11 - if (_RGFW.windowCount != -1) return 0; - #ifdef RGFW_USE_XDL - XDL_init(); - #endif - - #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so"); - #else - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1"); - #endif - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate); - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy); - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor); - #endif - - #if !defined(RGFW_NO_X11_XI_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so"); - #else - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6"); - #endif - RGFW_PROC_DEF(X11Xihandle, XISelectEvents); - #endif - - #if !defined(RGFW_NO_X11_EXT_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so"); - #else - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6"); - #endif - RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter); - RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue); - RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter); - RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion); - RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask); - #endif - - XInitThreads(); /*!< init X11 threading */ - _RGFW.display = XOpenDisplay(0); - XSetWindowAttributes wa; - RGFW_MEMSET(&wa, 0, sizeof(wa)); - wa.event_mask = PropertyChangeMask; - _RGFW.helperWindow = XCreateWindow(_RGFW.display, XDefaultRootWindow(_RGFW.display), 0, 0, 1, 1, 0, 0, - InputOnly, DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)), CWEventMask, &wa); - - _RGFW.windowCount = 0; - u8 RGFW_blk[] = { 0, 0, 0, 0 }; - _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4); - _RGFW.clipboard = NULL; - - XkbComponentNamesRec rec; - XkbDescPtr desc = XkbGetMap(_RGFW.display, 0, XkbUseCoreKbd); - XkbDescPtr evdesc; - u8 old[sizeof(RGFW_keycodes) / sizeof(RGFW_keycodes[0])]; - - XkbGetNames(_RGFW.display, XkbKeyNamesMask, desc); - - RGFW_MEMSET(&rec, 0, sizeof(rec)); - rec.keycodes = (char*)"evdev"; - evdesc = XkbGetKeyboardByName(_RGFW.display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False); - /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */ - if(evdesc != NULL && desc != NULL){ - for(int i = 0; i < (int)sizeof(RGFW_keycodes) / (int)sizeof(RGFW_keycodes[0]); i++){ - old[i] = RGFW_keycodes[i]; - RGFW_keycodes[i] = 0; - } - for(int i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){ - for(int j = desc->min_key_code; j <= desc->max_key_code; j++){ - if(strncmp(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){ - RGFW_keycodes[j] = old[i]; - break; - } - } - } - XkbFreeKeyboard(desc, 0, True); - XkbFreeKeyboard(evdesc, 0, True); - } -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL - _RGFW.wl_display = wl_display_connect(NULL); -#endif - _RGFW.windowCount = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); - return 0; -} - - -RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { - RGFW_window_basic_init(win, rect, flags); - -#ifdef RGFW_WAYLAND - win->src.compositor = NULL; -#endif - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted */ - - win->src.display = XOpenDisplay(NULL); - RGFW_window_getVisual(win); - - /* make X window attrubutes */ - XSetWindowAttributes swa; - RGFW_MEMSET(&swa, 0, sizeof(swa)); - - Colormap cmap; - swa.colormap = cmap = XCreateColormap(win->src.display, - DefaultRootWindow(win->src.display), - win->src.visual.visual, AllocNone); - swa.event_mask = event_mask; - - /* create the window */ - win->src.window = XCreateWindow(win->src.display, DefaultRootWindow(win->src.display), win->r.x, win->r.y, (u32)win->r.w, (u32)win->r.h, - 0, win->src.visual.depth, InputOutput, win->src.visual.visual, - CWColormap | CWBorderPixel | CWEventMask, &swa); - - XFreeColors(win->src.display, cmap, NULL, 0, 0); - - win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL); - - /* In your .desktop app, if you set the property - StartupWMClass=RGFW that will assoicate the launcher icon - with your application - robrohan */ - if (RGFW_className == NULL) - RGFW_className = (char*)name; - - XClassHint hint; - hint.res_class = (char*)RGFW_className; - if (RGFW_instName == NULL) hint.res_name = (char*)name; - else hint.res_name = (char*)RGFW_instName; - XSetClassHint(win->src.display, win->src.window, &hint); - - #ifndef RGFW_NO_MONITOR - if (flags & RGFW_windowScaleToMonitor) - RGFW_window_scaleToMonitor(win); - #endif - XSelectInput(win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */ - - /* make it so the user can't close the window until the program does */ - if (wm_delete_window == 0) { - wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False); - RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False); - RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False); - } - - XSetWMProtocols(win->src.display, (Drawable) win->src.window, &wm_delete_window, 1); - /* set the background */ - RGFW_window_setName(win, name); - - XMoveWindow(win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords */ - - if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */ - win->_flags |= RGFW_windowAllowDND; - - /* actions */ - XtextUriList = XInternAtom(win->src.display, "text/uri-list", False); - XtextPlain = XInternAtom(win->src.display, "text/plain", False); - XdndAware = XInternAtom(win->src.display, "XdndAware", False); - const u8 version = 5; - - XChangeProperty(win->src.display, win->src.window, - XdndAware, 4, 32, - PropModeReplace, &version, 1); /*!< turns on drag and drop */ - } - -#ifdef RGFW_ADVANCED_SMOOTH_RESIZE - RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER) - RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST) - Atom protcols[2] = {_NET_WM_SYNC_REQUEST, wm_delete_window}; - XSetWMProtocols(win->src.display, win->src.window, protcols, 2); - - XSyncValue initial_value; - XSyncIntToValue(&initial_value, 0); - win->src.counter = XSyncCreateCounter(win->src.display, initial_value); - - XChangeProperty(win->src.display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1); -#endif - - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initOpenGL(win); - RGFW_window_initBuffer(win); - } - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - RGFW_window_setMouseDefault(win); - RGFW_window_setFlags(win, flags); - - win->src.r = win->r; - - RGFW_window_show(win); - return win; /*return newly created window */ -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "RGFW Wayland support is experimental"); - - win->src.wl_display = _RGFW.wl_display; - if (win->src.wl_display == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Failed to load Wayland display"); + #endif + } else { #ifdef RGFW_X11 - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "Falling back to X11"); - RGFW_useWayland(0); - return RGFW_createWindowPtr(name, rect, flags, win); + fds[0].fd = ConnectionNumber(_RGFW->display); #endif - return NULL; } + i32 clock = 0; + #if defined(_POSIX_MONOTONIC_CLOCK) + struct timespec ts; + RGFW_MEMSET(&ts, 0, sizeof(struct timespec)); - #ifdef RGFW_X11 - win->src.display = _RGFW.display; - win->src.window = _RGFW.helperWindow; - XMapWindow(_RGFW.display, win->src.window); - XFlush(win->src.display); - if (wm_delete_window == 0) { - wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False); - RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False); - RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False); - } + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + clock = CLOCK_MONOTONIC; + #else + clock = CLOCK_REALTIME; #endif - struct wl_registry *registry = wl_display_get_registry(win->src.wl_display); - wl_registry_add_listener(registry, ®istry_listener, win); + u64 start = RGFW_linux_getTimeNS(clock); + if (RGFW_usingWayland()) { + #ifdef RGFW_WAYLAND + while (wl_display_dispatch_pending(_RGFW->wl_display) == 0) { + if (poll(fds, 1, waitMS) <= 0) { + wl_display_cancel_read(_RGFW->wl_display); + break; + } else { + if (wl_display_read_events(_RGFW->wl_display) == -1) + return; + } - wl_display_roundtrip(win->src.wl_display); - wl_display_dispatch(win->src.wl_display); - - if (win->src.compositor == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Can't find compositor."); - return NULL; - } - - if (RGFW_wl_cursor_theme == NULL) { - RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, win->src.shm); - RGFW_cursor_surface = wl_compositor_create_surface(win->src.compositor); - - struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr"); - RGFW_cursor_image = cursor->images[0]; - struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); - - wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); - wl_surface_commit(RGFW_cursor_surface); - } - - xdg_wm_base_add_listener(win->src.xdg_wm_base, &xdg_wm_base_listener, NULL); - - xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - win->src.surface = wl_compositor_create_surface(win->src.compositor); - wl_surface_set_user_data(win->src.surface, win); - - win->src.xdg_surface = xdg_wm_base_get_xdg_surface(win->src.xdg_wm_base, win->src.surface); - xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL); - - xdg_wm_base_set_user_data(win->src.xdg_wm_base, win); - - win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); - xdg_toplevel_set_user_data(win->src.xdg_toplevel, win); - xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL); - - xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h); - - if (!(flags & RGFW_windowNoBorder)) { - win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - decoration_manager, win->src.xdg_toplevel); - } - - wl_display_roundtrip(win->src.wl_display); - - wl_surface_commit(win->src.surface); - RGFW_window_show(win); - - /* wait for the surface to be configured */ - while (wl_display_dispatch(win->src.wl_display) != -1 && !RGFW_wl_configured) { } - - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initOpenGL(win); - RGFW_window_initBuffer(win); - } - struct wl_callback* callback = wl_surface_frame(win->src.surface); - wl_callback_add_listener(callback, &wl_surface_frame_listener, win); - wl_surface_commit(win->src.surface); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - - #ifndef RGFW_NO_MONITOR - if (flags & RGFW_windowScaleToMonitor) - RGFW_window_scaleToMonitor(win); - #endif - - RGFW_window_setName(win, name); - RGFW_window_setMouseDefault(win); - RGFW_window_setFlags(win, flags); - return win; /* return newly created window */ -#endif -} - -RGFW_area RGFW_getScreenSize(void) { - RGFW_GOTO_WAYLAND(1); - RGFW_init(); - - #ifdef RGFW_X11 - Screen* scrn = DefaultScreenOfDisplay(_RGFW.display); - return RGFW_AREA(scrn->width, scrn->height); - #endif - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL return RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h); /* TODO */ - #endif -} - -RGFW_point RGFW_getGlobalMousePoint(void) { - RGFW_init(); - RGFW_point RGFWMouse = RGFW_POINT(0, 0); - RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 - i32 x, y; - u32 z; - Window window1, window2; - XQueryPointer(_RGFW.display, XDefaultRootWindow(_RGFW.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z); - return RGFWMouse; -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - return RGFWMouse; -#endif -} - -RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event); -void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event); -#ifdef RGFW_X11 - RGFW_LOAD_ATOM(ATOM_PAIR); - RGFW_LOAD_ATOM(MULTIPLE); - RGFW_LOAD_ATOM(TARGETS); - RGFW_LOAD_ATOM(SAVE_TARGETS); - - const XSelectionRequestEvent* request = &event->xselectionrequest; - const Atom formats[] = { RGFW_XUTF8_STRING, XA_STRING }; - const int formatCount = sizeof(formats) / sizeof(formats[0]); - - if (request->target == TARGETS) { - const Atom targets[] = { TARGETS, MULTIPLE, RGFW_XUTF8_STRING, XA_STRING }; - - XChangeProperty(_RGFW.display, request->requestor, request->property, - XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom)); - } else if (request->target == MULTIPLE) { - Atom* targets = NULL; - - Atom actualType = 0; - int actualFormat = 0; - unsigned long count = 0, bytesAfter = 0; - - XGetWindowProperty(_RGFW.display, request->requestor, request->property, 0, LONG_MAX, - False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); - - unsigned long i; - for (i = 0; i < (u32)count; i += 2) { - if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING) - XChangeProperty(_RGFW.display, request->requestor, targets[i + 1], targets[i], - 8, PropModeReplace, (const unsigned char *)_RGFW.clipboard, (i32)_RGFW.clipboard_len); - else - targets[i + 1] = None; + if (waitMS != RGFW_eventWaitNext) { + waitMS -= (i32)(RGFW_linux_getTimeNS(clock) - start) / (i32)1e+6; + } } - XChangeProperty(_RGFW.display, - request->requestor, request->property, ATOM_PAIR, 32, - PropModeReplace, (u8*) targets, (i32)count); - - XFlush(_RGFW.display); - XFree(targets); - } else if (request->target == SAVE_TARGETS) - XChangeProperty(_RGFW.display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0); - else { - int i; - for (i = 0; i < formatCount; i++) { - if (request->target != formats[i]) - continue; - XChangeProperty(_RGFW.display, request->requestor, request->property, request->target, - 8, PropModeReplace, (u8*) _RGFW.clipboard, (i32)_RGFW.clipboard_len); + /* queue contains events from read, dispatch them */ + if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { + return; } + #endif + } else { + #ifdef RGFW_X11 + while (XPending(_RGFW->display) == 0) { + if (poll(fds, 1, waitMS) <= 0) + break; + + if (waitMS != RGFW_eventWaitNext) { + waitMS -= (i32)(RGFW_linux_getTimeNS(clock) - start) / (i32)1e+6; + } + } + #endif } - XEvent reply = { SelectionNotify }; - reply.xselection.property = request->property; - reply.xselection.display = request->display; - reply.xselection.requestor = request->requestor; - reply.xselection.selection = request->selection; - reply.xselection.target = request->target; - reply.xselection.time = request->time; + /* drain any data in the stop request */ + if (_RGFW->eventWait_forceStop[2]) { + char data[64]; + RGFW_MEMSET(data, 0, sizeof(data)); + (void)!read(_RGFW->eventWait_forceStop[0], data, sizeof(data)); - XSendEvent(_RGFW.display, request->requestor, False, 0, &reply); -#endif + _RGFW->eventWait_forceStop[2] = 0; + } } char* RGFW_strtok(char* str, const char* delimStr); @@ -4496,19 +4882,678 @@ char* RGFW_strtok(char* str, const char* delimStr) { return token_start; } +#ifdef RGFW_X11 +RGFWDEF i32 RGFW_initPlatform_X11(void); +RGFWDEF void RGFW_deinitPlatform_X11(void); +#endif +#ifdef RGFW_WAYLAND +RGFWDEF i32 RGFW_initPlatform_Wayland(void); +RGFWDEF void RGFW_deinitPlatform_Wayland(void); +#endif + +RGFWDEF void RGFW_load_X11(void); +RGFWDEF void RGFW_load_Wayland(void); + +#if !defined(RGFW_X11) || !defined(RGFW_WAYLAND) +void RGFW_load_X11(void) { } +void RGFW_load_Wayland(void) { } +#endif + +/* + * Sadly we have to use magic linux keycodes + * We can't use X11 functions, because that breaks Wayland, but they use the same keycodes so there's no use redeffing them + * We can't use linux enums, because the headers don't exist on BSD + */ +void RGFW_initKeycodesPlatform(void) { + _RGFW->keycodes[49] = RGFW_backtick; + _RGFW->keycodes[19] = RGFW_0; + _RGFW->keycodes[10] = RGFW_1; + _RGFW->keycodes[11] = RGFW_2; + _RGFW->keycodes[12] = RGFW_3; + _RGFW->keycodes[13] = RGFW_4; + _RGFW->keycodes[14] = RGFW_5; + _RGFW->keycodes[15] = RGFW_6; + _RGFW->keycodes[16] = RGFW_7; + _RGFW->keycodes[17] = RGFW_8; + _RGFW->keycodes[18] = RGFW_9; + _RGFW->keycodes[65] = RGFW_space; + _RGFW->keycodes[38] = RGFW_a; + _RGFW->keycodes[56] = RGFW_b; + _RGFW->keycodes[54] = RGFW_c; + _RGFW->keycodes[40] = RGFW_d; + _RGFW->keycodes[26] = RGFW_e; + _RGFW->keycodes[41] = RGFW_f; + _RGFW->keycodes[42] = RGFW_g; + _RGFW->keycodes[43] = RGFW_h; + _RGFW->keycodes[31] = RGFW_i; + _RGFW->keycodes[44] = RGFW_j; + _RGFW->keycodes[45] = RGFW_k; + _RGFW->keycodes[46] = RGFW_l; + _RGFW->keycodes[58] = RGFW_m; + _RGFW->keycodes[57] = RGFW_n; + _RGFW->keycodes[32] = RGFW_o; + _RGFW->keycodes[33] = RGFW_p; + _RGFW->keycodes[24] = RGFW_q; + _RGFW->keycodes[27] = RGFW_r; + _RGFW->keycodes[39] = RGFW_s; + _RGFW->keycodes[28] = RGFW_t; + _RGFW->keycodes[30] = RGFW_u; + _RGFW->keycodes[55] = RGFW_v; + _RGFW->keycodes[25] = RGFW_w; + _RGFW->keycodes[53] = RGFW_x; + _RGFW->keycodes[29] = RGFW_y; + _RGFW->keycodes[52] = RGFW_z; + _RGFW->keycodes[60] = RGFW_period; + _RGFW->keycodes[59] = RGFW_comma; + _RGFW->keycodes[61] = RGFW_slash; + _RGFW->keycodes[34] = RGFW_bracket; + _RGFW->keycodes[35] = RGFW_closeBracket; + _RGFW->keycodes[47] = RGFW_semicolon; + _RGFW->keycodes[48] = RGFW_apostrophe; + _RGFW->keycodes[51] = RGFW_backSlash; + _RGFW->keycodes[36] = RGFW_return; + _RGFW->keycodes[119] = RGFW_delete; + _RGFW->keycodes[77] = RGFW_numLock; + _RGFW->keycodes[106] = RGFW_kpSlash; + _RGFW->keycodes[63] = RGFW_kpMultiply; + _RGFW->keycodes[86] = RGFW_kpPlus; + _RGFW->keycodes[82] = RGFW_kpMinus; + _RGFW->keycodes[87] = RGFW_kp1; + _RGFW->keycodes[88] = RGFW_kp2; + _RGFW->keycodes[89] = RGFW_kp3; + _RGFW->keycodes[83] = RGFW_kp4; + _RGFW->keycodes[84] = RGFW_kp5; + _RGFW->keycodes[85] = RGFW_kp6; + _RGFW->keycodes[81] = RGFW_kp9; + _RGFW->keycodes[90] = RGFW_kp0; + _RGFW->keycodes[91] = RGFW_kpPeriod; + _RGFW->keycodes[104] = RGFW_kpReturn; + _RGFW->keycodes[20] = RGFW_minus; + _RGFW->keycodes[21] = RGFW_equals; + _RGFW->keycodes[22] = RGFW_backSpace; + _RGFW->keycodes[23] = RGFW_tab; + _RGFW->keycodes[66] = RGFW_capsLock; + _RGFW->keycodes[50] = RGFW_shiftL; + _RGFW->keycodes[37] = RGFW_controlL; + _RGFW->keycodes[64] = RGFW_altL; + _RGFW->keycodes[133] = RGFW_superL; + _RGFW->keycodes[105] = RGFW_controlR; + _RGFW->keycodes[134] = RGFW_superR; + _RGFW->keycodes[62] = RGFW_shiftR; + _RGFW->keycodes[108] = RGFW_altR; + _RGFW->keycodes[67] = RGFW_F1; + _RGFW->keycodes[68] = RGFW_F2; + _RGFW->keycodes[69] = RGFW_F3; + _RGFW->keycodes[70] = RGFW_F4; + _RGFW->keycodes[71] = RGFW_F5; + _RGFW->keycodes[72] = RGFW_F6; + _RGFW->keycodes[73] = RGFW_F7; + _RGFW->keycodes[74] = RGFW_F8; + _RGFW->keycodes[75] = RGFW_F9; + _RGFW->keycodes[76] = RGFW_F10; + _RGFW->keycodes[95] = RGFW_F11; + _RGFW->keycodes[96] = RGFW_F12; + _RGFW->keycodes[111] = RGFW_up; + _RGFW->keycodes[116] = RGFW_down; + _RGFW->keycodes[113] = RGFW_left; + _RGFW->keycodes[114] = RGFW_right; + _RGFW->keycodes[118] = RGFW_insert; + _RGFW->keycodes[115] = RGFW_end; + _RGFW->keycodes[112] = RGFW_pageUp; + _RGFW->keycodes[117] = RGFW_pageDown; + _RGFW->keycodes[9] = RGFW_escape; + _RGFW->keycodes[110] = RGFW_home; + _RGFW->keycodes[78] = RGFW_scrollLock; + _RGFW->keycodes[107] = RGFW_printScreen; + _RGFW->keycodes[128] = RGFW_pause; + _RGFW->keycodes[191] = RGFW_F13; + _RGFW->keycodes[192] = RGFW_F14; + _RGFW->keycodes[193] = RGFW_F15; + _RGFW->keycodes[194] = RGFW_F16; + _RGFW->keycodes[195] = RGFW_F17; + _RGFW->keycodes[196] = RGFW_F18; + _RGFW->keycodes[197] = RGFW_F19; + _RGFW->keycodes[198] = RGFW_F20; + _RGFW->keycodes[199] = RGFW_F21; + _RGFW->keycodes[200] = RGFW_F22; + _RGFW->keycodes[201] = RGFW_F23; + _RGFW->keycodes[202] = RGFW_F24; + _RGFW->keycodes[203] = RGFW_F25; + _RGFW->keycodes[142] = RGFW_kpEqual; + _RGFW->keycodes[161] = RGFW_world1; /* non-US key #1 */ + _RGFW->keycodes[162] = RGFW_world2; /* non-US key #2 */ +} + +i32 RGFW_initPlatform(void) { +#ifdef RGFW_WAYLAND + RGFW_load_Wayland(); + i32 ret = RGFW_initPlatform_Wayland(); + if (ret == 0) { + return 0; + } else { + #ifdef RGFW_X11 + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, "Falling back to X11"); + RGFW_useWayland(0); + #else + return ret; + #endif + } +#endif +#ifdef RGFW_X11 + RGFW_load_X11(); + return RGFW_initPlatform_X11(); +#else + return 0; +#endif +} + + +void RGFW_deinitPlatform(void) { + if (_RGFW->eventWait_forceStop[0] || _RGFW->eventWait_forceStop[1]){ + close(_RGFW->eventWait_forceStop[0]); + close(_RGFW->eventWait_forceStop[1]); + } +#ifdef RGFW_WAYLAND + if (_RGFW->useWaylandBool) { + RGFW_deinitPlatform_Wayland(); + return; + } +#endif +#ifdef RGFW_X11 + RGFW_deinitPlatform_X11(); +#endif +} + +#endif /* end of wayland or X11 defines */ + + +/* + + +Start of Linux / Unix defines + + +*/ + +#ifdef RGFW_X11 +#ifdef RGFW_WAYLAND +#define RGFW_FUNC(func) func##_X11 +#else +#define RGFW_FUNC(func) func +#endif + +#include +#include + +#include /* for data limits (mainly used in drag and drop functions) */ +#include + +void RGFW_setXInstName(const char* name) { _RGFW->instName = name; } +#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11) + #include +#endif + +#ifndef RGFW_NO_DPI + #include + #include +#endif + +#include +#include +#include + +#include /* for converting keycode to string */ +#include /* for hiding */ +#include +#include +#include + +#ifdef RGFW_OPENGL + #ifndef __gl_h_ + #define __gl_h_ + #define RGFW_gl_ndef + #define GLubyte unsigned char + #define GLenum unsigned int + #define GLint int + #define GLuint unsigned int + #define GLsizei int + #define GLfloat float + #define GLvoid void + #define GLbitfield unsigned int + #define GLintptr ptrdiff_t + #define GLsizeiptr ptrdiff_t + #define GLboolean unsigned char + #endif + + #include /* GLX defs, xlib.h, gl.h */ + #ifndef GLX_MESA_swap_control + #define GLX_MESA_swap_control + #endif + + #ifdef RGFW_gl_ndef + #undef __gl_h_ + #undef GLubyte + #undef GLenum + #undef GLint + #undef GLuint + #undef GLsizei + #undef GLfloat + #undef GLvoid + #undef GLbitfield + #undef GLintptr + #undef GLsizeiptr + #undef GLboolean + #endif + typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); +#endif + +/* atoms needed for drag and drop */ +#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) + typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int); + typedef void (*PFN_XcursorImageDestroy)(XcursorImage*); + typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*); +#endif + +#if !defined(RGFW_NO_X11_XI_PRELOAD) + typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); + PFN_XISelectEvents XISelectEventsSRC = NULL; + #define XISelectEvents XISelectEventsSRC + + void* X11Xihandle = NULL; +#endif + +#if !defined(RGFW_NO_X11_EXT_PRELOAD) + typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int); + PFN_XSyncIntToValue XSyncIntToValueSRC = NULL; + #define XSyncIntToValue XSyncIntToValueSRC + + typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue); + PFN_XSyncSetCounter XSyncSetCounterSRC = NULL; + #define XSyncSetCounter XSyncSetCounterSRC + + typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue); + PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL; + #define XSyncCreateCounter XSyncCreateCounterSRC + + typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); + PFN_XShapeCombineMask XShapeCombineMaskSRC; + #define XShapeCombineMask XShapeCombineMaskSRC + + typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); + PFN_XShapeCombineRegion XShapeCombineRegionSRC; + #define XShapeCombineRegion XShapeCombineRegionSRC + void* X11XEXThandle = NULL; +#endif + +#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) + PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL; + PFN_XcursorImageCreate XcursorImageCreateSRC = NULL; + PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL; + + #define XcursorImageLoadCursor XcursorImageLoadCursorSRC + #define XcursorImageCreate XcursorImageCreateSRC + #define XcursorImageDestroy XcursorImageDestroySRC + + void* X11Cursorhandle = NULL; +#endif + +void* RGFW_getDisplay_X11(void) { return _RGFW->display; } +u64 RGFW_window_getWindow_X11(RGFW_window* win) { return (u64)win->src.window; } + +RGFWDEF RGFW_format RGFW_XImage_getFormat(XImage* image); +RGFW_format RGFW_XImage_getFormat(XImage* image) { + switch (image->bits_per_pixel) { + case 24: + if (image->red_mask == 0xFF0000 && image->green_mask == 0x00FF00 && image->blue_mask == 0x0000FF) + return RGFW_formatRGB8; + if (image->red_mask == 0x0000FF && image->green_mask == 0x00FF00 && image->blue_mask == 0xFF0000) + return RGFW_formatBGR8; + break; + case 32: + if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF) + return RGFW_formatBGRA8; + if (image->red_mask == 0x000000FF && image->green_mask == 0x0000FF00 && image->blue_mask == 0x00FF0000) + return RGFW_formatRGBA8; + if (image->red_mask == 0x0000FF00 && image->green_mask == 0x00FF0000 && image->blue_mask == 0xFF000000) + return RGFW_formatABGR8; + if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF) + return RGFW_formatARGB8; /* ambiguous without alpha */ + break; + } + return RGFW_formatARGB8; +} + +RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { + RGFW_ASSERT(surface != NULL); + surface->data = data; + surface->w = w; + surface->h = h; + surface->format = format; + + XWindowAttributes attrs; + if (XGetWindowAttributes(_RGFW->display, win->src.window, &attrs) == 0) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to get window attributes."); + return RGFW_FALSE; + } + + surface->native.bitmap = XCreateImage(_RGFW->display, attrs.visual, (u32)attrs.depth, + ZPixmap, 0, NULL, (u32)surface->w, (u32)surface->h, 32, 0); + + surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4)); + surface->native.format = RGFW_XImage_getFormat(surface->native.bitmap); + + if (surface->native.bitmap == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create XImage."); + return RGFW_FALSE; + } + + surface->native.format = RGFW_formatBGRA8; + return RGFW_TRUE; +} + +RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { + return RGFW_window_createSurfacePtr(_RGFW->root, data, w, h, format, surface); +} + +void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) { + RGFW_ASSERT(surface != NULL); + surface->native.bitmap->data = (char*)surface->native.buffer; + RGFW_copyImageData((u8*)surface->native.buffer, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); + + XPutImage(_RGFW->display, win->src.window, win->src.gc, surface->native.bitmap, 0, 0, 0, 0, (u32)RGFW_MIN(win->w, surface->w), (u32)RGFW_MIN(win->h, surface->h)); + surface->native.bitmap->data = NULL; + return; +} + +void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) { + RGFW_ASSERT(surface != NULL); + RGFW_FREE(surface->native.buffer); + XDestroyImage(surface->native.bitmap); + return; +} + +#define RGFW_LOAD_ATOM(name) \ + static Atom name = 0; \ + if (name == 0) name = XInternAtom(_RGFW->display, #name, False); + +void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) { + RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); + RGFW_LOAD_ATOM(_MOTIF_WM_HINTS); + + struct __x11WindowHints { + unsigned long flags, functions, decorations, status; + long input_mode; + } hints; + hints.flags = 2; + hints.decorations = border; + + XChangeProperty(_RGFW->display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (u8*)&hints, 5); + + if (RGFW_window_isHidden(win) == 0) { + RGFW_window_hide(win); + RGFW_window_show(win); + } +} + +void RGFW_FUNC(RGFW_releaseCursor) (RGFW_window* win) { + RGFW_UNUSED(win); + XUngrabPointer(_RGFW->display, CurrentTime); + + /* disable raw input */ + unsigned char mask[] = { 0 }; + XIEventMask em; + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1); +} + +void RGFW_FUNC(RGFW_captureCursor) (RGFW_window* win) { + /* enable raw input */ + unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; + XISetMask(mask, XI_RawMotion); + + XIEventMask em; + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1); + + unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask; + XGrabPointer(_RGFW->display, win->src.window, False, event_mask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); + RGFW_window_moveMouse(win, win->x + (i32)(win->w / 2), win->y + (i32)(win->h / 2)); +} + +#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL) +#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \ + void* ptr = dlsym(proc, #name); \ + if (ptr != NULL) RGFW_MEMCPY(&name##SRC, &ptr, sizeof(PFN_##name)); \ +} + +RGFWDEF void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent); +void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent) { + visual->visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)); + visual->depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)); + if (transparent) { + XMatchVisualInfo(_RGFW->display, DefaultScreen(_RGFW->display), 32, TrueColor, visual); /*!< for RGBA backgrounds */ + if (visual->depth != 32) + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a 32-bit depth."); + } +} + +RGFWDEF int RGFW_XErrorHandler(Display* display, XErrorEvent* ev); +int RGFW_XErrorHandler(Display* display, XErrorEvent* ev) { + char errorText[512]; + XGetErrorText(display, ev->error_code, errorText, sizeof(errorText)); + + char buf[1024]; + RGFW_SNPRINTF(buf, sizeof(buf), "[X Error] %s\n Error code: %d\n Request code: %d\n Minor code: %d\n Serial: %lu\n", + errorText, + ev->error_code, ev->request_code, ev->minor_code, ev->serial); + + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errX11, buf); + _RGFW->x11Error = ev; + return 0; +} + +void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win) { + i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | + LeaveWindowMask | EnterWindowMask | ExposureMask | VisibilityChangeMask | PropertyChangeMask; + + /* make X window attrubutes */ + XSetWindowAttributes swa; + RGFW_MEMSET(&swa, 0, sizeof(swa)); + + win->src.parent = DefaultRootWindow(_RGFW->display); + + Colormap cmap; + swa.colormap = cmap = XCreateColormap(_RGFW->display, + win->src.parent, + visual.visual, AllocNone); + swa.event_mask = event_mask; + swa.background_pixmap = None; + + /* create the window */ + win->src.window = XCreateWindow(_RGFW->display, win->src.parent, win->x, win->y, (u32)win->w, (u32)win->h, + 0, visual.depth, InputOutput, visual.visual, + CWBorderPixel | CWColormap | CWEventMask, &swa); + + XFreeColors(_RGFW->display, cmap, NULL, 0, 0); + + XSaveContext(_RGFW->display, win->src.window, _RGFW->context, (XPointer)win); + + win->src.gc = XCreateGC(_RGFW->display, win->src.window, 0, NULL); + + /* In your .desktop app, if you set the property + StartupWMClass=RGFW that will assoicate the launcher icon + with your application - robrohan */ + if (_RGFW->className == NULL) + _RGFW->className = (char*)name; + + XClassHint hint; + hint.res_class = (char*)_RGFW->className; + if (_RGFW->instName == NULL) hint.res_name = (char*)name; + else hint.res_name = (char*)_RGFW->instName; + XSetClassHint(_RGFW->display, win->src.window, &hint); + + #ifndef RGFW_NO_MONITOR + if (flags & RGFW_windowScaleToMonitor) + RGFW_window_scaleToMonitor(win); + #endif + XSelectInput(_RGFW->display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */ + + /* make it so the user can't close the window until the program does */ + RGFW_LOAD_ATOM(WM_DELETE_WINDOW); + XSetWMProtocols(_RGFW->display, (Drawable) win->src.window, &WM_DELETE_WINDOW, 1); + /* set the background */ + RGFW_window_setName(win, name); + + XMoveWindow(_RGFW->display, (Drawable) win->src.window, win->x, win->y); /*!< move the window to it's proper cords */ + + if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */ + win->internal.flags |= RGFW_windowAllowDND; + + /* actions */ + Atom XdndAware = XInternAtom(_RGFW->display, "XdndAware", False); + const u8 version = 5; + + XChangeProperty(_RGFW->display, win->src.window, + XdndAware, 4, 32, + PropModeReplace, &version, 1); /*!< turns on drag and drop */ + } + +#ifdef RGFW_ADVANCED_SMOOTH_RESIZE + RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER) + RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST) + + Atom protcols[2] = {_NET_WM_SYNC_REQUEST, WM_DELETE_WINDOW}; + XSetWMProtocols(_RGFW->display, win->src.window, protcols, 2); + + XSyncValue initial_value; + XSyncIntToValue(&initial_value, 0); + win->src.counter = XSyncCreateCounter(_RGFW->display, initial_value); + + XChangeProperty(_RGFW->display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1); +#endif + + win->src.x = win->x; + win->src.y = win->y; + win->src.w = win->w; + win->src.h = win->h; + + XSetWindowBackground(_RGFW->display, win->src.window, None); + XClearWindow(_RGFW->display, win->src.window); + + /* stupid hack to make resizing the window less bad */ + XSetWindowBackgroundPixmap(_RGFW->display, win->src.window, None); +} + +RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) { + if ((flags & RGFW_windowOpenGL) || (flags & RGFW_windowEGL)) { + win->src.window = 0; + return win; + } + + XVisualInfo visual; + RGFW_window_getVisual(&visual, RGFW_BOOL(win->internal.flags & RGFW_windowTransparent)); + RGFW_XCreateWindow(visual, name, flags, win); + return win; /*return newly created window */ +} + +RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* fX, i32* fY) { + RGFW_init(); + i32 x, y; + u32 z; + Window window1, window2; + XQueryPointer(_RGFW->display, XDefaultRootWindow(_RGFW->display), &window1, &window2, fX, fY, &x, &y, &z); + return RGFW_TRUE; +} + +RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event); +void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event); + RGFW_LOAD_ATOM(ATOM_PAIR); + RGFW_LOAD_ATOM(MULTIPLE); + RGFW_LOAD_ATOM(TARGETS); + RGFW_LOAD_ATOM(SAVE_TARGETS); + RGFW_LOAD_ATOM(UTF8_STRING); + + const XSelectionRequestEvent* request = &event->xselectionrequest; + Atom formats[2] = {0}; + formats[0] = UTF8_STRING; + formats[1] = XA_STRING; + const int formatCount = sizeof(formats) / sizeof(formats[0]); + + if (request->target == TARGETS) { + Atom targets[4] = {0}; + targets[0] = TARGETS; + targets[1] = MULTIPLE; + targets[2] = UTF8_STRING; + targets[3] = XA_STRING; + + XChangeProperty(_RGFW->display, request->requestor, request->property, + XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom)); + } else if (request->target == MULTIPLE) { + Atom* targets = NULL; + + Atom actualType = 0; + int actualFormat = 0; + unsigned long count = 0, bytesAfter = 0; + + XGetWindowProperty(_RGFW->display, request->requestor, request->property, 0, LONG_MAX, + False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); + + unsigned long i; + for (i = 0; i < (u32)count; i += 2) { + if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) + XChangeProperty(_RGFW->display, request->requestor, targets[i + 1], targets[i], + 8, PropModeReplace, (const unsigned char *)_RGFW->clipboard, (i32)_RGFW->clipboard_len); + else + targets[i + 1] = None; + } + + XChangeProperty(_RGFW->display, + request->requestor, request->property, ATOM_PAIR, 32, + PropModeReplace, (u8*) targets, (i32)count); + + XFlush(_RGFW->display); + XFree(targets); + } else if (request->target == SAVE_TARGETS) + XChangeProperty(_RGFW->display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0); + else { + int i; + for (i = 0; i < formatCount; i++) { + if (request->target != formats[i]) + continue; + XChangeProperty(_RGFW->display, request->requestor, request->property, request->target, + 8, PropModeReplace, (u8*) _RGFW->clipboard, (i32)_RGFW->clipboard_len); + } + } + + XEvent reply = { SelectionNotify }; + reply.xselection.property = request->property; + reply.xselection.display = request->display; + reply.xselection.requestor = request->requestor; + reply.xselection.selection = request->selection; + reply.xselection.target = request->target; + reply.xselection.time = request->time; + + XSendEvent(_RGFW->display, request->requestor, False, 0, &reply); + XFlush(_RGFW->display); +} + i32 RGFW_XHandleClipboardSelectionHelper(void); - -u8 RGFW_rgfwToKeyChar(u32 key) { +u8 RGFW_FUNC(RGFW_rgfwToKeyChar) (u32 key) { u32 keycode = RGFW_rgfwToApiKey(key); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - Window root = DefaultRootWindow(_RGFW.display); + + Window root = DefaultRootWindow(_RGFW->display); Window ret_root, ret_child; int root_x, root_y, win_x, win_y; unsigned int mask; - XQueryPointer(_RGFW.display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask); - KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW.display, (KeyCode)keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0); + XQueryPointer(_RGFW->display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask); + KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW->display, (KeyCode)keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0); if ((mask & LockMask) && sym >= XK_a && sym <= XK_z) sym = (mask & ShiftMask) ? sym + 32 : sym - 32; @@ -4516,25 +5561,10 @@ u8 RGFW_rgfwToKeyChar(u32 key) { sym = 0; return (u8)sym; -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL RGFW_UNUSED(keycode); - return (u8)key; -#endif } -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - RGFW_XHandleClipboardSelectionHelper(); - - if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; - RGFW_event* ev = RGFW_window_checkEventCore(win); - if (ev) return ev; - - #if defined(__linux__) && !defined(RGFW_NO_LINUX) - if (RGFW_linux_updateGamepad(win)) return &win->event; - #endif - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 +RGFWDEF void RGFW_XHandleEvent(void); +void RGFW_XHandleEvent(void) { RGFW_LOAD_ATOM(XdndTypeList); RGFW_LOAD_ATOM(XdndSelection); RGFW_LOAD_ATOM(XdndEnter); @@ -4546,20 +5576,8 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { RGFW_LOAD_ATOM(XdndActionCopy); RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST); RGFW_LOAD_ATOM(WM_PROTOCOLS); - XPending(win->src.display); - - XEvent E; /*!< raw X11 event */ - - /* if there is no unread qued events, get a new one */ - if ((QLength(win->src.display) || XEventsQueued(win->src.display, QueuedAlready) + XEventsQueued(win->src.display, QueuedAfterReading)) - && win->event.type != RGFW_quit - ) - XNextEvent(win->src.display, &E); - else { - return NULL; - } - - win->event.type = 0; + RGFW_LOAD_ATOM(WM_STATE); + RGFW_LOAD_ATOM(_NET_WM_STATE); /* xdnd data */ static Window source = 0; @@ -4567,550 +5585,641 @@ RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { static i32 format = 0; XEvent reply = { ClientMessage }; + XEvent E; + RGFW_event event; + RGFW_MEMSET(&event, 0, sizeof(event)); + XNextEvent(_RGFW->display, &E); switch (E.type) { - case KeyPress: - case KeyRelease: { - win->event.repeat = RGFW_FALSE; - /* check if it's a real key release */ - if (E.type == KeyRelease && XEventsQueued(win->src.display, QueuedAfterReading)) { /* get next event if there is one */ - XEvent NE; - XPeekEvent(win->src.display, &NE); + case SelectionRequest: + RGFW_XHandleClipboardSelection(&E); + return; + case GenericEvent: { + RGFW_window* win = _RGFW->mouseOwner; + if (win == NULL) return; + if (!(win->internal.enabledEvents & RGFW_BIT(RGFW_mousePosChanged))) return; - if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same */ - win->event.repeat = RGFW_TRUE; - } - - /* set event key data */ - win->event.key = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode); - win->event.keyChar = (u8)RGFW_rgfwToKeyChar(win->event.key); - - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - - /* get keystate data */ - win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased; - - XKeyboardState keystate; - XGetKeyboardControl(win->src.display, &keystate); - - RGFW_keyboard[win->event.key].current = (E.type == KeyPress); - - XkbStateRec state; - XkbGetState(win->src.display, XkbUseCoreKbd, &state); - RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, (E.type == KeyPress)); - break; - } - case ButtonPress: - case ButtonRelease: - if (E.xbutton.button > RGFW_mouseFinal) { /* skip this event */ - XFlush(win->src.display); - return RGFW_window_checkEvent(win); - } - - win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); /* the events match */ - win->event.button = (u8)(E.xbutton.button - 1); - switch(win->event.button) { - case RGFW_mouseScrollUp: - win->event.scroll = 1; - break; - case RGFW_mouseScrollDown: - win->event.scroll = -1; - break; - default: break; - } - - 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.key); - - RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress); - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress)); - break; - - case MotionNotify: - win->event.point.x = E.xmotion.x; - win->event.point.y = E.xmotion.y; - - win->event.vector.x = win->event.point.x - win->_lastMousePoint.x; - win->event.vector.y = win->event.point.y - win->_lastMousePoint.y; - win->_lastMousePoint = win->event.point; - - win->event.type = RGFW_mousePosChanged; - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - break; - - case GenericEvent: { - /* MotionNotify is used for mouse events if the mouse isn't held */ - if (!(win->_flags & RGFW_HOLD_MOUSE)) { - XFreeEventData(win->src.display, &E.xcookie); - break; - } - - XGetEventData(win->src.display, &E.xcookie); - if (E.xcookie.evtype == XI_RawMotion) { - XIRawEvent *raw = (XIRawEvent *)E.xcookie.data; - if (raw->valuators.mask_len == 0) { - XFreeEventData(win->src.display, &E.xcookie); - break; + /* MotionNotify is used for mouse events if the mouse isn't held */ + if (!(win->internal.holdMouse)) { + XFreeEventData(_RGFW->display, &E.xcookie); + return; } - double deltaX = 0.0f; - double deltaY = 0.0f; - - /* check if relative motion data exists where we think it does */ - if (XIMaskIsSet(raw->valuators.mask, 0) != 0) - deltaX += raw->raw_values[0]; - if (XIMaskIsSet(raw->valuators.mask, 1) != 0) - deltaY += raw->raw_values[1]; - - win->event.vector = RGFW_POINT((i32)deltaX, (i32)deltaY); - win->event.point.x = win->_lastMousePoint.x + win->event.vector.x; - win->event.point.y = win->_lastMousePoint.y + win->event.vector.y; - win->_lastMousePoint = win->event.point; - - RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); - - win->event.type = RGFW_mousePosChanged; - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - } - - XFreeEventData(win->src.display, &E.xcookie); - break; - } - - case Expose: { - win->event.type = RGFW_windowRefresh; - RGFW_windowRefreshCallback(win); - -#ifdef RGFW_ADVANCED_SMOOTH_RESIZE - XSyncValue value; - XSyncIntToValue(&value, (i32)win->src.counter_value); - XSyncSetCounter(win->src.display, win->src.counter, value); -#endif - break; - } - case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break; - case ClientMessage: { - /* if the client closed the window */ - if (E.xclient.data.l[0] == (long)wm_delete_window) { - win->event.type = RGFW_quit; - RGFW_window_setShouldClose(win, RGFW_TRUE); - RGFW_windowQuitCallback(win); - break; - } -#ifdef RGFW_ADVANCED_SMOOTH_RESIZE - if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) { - RGFW_windowRefreshCallback(win); - win->src.counter_value = 0; - win->src.counter_value |= E.xclient.data.l[2]; - win->src.counter_value |= (E.xclient.data.l[3] << 32); - - XSyncValue value; - XSyncIntToValue(&value, (i32)win->src.counter_value); - XSyncSetCounter(win->src.display, win->src.counter, value); - break; - } -#endif - if ((win->_flags & RGFW_windowAllowDND) == 0) - break; - - reply.xclient.window = source; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)win->src.window; - reply.xclient.data.l[1] = 0; - reply.xclient.data.l[2] = None; - - if (E.xclient.message_type == XdndEnter) { - if (version > 5) - break; - - unsigned long count; - Atom* formats; - Atom real_formats[6]; - Bool list = E.xclient.data.l[1] & 1; - - source = (unsigned long int)E.xclient.data.l[0]; - version = E.xclient.data.l[1] >> 24; - format = None; - if (list) { - Atom actualType; - i32 actualFormat; - unsigned long bytesAfter; - - XGetWindowProperty( - win->src.display, source, XdndTypeList, - 0, LONG_MAX, False, 4, - &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats - ); - } else { - count = 0; - - size_t i; - for (i = 2; i < 5; i++) { - if (E.xclient.data.l[i] != None) { - real_formats[count] = (unsigned long int)E.xclient.data.l[i]; - count += 1; - } + XGetEventData(_RGFW->display, &E.xcookie); + if (E.xcookie.evtype == XI_RawMotion) { + XIRawEvent *raw = (XIRawEvent *)E.xcookie.data; + if (raw->valuators.mask_len == 0) { + XFreeEventData(_RGFW->display, &E.xcookie); + return; } - formats = real_formats; + double deltaX = 0.0f; + double deltaY = 0.0f; + + /* check if relative motion data exists where we think it does */ + if (XIMaskIsSet(raw->valuators.mask, 0) != 0) + deltaX += raw->raw_values[0]; + if (XIMaskIsSet(raw->valuators.mask, 1) != 0) + deltaY += raw->raw_values[1]; + + event.mouse.vecX = (float)deltaX; + event.mouse.vecY = (float)deltaY; + _RGFW->vectorX = (float)event.mouse.vecX; + _RGFW->vectorY = (float)event.mouse.vecY; + event.mouse.x = win->internal.lastMouseX + (i32)event.mouse.vecX; + event.mouse.y = win->internal.lastMouseY + (i32)event.mouse.vecY; + win->internal.lastMouseX = event.mouse.x; + win->internal.lastMouseY = event.mouse.y; + RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); + + event.type = RGFW_mousePosChanged; + RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, (float)event.mouse.vecX, (float)event.mouse.vecY); } - size_t i; - for (i = 0; i < count; i++) { - if (formats[i] == XtextUriList || formats[i] == XtextPlain) { - format = (int)formats[i]; + XFreeEventData(_RGFW->display, &E.xcookie); + if (event.type) + RGFW_eventQueuePush(&event); + return; + } + } + + RGFW_window* win = NULL; + if (XFindContext(_RGFW->display, E.xany.window, _RGFW->context, (XPointer*) &win) != 0) { + return; + } + + event.common.win = win; + + /* + Repeated key presses are sent as a release followed by another press at the same time. + We want to convert that into a single key press event with the repeat flag set + */ + if (E.type == KeyRelease && XEventsQueued(_RGFW->display, QueuedAfterReading)) { + XEvent NE; + XPeekEvent(_RGFW->display, &NE); + if (NE.type == KeyPress && E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) { + /* Use the next KeyPress event */ + XNextEvent(_RGFW->display, &E); + event.key.repeat = RGFW_TRUE; + } + } + + switch (E.type) { + case KeyPress: { + if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return; + event.type = RGFW_keyPressed; + event.key.value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode); + event.key.sym = (u8)RGFW_rgfwToKeyChar(event.key.value); + + _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; + _RGFW->keyboard[event.key.value].current = RGFW_TRUE; + + XkbStateRec state; + XkbGetState(_RGFW->display, XkbUseCoreKbd, &state); + RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); + + RGFW_keyCallback(win, event.key.value, event.key.sym, win->internal.mod, event.key.repeat, RGFW_TRUE); + break; + } + case KeyRelease: { + if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return; + + event.type = RGFW_keyReleased; + event.key.value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode); + event.key.sym = (u8)RGFW_rgfwToKeyChar(event.key.value); + + /* get keystate data */ + _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; + _RGFW->keyboard[event.key.value].current = RGFW_FALSE; + + XkbStateRec state; + XkbGetState(_RGFW->display, XkbUseCoreKbd, &state); + RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); + + RGFW_keyCallback(win, event.key.value, event.key.sym, win->internal.mod, event.key.repeat, RGFW_FALSE); + break; + } + case ButtonPress: + if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) { + if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return; + event.type = RGFW_mouseScroll; + } else { + if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag) || E.xbutton.button > RGFW_mouseFinal) return; + event.type = RGFW_mouseButtonPressed; + } + + switch(E.xbutton.button) { + case Button1: event.button.value = RGFW_mouseLeft; break; + case Button2: event.button.value = RGFW_mouseMiddle; break; + case Button3: event.button.value = RGFW_mouseRight; break; + case Button4: event.scroll.y = 1.0; break; + case Button5: event.scroll.y = -1.0; break; + case 6: event.scroll.x = 1.0f; break; + case 7: event.scroll.x = -1.0f; break; + default: + event.button.value = (u8)E.xbutton.button - Button1 - 4; + break; + } + + if (event.type == RGFW_mouseScroll) { + _RGFW->scrollX = event.scroll.x; + _RGFW->scrollY = event.scroll.y; + RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); + break; + } + + _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; + _RGFW->mouseButtons[event.button.value].current = RGFW_TRUE; + RGFW_mouseButtonCallback(win, event.button.value, RGFW_TRUE); + break; + case ButtonRelease: + if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) break; + if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag) || E.xbutton.button > RGFW_mouseFinal) return; + event.type = RGFW_mouseButtonReleased; + switch(E.xbutton.button) { + case Button1: event.button.value = RGFW_mouseLeft; break; + case Button2: event.button.value = RGFW_mouseMiddle; break; + case Button3: event.button.value = RGFW_mouseRight; break; + default: + event.button.value = (u8)E.xbutton.button - Button1 - 4; + break; + } + + _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; + _RGFW->mouseButtons[event.button.value].current = RGFW_FALSE; + RGFW_mouseButtonCallback(win, event.button.value, RGFW_FALSE); + break; + case MotionNotify: + if (win->internal.holdMouse) return; + if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return; + event.mouse.x = E.xmotion.x; + event.mouse.y = E.xmotion.y; + + event.mouse.vecX = (float)(event.mouse.x - win->internal.lastMouseX); + event.mouse.vecY = (float)(event.mouse.y - win->internal.lastMouseY); + _RGFW->vectorX = event.mouse.vecX; + _RGFW->vectorY = event.mouse.vecY; + win->internal.lastMouseX = event.mouse.x; + win->internal.lastMouseY = event.mouse.y; + event.type = RGFW_mousePosChanged; + RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, (float)event.mouse.vecX, (float)event.mouse.vecY); + break; + + case Expose: { + if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return; + event.type = RGFW_windowRefresh; + RGFW_windowRefreshCallback(win); + +#ifdef RGFW_ADVANCED_SMOOTH_RESIZE + XSyncValue value; + XSyncIntToValue(&value, (i32)win->src.counter_value); + XSyncSetCounter(_RGFW->display, win->src.counter, value); +#endif + break; + } + + case PropertyNotify: + if (E.xproperty.state != PropertyNewValue) break; + + if (E.xproperty.atom == WM_STATE) { + if (RGFW_window_isMinimized(win) && !(win->internal.flags & RGFW_windowMinimized)) { + win->internal.flags |= RGFW_windowMinimize; + RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); + RGFW_windowMinimizedCallback(win); + break; + } + } else if (E.xproperty.atom == _NET_WM_STATE) { + if (!(win->internal.flags & RGFW_windowMaximize)) { + win->internal.flags |= RGFW_windowMaximize; + RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); + RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h); break; } } - if (list) { - XFree(formats); + RGFW_window_checkMode(win); + break; + case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break; + case ClientMessage: { + RGFW_LOAD_ATOM(WM_DELETE_WINDOW); + /* if the client closed the window */ + if (E.xclient.data.l[0] == (long)WM_DELETE_WINDOW) { + event.type = RGFW_quit; + RGFW_window_setShouldClose(win, RGFW_TRUE); + RGFW_windowQuitCallback(win); + break; + } +#ifdef RGFW_ADVANCED_SMOOTH_RESIZE + if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) { + RGFW_windowRefreshCallback(win); + win->src.counter_value = 0; + win->src.counter_value |= E.xclient.data.l[2]; + win->src.counter_value |= (E.xclient.data.l[3] << 32); + + XSyncValue value; + XSyncIntToValue(&value, (i32)win->src.counter_value); + XSyncSetCounter(_RGFW->display, win->src.counter, value); + break; + } +#endif + if ((win->internal.flags & RGFW_windowAllowDND) == 0) + return; + + reply.xclient.window = source; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long)win->src.window; + reply.xclient.data.l[1] = 0; + reply.xclient.data.l[2] = None; + + if (E.xclient.message_type == XdndEnter) { + if (version > 5) + break; + + unsigned long count; + Atom* formats; + Atom real_formats[6]; + Bool list = E.xclient.data.l[1] & 1; + + source = (unsigned long int)E.xclient.data.l[0]; + version = E.xclient.data.l[1] >> 24; + format = None; + if (list) { + Atom actualType; + i32 actualFormat; + unsigned long bytesAfter; + + XGetWindowProperty( + _RGFW->display, source, XdndTypeList, + 0, LONG_MAX, False, 4, + &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats + ); + } else { + count = 0; + + size_t i; + for (i = 2; i < 5; i++) { + if (E.xclient.data.l[i] != None) { + real_formats[count] = (unsigned long int)E.xclient.data.l[i]; + count += 1; + } + } + + formats = real_formats; + } + + Atom XtextPlain = XInternAtom(_RGFW->display, "text/plain", False); + Atom XtextUriList = XInternAtom(_RGFW->display, "text/uri-list", False); + + size_t i; + for (i = 0; i < count; i++) { + if (formats[i] == XtextUriList || formats[i] == XtextPlain) { + format = (int)formats[i]; + break; + } + } + + if (list) { + XFree(formats); + } + + break; } - break; - } + if (E.xclient.message_type == XdndPosition) { + const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff; + const i32 yabs = (E.xclient.data.l[2]) & 0xffff; + Window dummy; + i32 xpos, ypos; - if (E.xclient.message_type == XdndPosition) { - const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff; - const i32 yabs = (E.xclient.data.l[2]) & 0xffff; - Window dummy; - i32 xpos, ypos; + if (version > 5) + break; + + XTranslateCoordinates( + _RGFW->display, XDefaultRootWindow(_RGFW->display), win->src.window, + xabs, yabs, &xpos, &ypos, &dummy + ); + + event.drag.x = xpos; + event.drag.y = ypos; + + reply.xclient.window = source; + reply.xclient.message_type = XdndStatus; + + if (format) { + reply.xclient.data.l[1] = 1; + if (version >= 2) + reply.xclient.data.l[4] = (long)XdndActionCopy; + } + + XSendEvent(_RGFW->display, source, False, NoEventMask, &reply); + XFlush(_RGFW->display); + break; + } + if (E.xclient.message_type != XdndDrop) + break; if (version > 5) break; - XTranslateCoordinates( - win->src.display, XDefaultRootWindow(win->src.display), win->src.window, - xabs, yabs, &xpos, &ypos, &dummy - ); - - win->event.point.x = xpos; - win->event.point.y = ypos; - - reply.xclient.window = source; - reply.xclient.message_type = XdndStatus; + event.type = RGFW_dataDrag; if (format) { - reply.xclient.data.l[1] = 1; - if (version >= 2) - reply.xclient.data.l[4] = (long)XdndActionCopy; + Time time = (version >= 1) + ? (Time)E.xclient.data.l[2] + : CurrentTime; + + XConvertSelection( + _RGFW->display, XdndSelection, (Atom)format, + XdndSelection, win->src.window, time + ); + } else if (version >= 2) { + XEvent new_reply = { ClientMessage }; + + XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply); + XFlush(_RGFW->display); } - XSendEvent(win->src.display, source, False, NoEventMask, &reply); - XFlush(win->src.display); - break; - } - if (E.xclient.message_type != XdndDrop) - break; + _RGFW->windowState.win = win; + _RGFW->windowState.dataDragging = RGFW_TRUE; + _RGFW->windowState.dropX = event.drag.x; + _RGFW->windowState.dropY = event.drag.y; - if (version > 5) - break; + if (win->internal.enabledEvents & RGFW_dataDragFlag) return; + RGFW_dataDragCallback(win, event.drag.x, event.drag.y); + } break; + case SelectionNotify: { + /* this is only for checking for xdnd drops */ + if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || E.xselection.property != XdndSelection || !(win->internal.flags & RGFW_windowAllowDND)) + return; + char* data; + unsigned long result; - size_t i; - for (i = 0; i < win->event.droppedFilesCount; i++) - win->event.droppedFiles[i][0] = '\0'; + Atom actualType; + i32 actualFormat; + unsigned long bytesAfter; - win->event.droppedFilesCount = 0; + XGetWindowProperty(_RGFW->display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data); + if (result == 0) + break; - win->event.type = RGFW_DNDInit; + const char* prefix = (const char*)"file://"; - if (format) { - Time time = (version >= 1) - ? (Time)E.xclient.data.l[2] - : CurrentTime; + char* line; - XConvertSelection( - win->src.display, XdndSelection, (Atom)format, - XdndSelection, win->src.window, time - ); - } else if (version >= 2) { - XEvent new_reply = { ClientMessage }; + event.drop.files = _RGFW->files; + event.drop.count = 0; + event.type = RGFW_dataDrop; - XSendEvent(win->src.display, source, False, NoEventMask, &new_reply); - XFlush(win->src.display); - } + while ((line = (char*)RGFW_strtok(data, "\r\n"))) { + char path[RGFW_MAX_PATH]; - RGFW_dndInitCallback(win, win->event.point); - } break; - case SelectionRequest: - RGFW_XHandleClipboardSelection(&E); - XFlush(win->src.display); - return RGFW_window_checkEvent(win); - case SelectionNotify: { - /* this is only for checking for xdnd drops */ - if (E.xselection.property != XdndSelection || !(win->_flags & RGFW_windowAllowDND)) - break; - char* data; - unsigned long result; + data = NULL; - Atom actualType; - i32 actualFormat; - unsigned long bytesAfter; + if (line[0] == '#') + continue; - XGetWindowProperty(win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data); + char* l; + for (l = line; 1; l++) { + if ((l - line) > 7) + break; + else if (*l != prefix[(l - line)]) + break; + else if (*l == '\0' && prefix[(l - line)] == '\0') { + line += 7; + while (*line != '/') + line++; + break; + } else if (*l == '\0') + break; + } - if (result == 0) - break; + event.drop.count++; - const char* prefix = (const char*)"file://"; - - char* line; - - win->event.droppedFilesCount = 0; - win->event.type = RGFW_DND; - - while ((line = (char*)RGFW_strtok(data, "\r\n"))) { - char path[RGFW_MAX_PATH]; - - data = NULL; - - if (line[0] == '#') - continue; - - char* l; - for (l = line; 1; l++) { - if ((l - line) > 7) - break; - else if (*l != prefix[(l - line)]) - break; - else if (*l == '\0' && prefix[(l - line)] == '\0') { - line += 7; - while (*line != '/') - line++; - break; - } else if (*l == '\0') - break; - } - - win->event.droppedFilesCount++; - - size_t index = 0; - while (*line) { - if (line[0] == '%' && line[1] && line[2]) { - const char digits[3] = { line[1], line[2], '\0' }; - path[index] = (char) RGFW_STRTOL(digits, NULL, 16); - line += 2; - } else + size_t index = 0; + while (*line) { + if (line[0] == '%' && line[1] && line[2]) { + char digits[3] = {0}; + digits[0] = line[1]; + digits[1] = line[2]; + digits[2] = '\0'; + path[index] = (char) RGFW_STRTOL(digits, NULL, 16); + line += 2; + } else path[index] = *line; - index++; - line++; + index++; + line++; + } + path[index] = '\0'; + RGFW_MEMCPY(event.drop.files[event.drop.count - 1], path, index + 1); } - path[index] = '\0'; - RGFW_MEMCPY(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1); + + _RGFW->windowState.win = win; + _RGFW->windowState.dataDrop = RGFW_TRUE; + _RGFW->windowState.filesCount = event.drop.count; + + RGFW_dataDropCallback(win, event.drop.files, event.drop.count); + if (data) + XFree(data); + + if (version >= 2) { + XEvent new_reply = { ClientMessage }; + new_reply.xclient.window = source; + new_reply.xclient.message_type = XdndFinished; + new_reply.xclient.format = 32; + new_reply.xclient.data.l[1] = (long int)result; + new_reply.xclient.data.l[2] = (long int)XdndActionCopy; + XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply); + XFlush(_RGFW->display); + } + break; } + case FocusIn: + if ((win->internal.flags & RGFW_windowFullscreen)) + XMapRaised(_RGFW->display, win->src.window); + if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); - RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); - if (data) - XFree(data); + if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; + win->internal.inFocus = RGFW_TRUE; + event.type = RGFW_focusIn; + RGFW_focusCallback(win, 1); - if (version >= 2) { - XEvent new_reply = { ClientMessage }; - new_reply.xclient.window = source; - new_reply.xclient.message_type = XdndFinished; - new_reply.xclient.format = 32; - new_reply.xclient.data.l[1] = (long int)result; - new_reply.xclient.data.l[2] = (long int)XdndActionCopy; - XSendEvent(win->src.display, source, False, NoEventMask, &new_reply); - XFlush(win->src.display); - } - break; - } - case FocusIn: - if ((win->_flags & RGFW_windowFullscreen)) - XMapRaised(win->src.display, win->src.window); + break; + case FocusOut: + if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; + event.type = RGFW_focusOut; + RGFW_focusCallback(win, 0); + RGFW_window_focusLost(win); + break; + case EnterNotify: { + win->internal.mouseInside = RGFW_TRUE; + _RGFW->windowState.win = win; + _RGFW->windowState.mouseEnter = RGFW_TRUE; - win->_flags |= RGFW_windowFocus; - win->event.type = RGFW_focusIn; - RGFW_focusCallback(win, 1); - - - if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h)); - break; - case FocusOut: - win->event.type = RGFW_focusOut; - RGFW_focusCallback(win, 0); - RGFW_window_focusLost(win); - break; - case PropertyNotify: RGFW_window_checkMode(win); break; - case EnterNotify: { - win->event.type = RGFW_mouseEnter; - win->event.point.x = E.xcrossing.x; - win->event.point.y = E.xcrossing.y; - RGFW_mouseNotifyCallback(win, win->event.point, 1); - break; - } - - case LeaveNotify: { - win->event.type = RGFW_mouseLeave; - RGFW_mouseNotifyCallback(win, win->event.point, 0); - break; - } - - case ConfigureNotify: { - /* detect resize */ - RGFW_window_checkMode(win); - if (E.xconfigure.width != win->src.r.w || E.xconfigure.height != win->src.r.h) { - win->event.type = RGFW_windowResized; - win->src.r = win->r = RGFW_RECT(win->src.r.x, win->src.r.y, E.xconfigure.width, E.xconfigure.height); - RGFW_windowResizedCallback(win, win->r); + if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; + event.type = RGFW_mouseEnter; + event.mouse.x = E.xcrossing.x; + event.mouse.y = E.xcrossing.y; + RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 1); break; } - /* detect move */ - if (E.xconfigure.x != win->src.r.x || E.xconfigure.y != win->src.r.y) { - win->event.type = RGFW_windowMoved; - win->src.r = win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->src.r.w, win->src.r.h); - RGFW_windowMovedCallback(win, win->r); + case LeaveNotify: { + win->internal.mouseInside = RGFW_FALSE; + _RGFW->windowState.winLeave = win; + _RGFW->windowState.mouseLeave = RGFW_TRUE; + if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; + event.type = RGFW_mouseLeave; + RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 0); break; } + case ReparentNotify: + win->src.parent = E.xreparent.parent; + break; + case ConfigureNotify: { + /* detect resize */ + RGFW_window_checkMode(win); + if (E.xconfigure.width != win->src.w || E.xconfigure.height != win->src.h) { + win->src.w = win->w = E.xconfigure.width; + win->src.h = win->h = E.xconfigure.height; - break; - } - default: - XFlush(win->src.display); - return RGFW_window_checkEvent(win); - } - XFlush(win->src.display); - if (win->event.type) return &win->event; - else return NULL; -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - if ((win->_flags & RGFW_windowHide) == 0) - wl_display_roundtrip(win->src.wl_display); - return NULL; -#endif -} - -void RGFW_window_move(RGFW_window* win, RGFW_point v) { - RGFW_ASSERT(win != NULL); - win->r.x = v.x; - win->r.y = v.y; - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XMoveWindow(win->src.display, win->src.window, v.x, v.y); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_ASSERT(win != NULL); - - if (win->src.compositor) { - struct wl_pointer *pointer = wl_seat_get_pointer(win->src.seat); - if (!pointer) { - return; + if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return; + event.type = RGFW_windowResized; + RGFW_windowResizedCallback(win, win->w, win->h); + RGFW_eventQueuePush(&event); } - wl_display_flush(win->src.wl_display); + i32 x = E.xconfigure.x; + i32 y = E.xconfigure.y; + + /* + if the event came from the server and we're not a direct child of the root window then + we're using local coords which need to be translated into screen coords + */ + Window root = DefaultRootWindow(_RGFW->display); + if (E.xany.send_event == 0 && win->src.parent != root) { + Window dummy = 0; + XTranslateCoordinates(_RGFW->display, win->src.parent, root, x, y, &x, &y, &dummy); + } + + /* detect move */ + if (E.xconfigure.x != win->src.x || E.xconfigure.y != win->src.y) { + win->src.x = win->x = E.xconfigure.x; + win->src.y = win->y = E.xconfigure.y; + + if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; + event.type = RGFW_windowMoved; + RGFW_windowMovedCallback(win, win->x, win->y); + RGFW_eventQueuePush(&event); + } + return; + } + default: + break; } -#endif + + if (event.type) { + RGFW_eventQueuePush(&event); + } + + XFlush(_RGFW->display); +} + +void RGFW_FUNC(RGFW_pollEvents) (void) { + RGFW_resetPrevState(); + + XPending(_RGFW->display); + /* if there is no unread queued events, get a new one */ + while ((QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading))) { + RGFW_XHandleEvent(); + } +} + +void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) { + RGFW_ASSERT(win != NULL); + win->x = x; + win->y = y; + + XMoveWindow(_RGFW->display, win->src.window, x, y); + return; } -void RGFW_window_resize(RGFW_window* win, RGFW_area a) { +void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); - win->r.w = (i32)a.w; - win->r.h = (i32)a.h; - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XResizeWindow(win->src.display, win->src.window, a.w, a.h); + win->w = (i32)w; + win->h = (i32)h; - if ((win->_flags & RGFW_windowNoResize)) { + XResizeWindow(_RGFW->display, win->src.window, (u32)w, (u32)h); + + if ((win->internal.flags & RGFW_windowNoResize)) { XSizeHints sh; sh.flags = (1L << 4) | (1L << 5); - sh.min_width = sh.max_width = (i32)a.w; - sh.min_height = sh.max_height = (i32)a.h; + sh.min_width = sh.max_width = (i32)w; + sh.min_height = sh.max_height = (i32)h; - XSetWMSizeHints(win->src.display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS); + XSetWMSizeHints(_RGFW->display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS); } -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - if (win->src.compositor) { - xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h); - #ifdef RGFW_OPENGL - wl_egl_window_resize(win->src.eglWindow, (i32)a.w, (i32)a.h, 0, 0); - #endif - } -#endif + return; } -void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { +void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); - if (a.w == 0 && a.h == 0) + + if (w == 0 && h == 0) return; -#ifdef RGFW_X11 XSizeHints hints; long flags; - XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); + XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); hints.flags |= PAspect; - hints.min_aspect.x = hints.max_aspect.x = (i32)a.w; - hints.min_aspect.y = hints.max_aspect.y = (i32)a.h; + hints.min_aspect.x = hints.max_aspect.x = (i32)w; + hints.min_aspect.y = hints.max_aspect.y = (i32)h; - XSetWMNormalHints(win->src.display, win->src.window, &hints); + XSetWMNormalHints(_RGFW->display, win->src.window, &hints); return; -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL -#endif } -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { +void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 + long flags; XSizeHints hints; RGFW_MEMSET(&hints, 0, sizeof(XSizeHints)); - XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); + XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); hints.flags |= PMinSize; - hints.min_width = (i32)a.w; - hints.min_height = (i32)a.h; + hints.min_width = (i32)w; + hints.min_height = (i32)h; - XSetWMNormalHints(win->src.display, win->src.window, &hints); + XSetWMNormalHints(_RGFW->display, win->src.window, &hints); return; -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL RGFW_UNUSED(a); -#endif } -void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { +void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 + long flags; XSizeHints hints; RGFW_MEMSET(&hints, 0, sizeof(XSizeHints)); - XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); + XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); hints.flags |= PMaxSize; - hints.max_width = (i32)a.w; - hints.max_height = (i32)a.h; + hints.max_width = (i32)w; + hints.max_height = (i32)h; - XSetWMNormalHints(win->src.display, win->src.window, &hints); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL RGFW_UNUSED(a); -#endif + XSetWMNormalHints(_RGFW->display, win->src.window, &hints); + return; } -#ifdef RGFW_X11 void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized); void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) { RGFW_ASSERT(win != NULL); @@ -5129,52 +6238,36 @@ void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) { xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } -#endif -void RGFW_window_maximize(RGFW_window* win) { - win->_oldRect = win->r; - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 +void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) { + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; + RGFW_toggleXMaximized(win, 1); return; -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - return; -#endif } -void RGFW_window_focus(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_focus) (RGFW_window* win) { RGFW_ASSERT(win); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 + XWindowAttributes attr; - XGetWindowAttributes(win->src.display, win->src.window, &attr); + XGetWindowAttributes(_RGFW->display, win->src.window, &attr); if (attr.map_state != IsViewable) return; - XSetInputFocus(win->src.display, win->src.window, RevertToPointerRoot, CurrentTime); - XFlush(win->src.display); -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL; -#endif + XSetInputFocus(_RGFW->display, win->src.window, RevertToPointerRoot, CurrentTime); + XFlush(_RGFW->display); } -void RGFW_window_raise(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_raise) (RGFW_window* win) { RGFW_ASSERT(win); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XRaiseWindow(win->src.display, win->src.window); - XMapRaised(win->src.display, win->src.window); -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL; -#endif + XRaiseWindow(_RGFW->display, win->src.window); + XMapRaised(_RGFW->display, win->src.window); } -#ifdef RGFW_X11 void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen); void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); @@ -5191,94 +6284,66 @@ void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) xev.xclient.data.l[1] = (long int)netAtom; xev.xclient.data.l[2] = 0; - XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); + XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); } -#endif -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { +void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); + if (fullscreen) { - win->_flags |= RGFW_windowFullscreen; - win->_oldRect = win->r; + win->internal.flags |= RGFW_windowFullscreen; + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; } - else win->_flags &= ~(u32)RGFW_windowFullscreen; -#ifdef RGFW_X11 + else win->internal.flags &= ~(u32)RGFW_windowFullscreen; RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN); RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen); - XRaiseWindow(win->src.display, win->src.window); - XMapRaised(win->src.display, win->src.window); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL; -#endif + XRaiseWindow(_RGFW->display, win->src.window); + XMapRaised(_RGFW->display, win->src.window); } -void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { +void RGFW_FUNC(RGFW_window_setFloating)(RGFW_window* win, RGFW_bool floating) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating); -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL RGFW_UNUSED(floating); -#endif } -void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { +void RGFW_FUNC(RGFW_window_setOpacity)(RGFW_window* win, u8 opacity) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 const u32 value = (u32) (0xffffffffu * (double) opacity); RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY); - XChangeProperty(win->src.display, win->src.window, + XChangeProperty(_RGFW->display, win->src.window, NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1); -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL RGFW_UNUSED(opacity); -#endif } -void RGFW_window_minimize(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); + if (RGFW_window_isMaximized(win)) return; - win->_oldRect = win->r; -#ifdef RGFW_X11 - XIconifyWindow(win->src.display, win->src.window, DefaultScreen(win->src.display)); - XFlush(win->src.display); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL; -#endif + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; + XIconifyWindow(_RGFW->display, win->src.window, DefaultScreen(_RGFW->display)); + XFlush(_RGFW->display); } -void RGFW_window_restore(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - RGFW_toggleXMaximized(win, 0); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL -#endif - win->r = win->_oldRect; - RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y)); - RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); - + RGFW_toggleXMaximized(win, RGFW_FALSE); + RGFW_window_move(win, win->internal.oldX, win->internal.oldY); + RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); + RGFW_window_show(win); -#ifdef RGFW_X11 - XFlush(win->src.display); -#endif + XFlush(_RGFW->display); } -RGFW_bool RGFW_window_isFloating(RGFW_window* win) { - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 +RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) { RGFW_LOAD_ATOM(_NET_WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); @@ -5287,7 +6352,7 @@ RGFW_bool RGFW_window_isFloating(RGFW_window* win) { unsigned long nitems, bytes_after; Atom* prop_return = NULL; - int status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM, + int status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, (unsigned char **)&prop_return); @@ -5300,226 +6365,148 @@ RGFW_bool RGFW_window_isFloating(RGFW_window* win) { if (prop_return) XFree(prop_return); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL RGFW_UNUSED(win); -#endif return RGFW_FALSE; } -void RGFW_window_setName(RGFW_window* win, const char* name) { +void RGFW_FUNC(RGFW_window_setName)(RGFW_window* win, const char* name) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); - #ifdef RGFW_X11 - XStoreName(win->src.display, win->src.window, name); - RGFW_LOAD_ATOM(_NET_WM_NAME); + XStoreName(_RGFW->display, win->src.window, name); + + RGFW_LOAD_ATOM(_NET_WM_NAME); RGFW_LOAD_ATOM(UTF8_STRING); char buf[256]; RGFW_MEMSET(buf, 0, sizeof(buf)); RGFW_STRNCPY(buf, name, sizeof(buf) - 1); XChangeProperty( - win->src.display, win->src.window, _NET_WM_NAME, RGFW_XUTF8_STRING, + _RGFW->display, win->src.window, _NET_WM_NAME, UTF8_STRING, 8, PropModeReplace, (u8*)buf, sizeof(buf) ); - #endif - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - if (win->src.compositor) - xdg_toplevel_set_title(win->src.xdg_toplevel, name); - #endif } #ifndef RGFW_NO_PASSTHROUGH -void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { +void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 if (passthrough) { Region region = XCreateRegion(); - XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet); + XShapeCombineRegion(_RGFW->display, win->src.window, ShapeInput, 0, 0, region, ShapeSet); XDestroyRegion(region); return; } - XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL RGFW_UNUSED(passthrough); -#endif + XShapeCombineMask(_RGFW->display, win->src.window, ShapeInput, 0, 0, None, ShapeSet); } #endif /* RGFW_NO_PASSTHROUGH */ -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { +RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data_src, i32 w, i32 h, RGFW_format format, RGFW_icon type) { + Atom _NET_WM_ICON = XInternAtom(_RGFW->display, "_NET_WM_ICON", False); RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - RGFW_LOAD_ATOM(_NET_WM_ICON); - if (icon == NULL || (channels != 3 && channels != 4)) { + if (data_src == NULL) { RGFW_bool res = (RGFW_bool)XChangeProperty( - win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, + _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8*)NULL, 0 ); return res; } - i32 count = (i32)(2 + (a.w * a.h)); + i32 count = (i32)(2 + (w * h)); unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long)); RGFW_ASSERT(data != NULL); - data[0] = (unsigned long)a.w; - data[1] = (unsigned long)a.h; - - unsigned long* target = &data[2]; - u32 x, y; - - for (x = 0; x < a.w; x++) { - for (y = 0; y < a.h; y++) { - size_t i = y * a.w + x; - u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF; - - target[i] = (unsigned long)((icon[i * 4 + 0]) << 16) | - (unsigned long)((icon[i * 4 + 1]) << 8) | - (unsigned long)((icon[i * 4 + 2]) << 0) | - (unsigned long)(alpha << 24); - } - } + RGFW_MEMSET(data, 0, (u32)count * sizeof(unsigned long)); + data[0] = (unsigned long)w; + data[1] = (unsigned long)h; + RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_TRUE); RGFW_bool res = RGFW_TRUE; if (type & RGFW_iconTaskbar) { res = (RGFW_bool)XChangeProperty( - win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, + _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8*)data, count ); } + RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_FALSE); + if (type & RGFW_iconWindow) { XWMHints wm_hints; wm_hints.flags = IconPixmapHint; - i32 depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display)); - XImage *image = XCreateImage(win->src.display, DefaultVisual(win->src.display, DefaultScreen(win->src.display)), - (u32)depth, ZPixmap, 0, (char *)target, a.w, a.h, 32, 0); + i32 depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)); + XImage *image = XCreateImage(_RGFW->display, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), + (u32)depth, ZPixmap, 0, (char *)&data[2], (u32)w, (u32)h, 32, 0); - wm_hints.icon_pixmap = XCreatePixmap(win->src.display, win->src.window, a.w, a.h, (u32)depth); - XPutImage(win->src.display, wm_hints.icon_pixmap, DefaultGC(win->src.display, DefaultScreen(win->src.display)), image, 0, 0, 0, 0, a.w, a.h); + wm_hints.icon_pixmap = XCreatePixmap(_RGFW->display, win->src.window, (u32)w, (u32)h, (u32)depth); + XPutImage(_RGFW->display, wm_hints.icon_pixmap, DefaultGC(_RGFW->display, DefaultScreen(_RGFW->display)), image, 0, 0, 0, 0, (u32)w, (u32)h); image->data = NULL; XDestroyImage(image); - XSetWMHints(win->src.display, win->src.window, &wm_hints); + XSetWMHints(_RGFW->display, win->src.window, &wm_hints); } RGFW_FREE(data); - XFlush(win->src.display); + XFlush(_RGFW->display); return RGFW_BOOL(res); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); - return RGFW_FALSE; -#endif } -RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { - RGFW_ASSERT(icon); - RGFW_ASSERT(channels == 3 || channels == 4); - RGFW_GOTO_WAYLAND(0); - -#ifdef RGFW_X11 +RGFW_mouse* RGFW_FUNC(RGFW_loadMouse) (u8* data, i32 w, i32 h, RGFW_format format) { + RGFW_ASSERT(data); #ifndef RGFW_NO_X11_CURSOR RGFW_init(); - XcursorImage* native = XcursorImageCreate((i32)a.w, (i32)a.h); + XcursorImage* native = XcursorImageCreate((i32)w, (i32)h); native->xhot = 0; native->yhot = 0; + RGFW_MEMSET(native->pixels, 0, (u32)(w * h * 4)); + RGFW_copyImageData((u8*)native->pixels, w, h, RGFW_formatBGRA8, data, format); - XcursorPixel* target = native->pixels; - size_t x, y; - for (x = 0; x < a.w; x++) { - for (y = 0; y < a.h; y++) { - size_t i = y * a.w + x; - u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF; - - target[i] = (u32)((icon[i * 4 + 0]) << 16) - | (u32)((icon[i * 4 + 1]) << 8) - | (u32)((icon[i * 4 + 2]) << 0) - | (u32)(alpha << 24); - } - } - - Cursor cursor = XcursorImageLoadCursor(_RGFW.display, native); + Cursor cursor = XcursorImageLoadCursor(_RGFW->display, native); XcursorImageDestroy(native); return (void*)cursor; #else - RGFW_UNUSED(image); RGFW_UNUSED(a.w); RGFW_UNUSED(channels); + RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); return NULL; #endif -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); - return NULL; /* TODO */ -#endif } -void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { -RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 +void RGFW_FUNC(RGFW_window_setMouse)(RGFW_window* win, RGFW_mouse* mouse) { RGFW_ASSERT(win && mouse); - XDefineCursor(win->src.display, win->src.window, (Cursor)mouse); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_UNUSED(win); RGFW_UNUSED(mouse); -#endif + XDefineCursor(_RGFW->display, win->src.window, (Cursor)mouse); } -void RGFW_freeMouse(RGFW_mouse* mouse) { -RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 +void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) { RGFW_ASSERT(mouse); - XFreeCursor(_RGFW.display, (Cursor)mouse); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_UNUSED(mouse); -#endif + XFreeCursor(_RGFW->display, (Cursor)mouse); } -void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { -RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 +void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); XEvent event; - XQueryPointer(win->src.display, DefaultRootWindow(win->src.display), + XQueryPointer(_RGFW->display, DefaultRootWindow(_RGFW->display), &event.xbutton.root, &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); - 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) + win->internal.lastMouseX = x - win->x; + win->internal.lastMouseY = y - win->y; + if (event.xbutton.x == x && event.xbutton.y == y) return; - XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) p.x - win->r.x, (int) p.y - win->r.y); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_UNUSED(win); RGFW_UNUSED(p); -#endif + XWarpPointer(_RGFW->display, None, win->src.window, 0, 0, 0, 0, (int) x - win->x, (int) y - win->y); } -RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { +RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault) (RGFW_window* win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } -RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { +RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard) (RGFW_window* win, u8 mouse) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 + static const u8 mouseIconSrc[16] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; if (mouse > (sizeof(mouseIconSrc) / sizeof(u8))) @@ -5527,63 +6514,33 @@ RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { mouse = mouseIconSrc[mouse]; - Cursor cursor = XCreateFontCursor(win->src.display, mouse); - XDefineCursor(win->src.display, win->src.window, (Cursor) cursor); - - XFreeCursor(win->src.display, (Cursor) cursor); + Cursor cursor = XCreateFontCursor(_RGFW->display, mouse); + XDefineCursor(_RGFW->display, win->src.window, (Cursor) cursor); + XFreeCursor(_RGFW->display, (Cursor) cursor); return RGFW_TRUE; -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL { } - static const char* iconStrings[16] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" }; - - struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]); - RGFW_cursor_image = wlcursor->images[0]; - struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); - - wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); - wl_surface_commit(RGFW_cursor_surface); - return RGFW_TRUE; - -#endif } -void RGFW_window_hide(RGFW_window* win) { - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XUnmapWindow(win->src.display, win->src.window); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - wl_surface_attach(win->src.surface, NULL, 0, 0); - wl_surface_commit(win->src.surface); - win->_flags |= RGFW_windowHide; -#endif +void RGFW_FUNC(RGFW_window_hide)(RGFW_window* win) { + XUnmapWindow(_RGFW->display, win->src.window); } -void RGFW_window_show(RGFW_window* win) { - win->_flags &= ~(u32)RGFW_windowHide; - if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XMapWindow(win->src.display, win->src.window); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - /* wl_surface_attach(win->src.surface, win->rc., 0, 0); */ - wl_surface_commit(win->src.surface); -#endif +void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) { + win->internal.flags &= ~(u32)RGFW_windowHide; + if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); + + XMapWindow(_RGFW->display, win->src.window); + RGFW_window_move(win, win->x, win->y); + return; } -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { - RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 +RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr)(char* str, size_t strCapacity) { RGFW_init(); - if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) { + RGFW_LOAD_ATOM(XSEL_DATA); RGFW_LOAD_ATOM(UTF8_STRING); RGFW_LOAD_ATOM(CLIPBOARD); + if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) { if (str != NULL) - RGFW_STRNCPY(str, _RGFW.clipboard, _RGFW.clipboard_len - 1); - _RGFW.clipboard[_RGFW.clipboard_len - 1] = '\0'; - return (RGFW_ssize_t)_RGFW.clipboard_len - 1; + RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1); + _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0'; + return (RGFW_ssize_t)_RGFW->clipboard_len - 1; } XEvent event; @@ -5592,15 +6549,13 @@ RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { char* data; Atom target; - RGFW_LOAD_ATOM(XSEL_DATA); - - XConvertSelection(_RGFW.display, RGFW_XCLIPBOARD, RGFW_XUTF8_STRING, XSEL_DATA, _RGFW.helperWindow, CurrentTime); - XSync(_RGFW.display, 0); + XConvertSelection(_RGFW->display, CLIPBOARD, UTF8_STRING, XSEL_DATA, _RGFW->helperWindow, CurrentTime); + XSync(_RGFW->display, 0); while (1) { - XNextEvent(_RGFW.display, &event); + XNextEvent(_RGFW->display, &event); if (event.type != SelectionNotify) continue; - if (event.xselection.selection != RGFW_XCLIPBOARD || event.xselection.property == 0) + if (event.xselection.selection != CLIPBOARD || event.xselection.property == 0) return -1; break; } @@ -5613,7 +6568,7 @@ RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { if (sizeN > strCapacity && str != NULL) size = -1; - if ((target == RGFW_XUTF8_STRING || target == XA_STRING) && str != NULL) { + if ((target == UTF8_STRING || target == XA_STRING) && str != NULL) { RGFW_MEMCPY(str, data, sizeN); str[sizeN] = '\0'; XFree(data); @@ -5623,22 +6578,16 @@ RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { size = (RGFW_ssize_t)sizeN; return size; - #endif - #if defined(RGFW_WAYLAND) - RGFW_WAYLAND_LABEL RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); - return 0; - #endif } i32 RGFW_XHandleClipboardSelectionHelper(void) { -#ifdef RGFW_X11 RGFW_LOAD_ATOM(SAVE_TARGETS); XEvent event; - XPending(_RGFW.display); + XPending(_RGFW->display); - if (QLength(_RGFW.display) || XEventsQueued(_RGFW.display, QueuedAlready) + XEventsQueued(_RGFW.display, QueuedAfterReading)) - XNextEvent(_RGFW.display, &event); + if (QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading)) + XNextEvent(_RGFW->display, &event); else return 0; @@ -5654,60 +6603,41 @@ i32 RGFW_XHandleClipboardSelectionHelper(void) { } return 0; -#else - return 1; -#endif } -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_GOTO_WAYLAND(1); - #ifdef RGFW_X11 - RGFW_LOAD_ATOM(SAVE_TARGETS); +void RGFW_FUNC(RGFW_writeClipboard)(const char* text, u32 textLen) { + RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(CLIPBOARD); RGFW_init(); /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */ - XSetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD, _RGFW.helperWindow, CurrentTime); - if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) != _RGFW.helperWindow) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(_RGFW.root, 0), "X11 failed to become owner of clipboard selection"); + XSetSelectionOwner(_RGFW->display, CLIPBOARD, _RGFW->helperWindow, CurrentTime); + if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) != _RGFW->helperWindow) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "X11 failed to become owner of clipboard selection"); return; } - if (_RGFW.clipboard) - RGFW_FREE(_RGFW.clipboard); + if (_RGFW->clipboard) + RGFW_FREE(_RGFW->clipboard); - _RGFW.clipboard = (char*)RGFW_ALLOC(textLen); - RGFW_ASSERT(_RGFW.clipboard != NULL); + _RGFW->clipboard = (char*)RGFW_ALLOC(textLen); + RGFW_ASSERT(_RGFW->clipboard != NULL); - RGFW_STRNCPY(_RGFW.clipboard, text, textLen - 1); - _RGFW.clipboard[textLen - 1] = '\0'; - _RGFW.clipboard_len = textLen; - #endif - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - RGFW_UNUSED(text); RGFW_UNUSED(textLen); - #endif + RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1); + _RGFW->clipboard[textLen - 1] = '\0'; + _RGFW->clipboard_len = textLen; + return; } -RGFW_bool RGFW_window_isHidden(RGFW_window* win) { +RGFW_bool RGFW_FUNC(RGFW_window_isHidden)(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 - XWindowAttributes windowAttributes; - XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes); + XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes); return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win)); -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - return RGFW_FALSE; -#endif } -RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { +RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 RGFW_LOAD_ATOM(WM_STATE); Atom actual_type; @@ -5715,7 +6645,7 @@ RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { unsigned long nitems, bytes_after; unsigned char* prop_data; - i32 status = XGetWindowProperty(win->src.display, win->src.window, WM_STATE, 0, 2, False, + i32 status = XGetWindowProperty(_RGFW->display, win->src.window, WM_STATE, 0, 2, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data); @@ -5728,19 +6658,12 @@ RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { XFree(prop_data); XWindowAttributes windowAttributes; - XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes); + XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes); return windowAttributes.map_state != IsViewable; -#endif -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - return RGFW_FALSE; -#endif } -RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { +RGFW_bool RGFW_FUNC(RGFW_window_isMaximized)(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#ifdef RGFW_X11 RGFW_LOAD_ATOM(_NET_WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); @@ -5750,7 +6673,7 @@ RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { unsigned long nitems, bytes_after; unsigned char* prop_data; - i32 status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, 1024, False, + i32 status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, 1024, False, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data); @@ -5772,23 +6695,10 @@ RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { if (prop_data != NULL) XFree(prop_data); -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL; -#endif + return RGFW_FALSE; } -#ifndef RGFW_NO_DPI -u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi); -u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi) { - if (mi.hTotal == 0 || mi.vTotal == 0) return 0; - return (u32) RGFW_ROUND((double) mi.dotClock / ((double) mi.hTotal * (double) mi.vTotal)); -} -#endif - - -#ifdef RGFW_X11 static float XGetSystemContentDPI(Display* display, i32 screen) { float dpi = 96.0f; @@ -5812,49 +6722,53 @@ static float XGetSystemContentDPI(Display* display, i32 screen) { return dpi; } -#endif RGFW_monitor RGFW_XCreateMonitor(i32 screen); RGFW_monitor RGFW_XCreateMonitor(i32 screen) { RGFW_monitor monitor; RGFW_init(); - RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 - Display* display = _RGFW.display; + Display* display = _RGFW->display; if (screen == -1) screen = DefaultScreen(display); Screen* scrn = DefaultScreenOfDisplay(display); - RGFW_area size = RGFW_AREA(scrn->width, scrn->height); monitor.x = 0; monitor.y = 0; - monitor.mode.area = RGFW_AREA(size.w, size.h); + monitor.mode.w = scrn->width; + monitor.mode.h = scrn->height; monitor.physW = (float)DisplayWidthMM(display, screen) / 25.4f; monitor.physH = (float)DisplayHeightMM(display, screen) / 25.4f; - RGFW_splitBPP((u32)DefaultDepth(display, DefaultScreen(display)), &monitor.mode); + RGFW_splitBPP((u32)DefaultDepth(display, screen), &monitor.mode); char* name = XDisplayName((const char*)display); RGFW_STRNCPY(monitor.name, name, sizeof(monitor.name) - 1); monitor.name[sizeof(monitor.name) - 1] = '\0'; float dpi = XGetSystemContentDPI(display, screen); - monitor.pixelRatio = dpi >= 192.0f ? 2 : 1; + monitor.pixelRatio = dpi >= 192.0f ? 2 : 1.0f; monitor.scaleX = (float) (dpi) / 96.0f; monitor.scaleY = (float) (dpi) / 96.0f; #ifndef RGFW_NO_DPI - XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); - monitor.mode.refreshRate = RGFW_XCalculateRefreshRate(sr->modes[screen]); + XRRCrtcInfo* ci = NULL; + XRRScreenResources* sr = NULL; - XRRCrtcInfo* ci = NULL; + { + XRRScreenConfiguration* conf = XRRGetScreenInfo(display, RootWindow(display, screen)); + monitor.mode.refreshRate = (u32)XRRConfigCurrentRate(conf); + + sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); int crtc = screen; if (sr->ncrtc > crtc) { ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]); } + + XRRFreeScreenConfigInfo(conf); + } #endif #ifndef RGFW_NO_DPI @@ -5862,7 +6776,7 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { if (info == NULL || ci == NULL) { XRRFreeScreenResources(sr); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); return monitor; } @@ -5873,18 +6787,21 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1); monitor.name[sizeof(monitor.name) - 1] = '\0'; - if ((u8)physW && (u8)physH) { - monitor.physW = physW; - monitor.physH = physH; - } + XRRFreeOutputInfo(info); + info = NULL; - monitor.x = ci->x; - monitor.y = ci->y; + if (physW > 0.0f && physH > 0.0f) { + monitor.physW = physW; + monitor.physH = physH; + } - if (ci->width && ci->height) { - monitor.mode.area.w = (u32)ci->width; - monitor.mode.area.h = (u32)ci->height; - } + monitor.x = ci->x; + monitor.y = ci->y; + + if (ci->width && ci->height) { + monitor.mode.w = (i32)ci->width; + monitor.mode.h = (i32)ci->height; + } #endif #ifndef RGFW_NO_DPI @@ -5892,24 +6809,15 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { XRRFreeScreenResources(sr); #endif - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); return monitor; -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL RGFW_UNUSED(screen); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); - return monitor; -#endif } -RGFW_monitor* RGFW_getMonitors(size_t* len) { +RGFW_monitor* RGFW_FUNC(RGFW_getMonitors)(size_t* len) { static RGFW_monitor monitors[7]; - - RGFW_GOTO_WAYLAND(1); - #ifdef RGFW_X11 RGFW_init(); - Display* display = _RGFW.display; + Display* display = _RGFW->display; i32 max = ScreenCount(display); i32 i; @@ -5919,52 +6827,41 @@ RGFW_monitor* RGFW_getMonitors(size_t* len) { if (len != NULL) *len = (size_t)((max <= 6) ? (max) : (6)); return monitors; - #endif - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL RGFW_UNUSED(len); - return monitors; /* TODO WAYLAND */ - #endif } -RGFW_monitor RGFW_getPrimaryMonitor(void) { - RGFW_GOTO_WAYLAND(1); - #ifdef RGFW_X11 +RGFW_monitor RGFW_FUNC(RGFW_getPrimaryMonitor)(void) { return RGFW_XCreateMonitor(-1); - #endif - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL return (RGFW_monitor){ 0 }; /* TODO WAYLAND */ - #endif } -RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { - RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 +RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { #ifndef RGFW_NO_DPI RGFW_init(); - XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW.display, DefaultRootWindow(_RGFW.display)); + XRRScreenConfiguration *conf = XRRGetScreenInfo(_RGFW->display, DefaultRootWindow(_RGFW->display)); + XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW->display, DefaultRootWindow(_RGFW->display)); if (screenRes == NULL) return RGFW_FALSE; int i; for (i = 0; i < screenRes->ncrtc; i++) { - XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW.display, screenRes, screenRes->crtcs[i]); + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW->display, screenRes, screenRes->crtcs[i]); if (!crtcInfo) continue; - if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.area.w == crtcInfo->width && (u32)mon.mode.area.h == crtcInfo->height) { + if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.w == crtcInfo->width && (u32)mon.mode.h == crtcInfo->height) { RRMode rmode = None; int index; for (index = 0; index < screenRes->nmode; index++) { RGFW_monitorMode foundMode; - foundMode.area = RGFW_AREA(screenRes->modes[index].width, screenRes->modes[index].height); - foundMode.refreshRate = RGFW_XCalculateRefreshRate(screenRes->modes[index]); - RGFW_splitBPP((u32)DefaultDepth(_RGFW.display, DefaultScreen(_RGFW.display)), &foundMode); + foundMode.w = (i32)screenRes->modes[index].width; + foundMode.h = (i32)screenRes->modes[index].height; + foundMode.refreshRate = (u32)XRRConfigCurrentRate(conf); + RGFW_splitBPP((u32)DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)), &foundMode); if (RGFW_monitorModeCompare(mode, foundMode, request)) { rmode = screenRes->modes[index].id; RROutput output = screenRes->outputs[i]; - XRROutputInfo* info = XRRGetOutputInfo(_RGFW.display, screenRes, output); + XRROutputInfo* info = XRRGetOutputInfo(_RGFW->display, screenRes, output); if (info) { - XRRSetCrtcConfig(_RGFW.display, screenRes, screenRes->crtcs[i], + XRRSetCrtcConfig(_RGFW->display, screenRes, screenRes->crtcs[i], CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1); XRRFreeOutputInfo(info); XRRFreeCrtcInfo(crtcInfo); @@ -5983,144 +6880,394 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW } XRRFreeScreenResources(screenRes); - return RGFW_FALSE; - #endif -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); + XRRFreeScreenConfigInfo(conf); #endif return RGFW_FALSE; } -RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { +RGFW_monitor RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) { RGFW_monitor mon; RGFW_MEMSET(&mon, 0, sizeof(mon)); RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(1); -#ifdef RGFW_X11 + XWindowAttributes attrs; - if (!XGetWindowAttributes(win->src.display, win->src.window, &attrs)) { + if (!XGetWindowAttributes(_RGFW->display, win->src.window, &attrs)) { return mon; } i32 i; - for (i = 0; i < ScreenCount(win->src.display) && i < 6; i++) { - Screen* screen = ScreenOfDisplay(win->src.display, i); + for (i = 0; i < ScreenCount(_RGFW->display) && i < 6; i++) { + Screen* screen = ScreenOfDisplay(_RGFW->display, i); if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) && attrs.y >= 0 && attrs.y < XHeightOfScreen(screen)) return RGFW_XCreateMonitor(i); } -#endif -#ifdef RGFW_WAYLAND -RGFW_WAYLAND_LABEL -#endif return mon; } -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) -void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { +#ifdef RGFW_OPENGL +RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* context, RGFW_glHints* hints) { + /* for checking extensions later */ + const char sRGBARBstr[] = "GLX_ARB_framebuffer_sRGB"; + const char sRGBEXTstr[] = "GLX_EXT_framebuffer_sRGB"; + const char noErorrStr[] = "GLX_ARB_create_context_no_error"; + const char flushStr[] = "GLX_ARB_context_flush_control"; + const char robustStr[] = "GLX_ARB_create_context_robustness"; + + /* basic RGFW int */ + win->src.ctx.native = context; + win->src.gfxType = RGFW_gfxNativeOpenGL; + /* This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */ + if (win->src.window) RGFW_window_closePlatform(win); + + RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent); + + /* start by creating a GLX config / X11 Viusal */ + XVisualInfo visual; + GLXFBConfig bestFbc; + + i32 visual_attribs[40]; + RGFW_attribStack stack; + RGFW_attribStack_init(&stack, visual_attribs, 40); + RGFW_attribStack_pushAttribs(&stack, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR); + RGFW_attribStack_pushAttribs(&stack, GLX_X_RENDERABLE, 1); + RGFW_attribStack_pushAttribs(&stack, GLX_RENDER_TYPE, GLX_RGBA_BIT); + RGFW_attribStack_pushAttribs(&stack, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT); + RGFW_attribStack_pushAttribs(&stack, GLX_DOUBLEBUFFER, 1); + RGFW_attribStack_pushAttribs(&stack, GLX_ALPHA_SIZE, hints->alpha); + RGFW_attribStack_pushAttribs(&stack, GLX_DEPTH_SIZE, hints->depth); + RGFW_attribStack_pushAttribs(&stack, GLX_STENCIL_SIZE, hints->stencil); + RGFW_attribStack_pushAttribs(&stack, GLX_STEREO, hints->stereo); + RGFW_attribStack_pushAttribs(&stack, GLX_AUX_BUFFERS, hints->auxBuffers); + RGFW_attribStack_pushAttribs(&stack, GLX_RED_SIZE, hints->red); + RGFW_attribStack_pushAttribs(&stack, GLX_GREEN_SIZE, hints->green); + RGFW_attribStack_pushAttribs(&stack, GLX_BLUE_SIZE, hints->blue); + RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_RED_SIZE, hints->accumRed); + RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_GREEN_SIZE, hints->accumGreen); + RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_BLUE_SIZE, hints->accumBlue); + RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_ALPHA_SIZE, hints->accumAlpha); + + if (hints->sRGB) { + if (RGFW_extensionSupportedPlatform_OpenGL(sRGBARBstr, sizeof(sRGBARBstr))) + RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, hints->sRGB); + if (RGFW_extensionSupportedPlatform_OpenGL(sRGBEXTstr, sizeof(sRGBEXTstr))) + RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, hints->sRGB); + } + + RGFW_attribStack_pushAttribs(&stack, 0, 0); + + /* find the configs */ + i32 fbcount; + GLXFBConfig* fbc = glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount); + + i32 best_fbc = -1; + i32 best_depth = 0; + i32 best_samples = 0; + + if (fbcount == 0) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to find any valid GLX visual configs."); + return 0; + } + + /* search through all found configs to find the best match */ + i32 i; + for (i = 0; i < fbcount; i++) { + XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, fbc[i]); + if (vi == NULL) + continue; + + i32 samp_buf, samples; + glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); + glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLES, &samples); + + if (best_fbc == -1) best_fbc = i; + if ((!(transparent) || vi->depth == 32) && best_depth == 0) { + best_fbc = i; + best_depth = vi->depth; + } + if ((!(transparent) || vi->depth == 32) && samples <= hints->samples && samples > best_samples) { + best_fbc = i; + best_depth = vi->depth; + best_samples = samples; + } + XFree(vi); + } + + if (best_fbc == -1) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to get a valid GLX visual."); + return 0; + } + + /* we found a config */ + bestFbc = fbc[best_fbc]; + XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, bestFbc); + if (vi->depth != 32 && transparent) + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to to find a matching visual with a 32-bit depth."); + + if (best_samples < hints->samples) + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a matching sample count."); + + XFree(fbc); + visual = *vi; + XFree(vi); + + /* use the visual to create a new window */ + RGFW_XCreateWindow(visual, "", win->internal.flags, win); + + /* create the actual OpenGL context */ + i32 context_attribs[40]; + RGFW_attribStack_init(&stack, context_attribs, 40); + + i32 mask = 0; + switch (hints->profile) { + case RGFW_glES: mask |= GLX_CONTEXT_ES_PROFILE_BIT_EXT; break; + case RGFW_glCompatibility: mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break; + case RGFW_glCore: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break; + default: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break; + } + + RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_PROFILE_MASK_ARB, mask); + + if (hints->minor || hints->major) { + RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MAJOR_VERSION_ARB, hints->major); + RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MINOR_VERSION_ARB, hints->minor); + } + + + if (RGFW_extensionSupportedPlatform_OpenGL(flushStr, sizeof(flushStr))) { + if (hints->releaseBehavior == RGFW_glReleaseFlush) { + RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } else if (hints->releaseBehavior == RGFW_glReleaseNone) { + RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + } + + i32 flags = 0; + if (hints->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustStr, sizeof(robustStr))) flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + if (flags) { + RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_FLAGS_ARB, flags); + } + + if (RGFW_extensionSupportedPlatform_OpenGL(noErorrStr, sizeof(noErorrStr))) { + RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError); + } + + RGFW_attribStack_pushAttribs(&stack, 0, 0); + + /* create the context */ + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + char str[] = "glXCreateContextAttribsARB"; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((u8*) str); + + GLXContext ctx = NULL; + if (hints->share) { + ctx = hints->share->ctx; + } + + if (glXCreateContextAttribsARB == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load proc address 'glXCreateContextAttribsARB', loading a generic OpenGL context."); + win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True); + } else { + _RGFW->x11Error = NULL; + win->src.ctx.native->ctx = glXCreateContextAttribsARB(_RGFW->display, bestFbc, ctx, True, context_attribs); + if (_RGFW->x11Error || win->src.ctx.native->ctx == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL context with AttribsARB, loading a generic OpenGL context."); + win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True); + } + } + + #ifndef RGFW_NO_GLXWINDOW + win->src.ctx.native->window = glXCreateWindow(_RGFW->display, bestFbc, win->src.window, NULL); + #else + win->src.ctx.native->window = win->src.window; + #endif + + glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext)win->src.ctx.native->ctx); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); + + return RGFW_TRUE; +} + +void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) { + #ifndef RGFW_NO_GLXWINDOW + if (win->src.ctx.native->window != win->src.window) { + glXDestroyWindow(_RGFW->display, win->src.ctx.native->window); + } + #endif + + glXDestroyContext(_RGFW->display, ctx->ctx); + win->src.ctx.native = NULL; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); +} + +RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL)(const char * extension, size_t len) { + RGFW_init(); + const char* extensions = glXQueryExtensionsString(_RGFW->display, XDefaultScreen(_RGFW->display)); + return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len); +} + +RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL)(const char* procname) { return glXGetProcAddress((u8*) procname); } + +void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.native); if (win == NULL) glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL); else - glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); + glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx); + return; } -void* RGFW_getCurrent_OpenGL(void) { return glXGetCurrentContext(); } -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { glXSwapBuffers(win->src.display, win->src.window); } -#endif +void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return glXGetCurrentContext(); } +void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_ASSERT(win->src.ctx.native); glXSwapBuffers(_RGFW->display, win->src.ctx.native->window); } -void RGFW_window_swapBuffers_software(RGFW_window* win) { +void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) { RGFW_ASSERT(win != NULL); - RGFW_GOTO_WAYLAND(0); -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - #ifdef RGFW_X11 - win->src.bitmap->data = (char*) win->buffer; - RGFW_RGB_to_BGR(win, (u8*)win->src.bitmap->data); - XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, win->bufferSize.w, win->bufferSize.h); - win->src.bitmap->data = NULL; - return; - #endif - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA) - RGFW_RGB_to_BGR(win, win->src.buffer); - #else - size_t y; - for (y = 0; y < win->r.h; y++) { - u32 index = (y * 4 * win->r.w); - u32 index2 = (y * 4 * win->bufferSize.w); - RGFW_MEMCPY(&win->src.buffer[index], &win->buffer[index2], win->r.w * 4); - } - #endif + /* cached pfn to avoid calling glXGetProcAddress more than once */ + static PFNGLXSWAPINTERVALEXTPROC pfn = NULL; + static int (*pfn2)(int) = NULL; - wl_surface_frame_done(win, NULL, 0); - wl_surface_commit(win->src.surface); - #endif -#else -#ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL -#endif - RGFW_UNUSED(win); -#endif -} - -#if !defined(RGFW_EGL) - -void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { - RGFW_ASSERT(win != NULL); - - #if defined(RGFW_OPENGL) - // cached pfn to avoid calling glXGetProcAddress more than once - static PFNGLXSWAPINTERVALEXTPROC pfn = (PFNGLXSWAPINTERVALEXTPROC)123; - static int (*pfn2)(int) = NULL; - - if (pfn == (PFNGLXSWAPINTERVALEXTPROC)123) { - pfn = ((PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT")); + if (pfn == NULL) { + u8 str[] = "glXSwapIntervalEXT"; + pfn = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress(str); if (pfn == NULL) { - const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"}; - u32 i; - for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++) - pfn2 = ((int(*)(int))glXGetProcAddress((GLubyte*) array[i])); + pfn = (PFNGLXSWAPINTERVALEXTPROC)1; + const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"}; - if (pfn2 != NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function, fallingback to the native swapinterval function"); - } else { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function"); - } - } - } - if (pfn != NULL) - pfn(win->src.display, win->src.window, swapInterval); - else if (pfn2 != NULL) { - pfn2(swapInterval); - } - #else - RGFW_UNUSED(swapInterval); - #endif + size_t i; + for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++) { + pfn2 = (int(*)(int))glXGetProcAddress((u8*)array[i]); + } + + if (pfn2 != NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function, fallingback to the native swapinterval function"); + } else { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function"); + } + } + } + + if (pfn != (PFNGLXSWAPINTERVALEXTPROC)1) { + pfn(_RGFW->display, win->src.ctx.native->window, swapInterval); + } + else if (pfn2 != NULL) { + pfn2(swapInterval); + } } -#endif +#endif /* RGFW_OPENGL */ -void RGFW_deinit(void) { - if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) return; +i32 RGFW_initPlatform_X11(void) { + #ifdef RGFW_USE_XDL + XDL_init(); + #endif + + #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) + #if defined(__CYGWIN__) + RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so"); + #elif defined(__OpenBSD__) || defined(__NetBSD__) + RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so"); + #else + RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1"); + #endif + RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate); + RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy); + RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor); + #endif + + #if !defined(RGFW_NO_X11_XI_PRELOAD) + #if defined(__CYGWIN__) + RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so"); + #elif defined(__OpenBSD__) || defined(__NetBSD__) + RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so"); + #else + RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6"); + #endif + RGFW_PROC_DEF(X11Xihandle, XISelectEvents); + #endif + + #if !defined(RGFW_NO_X11_EXT_PRELOAD) + #if defined(__CYGWIN__) + RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so"); + #elif defined(__OpenBSD__) || defined(__NetBSD__) + RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so"); + #else + RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6"); + #endif + RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter); + RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue); + RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter); + RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion); + RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask); + #endif + + XInitThreads(); /*!< init X11 threading */ + _RGFW->display = XOpenDisplay(0); + _RGFW->context = XUniqueContext(); + + XSetWindowAttributes wa; + RGFW_MEMSET(&wa, 0, sizeof(wa)); + wa.event_mask = PropertyChangeMask; + _RGFW->helperWindow = XCreateWindow(_RGFW->display, XDefaultRootWindow(_RGFW->display), 0, 0, 1, 1, 0, 0, + InputOnly, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), CWEventMask, &wa); + + u8 RGFW_blk[] = { 0, 0, 0, 0 }; + _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); + _RGFW->clipboard = NULL; + + XkbComponentNamesRec rec; + XkbDescPtr desc = XkbGetMap(_RGFW->display, 0, XkbUseCoreKbd); + XkbDescPtr evdesc; + XSetErrorHandler(RGFW_XErrorHandler); + u8 old[256]; + + XkbGetNames(_RGFW->display, XkbKeyNamesMask, desc); + + RGFW_MEMSET(&rec, 0, sizeof(rec)); + char evdev[] = "evdev"; + rec.keycodes = evdev; + evdesc = XkbGetKeyboardByName(_RGFW->display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False); + /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */ + if(evdesc != NULL && desc != NULL) { + int i, j; + for(i = 0; i < (int)sizeof(old); i++){ + old[i] = _RGFW->keycodes[i]; + _RGFW->keycodes[i] = 0; + } + for(i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){ + for(j = desc->min_key_code; j <= desc->max_key_code; j++){ + if(RGFW_STRNCMP(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){ + _RGFW->keycodes[j] = old[i]; + break; + } + } + } + XkbFreeKeyboard(desc, 0, True); + XkbFreeKeyboard(evdesc, 0, True); + } + return 0; +} + +void RGFW_deinitPlatform_X11(void) { #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL; -#ifdef RGFW_X11 /* to save the clipboard on the x server after the window is closed */ - RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); + RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); RGFW_LOAD_ATOM(CLIPBOARD); RGFW_LOAD_ATOM(SAVE_TARGETS); - if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) { - XConvertSelection(_RGFW.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW.helperWindow, CurrentTime); + if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) { + XConvertSelection(_RGFW->display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW->helperWindow, CurrentTime); while (RGFW_XHandleClipboardSelectionHelper()); } - if (_RGFW.clipboard) { - RGFW_FREE(_RGFW.clipboard); - _RGFW.clipboard = NULL; + if (_RGFW->clipboard) { + RGFW_FREE(_RGFW->clipboard); + _RGFW->clipboard = NULL; } - RGFW_freeMouse(_RGFW.hiddenMouse); + if (_RGFW->hiddenMouse) { + RGFW_freeMouse(_RGFW->hiddenMouse); + _RGFW->hiddenMouse = NULL; + } - XDestroyWindow(_RGFW.display, (Drawable) _RGFW.helperWindow); /*!< close the window */ - XCloseDisplay(_RGFW.display); /*!< kill connection to the x server */ + XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /*!< close the window */ + XCloseDisplay(_RGFW->display); /*!< kill connection to the x server */ #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) RGFW_FREE_LIBRARY(X11Cursorhandle); @@ -6136,210 +7283,1592 @@ void RGFW_deinit(void) { #if !defined(RGFW_NO_X11_EXT_PRELOAD) RGFW_FREE_LIBRARY(X11XEXThandle); #endif -#endif -#ifdef RGFW_WAYLAND - wl_display_disconnect(_RGFW.wl_display); -#endif - #ifndef RGFW_NO_LINUX - if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){ - close(RGFW_eventWait_forceStop[0]); - close(RGFW_eventWait_forceStop[1]); - } - - u8 i; - for (i = 0; i < RGFW_gamepadCount; i++) { - if(RGFW_gamepads[i]) - close(RGFW_gamepads[i]); - } - #endif - - _RGFW.root = NULL; - _RGFW.windowCount = -1; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); } -void RGFW_window_close(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); +void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) { + if (win->internal.holdMouse) + XUngrabPointer(_RGFW->display, CurrentTime); - RGFW_GOTO_WAYLAND(0); - #ifdef RGFW_X11 - /* ungrab pointer if it was grabbed */ - if (win->_flags & RGFW_HOLD_MOUSE) - XUngrabPointer(win->src.display, CurrentTime); - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if (win->buffer != NULL) { - if ((win->_flags & RGFW_BUFFER_ALLOC)) - RGFW_FREE(win->buffer); - XDestroyImage((XImage*) win->src.bitmap); - } - #endif - - XFreeGC(win->src.display, win->src.gc); - XDestroyWindow(win->src.display, (Drawable) win->src.window); /*!< close the window */ - win->src.window = 0; - XCloseDisplay(win->src.display); - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } + XFreeGC(_RGFW->display, win->src.gc); + XDeleteContext(_RGFW->display, win->src.window, _RGFW->context); + XDestroyWindow(_RGFW->display, (Drawable) win->src.window); /*!< close the window */ return; - #endif - - #ifdef RGFW_WAYLAND - RGFW_WAYLAND_LABEL - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); - - xdg_toplevel_destroy(win->src.xdg_toplevel); - xdg_surface_destroy(win->src.xdg_surface); - wl_surface_destroy(win->src.surface); - - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - wl_buffer_destroy(win->src.wl_buffer); - if ((win->_flags & RGFW_BUFFER_ALLOC)) - RGFW_FREE(win->buffer); - - munmap(win->src.buffer, (size_t)(win->r.w * win->r.h * 4)); - #endif - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } - #endif } +#ifdef RGFW_WEBGPU +WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) { + WGPUSurfaceDescriptor surfaceDesc = {0}; + WGPUSurfaceSourceXlibWindow fromXlib = {0}; + fromXlib.chain.sType = WGPUSType_SurfaceSourceXlibWindow; + fromXlib.display = _RGFW->display; + fromXlib.window = window->src.window; + surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromXlib.chain; + return wgpuInstanceCreateSurface(instance, &surfaceDesc); +} +#endif + +#endif /* End of X11 linux / wayland / unix defines */ -#include -#include -#include +/* -void RGFW_stopCheckEvents(void) { + Start of Wayland defayland +*/ - RGFW_eventWait_forceStop[2] = 1; - while (1) { - const char byte = 0; - const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1); - if (result == 1 || result == -1) - break; - } -} - -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - if (waitMS == 0) return; - - u8 i; - if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) { - if (pipe(RGFW_eventWait_forceStop) != -1) { - fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0); - fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0); - fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0); - fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0); - } - } - - struct pollfd fds[] = { - #ifdef RGFW_WAYLAND - { wl_display_get_fd(win->src.wl_display), POLLIN, 0 }, - #else - { ConnectionNumber(win->src.display), POLLIN, 0 }, - #endif - #ifdef RGFW_X11 - { ConnectionNumber(_RGFW.display), POLLIN, 0 }, - #endif - { RGFW_eventWait_forceStop[0], POLLIN, 0 }, - #if defined(__linux__) - { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0} - #endif - }; - - u8 index = 2; +#ifdef RGFW_WAYLAND #ifdef RGFW_X11 - index++; +#undef RGFW_FUNC /* remove previous define */ +#define RGFW_FUNC(func) func##_Wayland +#else +#define RGFW_FUNC(func) func #endif - #if defined(__linux__) || defined(__NetBSD__) - for (i = 0; i < RGFW_gamepadCount; i++) { - if (RGFW_gamepads[i] == 0) - continue; +/* +Wayland TODO: (out of date) +- fix RGFW_keyPressed lock state - fds[index].fd = RGFW_gamepads[i]; - index++; + RGFW_windowMoved, the window was moved (by the user) + RGFW_windowRefresh The window content needs to be refreshed + + RGFW_dataDrop a file has been dropped into the window + RGFW_dataDrag + +- window args: + #define RGFW_windowNoResize the window cannot be resized by the user + #define RGFW_windowAllowDND the window supports drag and drop + #define RGFW_scaleToMonitor scale the window to the screen + +- other missing functions functions ("TODO wayland") (~30 functions) +- fix buffer rendering weird behavior +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct wl_display* RGFW_getDisplay_Wayland(void) { return _RGFW->wl_display; } +struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { return win->src.surface; } + + +/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */ +#include "xdg-shell.h" +#include "xdg-toplevel-icon-v1.h" +#include "xdg-decoration-unstable-v1.h" +#include "relative-pointer-unstable-v1.h" +#include "pointer-constraints-unstable-v1.h" +#include "xdg-output-unstable-v1.h" + + +void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized); + +static void RGFW_wl_setOpaque(RGFW_window* win) { + struct wl_region* wl_region = wl_compositor_create_region(_RGFW->compositor); + + if (!wl_region) return; /* return if no region was created */ + + wl_region_add(wl_region, 0, 0, win->w, win->h); + wl_surface_set_opaque_region(win->src.surface, wl_region); + wl_region_destroy(wl_region); + +} + +static void RGFW_wl_xdg_wm_base_ping_handler(void* data, struct xdg_wm_base* wm_base, + u32 serial) { + RGFW_UNUSED(data); + xdg_wm_base_pong(wm_base, serial); +} +static void RGFW_wl_xdg_surface_configure_handler(void* data, struct xdg_surface* xdg_surface, + u32 serial) { + + xdg_surface_ack_configure(xdg_surface, serial); + + RGFW_window* win = (RGFW_window*)data; + + if (win == NULL) { + win = _RGFW->kbOwner; + if (win == NULL) + return; + } + + /* useful for libdecor */ + if (win->src.activated != win->src.pending_activated) { + win->src.activated = win->src.pending_activated; + } + + if (win->src.maximized != win->src.pending_maximized) { + RGFW_toggleWaylandMaximized(win, win->src.pending_maximized); + + RGFW_window_checkMode(win); + } + + + if (win->src.resizing) { + + /* Do not create a resize event if the window is maximized */ + if (!win->src.maximized && win->internal.enabledEvents & RGFW_windowResizedFlag) { + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); + RGFW_windowResizedCallback(win, win->w, win->h); + } + RGFW_window_resize(win, win->w, win->h); + if (!(win->internal.flags & RGFW_windowTransparent)) { + RGFW_wl_setOpaque(win); } - #endif - - - u64 start = RGFW_getTimeNS(); - - - #ifdef RGFW_WAYLAND - while (wl_display_dispatch(win->src.wl_display) <= 0 - #else - while (XPending(win->src.display) == 0 - #endif - #ifdef RGFW_X11 - && XPending(_RGFW.display) == 0 - #endif - ) { - if (poll(fds, index, waitMS) <= 0) - break; - - if (waitMS != RGFW_eventWaitNext) - waitMS -= (i32)(RGFW_getTimeNS() - start) / (i32)1e+6; } - /* drain any data in the stop request */ - if (RGFW_eventWait_forceStop[2]) { - char data[64]; - (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data)); +} - RGFW_eventWait_forceStop[2] = 0; +static void RGFW_wl_xdg_toplevel_configure_handler(void* data, struct xdg_toplevel* toplevel, + i32 width, i32 height, struct wl_array* states) { + + RGFW_UNUSED(toplevel); + RGFW_window* win = (RGFW_window*)data; + + + win->src.pending_activated = RGFW_FALSE; + win->src.pending_maximized = RGFW_FALSE; + win->src.resizing = RGFW_FALSE; + + + enum xdg_toplevel_state* state; + wl_array_for_each(state, states) { + switch (*state) { + case XDG_TOPLEVEL_STATE_ACTIVATED: + win->src.pending_activated = RGFW_TRUE; + break; + case XDG_TOPLEVEL_STATE_MAXIMIZED: + win->src.pending_maximized = RGFW_TRUE; + break; + default: + break; + } + + } + /* if width and height are not zero and are not the same as the window */ + /* the window is resizing so update the values */ + if ((width && height) && (win->w != width || win->h != height)) { + win->src.resizing = RGFW_TRUE; + win->src.w = win->w = width; + win->src.h = win->h = height; } } -i32 RGFW_getClock(void); -i32 RGFW_getClock(void) { - static i32 clock = -1; - if (clock != -1) return clock; +static void RGFW_wl_xdg_toplevel_close_handler(void* data, struct xdg_toplevel *toplevel) { + RGFW_UNUSED(toplevel); + RGFW_window* win = (RGFW_window*)data; - #if defined(_POSIX_MONOTONIC_CLOCK) - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - clock = CLOCK_MONOTONIC; - #else - clock = CLOCK_REALTIME; - #endif - - return clock; + if (!win->internal.shouldClose) { + RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); + RGFW_window_setShouldClose(win, RGFW_TRUE); + RGFW_windowQuitCallback(win); + } } -u64 RGFW_getTimerFreq(void) { return 1000000000LLU; } -u64 RGFW_getTimerValue(void) { +static void RGFW_wl_xdg_decoration_configure_handler(void* data, + struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, u32 mode) { + RGFW_window* win = (RGFW_window*)data; RGFW_UNUSED(zxdg_toplevel_decoration_v1); + + /* this is expected to run once */ + /* set the decoration mode set by earlier request */ + if (mode != win->src.decoration_mode) { + win->src.decoration_mode = mode; + } +} + +static void RGFW_wl_shm_format_handler(void* data, struct wl_shm *shm, u32 format) { + RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format); +} + +static void RGFW_wl_relative_pointer_motion(void *data, struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, + u32 time_hi, u32 time_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) { + + RGFW_UNUSED(zwp_relative_pointer_v1); RGFW_UNUSED(time_hi); RGFW_UNUSED(time_lo); + RGFW_UNUSED(dx_unaccel); RGFW_UNUSED(dy_unaccel); + + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_window* win = RGFW->mouseOwner; + + RGFW_ASSERT(win); + + float vecX = (float)wl_fixed_to_double(dx); + float vecY = (float)wl_fixed_to_double(dy); + + RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; + e.mouse.x = win->internal.lastMouseX; + e.mouse.y = win->internal.lastMouseY; + e.mouse.vecX = vecX; + e.mouse.vecY = vecY; + e.common.win = win); + + RGFW->vectorX = vecX; + RGFW->vectorY = vecY; + RGFW_mousePosCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, vecX, vecY); +} + +static void RGFW_wl_pointer_locked(void *data, struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) { + RGFW_UNUSED(zwp_locked_pointer_v1); + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_window* win = RGFW->mouseOwner; + + win->internal.lastMouseX = win->w / 2; + win->internal.lastMouseY = win->h / 2; + zwp_locked_pointer_v1_set_cursor_position_hint(win->src.locked_pointer, wl_fixed_from_int((win->w / 2)), wl_fixed_from_int((win->h / 2))); + wl_pointer_set_cursor(RGFW->wl_pointer, RGFW->mouse_enter_serial, NULL, 0, 0); /* draw no cursor */ +} + +static void RGFW_wl_pointer_enter(void* data, struct wl_pointer* pointer, u32 serial, + struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + + /* save when the pointer is locked or using default cursor */ + RGFW->mouse_enter_serial = serial; + win->internal.mouseInside = RGFW_TRUE; + RGFW->windowState.win = win; + RGFW->windowState.mouseEnter = RGFW_TRUE; + + RGFW->mouseOwner = win; + + /* set the cursor */ + if (win->src.using_custom_cursor) { + wl_pointer_set_cursor(pointer, serial, win->src.custom_cursor_surface, 0, 0); + } + else { + RGFW_window_setMouseDefault(win); + } + + if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; + + i32 x = (i32)wl_fixed_to_double(surface_x); + i32 y = (i32)wl_fixed_to_double(surface_y); + + RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter; + e.mouse.x = x; + e.mouse.y = y; + e.common.win = win); + + win->internal.lastMouseX = x; + win->internal.lastMouseY = y; + + RGFW_mouseNotifyCallback(win, x, y, RGFW_TRUE); +} + +static void RGFW_wl_pointer_leave(void* data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface) { + RGFW_UNUSED(pointer); RGFW_UNUSED(serial); + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + RGFW_info* RGFW = (RGFW_info*)data; + if (RGFW->mouseOwner == win) + RGFW->mouseOwner = NULL; + + win->internal.mouseInside = RGFW_FALSE; + RGFW->windowState.winLeave = win; + RGFW->windowState.mouseLeave = RGFW_TRUE; + + if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; + + RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave; + e.mouse.x = win->internal.lastMouseX; + e.mouse.y = win->internal.lastMouseY; + e.common.win = win); + + RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE); +} + +static void RGFW_wl_pointer_motion(void* data, struct wl_pointer *pointer, u32 time, wl_fixed_t x, wl_fixed_t y) { + RGFW_UNUSED(pointer); RGFW_UNUSED(time); + + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_ASSERT(RGFW->mouseOwner != NULL); + + RGFW_window* win = RGFW->mouseOwner; + + if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return; + + i32 convertedX = (i32)wl_fixed_to_double(x); + i32 convertedY = (i32)wl_fixed_to_double(y); + float newVecX = (float)(convertedX - win->internal.lastMouseX); + float newVecY = (float)(convertedY - win->internal.lastMouseY); + + RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; + e.mouse.x = convertedX; + e.mouse.y = convertedY; + e.mouse.vecX = newVecX; + e.mouse.vecY = newVecY; + e.common.win = win); + + RGFW->vectorX = newVecX; + RGFW->vectorY = newVecY; + win->internal.lastMouseX = convertedX; + win->internal.lastMouseY = convertedY; + RGFW_mousePosCallback(win, convertedX, convertedY, newVecX, newVecY); +} + +static void RGFW_wl_pointer_button(void* data, struct wl_pointer *pointer, u32 serial, u32 time, u32 button, u32 state) { + RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); + RGFW_info* RGFW = (RGFW_info*)data; + + RGFW_ASSERT(RGFW->mouseOwner != NULL); + RGFW_window* win = RGFW->mouseOwner; + + if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseButtonReleased - RGFW_BOOL(state))))) return; + u32 b = (button - 0x110); + + /* flip right and middle button codes */ + if (b == 1) b = 2; + else if (b == 2) b = 1; + + RGFW->mouseButtons[b].prev = RGFW->mouseButtons[b].current; + RGFW->mouseButtons[b].current = RGFW_BOOL(state); + + RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased - RGFW_BOOL(state); + e.button.value = (u8)b; + e.common.win = win); + RGFW_mouseButtonCallback(win, (u8)b, RGFW_BOOL(state)); +} + +static void RGFW_wl_pointer_axis(void* data, struct wl_pointer *pointer, u32 time, u32 axis, wl_fixed_t value) { + RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis); + + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_ASSERT(RGFW->mouseOwner != NULL); + RGFW_window* win = RGFW->mouseOwner; + + float scrollX = 0.0; + float scrollY = 0.0; + + if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseScroll)))) return; + + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) + scrollX = (float)(-wl_fixed_to_double(value) / 10.0); + else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + scrollY = (float)(-wl_fixed_to_double(value) / 10.0); + + + RGFW->scrollX = (float)scrollX; + RGFW->scrollY = (float)scrollY; + RGFW_mouseScrollCallback(win, scrollX, scrollY); + RGFW_eventQueuePushEx(e.type = RGFW_mouseScroll; + e.scroll.x = scrollX; + e.scroll.y = scrollY; + e.common.win = win); +} + + +static void RGFW_doNothing(void) { } + +static void RGFW_wl_keyboard_keymap(void* data, struct wl_keyboard *keyboard, u32 format, i32 fd, u32 size) { + RGFW_UNUSED(keyboard); RGFW_UNUSED(format); + RGFW_info* RGFW = (RGFW_info*)data; + + char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); + xkb_keymap_unref(RGFW->keymap); + RGFW->keymap = xkb_keymap_new_from_string(RGFW->xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + + munmap(keymap_string, size); + close(fd); + xkb_state_unref(RGFW->xkb_state); + RGFW->xkb_state = xkb_state_new(RGFW->keymap); +} + +static void RGFW_wl_keyboard_enter(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface, struct wl_array *keys) { + RGFW_UNUSED(keyboard); RGFW_UNUSED(keys); + + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + RGFW->kbOwner = win; + + // this is to prevent race conditions + if (RGFW->data_device != NULL && win->src.data_source != NULL) { + wl_data_device_set_selection(RGFW->data_device, win->src.data_source, serial); + } + if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; + + /* is set when RGFW_window_minimize is called; if the minimize button is */ + /* pressed this flag is not set since there is no event to listen for */ + if (win->src.minimized == RGFW_TRUE) win->src.minimized = RGFW_FALSE; + + win->internal.inFocus = RGFW_TRUE; + RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = win); + RGFW_focusCallback(win, RGFW_TRUE); + + if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); +} + +static void RGFW_wl_keyboard_leave(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface) { + RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); + + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + if (RGFW->kbOwner == win) + RGFW->kbOwner = NULL; + + if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; + + RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = win); + RGFW_focusCallback(win, RGFW_FALSE); + RGFW_window_focusLost(win); +} + +static void RGFW_wl_keyboard_key(void* data, struct wl_keyboard *keyboard, u32 serial, u32 time, u32 key, u32 state) { + RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); + + RGFW_info* RGFW = (RGFW_info*)data; + if (RGFW->kbOwner == NULL) return; + + RGFW_window *RGFW_key_win = RGFW->kbOwner; + if (!(RGFW_key_win->internal.enabledEvents & (RGFW_BIT(RGFW_keyPressed + state)))) return; + + xkb_keysym_t keysym = xkb_state_key_get_one_sym(RGFW->xkb_state, key + 8); + + u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8); + RGFW->keyboard[RGFWkey].prev = RGFW->keyboard[RGFWkey].current; + RGFW->keyboard[RGFWkey].current = RGFW_BOOL(state); + + RGFW_eventQueuePushEx(e.type = (u8)(RGFW_keyPressed + state); + e.key.value = (u8)RGFWkey; + e.key.sym = (u8)keysym; + e.key.repeat = RGFW_window_isKeyDown(RGFW_key_win, (u8)RGFWkey); + e.common.win = RGFW_key_win); + + RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "ScrollLock"))); + RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->internal.mod, RGFW_window_isKeyDown(RGFW_key_win, (u8)RGFWkey), RGFW_BOOL(state)); +} + +static void RGFW_wl_keyboard_modifiers(void* data, struct wl_keyboard *keyboard, u32 serial, u32 mods_depressed, u32 mods_latched, u32 mods_locked, u32 group) { + RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); + RGFW_info* RGFW = (RGFW_info*)data; + xkb_state_update_mask(RGFW->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); +} + +static void RGFW_wl_seat_capabilities(void* data, struct wl_seat *seat, u32 capabilities) { + RGFW_info* RGFW = (RGFW_info*)data; + static struct wl_pointer_listener pointer_listener; + RGFW_MEMSET(&pointer_listener, 0, sizeof(pointer_listener)); + pointer_listener.enter = &RGFW_wl_pointer_enter; + pointer_listener.leave = &RGFW_wl_pointer_leave; + pointer_listener.motion = &RGFW_wl_pointer_motion; + pointer_listener.button = &RGFW_wl_pointer_button; + pointer_listener.axis = &RGFW_wl_pointer_axis; + + static struct wl_keyboard_listener keyboard_listener; + RGFW_MEMSET(&keyboard_listener, 0, sizeof(keyboard_listener)); + keyboard_listener.keymap = &RGFW_wl_keyboard_keymap; + keyboard_listener.enter = &RGFW_wl_keyboard_enter; + keyboard_listener.leave = &RGFW_wl_keyboard_leave; + keyboard_listener.key = &RGFW_wl_keyboard_key; + keyboard_listener.modifiers = &RGFW_wl_keyboard_modifiers; + + if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !RGFW->wl_pointer) { + RGFW->wl_pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(RGFW->wl_pointer, &pointer_listener, RGFW); + } + if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !RGFW->wl_keyboard) { + RGFW->wl_keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(RGFW->wl_keyboard, &keyboard_listener, RGFW); + } + + if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && RGFW->wl_pointer) { + wl_pointer_destroy(RGFW->wl_pointer); + } + if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && RGFW->wl_keyboard) { + wl_keyboard_destroy(RGFW->wl_keyboard); + } +} + +static void RGFW_wl_output_set_geometry(void *data, struct wl_output *wl_output, + int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, + int32_t subpixel, const char *make, const char *model, int32_t transform) { + + RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; + monitor->x = x; + monitor->y = y; + + monitor->physW = (float)physical_width / 25.4f; + monitor->physH = (float)physical_height / 25.4f; + + RGFW_UNUSED(wl_output); + RGFW_UNUSED(subpixel); + RGFW_UNUSED(make); + RGFW_UNUSED(model); + RGFW_UNUSED(transform); +} + +static void RGFW_wl_output_set_mode(void *data, struct wl_output *wl_output, uint32_t flags, + int32_t width, int32_t height, int32_t refresh) { + + RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; + + monitor->mode.w = width; + monitor->mode.h = height; + monitor->mode.refreshRate = (u32)RGFW_ROUND( ((float)refresh / 1000) ); + RGFW_UNUSED(width); + RGFW_UNUSED(height); + RGFW_UNUSED(wl_output); + RGFW_UNUSED(flags); +} + +static void RGFW_wl_output_set_scale(void *data, struct wl_output *wl_output, int32_t factor) { + /* this is for pixelRatio */ + RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; + + monitor->pixelRatio = (float)factor; + RGFW_UNUSED(wl_output); +} + +static void RGFW_wl_output_set_name(void *data, struct wl_output *wl_output, const char *name) { + RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; + + RGFW_STRNCPY(monitor->name, name, sizeof(monitor->name) - 1); + monitor->name[sizeof(monitor->name) - 1] = '\0'; + + RGFW_UNUSED(wl_output); + +} + +static void RGFW_xdg_output_logical_pos(void *data, struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y) { + RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; + monitor->x = x; + monitor->y = y; + RGFW_UNUSED(zxdg_output_v1); +} + +static void RGFW_xdg_output_logical_size(void *data, struct zxdg_output_v1 *zxdg_output_v1, int32_t width, int32_t height) { + RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; + + float mon_float_width = (float) monitor->mode.w; + float mon_float_height = (float) monitor->mode.h; + + monitor->scaleX = (mon_float_width / (float) width); + monitor->scaleY = (mon_float_height / (float) height); + + /* under xwayland the monitor changes w & h when compositor scales it */ + monitor->mode.w = width; + monitor->mode.h = height; + RGFW_UNUSED(zxdg_output_v1); +} + +static void RGFW_wl_create_outputs(struct wl_registry *const registry, uint32_t id) { + struct wl_output *output = wl_registry_bind(registry, id, &wl_output_interface, wl_display_get_version(_RGFW->wl_display) < 4 ? 3 : 4); + RGFW_monitorNode* node; + RGFW_monitor mon; + + if (!output) return; + + char RGFW_mon_default_name[10]; + + RGFW_SNPRINTF(RGFW_mon_default_name, sizeof(RGFW_mon_default_name), "monitor-%li", _RGFW->monitors.count); + RGFW_STRNCPY(mon.name, RGFW_mon_default_name, sizeof(mon.name) - 1); + mon.name[sizeof(mon.name) - 1] = '\0'; + + /* set in case compositor does not send one */ + /* or no xdg_output support */ + mon.scaleY = mon.scaleX = mon.pixelRatio = 1.0f; + + node = RGFW_monitors_add(mon); + if (node == NULL) return; + + node->id = id; + node->output = output; + + static const struct wl_output_listener wl_output_listener = { + .geometry = RGFW_wl_output_set_geometry, + .mode = RGFW_wl_output_set_mode, + .done = (void (*)(void *,struct wl_output *))&RGFW_doNothing, + .scale = RGFW_wl_output_set_scale, + .name = RGFW_wl_output_set_name, + .description = (void (*)(void *, struct wl_output *, const char *))&RGFW_doNothing + }; + + /* the wl_output will have a reference to the node */ + wl_output_set_user_data(output, node); + + /* pass the monitor so we can access it in the callback functions */ + wl_output_add_listener(output, &wl_output_listener, node); + + if (!_RGFW->xdg_output_manager) return; /* compositor does not support it */ + + static const struct zxdg_output_v1_listener xdg_output_listener = { + .name = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing, + .done = (void (*)(void *,struct zxdg_output_v1 *))&RGFW_doNothing, + .description = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing, + .logical_position = RGFW_xdg_output_logical_pos, + .logical_size = RGFW_xdg_output_logical_size + }; + + node->xdg_output = zxdg_output_manager_v1_get_xdg_output(_RGFW->xdg_output_manager, node->output); + zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node); +} + +static void RGFW_wl_surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) { + RGFW_UNUSED(wl_surface); + + RGFW_window* win = (RGFW_window*)data; + RGFW_monitorNode* node = wl_output_get_user_data(output); + win->src.active_monitor = node->mon; + + #ifndef RGFW_NO_MONITOR + if (win->internal.flags & RGFW_windowScaleToMonitor) + RGFW_window_scaleToMonitor(win); + #endif +} + +static void RGFW_wl_data_source_send(void *data, struct wl_data_source *wl_data_source, const char *mime_type, int32_t fd) { + RGFW_UNUSED(data); RGFW_UNUSED(wl_data_source); + + // a client can accept our clipboard + if (RGFW_STRNCMP(mime_type, "text/plain;charset=utf-8", 25) == 0) { + // do not write \0 + write(fd, _RGFW->clipboard, _RGFW->clipboard_len - 1); + } + + close(fd); +} + +static void RGFW_wl_data_source_cancelled(void *data, struct wl_data_source *wl_data_source) { + + RGFW_info* RGFW = (RGFW_info*)data; + + if (RGFW->kbOwner->src.data_source == wl_data_source) { + RGFW->kbOwner->src.data_source = NULL; + } + + wl_data_source_destroy(wl_data_source); + +} + +static void RGFW_wl_data_device_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) { + + RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device); + static const struct wl_data_offer_listener wl_data_offer_listener = { + .offer = (void (*)(void *data, struct wl_data_offer *wl_data_offer, const char *))RGFW_doNothing, + .source_actions = (void (*)(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action))RGFW_doNothing, + .action = (void (*)(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action))RGFW_doNothing + }; + wl_data_offer_add_listener(wl_data_offer, &wl_data_offer_listener, NULL); +} + +static void RGFW_wl_data_device_selection(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) { + RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device); + /* Clipboard is empty */ + if (wl_data_offer == NULL) { + return; + } + + int pfds[2]; + pipe(pfds); + + wl_data_offer_receive(wl_data_offer, "text/plain;charset=utf-8", pfds[1]); + close(pfds[1]); + + wl_display_roundtrip(_RGFW->wl_display); + + char buf[1024]; + + ssize_t n = read(pfds[0], buf, sizeof(buf)); + + _RGFW->clipboard = (char*)RGFW_ALLOC((size_t)n); + RGFW_ASSERT(_RGFW->clipboard != NULL); + RGFW_STRNCPY(_RGFW->clipboard, buf, (size_t)n); + + _RGFW->clipboard_len = (size_t)n + 1; + + close(pfds[0]); + + wl_data_offer_destroy(wl_data_offer); + +} + +static void RGFW_wl_global_registry_handler(void* data, struct wl_registry *registry, u32 id, const char *interface, u32 version) { + + static struct wl_seat_listener seat_listener = {&RGFW_wl_seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing}; + static const struct wl_shm_listener shm_listener = { .format = RGFW_wl_shm_format_handler }; + + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_UNUSED(version); + + if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) { + RGFW->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 4); + } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) { + RGFW->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1); + } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) { + RGFW->decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); + } else if (RGFW_STRNCMP(interface, zwp_pointer_constraints_v1_interface.name, 255) == 0) { + RGFW->constraint_manager = wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, 1); + } else if (RGFW_STRNCMP(interface, zwp_relative_pointer_manager_v1_interface.name, 255) == 0) { + RGFW->relative_pointer_manager = wl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, 1); + } else if (RGFW_STRNCMP(interface, xdg_toplevel_icon_manager_v1_interface.name, 255) == 0) { + RGFW->icon_manager = wl_registry_bind(registry, id, &xdg_toplevel_icon_manager_v1_interface, 1); + } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) { + RGFW->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); + wl_shm_add_listener(RGFW->shm, &shm_listener, RGFW); + } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) { + RGFW->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); + wl_seat_add_listener(RGFW->seat, &seat_listener, RGFW); + } else if (RGFW_STRNCMP(interface, zxdg_output_manager_v1_interface.name, 255) == 0) { + RGFW->xdg_output_manager = wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 1); + } else if (RGFW_STRNCMP(interface,"wl_output", 10) == 0) { + RGFW_wl_create_outputs(registry, id); + } else if (RGFW_STRNCMP(interface,"wl_data_device_manager", 23) == 0) { + RGFW->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface, 1); + } +} + +static void RGFW_wl_global_registry_remove(void* data, struct wl_registry *registry, u32 id) { + RGFW_UNUSED(data); RGFW_UNUSED(registry); + RGFW_info* RGFW = (RGFW_info*)data; + RGFW_monitorNode* prev = RGFW->monitors.list.head; + RGFW_monitorNode* node = NULL; + if (prev == NULL) return; + + if (prev->id != id) { + /* find the first node that has a matching id */ + while(prev->next != NULL && prev->next->id != id) { + prev = prev->next; + } + + if (prev->next == NULL) return; + node = prev->next; + } else { + node = prev; + } + + if (node->output) { + wl_output_destroy(node->output); + } + + if (node->xdg_output) { + zxdg_output_v1_destroy(node->xdg_output); + } + + RGFW_monitors_remove(node, prev); +} + +static void RGFW_wl_randname(char *buf) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); - return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec; + long r = ts.tv_nsec; + + int i; + for (i = 0; i < 6; ++i) { + buf[i] = (char)('A'+(r&15)+(r&16)*2); + r >>= 5; + } +} + +static size_t RGFW_wl_stringlen(char* name) { + size_t i = 0; + while (name[i]) { i++; } + return i; +} + +static int RGFW_wl_anonymous_shm_open(void) { + char name[] = "/RGFW-wayland-XXXXXX"; + int retries = 100; + + do { + RGFW_wl_randname(name + RGFW_wl_stringlen(name) - 6); + + --retries; + /* shm_open guarantees that O_CLOEXEC is set */ + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + + return -1; +} + +static int RGFW_wl_create_shm_file(off_t size) { + int fd = RGFW_wl_anonymous_shm_open(); + if (fd < 0) { + return fd; + } + + if (ftruncate(fd, size) < 0) { + close(fd); + return -1; + } + + return fd; +} + +i32 RGFW_initPlatform_Wayland(void) { + _RGFW->wl_display = wl_display_connect(NULL); + if (_RGFW->wl_display == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Failed to load Wayland display"); + return -1; + } + + _RGFW->compositor = NULL; + static const struct wl_registry_listener registry_listener = { + .global = RGFW_wl_global_registry_handler, + .global_remove = RGFW_wl_global_registry_remove, + }; + + _RGFW->registry = wl_display_get_registry(_RGFW->wl_display); + wl_registry_add_listener(_RGFW->registry, ®istry_listener, _RGFW); + + wl_display_roundtrip(_RGFW->wl_display); /* bind to globals */ + + if (_RGFW->compositor == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Can't find compositor."); + return 1; + } + + if (_RGFW->wl_cursor_theme == NULL) { + _RGFW->wl_cursor_theme = wl_cursor_theme_load(NULL, 24, _RGFW->shm); + _RGFW->cursor_surface = wl_compositor_create_surface(_RGFW->compositor); + } + + u8 RGFW_blk[] = { 0, 0, 0, 0 }; + _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); + + static const struct xdg_wm_base_listener xdg_wm_base_listener = { + .ping = RGFW_wl_xdg_wm_base_ping_handler, + }; + + xdg_wm_base_add_listener(_RGFW->xdg_wm_base, &xdg_wm_base_listener, NULL); + + _RGFW->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + static const struct wl_data_device_listener wl_data_device_listener = { + .data_offer = RGFW_wl_data_device_data_offer, + .enter = (void (*)(void *, struct wl_data_device *, u32, struct wl_surface*, wl_fixed_t, wl_fixed_t, struct wl_data_offer *))&RGFW_doNothing, + .leave = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing, + .motion = (void (*)(void *, struct wl_data_device *, u32, wl_fixed_t, wl_fixed_t))&RGFW_doNothing, + .drop = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing, + .selection = RGFW_wl_data_device_selection + }; + + if (_RGFW->seat && _RGFW->data_device_manager) { + _RGFW->data_device = wl_data_device_manager_get_data_device(_RGFW->data_device_manager, _RGFW->seat); + wl_data_device_add_listener(_RGFW->data_device, &wl_data_device_listener, NULL); + } + + return 0; +} + +void RGFW_deinitPlatform_Wayland(void) { + if (_RGFW->clipboard) { + RGFW_FREE(_RGFW->clipboard); + _RGFW->clipboard = NULL; + } + + if (_RGFW->wl_pointer) { + wl_pointer_destroy(_RGFW->wl_pointer); + } + if (_RGFW->wl_keyboard) { + wl_keyboard_destroy(_RGFW->wl_keyboard); + } + + wl_registry_destroy(_RGFW->registry); + if (_RGFW->decoration_manager != NULL) + zxdg_decoration_manager_v1_destroy(_RGFW->decoration_manager); + if (_RGFW->relative_pointer_manager != NULL) { + zwp_relative_pointer_manager_v1_destroy(_RGFW->relative_pointer_manager); + } + + if (_RGFW->relative_pointer) { + zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer); + } + + if (_RGFW->constraint_manager != NULL) { + zwp_pointer_constraints_v1_destroy(_RGFW->constraint_manager); + } + + if (_RGFW->xdg_output_manager != NULL) + if (_RGFW->icon_manager != NULL) { + xdg_toplevel_icon_manager_v1_destroy(_RGFW->icon_manager); + } + + if (_RGFW->xdg_output_manager) { + zxdg_output_manager_v1_destroy(_RGFW->xdg_output_manager); + } + + if (_RGFW->data_device_manager) { + wl_data_device_manager_destroy(_RGFW->data_device_manager); + } + + if (_RGFW->data_device) { + wl_data_device_destroy(_RGFW->data_device); + } + + if (_RGFW->wl_cursor_theme != NULL) { + wl_cursor_theme_destroy(_RGFW->wl_cursor_theme); + } + + RGFW_freeMouse(_RGFW->hiddenMouse); + + RGFW_monitorNode* node = _RGFW->monitors.list.head; + + while (node != NULL) { + if (node->output) { + wl_output_destroy(node->output); + } + + if (node->xdg_output) { + zxdg_output_v1_destroy(node->xdg_output); + } + + _RGFW->monitors.count -= 1; + node = node->next; + + } + + wl_surface_destroy(_RGFW->cursor_surface); + wl_shm_destroy(_RGFW->shm); + wl_seat_release(_RGFW->seat); + xdg_wm_base_destroy(_RGFW->xdg_wm_base); + wl_compositor_destroy(_RGFW->compositor); + wl_display_disconnect(_RGFW->wl_display); +} + +RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { + RGFW_ASSERT(surface != NULL); + surface->data = data; + surface->w = w; + surface->h = h; + surface->format = format; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, "Creating a 4 channel buffer"); + + u32 size = (u32)(surface->w * surface->h * 4); + int fd = RGFW_wl_create_shm_file(size); + if (fd < 0) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create a buffer."); + return RGFW_FALSE; + } + + surface->native.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (surface->native.buffer == MAP_FAILED) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "mmap failed."); + return RGFW_FALSE; + } + + struct wl_shm_pool* pool = wl_shm_create_pool(_RGFW->shm, fd, (i32)size); + surface->native.wl_buffer = wl_shm_pool_create_buffer(pool, 0, (i32)surface->w, (i32)surface->h, (i32)surface->w * 4, WL_SHM_FORMAT_ARGB8888); + wl_shm_pool_destroy(pool); + + close(fd); + + surface->native.format = RGFW_formatBGRA8; + return RGFW_TRUE; +} + +void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) { + RGFW_ASSERT(surface != NULL); + RGFW_copyImageData(surface->native.buffer, win->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); + + wl_surface_attach(win->src.surface, surface->native.wl_buffer, 0, 0); + wl_surface_damage(win->src.surface, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h)); + wl_surface_commit(win->src.surface); +} + +void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) { + RGFW_ASSERT(surface != NULL); + wl_buffer_destroy(surface->native.wl_buffer); + munmap(surface->native.buffer, (size_t)(surface->w * surface->h * 4)); +} + +void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) { + RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); + + /* for now just toggle between SSD & CSD depending on the bool */ + if (_RGFW->decoration_manager != NULL) { + zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, (border ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)); + } +} + +void RGFW_FUNC(RGFW_releaseCursor) (RGFW_window* win) { + RGFW_ASSERT(win); + /* compositor has no support or window is not locked do nothing */ + if (_RGFW->constraint_manager == NULL || _RGFW->relative_pointer_manager == NULL) return; + + if (win->src.locked_pointer != NULL) { + zwp_locked_pointer_v1_destroy(win->src.locked_pointer); + win->src.locked_pointer = NULL; + } + if (_RGFW->relative_pointer != NULL) { + zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer); + _RGFW->relative_pointer = NULL; + } + + _RGFW->mouseOwner = win; /* unhold mouse sets this to null; set it back */ +} + +void RGFW_FUNC(RGFW_captureCursor) (RGFW_window* win) { + RGFW_ASSERT(win); + /* compositor has no support or window already is locked do nothing */ + if (_RGFW->constraint_manager == NULL || _RGFW->relative_pointer_manager == NULL) return; + + if (_RGFW->relative_pointer == NULL) { + _RGFW->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(_RGFW->relative_pointer_manager, _RGFW->wl_pointer); + + static const struct zwp_relative_pointer_v1_listener relative_motion_listener = { + .relative_motion = RGFW_wl_relative_pointer_motion + }; + + zwp_relative_pointer_v1_add_listener(_RGFW->relative_pointer, &relative_motion_listener, _RGFW); + } + + if (win->src.locked_pointer == NULL) { + win->src.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(_RGFW->constraint_manager, win->src.surface, _RGFW->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + + static const struct zwp_locked_pointer_v1_listener locked_listener = { + .locked = RGFW_wl_pointer_locked, + .unlocked = (void (*)(void *, struct zwp_locked_pointer_v1 *))RGFW_doNothing + }; + + zwp_locked_pointer_v1_add_listener(win->src.locked_pointer, &locked_listener, _RGFW); + } +} + +RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) { + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, "RGFW Wayland support is experimental"); + + static const struct xdg_surface_listener xdg_surface_listener = { + .configure = RGFW_wl_xdg_surface_configure_handler, + }; + + static const struct wl_surface_listener wl_surface_listener = { + .enter = RGFW_wl_surface_enter, + .leave = (void (*)(void *, struct wl_surface *, struct wl_output *))&RGFW_doNothing, + .preferred_buffer_scale = (void (*)(void *, struct wl_surface *, i32))&RGFW_doNothing, + .preferred_buffer_transform = (void (*)(void *, struct wl_surface *, u32))&RGFW_doNothing + }; + + win->src.surface = wl_compositor_create_surface(_RGFW->compositor); + wl_surface_add_listener(win->src.surface, &wl_surface_listener, win); + + /* create a surface for a custom cursor */ + win->src.custom_cursor_surface = wl_compositor_create_surface(_RGFW->compositor); + + win->src.xdg_surface = xdg_wm_base_get_xdg_surface(_RGFW->xdg_wm_base, win->src.surface); + xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, win); + + xdg_wm_base_set_user_data(_RGFW->xdg_wm_base, win); + + win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); + + xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h); + + if (!(win->internal.flags & RGFW_windowTransparent)) { /* no transparency */ + RGFW_wl_setOpaque(win); + } + + static const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = RGFW_wl_xdg_toplevel_configure_handler, + .close = RGFW_wl_xdg_toplevel_close_handler, + }; + + xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, win); + + /* compositor supports both SSD & CSD + So choose accordingly + */ + if (_RGFW->decoration_manager) { + u32 decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; + win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + _RGFW->decoration_manager, win->src.xdg_toplevel); + + static const struct zxdg_toplevel_decoration_v1_listener xdg_decoration_listener = { + .configure = RGFW_wl_xdg_decoration_configure_handler + }; + + zxdg_toplevel_decoration_v1_add_listener(win->src.decoration, &xdg_decoration_listener, win); + + /* we want no decorations */ + if ((flags & RGFW_windowNoBorder)) { + decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; + } + + zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, decoration_mode); + + /* no xdg_decoration support */ + } else if (!(flags & RGFW_windowNoBorder)) { + /* TODO, some fallback */ + #ifdef RGFW_LIBDECOR + static struct libdecor_interface interface = { + .error = NULL, + }; + + static struct libdecor_frame_interface frameInterface = {0}; /*= { + RGFW_wl_handle_configure, + RGFW_wl_handle_close, + RGFW_wl_handle_commit, + RGFW_wl_handle_dismiss_popup, + };*/ + + win->src.decorContext = libdecor_new(_RGFW->wl_display, &interface); + if (win->src.decorContext) { + struct libdecor_frame *frame = libdecor_decorate(win->src.decorContext, win->src.surface, &frameInterface, win); + if (!frame) { + libdecor_unref(win->src.decorContext); + win->src.decorContext = NULL; + } else { + libdecor_frame_set_app_id(frame, "my-libdecor-app"); + libdecor_frame_set_title(frame, "My Libdecor Window"); + } + } + #endif + } + + if (_RGFW->icon_manager != NULL) { + /* set the default wayland icon */ + xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, NULL); + } + + wl_surface_commit(win->src.surface); + wl_display_dispatch(_RGFW->wl_display); + RGFW_UNUSED(name); + + return win; +} + +RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* x, i32* y) { + RGFW_init(); + if (x) *x = 0; + if (y) *y = 0; + return RGFW_FALSE; +} + +u8 RGFW_FUNC(RGFW_rgfwToKeyChar)(u32 key) { + return (u8)key; +} + +void RGFW_FUNC(RGFW_pollEvents) (void) { + RGFW_resetPrevState(); + + /* send buffered requests to compositor */ + while (wl_display_flush(_RGFW->wl_display) == -1) { + /* compositor not responding to new requests */ + /* so let's dispatch some events so the compositor responds */ + if (errno == EAGAIN) { + if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { + return; + } + } else { + return; + } + } + + /* read the events; if empty this reads from the */ + /* wayland file descriptor */ + if (wl_display_dispatch(_RGFW->wl_display) == -1) { + return; + } + +} + +void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) { + RGFW_ASSERT(win != NULL); + win->x = x; + win->y = y; } -#endif /* end of wayland or X11 defines */ +void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) { + RGFW_ASSERT(win != NULL); + win->w = w; + win->h = h; + if (_RGFW->compositor) { + xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h); + #ifdef RGFW_OPENGL + if (win->src.ctx.egl) + wl_egl_window_resize(win->src.ctx.egl->eglWindow, (i32)w, (i32)h, 0, 0); + #endif + } +} + +void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) { + RGFW_ASSERT(win != NULL); + + if (w == 0 && h == 0) + return; + xdg_toplevel_set_max_size(win->src.xdg_toplevel, (i32)w, (i32)h); +} + +void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) { + RGFW_ASSERT(win != NULL); + xdg_toplevel_set_min_size(win->src.xdg_toplevel, w, h); +} + +void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) { + RGFW_ASSERT(win != NULL); + xdg_toplevel_set_max_size(win->src.xdg_toplevel, w, h); +} + +void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized) { + win->src.maximized = maximized; + if (maximized) { + xdg_toplevel_set_maximized(win->src.xdg_toplevel); + } else { + xdg_toplevel_unset_maximized(win->src.xdg_toplevel); + } +} + +void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) { + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; + RGFW_toggleWaylandMaximized(win, 1); + return; +} + +void RGFW_FUNC(RGFW_window_focus)(RGFW_window* win) { + RGFW_ASSERT(win); +} + +void RGFW_FUNC(RGFW_window_raise)(RGFW_window* win) { + RGFW_ASSERT(win); +} + +void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) { + RGFW_ASSERT(win != NULL); + if (fullscreen) { + + win->internal.flags |= RGFW_windowFullscreen; + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; + xdg_toplevel_set_fullscreen(win->src.xdg_toplevel, NULL); /* let the compositor decide */ + } else { + win->internal.flags &= ~(u32)RGFW_windowFullscreen; + xdg_toplevel_unset_fullscreen(win->src.xdg_toplevel); + } + +} + +void RGFW_FUNC(RGFW_window_setFloating) (RGFW_window* win, RGFW_bool floating) { + RGFW_ASSERT(win != NULL); + RGFW_UNUSED(floating); +} + +void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window* win, u8 opacity) { + RGFW_ASSERT(win != NULL); + RGFW_UNUSED(opacity); +} + +void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + if (RGFW_window_isMaximized(win)) return; + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; + win->src.minimized = RGFW_TRUE; + xdg_toplevel_set_minimized(win->src.xdg_toplevel); +} + +void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_toggleWaylandMaximized(win, RGFW_FALSE); + + RGFW_window_move(win, win->internal.oldX, win->internal.oldY); + RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); + + RGFW_window_show(win); + RGFW_window_move(win, win->internal.oldX, win->internal.oldY); + RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); + + RGFW_window_show(win); +} + +RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) { + return (!RGFW_window_isFullscreen(win) && !RGFW_window_isMaximized(win)); +} + +void RGFW_FUNC(RGFW_window_setName) (RGFW_window* win, const char* name) { + RGFW_ASSERT(win != NULL); + if (_RGFW->compositor) + xdg_toplevel_set_title(win->src.xdg_toplevel, name); +} + +#ifndef RGFW_NO_PASSTHROUGH +void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) { + RGFW_ASSERT(win != NULL); + RGFW_UNUSED(passthrough); +} +#endif /* RGFW_NO_PASSTHROUGH */ + +RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { + RGFW_ASSERT(win != NULL); + RGFW_UNUSED(type); + + if (_RGFW->icon_manager == NULL || w != h) return RGFW_FALSE; + + if (win->src.icon) { + xdg_toplevel_icon_v1_destroy(win->src.icon); + win->src.icon= NULL; + } + + RGFW_surface* surface = RGFW_createSurface(data, w, h, format); + + if (surface == NULL) return RGFW_FALSE; + + RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format); + + win->src.icon = xdg_toplevel_icon_manager_v1_create_icon(_RGFW->icon_manager); + xdg_toplevel_icon_v1_add_buffer(win->src.icon, surface->native.wl_buffer, 1); + xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, win->src.icon); + + RGFW_surface_free(surface); + return RGFW_TRUE; +} + +RGFW_mouse* RGFW_FUNC(RGFW_loadMouse)(u8* data, i32 w, i32 h, RGFW_format format) { + + RGFW_surface *mouse_surface = RGFW_createSurface(data, w, h, format); + + if (mouse_surface == NULL) return NULL; + + RGFW_copyImageData(mouse_surface->native.buffer, RGFW_MIN(w, mouse_surface->w), RGFW_MIN(h, mouse_surface->h), mouse_surface->native.format, mouse_surface->data, mouse_surface->format); + + return (void*) mouse_surface; +} + +void RGFW_FUNC(RGFW_window_setMouse)(RGFW_window* win, RGFW_mouse* mouse) { + RGFW_ASSERT(win); RGFW_ASSERT(mouse); + RGFW_surface *mouse_surface = (RGFW_surface*)mouse; + + win->src.using_custom_cursor = RGFW_TRUE; + + struct wl_buffer *mouse_buffer = mouse_surface->native.wl_buffer; + + wl_surface_attach(win->src.custom_cursor_surface, mouse_buffer, 0, 0); + wl_surface_damage(win->src.custom_cursor_surface, 0, 0, mouse_surface->w, mouse_surface->h); + wl_surface_commit(win->src.custom_cursor_surface); + +} + +void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) { + if (mouse != NULL) { + RGFW_surface_free((RGFW_surface*)mouse); + } +} + +void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) { + RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); +} + +RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault)(RGFW_window* win) { + return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); +} + +RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard)(RGFW_window* win, u8 mouse) { + RGFW_ASSERT(win != NULL); + static const char* iconStrings[16] = { "arrow", "left_ptr", "xterm", "crosshair", "hand2", "sb_h_double_arrow", "sb_v_double_arrow", "bottom_left_corner", "bottom_right_corner", "fleur", "forbidden" }; + + win->src.using_custom_cursor = RGFW_FALSE; + + if (mouse > RGFW_mouseIconCount - 1) return RGFW_FALSE; + + struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(_RGFW->wl_cursor_theme, iconStrings[mouse]); + struct wl_cursor_image* cursor_image = wlcursor->images[0]; + struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(cursor_image); + wl_pointer_set_cursor(_RGFW->wl_pointer, _RGFW->mouse_enter_serial, _RGFW->cursor_surface, (i32)cursor_image->hotspot_x, (i32)cursor_image->hotspot_y); + wl_surface_attach(_RGFW->cursor_surface, cursor_buffer, 0, 0); + wl_surface_damage(_RGFW->cursor_surface, 0, 0, (i32)cursor_image->width, (i32)cursor_image->height); + wl_surface_commit(_RGFW->cursor_surface); + return RGFW_TRUE; +} + +void RGFW_FUNC(RGFW_window_hide) (RGFW_window* win) { + wl_surface_attach(win->src.surface, NULL, 0, 0); + wl_surface_commit(win->src.surface); + win->internal.flags |= RGFW_windowHide; +} + +void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) { + win->internal.flags &= ~(u32)RGFW_windowHide; + if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); + /* wl_surface_attach(win->src.surface, win->x, win->y, win->w, win->h, 0, 0); */ + wl_surface_commit(win->src.surface); +} + +RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char* str, size_t strCapacity) { + + RGFW_UNUSED(strCapacity); + + if (str != NULL) + RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1); + _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0'; + return (RGFW_ssize_t)_RGFW->clipboard_len - 1; +} + +void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) { + + // compositor does not support wl_data_device_manager + // clients cannot read rgfw's clipboard + if (_RGFW->data_device_manager == NULL) return; + // clear the clipboard + if (_RGFW->clipboard) + RGFW_FREE(_RGFW->clipboard); + + // set the contents + _RGFW->clipboard = (char*)RGFW_ALLOC(textLen); + RGFW_ASSERT(_RGFW->clipboard != NULL); + RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1); + _RGFW->clipboard[textLen - 1] = '\0'; + _RGFW->clipboard_len = textLen; + + // means we already wrote to the clipboard + // so destroy it to create a new one + RGFW_window* win = _RGFW->kbOwner; + + if (win->src.data_source != NULL) { + wl_data_source_destroy(win->src.data_source); + win->src.data_source = NULL; + } + + // advertise to other clients that we offer text + win->src.data_source = wl_data_device_manager_create_data_source(_RGFW->data_device_manager); + + // basic error checking + if (win->src.data_source == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "Could not create clipboard data source"); + return; + } + wl_data_source_offer(win->src.data_source , "text/plain;charset=utf-8"); + + // needed RGFW_doNothing because wayland will call the functions + // if not set they are random data that lead to a crash + static const struct wl_data_source_listener data_source_listener = { + .target = (void (*)(void *, struct wl_data_source *, const char *))&RGFW_doNothing, + .action = (void (*)(void *, struct wl_data_source *, u32))&RGFW_doNothing, + .dnd_drop_performed = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing, + .dnd_finished = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing, + .send = RGFW_wl_data_source_send, + .cancelled = RGFW_wl_data_source_cancelled + }; + + wl_data_source_add_listener(win->src.data_source, &data_source_listener, _RGFW); + +} + +RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window* win) { + RGFW_ASSERT(win != NULL); + return RGFW_FALSE; +} + +RGFW_bool RGFW_FUNC(RGFW_window_isMinimized) (RGFW_window* win) { + RGFW_ASSERT(win != NULL); + return win->src.minimized; +} + +RGFW_bool RGFW_FUNC(RGFW_window_isMaximized) (RGFW_window* win) { + RGFW_ASSERT(win != NULL); + return win->src.maximized; +} + +RGFW_monitor* RGFW_FUNC(RGFW_getMonitors) (size_t* len) { + static RGFW_monitor monitors[RGFW_MAX_MONITORS]; + RGFW_init(); + if (len != NULL) { + *len = _RGFW->monitors.count; + } + + u8 i = 0; + RGFW_monitorNode* cur_node = _RGFW->monitors.list.head; + while (cur_node != NULL) { + monitors[i] = cur_node->mon; + ++i; + cur_node = cur_node->next; + } + return monitors; +} + +RGFW_monitor RGFW_FUNC(RGFW_getPrimaryMonitor) (void) { + return _RGFW->monitors.list.head->mon; +} + +RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { + RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); + return RGFW_FALSE; +} + +RGFW_monitor RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) { + RGFW_ASSERT(win); + return win->src.active_monitor; +} + +#ifdef RGFW_OPENGL +RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL) (const char * extension, size_t len) { return RGFW_extensionSupportedPlatform_EGL(extension, len); } +RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL) (const char* procname) { return RGFW_getProcAddress_EGL(procname); } + + +RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { + RGFW_bool out = RGFW_window_createContextPtr_EGL(win, &ctx->egl, hints); + win->src.gfxType = RGFW_gfxNativeOpenGL; + return out; +} +void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) { RGFW_window_deleteContextPtr_EGL(win, &ctx->egl); win->src.ctx.native = NULL; } + +void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { RGFW_window_makeCurrentContext_EGL(win); } +void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return RGFW_getCurrentContext_EGL(); } +void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_window_swapBuffers_EGL(win); } +void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) { RGFW_window_swapInterval_EGL(win, swapInterval); } +#endif /* RGFW_OPENGL */ + +void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed"); + #ifdef RGFW_LIBDECOR + if (win->src.decorContext) + libdecor_unref(win->src.decorContext); + #endif + + if (win->src.decoration) { + zxdg_toplevel_decoration_v1_destroy(win->src.decoration); + } + + if (win->src.xdg_toplevel) { + xdg_toplevel_destroy(win->src.xdg_toplevel); + } + + wl_surface_destroy(win->src.custom_cursor_surface); + + if (win->src.locked_pointer) { + zwp_locked_pointer_v1_destroy(win->src.locked_pointer); + } + + if (win->src.icon) { + xdg_toplevel_icon_v1_destroy(win->src.icon); + } + + xdg_surface_destroy(win->src.xdg_surface); + wl_surface_destroy(win->src.surface); +} + +#ifdef RGFW_WEBGPU +WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) { + WGPUSurfaceDescriptor surfaceDesc = {0}; + WGPUSurfaceSourceWaylandSurface fromWl = {0}; + fromWl.chain.sType = WGPUSType_SurfaceSourceWaylandSurface; + fromWl.display = _RGFW->wl_display; + fromWl.surface = window->src.surface; + + surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromWl.chain; + return wgpuInstanceCreateSurface(instance, &surfaceDesc); +} +#endif + + + +#endif /* RGFW_WAYLAND */ +/* + End of Wayland defines +*/ /* @@ -6353,7 +8882,22 @@ u64 RGFW_getTimerValue(void) { #define OEMRESOURCE #include -#include +#ifndef OCR_NORMAL +#define OCR_NORMAL 32512 +#define OCR_IBEAM 32513 +#define OCR_WAIT 32514 +#define OCR_CROSS 32515 +#define OCR_UP 32516 +#define OCR_SIZENWSE 32642 +#define OCR_SIZENESW 32643 +#define OCR_SIZEWE 32644 +#define OCR_SIZENS 32645 +#define OCR_SIZEALL 32646 +#define OCR_NO 32648 +#define OCR_HAND 32649 +#define OCR_APPSTARTING 32650 +#endif + #include #include #include @@ -6365,19 +8909,7 @@ u64 RGFW_getTimerValue(void) { #define WM_DPICHANGED 0x02E0 #endif -#ifndef RGFW_NO_XINPUT - typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); - PFN_XInputGetState XInputGetStateSRC = NULL; - #define XInputGetState XInputGetStateSRC - - typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE); - PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL; - #define XInputGetKeystroke XInputGetKeystrokeSRC - - HMODULE RGFW_XInput_dll = NULL; -#endif - -char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source); +RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* out, size_t max); #define GL_FRONT 0x0404 #define GL_BACK 0x0405 @@ -6388,16 +8920,11 @@ typedef int (*PFN_wglGetSwapIntervalEXT)(void); PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL; #define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc - -void* RGFWgamepadApi = NULL; - /* these two wgl functions need to be preloaded */ typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList); PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; -#ifndef RGFW_EGL - HMODULE RGFW_wgl_dll = NULL; -#endif +HMODULE RGFW_wgl_dll = NULL; #ifndef RGFW_NO_LOAD_WGL typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC); @@ -6425,28 +8952,11 @@ PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; #define wglShareLists wglShareListsSRC #endif -#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) -RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { - const char* extensions = NULL; +void* RGFW_window_getHWND(RGFW_window* win) { return win->src.window; } +void* RGFW_window_getHDC(RGFW_window* win) { return win->src.hdc; } - RGFW_proc proc = RGFW_getProcAddress("wglGetExtensionsStringARB"); - RGFW_proc proc2 = RGFW_getProcAddress("wglGetExtensionsStringEXT"); - - if (proc) - extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC()); - else if (proc2) - extensions = ((const char*(*)(void))proc2)(); - - return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); -} - -RGFW_proc RGFW_getProcAddress(const char* procname) { - RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname); - if (proc) - return proc; - - return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); -} +#ifdef RGFW_OPENGL +RGFWDEF void RGFW_win32_loadOpenGLFuncs(HWND dummyWin); typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; @@ -6457,13 +8967,15 @@ PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #ifndef RGFW_NO_DWM HMODULE RGFW_dwm_dll = NULL; +#ifndef _DWMAPI_H_ typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND; +#endif typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*); PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL; #endif void RGFW_win32_makeWindowTransparent(RGFW_window* win); void RGFW_win32_makeWindowTransparent(RGFW_window* win) { - if (!(win->_flags & RGFW_windowTransparent)) return; + if (!(win->internal.flags & RGFW_windowTransparent)) return; #ifndef RGFW_NO_DWM if (DwmEnableBlurBehindWindowSRC != NULL) { @@ -6486,49 +8998,55 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW"); if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam); + static BYTE keyboardState[256]; + GetKeyboardState(keyboardState); + + RGFW_event event; + RGFW_MEMSET(&event, 0, sizeof(event)); + event.common.win = win; + RECT windowRect; GetWindowRect(hWnd, &windowRect); switch (message) { case WM_CLOSE: case WM_QUIT: - RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); + RGFW_window_setShouldClose(win, RGFW_TRUE); RGFW_windowQuitCallback(win); + RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); return 0; case WM_ACTIVATE: { RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE); - if (inFocus) win->_flags |= RGFW_windowFocus; - else win->_flags &= ~ (u32)RGFW_windowFocus; - RGFW_eventQueuePushEx(e.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus); e._win = win); - RGFW_focusCallback(win, inFocus); - RGFW_window_focusLost(win); - - if ((win->_flags & RGFW_windowFullscreen) == 0) - return DefWindowProcW(hWnd, message, wParam, lParam); - - win->_flags &= ~(u32)RGFW_EVENT_PASSED; - if (inFocus == RGFW_FALSE) RGFW_window_minimize(win); - else RGFW_window_setFullscreen(win, 1); + win->internal.inFocus = RGFW_BOOL(inFocus); + if ((win->internal.enabledEvents & (RGFW_BIT(RGFW_focusIn - inFocus)))) { + RGFW_eventQueuePushEx(e.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus); e.common.win = win); + RGFW_focusCallback(win, inFocus); + } + if (inFocus == RGFW_FALSE) RGFW_window_focusLost(win); + if ((win->internal.flags & RGFW_windowFullscreen) && inFocus == RGFW_TRUE) + RGFW_window_setFullscreen(win, 1); return DefWindowProcW(hWnd, message, wParam, lParam); } case WM_MOVE: - win->r.x = windowRect.left; - win->r.y = windowRect.top; - RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win); - RGFW_windowMovedCallback(win, win->r); + win->x = windowRect.left; + win->y = windowRect.top; + + if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; + RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e.common.win = win); + RGFW_windowMovedCallback(win, win->x, win->y); return DefWindowProcW(hWnd, message, wParam, lParam); case WM_SIZE: { - if (win->src.aspectRatio.w != 0 && win->src.aspectRatio.h != 0) { - double aspectRatio = (double)win->src.aspectRatio.w / win->src.aspectRatio.h; + if (win->src.aspectRatioW != 0 && win->src.aspectRatioH != 0) { + double aspectRatio = (double)win->src.aspectRatioW / win->src.aspectRatioH; int width = windowRect.right - windowRect.left; int height = windowRect.bottom - windowRect.top; int newHeight = (int)(width / aspectRatio); int newWidth = (int)(height * aspectRatio); - if (win->r.w > windowRect.right - windowRect.left || - win->r.h > (i32)((u32)(windowRect.bottom - windowRect.top) - win->src.hOffset)) + if (win->w > (i32)((windowRect.right - windowRect.left) - win->src.offsetW) || + win->h > (i32)((windowRect.bottom - windowRect.top) - win->src.offsetH)) { if (newHeight > height) windowRect.right = windowRect.left + newWidth; else windowRect.bottom = windowRect.top + newHeight; @@ -6537,43 +9055,47 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) else windowRect.bottom = windowRect.top + newHeight; } - RGFW_window_resize(win, RGFW_AREA((windowRect.right - windowRect.left), - (u32)(windowRect.bottom - windowRect.top) - (u32)win->src.hOffset)); + RGFW_window_resize(win, (windowRect.right - windowRect.left) - win->src.offsetW, + (windowRect.bottom - windowRect.top) - win->src.offsetH); } - win->r.w = windowRect.right - windowRect.left; - win->r.h = (windowRect.bottom - windowRect.top) - (i32)win->src.hOffset; - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win); - RGFW_windowResizedCallback(win, win->r); + win->w = (windowRect.right - windowRect.left) - (i32)win->src.offsetW; + win->h = (windowRect.bottom - windowRect.top) - (i32)win->src.offsetH; + if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); + RGFW_windowResizedCallback(win, win->w, win->h); RGFW_window_checkMode(win); return DefWindowProcW(hWnd, message, wParam, lParam); } #ifndef RGFW_NO_MONITOR case WM_DPICHANGED: { - if (win->_flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); + if (win->internal.flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); const float scaleX = HIWORD(wParam) / (float) 96; const float scaleY = LOWORD(wParam) / (float) 96; + + if (!(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; RGFW_scaleUpdatedCallback(win, scaleX, scaleY); - RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = scaleX; e.scaleY = scaleY; e._win = win); + RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scale.x = scaleX; e.scale.y = scaleY; e.common.win = win); return DefWindowProcW(hWnd, message, wParam, lParam); } #endif case WM_GETMINMAXINFO: { MINMAXINFO* mmi = (MINMAXINFO*) lParam; - mmi->ptMinTrackSize.x = (LONG)win->src.minSize.w; - mmi->ptMinTrackSize.y = (LONG)(win->src.minSize.h + win->src.hOffset); - if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0) + mmi->ptMinTrackSize.x = (LONG)(win->src.minSizeW + win->src.offsetW); + mmi->ptMinTrackSize.y = (LONG)(win->src.minSizeH + win->src.offsetH); + if (win->src.maxSizeW == 0 && win->src.maxSizeH == 0) return DefWindowProcW(hWnd, message, wParam, lParam); - mmi->ptMaxTrackSize.x = (LONG)win->src.maxSize.w; - mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSize.h + win->src.hOffset); + mmi->ptMaxTrackSize.x = (LONG)(win->src.maxSizeW + win->src.offsetW); + mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSizeH + win->src.offsetH); return DefWindowProcW(hWnd, message, wParam, lParam); } case WM_PAINT: { + if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); PAINTSTRUCT ps; BeginPaint(hWnd, &ps); - RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win); + RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e.common.win = win); RGFW_windowRefreshCallback(win); EndPaint(hWnd, &ps); @@ -6589,7 +9111,9 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) #ifdef RGFW_ADVANCED_SMOOTH_RESIZE case WM_ENTERSIZEMOVE: SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break; case WM_EXITSIZEMOVE: KillTimer(win->src.window, 1); break; - case WM_TIMER: RGFW_windowRefreshCallback(win); break; + case WM_TIMER: + if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + RGFW_windowRefreshCallback(win); break; #endif case WM_NCLBUTTONDOWN: { /* workaround for half-second pause when starting to move window @@ -6600,11 +9124,272 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; ScreenToClient(win->src.window, &point); - PostMessage(win->src.window, WM_MOUSEMOVE, 0, ((uint32_t)point.x)|(((uint32_t)point.y) << 16)); + PostMessage(win->src.window, WM_MOUSEMOVE, 0, (u32)(point.x)|((u32)(point.y) << 16)); break; } + case WM_MOUSELEAVE: + win->internal.mouseInside = RGFW_FALSE; + _RGFW->windowState.winLeave = win; + _RGFW->windowState.mouseLeave = RGFW_TRUE; + if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + event.type = RGFW_mouseLeave; + RGFW_window_getMouse(win, &event.mouse.x, &event.mouse.y); + RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 0); + break; + case WM_SYSKEYUP: case WM_KEYUP: { + if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); + if (scancode == 0) + scancode = (i32)MapVirtualKeyW((UINT)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; + } + + event.key.value = (u8)RGFW_apiKeyToRGFW((u32) scancode); + + if (wParam == VK_CONTROL) { + if (HIWORD(lParam) & KF_EXTENDED) + event.key.value = RGFW_controlR; + else event.key.value = RGFW_controlL; + } + + wchar_t charBuffer; + ToUnicodeEx((UINT)wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL); + + event.key.sym = (u8)charBuffer; + + _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; + event.type = RGFW_keyReleased; + event.key.repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, event.key.value); + _RGFW->keyboard[event.key.value].current = 0; + + RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); + event.key.mod = win->internal.mod; + + RGFW_keyCallback(win, event.key.value, event.key.sym, event.key.mod, event.key.repeat,0); + break; + } + case WM_SYSKEYDOWN: case WM_KEYDOWN: { + if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); + if (scancode == 0) + scancode = (i32)MapVirtualKeyW((u32)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; + } + + event.key.value = (u8)RGFW_apiKeyToRGFW((u32) scancode); + if (wParam == VK_CONTROL) { + if (HIWORD(lParam) & KF_EXTENDED) + event.key.value = RGFW_controlR; + else event.key.value = RGFW_controlL; + } + + wchar_t charBuffer; + ToUnicodeEx((UINT)wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL); + event.key.sym = (u8)charBuffer; + + _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; + event.type = RGFW_keyPressed; + event.key.repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, event.key.value); + _RGFW->keyboard[event.key.value].current = 1; + + RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); + event.key.mod = win->internal.mod; + + RGFW_keyCallback(win, event.key.value, event.key.sym, event.key.mod, event.key.repeat, 1); + break; + } + case WM_MOUSEMOVE: { + if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + if ((win->internal.holdMouse)) + break; + + + event.mouse.x = GET_X_LPARAM(lParam); + event.mouse.y = GET_Y_LPARAM(lParam); + event.mouse.vecX = (float)(event.mouse.x - win->internal.lastMouseX); + event.mouse.vecY = (float)(event.mouse.y - win->internal.lastMouseY); + _RGFW->vectorX = event.mouse.vecX; + _RGFW->vectorY = event.mouse.vecY; + + RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, event.mouse.vecX, event.mouse.vecY); + + if (win->internal.mouseInside == RGFW_FALSE) { + win->internal.mouseInside = RGFW_TRUE; + _RGFW->windowState.win = win; + _RGFW->windowState.mouseEnter = RGFW_TRUE; + event.type = RGFW_mouseEnter; + RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 1); + RGFW_eventQueuePush(&event); + } + + event.type = RGFW_mousePosChanged; + win->internal.lastMouseX = event.mouse.x; + win->internal.lastMouseY = event.mouse.y; + break; + } + case WM_INPUT: { + if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag) || !(win->internal.holdMouse)) return DefWindowProcW(hWnd, message, wParam, lParam); + unsigned size = sizeof(RAWINPUT); + static RAWINPUT raw; + + GetRawInputData((HRAWINPUT)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, 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) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width); + pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height); + ScreenToClient(win->src.window, &pos); + + event.mouse.vecX = (float)(pos.x - win->internal.lastMouseX); + event.mouse.vecY = (float)(pos.y - win->internal.lastMouseY); + } else { + event.mouse.vecX = (float)(raw.data.mouse.lLastX); + event.mouse.vecY = (float)(raw.data.mouse.lLastY); + } + + event.type = RGFW_mousePosChanged; + win->internal.lastMouseX += (i32)event.mouse.vecX; + win->internal.lastMouseY += (i32)event.mouse.vecY; + _RGFW->vectorX = event.mouse.vecX; + _RGFW->vectorY = event.mouse.vecY; + event.mouse.x = win->internal.lastMouseX; + event.mouse.y = win->internal.lastMouseY; + RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, event.mouse.vecX, event.mouse.vecY); + break; + } + case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: + if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + if (message == WM_XBUTTONDOWN) + event.button.value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2); + else event.button.value = (message == WM_LBUTTONDOWN) ? (u8)RGFW_mouseLeft : + (message == WM_RBUTTONDOWN) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle; + + event.type = RGFW_mouseButtonPressed; + _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; + _RGFW->mouseButtons[event.button.value].current = 1; + RGFW_mouseButtonCallback(win, event.button.value, 1); + break; + case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: + if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + if (message == WM_XBUTTONUP) + event.button.value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2); + else event.button.value = (message == WM_LBUTTONUP) ? (u8)RGFW_mouseLeft : + (message == WM_RBUTTONUP) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle; + event.type = RGFW_mouseButtonReleased; + _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; + _RGFW->mouseButtons[event.button.value].current = 0; + RGFW_mouseButtonCallback(win, event.button.value, 0); + break; + case WM_MOUSEWHEEL: + if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + + event.type = RGFW_mouseScroll; + event.scroll.x = 0.0f; + event.scroll.y = (float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA); + _RGFW->scrollX = event.scroll.x; + _RGFW->scrollY = event.scroll.y; + + RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); + break; + case 0x020E: /* WM_MOUSEHWHEEL */ + if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); + + event.type = RGFW_mouseScroll; + event.scroll.x = -(float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA); + event.scroll.y = (float)0.0f; + _RGFW->scrollX = event.scroll.x; + _RGFW->scrollY = event.scroll.y; + + RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); + break; + case WM_DROPFILES: { + event.type = RGFW_dataDrag; + + HDROP drop = (HDROP) wParam; + POINT pt; + + /* Move the mouse to the position of the drop */ + DragQueryPoint(drop, &pt); + + event.drag.x = pt.x; + event.drag.y = pt.y; + + _RGFW->windowState.win = win; + _RGFW->windowState.dataDragging = RGFW_TRUE; + _RGFW->windowState.dropX = event.drag.x; + _RGFW->windowState.dropY = event.drag.y; + + if ((win->internal.enabledEvents & RGFW_dataDrag)) { + RGFW_dataDragCallback(win, event.drag.x, event.drag.y); + RGFW_eventQueuePush(&event); + } + + if (!(win->internal.enabledEvents & RGFW_dataDrop)) return DefWindowProcW(hWnd, message, wParam, lParam); + event.type = 0; + event.type = RGFW_dataDrop; + event.drop.files = _RGFW->files; + event.drop.count = 0; + event.drop.count = DragQueryFileW(drop, 0xffffffff, NULL, 0); + + u32 i; + for (i = 0; i < event.drop.count; i++) { + UINT length = DragQueryFileW(drop, i, NULL, 0); + if (length == 0) + continue; + + WCHAR buffer[RGFW_MAX_PATH * 2]; + if (length > (RGFW_MAX_PATH * 2) - 1) + length = RGFW_MAX_PATH * 2; + + DragQueryFileW(drop, i, buffer, length + 1); + + RGFW_createUTF8FromWideStringWin32(buffer, event.drop.files[i], RGFW_MAX_PATH); + + event.drop.files[i][RGFW_MAX_PATH - 1] = '\0'; + event.common.win = win; + } + + DragFinish(drop); + + _RGFW->windowState.win = win; + _RGFW->windowState.dataDrop = RGFW_TRUE; + _RGFW->windowState.filesCount = event.drop.count; + RGFW_dataDropCallback(win, event.drop.files, event.drop.count); + break; + } default: break; } + + if (event.type) { + RGFW_eventQueuePush(&event); + } + return DefWindowProcW(hWnd, message, wParam, lParam); } @@ -6631,58 +9416,50 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) RGFW_ASSERT(name##SRC != NULL); \ } -#ifndef RGFW_NO_XINPUT -void RGFW_loadXInput(void); -void RGFW_loadXInput(void) { - u32 i; - static const char* names[] = {"xinput1_4.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll"}; - - for (i = 0; i < sizeof(names) / sizeof(const char*) && (XInputGetStateSRC == NULL || XInputGetKeystrokeSRC != NULL); i++) { - RGFW_XInput_dll = LoadLibraryA(names[i]); - RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetState); - RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetKeystroke); - } - - if (XInputGetStateSRC == NULL) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetState"); - if (XInputGetKeystrokeSRC == NULL) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetKeystroke"); -} -#endif - -void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){ -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - win->buffer = buffer; - win->bufferSize = area; +RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { + RGFW_ASSERT(surface != NULL); + surface->data = data; + surface->w = w; + surface->h = h; + surface->format = format; BITMAPV5HEADER bi; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); - bi.bV5Width = (i32)area.w; - bi.bV5Height = -((LONG) area.h); + bi.bV5Width = (i32)w; + bi.bV5Height = -((LONG) h); bi.bV5Planes = 1; - bi.bV5BitCount = 32; + bi.bV5BitCount = (format >= RGFW_formatRGBA8) ? 32 : 24; bi.bV5Compression = BI_RGB; - win->src.bitmap = CreateDIBSection(win->src.hdc, + surface->native.bitmap = CreateDIBSection(_RGFW->root->src.hdc, (BITMAPINFO*) &bi, DIB_RGB_COLORS, - (void**) &win->src.bitmapBits, + (void**) &surface->native.bitmapBits, NULL, (DWORD) 0); - if (win->buffer == NULL) - win->buffer = win->src.bitmapBits; + surface->native.format = (format >= RGFW_formatRGBA8) ? RGFW_formatBGRA8 : RGFW_formatBGR8; - win->src.hdcMem = CreateCompatibleDC(win->src.hdc); - SelectObject(win->src.hdcMem, win->src.bitmap); + if (surface->native.bitmap == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create DIB section."); + return RGFW_FALSE; + } - #if defined(RGFW_OSMESA) - win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - #else - RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ - #endif + surface->native.hdcMem = CreateCompatibleDC(_RGFW->root->src.hdc); + SelectObject(surface->native.hdcMem, surface->native.bitmap); + + return RGFW_TRUE; +} + +void RGFW_surface_freePtr(RGFW_surface* surface) { + RGFW_ASSERT(surface != NULL); + + DeleteDC(surface->native.hdcMem); + DeleteObject(surface->native.bitmap); +} + +void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { + RGFW_copyImageData(surface->native.bitmapBits, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); + BitBlt(win->src.hdc, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h), surface->native.hdcMem, 0, 0, SRCCOPY); } void RGFW_releaseCursor(RGFW_window* win) { @@ -6692,8 +9469,8 @@ void RGFW_releaseCursor(RGFW_window* win) { RegisterRawInputDevices(&id, 1, sizeof(id)); } -void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) { - RGFW_UNUSED(win); RGFW_UNUSED(rect); +void RGFW_captureCursor(RGFW_window* win) { + RGFW_UNUSED(win); RECT clipRect; GetClientRect(win->src.window, &clipRect); @@ -6708,13 +9485,13 @@ void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) { #define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); } #ifdef RGFW_DIRECTX -int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) { +int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) { RGFW_ASSERT(win && pFactory && pDevice && swapchain); static DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; swapChainDesc.BufferCount = 2; - swapChainDesc.BufferDesc.Width = win->r.w; - swapChainDesc.BufferDesc.Height = win->r.h; + swapChainDesc.BufferDesc.Width = win->w; + swapChainDesc.BufferDesc.Height = win->h; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.OutputWindow = (HWND)win->src.window; @@ -6725,7 +9502,7 @@ int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnk HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain); if (FAILED(hr)) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, RGFW_DEBUG_CTX(win, hr), "Failed to create DirectX swap chain!"); + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, "Failed to create DirectX swap chain!"); return -2; } @@ -6733,143 +9510,130 @@ int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnk } #endif -void RGFW_win32_loadOpenGLFuncs(HWND dummyWin); -void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) { -#ifdef RGFW_OPENGL - if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL) - return; - - HDC dummy_dc = GetDC(dummyWin); - u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - - PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0}; - - int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd); - SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd); - - HGLRC dummy_context = wglCreateContext(dummy_dc); - wglMakeCurrent(dummy_dc, dummy_context); - - wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB"); - wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB"); - - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT"); - if (wglSwapIntervalEXT == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function"); - } - - wglMakeCurrent(dummy_dc, 0); - wglDeleteContext(dummy_context); - ReleaseDC(dummyWin, dummy_dc); -#else - RGFW_UNUSED(dummyWin); -#endif +/* we're doing it with magic numbers because some keys are missing */ +void RGFW_initKeycodesPlatform(void) { + _RGFW->keycodes[0x00B] = RGFW_0; + _RGFW->keycodes[0x002] = RGFW_1; + _RGFW->keycodes[0x003] = RGFW_2; + _RGFW->keycodes[0x004] = RGFW_3; + _RGFW->keycodes[0x005] = RGFW_4; + _RGFW->keycodes[0x006] = RGFW_5; + _RGFW->keycodes[0x007] = RGFW_6; + _RGFW->keycodes[0x008] = RGFW_7; + _RGFW->keycodes[0x009] = RGFW_8; + _RGFW->keycodes[0x00A] = RGFW_9; + _RGFW->keycodes[0x01E] = RGFW_a; + _RGFW->keycodes[0x030] = RGFW_b; + _RGFW->keycodes[0x02E] = RGFW_c; + _RGFW->keycodes[0x020] = RGFW_d; + _RGFW->keycodes[0x012] = RGFW_e; + _RGFW->keycodes[0x021] = RGFW_f; + _RGFW->keycodes[0x022] = RGFW_g; + _RGFW->keycodes[0x023] = RGFW_h; + _RGFW->keycodes[0x017] = RGFW_i; + _RGFW->keycodes[0x024] = RGFW_j; + _RGFW->keycodes[0x025] = RGFW_k; + _RGFW->keycodes[0x026] = RGFW_l; + _RGFW->keycodes[0x032] = RGFW_m; + _RGFW->keycodes[0x031] = RGFW_n; + _RGFW->keycodes[0x018] = RGFW_o; + _RGFW->keycodes[0x019] = RGFW_p; + _RGFW->keycodes[0x010] = RGFW_q; + _RGFW->keycodes[0x013] = RGFW_r; + _RGFW->keycodes[0x01F] = RGFW_s; + _RGFW->keycodes[0x014] = RGFW_t; + _RGFW->keycodes[0x016] = RGFW_u; + _RGFW->keycodes[0x02F] = RGFW_v; + _RGFW->keycodes[0x011] = RGFW_w; + _RGFW->keycodes[0x02D] = RGFW_x; + _RGFW->keycodes[0x015] = RGFW_y; + _RGFW->keycodes[0x02C] = RGFW_z; + _RGFW->keycodes[0x028] = RGFW_apostrophe; + _RGFW->keycodes[0x02B] = RGFW_backSlash; + _RGFW->keycodes[0x033] = RGFW_comma; + _RGFW->keycodes[0x00D] = RGFW_equals; + _RGFW->keycodes[0x029] = RGFW_backtick; + _RGFW->keycodes[0x01A] = RGFW_bracket; + _RGFW->keycodes[0x00C] = RGFW_minus; + _RGFW->keycodes[0x034] = RGFW_period; + _RGFW->keycodes[0x01B] = RGFW_closeBracket; + _RGFW->keycodes[0x027] = RGFW_semicolon; + _RGFW->keycodes[0x035] = RGFW_slash; + _RGFW->keycodes[0x056] = RGFW_world2; + _RGFW->keycodes[0x00E] = RGFW_backSpace; + _RGFW->keycodes[0x153] = RGFW_delete; + _RGFW->keycodes[0x14F] = RGFW_end; + _RGFW->keycodes[0x01C] = RGFW_enter; + _RGFW->keycodes[0x001] = RGFW_escape; + _RGFW->keycodes[0x147] = RGFW_home; + _RGFW->keycodes[0x152] = RGFW_insert; + _RGFW->keycodes[0x15D] = RGFW_menu; + _RGFW->keycodes[0x151] = RGFW_pageDown; + _RGFW->keycodes[0x149] = RGFW_pageUp; + _RGFW->keycodes[0x045] = RGFW_pause; + _RGFW->keycodes[0x039] = RGFW_space; + _RGFW->keycodes[0x00F] = RGFW_tab; + _RGFW->keycodes[0x03A] = RGFW_capsLock; + _RGFW->keycodes[0x145] = RGFW_numLock; + _RGFW->keycodes[0x046] = RGFW_scrollLock; + _RGFW->keycodes[0x03B] = RGFW_F1; + _RGFW->keycodes[0x03C] = RGFW_F2; + _RGFW->keycodes[0x03D] = RGFW_F3; + _RGFW->keycodes[0x03E] = RGFW_F4; + _RGFW->keycodes[0x03F] = RGFW_F5; + _RGFW->keycodes[0x040] = RGFW_F6; + _RGFW->keycodes[0x041] = RGFW_F7; + _RGFW->keycodes[0x042] = RGFW_F8; + _RGFW->keycodes[0x043] = RGFW_F9; + _RGFW->keycodes[0x044] = RGFW_F10; + _RGFW->keycodes[0x057] = RGFW_F11; + _RGFW->keycodes[0x058] = RGFW_F12; + _RGFW->keycodes[0x064] = RGFW_F13; + _RGFW->keycodes[0x065] = RGFW_F14; + _RGFW->keycodes[0x066] = RGFW_F15; + _RGFW->keycodes[0x067] = RGFW_F16; + _RGFW->keycodes[0x068] = RGFW_F17; + _RGFW->keycodes[0x069] = RGFW_F18; + _RGFW->keycodes[0x06A] = RGFW_F19; + _RGFW->keycodes[0x06B] = RGFW_F20; + _RGFW->keycodes[0x06C] = RGFW_F21; + _RGFW->keycodes[0x06D] = RGFW_F22; + _RGFW->keycodes[0x06E] = RGFW_F23; + _RGFW->keycodes[0x076] = RGFW_F24; + _RGFW->keycodes[0x038] = RGFW_altL; + _RGFW->keycodes[0x01D] = RGFW_controlL; + _RGFW->keycodes[0x02A] = RGFW_shiftL; + _RGFW->keycodes[0x15B] = RGFW_superL; + _RGFW->keycodes[0x137] = RGFW_printScreen; + _RGFW->keycodes[0x138] = RGFW_altR; + _RGFW->keycodes[0x11D] = RGFW_controlR; + _RGFW->keycodes[0x036] = RGFW_shiftR; + _RGFW->keycodes[0x15C] = RGFW_superR; + _RGFW->keycodes[0x150] = RGFW_down; + _RGFW->keycodes[0x14B] = RGFW_left; + _RGFW->keycodes[0x14D] = RGFW_right; + _RGFW->keycodes[0x148] = RGFW_up; + _RGFW->keycodes[0x052] = RGFW_kp0; + _RGFW->keycodes[0x04F] = RGFW_kp1; + _RGFW->keycodes[0x050] = RGFW_kp2; + _RGFW->keycodes[0x051] = RGFW_kp3; + _RGFW->keycodes[0x04B] = RGFW_kp4; + _RGFW->keycodes[0x04C] = RGFW_kp5; + _RGFW->keycodes[0x04D] = RGFW_kp6; + _RGFW->keycodes[0x047] = RGFW_kp7; + _RGFW->keycodes[0x048] = RGFW_kp8; + _RGFW->keycodes[0x049] = RGFW_kp9; + _RGFW->keycodes[0x04E] = RGFW_kpPlus; + _RGFW->keycodes[0x053] = RGFW_kpPeriod; + _RGFW->keycodes[0x135] = RGFW_kpSlash; + _RGFW->keycodes[0x11C] = RGFW_kpReturn; + _RGFW->keycodes[0x059] = RGFW_kpEqual; + _RGFW->keycodes[0x037] = RGFW_kpMultiply; + _RGFW->keycodes[0x04A] = RGFW_kpMinus; } -#ifndef RGFW_EGL -void RGFW_window_initOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - PIXELFORMATDESCRIPTOR pfd; - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.iLayerType = PFD_MAIN_PLANE; - pfd.cColorBits = 32; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = (BYTE)RGFW_GL_HINTS[RGFW_glStencil]; - pfd.cAuxBuffers = (BYTE)RGFW_GL_HINTS[RGFW_glAuxBuffers]; - if (RGFW_GL_HINTS[RGFW_glStereo]) pfd.dwFlags |= PFD_STEREO; - - /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */ - if (win->_flags & RGFW_windowOpenglSoftware) - pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED; - - /* get pixel format, default to a basic pixel format */ - int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd); - if (wglChoosePixelFormatARB != NULL) { - i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs(); - - int new_pixel_format; - UINT num_formats; - wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats); - if (!num_formats) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create a pixel format for WGL"); - else pixel_format = new_pixel_format; - } - - PIXELFORMATDESCRIPTOR suggested; - if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) || - !SetPixelFormat(win->src.hdc, pixel_format, &pfd)) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set the WGL pixel format"); - - if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) { - win->_flags |= RGFW_windowOpenglSoftware; - } - - if (wglCreateContextAttribsARB != NULL) { - /* create opengl/WGL context for the specified version */ - u32 index = 0; - i32 attribs[40]; - - if (RGFW_GL_HINTS[RGFW_glProfile]== RGFW_glCore) { - SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB); - } - else { - SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); - } - - if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) { - SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMajor]); - SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMinor]); - } - - SET_ATTRIB(0, 0); - - win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); - } else { /* fall back to a default context (probably opengl 2 or something) */ - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create an accelerated OpenGL Context"); - win->src.ctx = wglCreateContext(win->src.hdc); - } - - ReleaseDC(win->src.window, win->src.hdc); - win->src.hdc = GetDC(win->src.window); - wglMakeCurrent(win->src.hdc, win->src.ctx); - - if (_RGFW.root != win) - wglShareLists(_RGFW.root->src.ctx, win->src.ctx); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); -#else - RGFW_UNUSED(win); -#endif -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - if (win->src.ctx == NULL) return; - wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */ - win->src.ctx = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); -#else - RGFW_UNUSED(win); -#endif -} -#endif - - -i32 RGFW_init(void) { -#if defined(RGFW_C89) || defined(__cplusplus) - if (_RGFW_init) return 0; - _RGFW_init = RGFW_TRUE; - _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; -#endif - - #ifndef RGFW_NO_XINPUT - if (RGFW_XInput_dll == NULL) - RGFW_loadXInput(); - #endif +i32 RGFW_initPlatform(void) { #ifndef RGFW_NO_DPI #if (_WIN32_WINNT >= 0x0600) SetProcessDPIAware(); @@ -6902,36 +9666,33 @@ i32 RGFW_init(void) { #endif u8 RGFW_blk[] = { 0, 0, 0, 0 }; - _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4); - - _RGFW.windowCount = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); + _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); return 1; } -RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { +RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { if (name[0] == 0) name = (char*) " "; - - RGFW_window_basic_init(win, rect, flags); - win->src.hIconSmall = win->src.hIconBig = NULL; - win->src.maxSize = RGFW_AREA(0, 0); - win->src.minSize = RGFW_AREA(0, 0); - win->src.aspectRatio = RGFW_AREA(0, 0); + win->src.maxSizeW = 0; + win->src.maxSizeH = 0; + win->src.minSizeW = 0; + win->src.minSizeH = 0; + win->src.aspectRatioW = 0; + win->src.aspectRatioH = 0; HINSTANCE inh = GetModuleHandleA(NULL); #ifndef __cplusplus - WNDCLASSW Class = { 0 }; /*!< Setup the Window class. */ + WNDCLASSW Class = {0}; /*!< Setup the Window class. */ #else - WNDCLASSW Class = { }; + WNDCLASSW Class = {}; #endif - if (RGFW_className == NULL) - RGFW_className = (char*)name; + if (_RGFW->className == NULL) + _RGFW->className = (char*)name; wchar_t wide_class[256]; - MultiByteToWideChar(CP_UTF8, 0, RGFW_className, -1, wide_class, 255); + MultiByteToWideChar(CP_UTF8, 0, _RGFW->className, -1, wide_class, 255); Class.lpszClassName = wide_class; Class.hInstance = inh; @@ -6950,7 +9711,7 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF RECT windowRect, clientRect; if (!(flags & RGFW_windowNoBorder)) { - window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX | WS_THICKFRAME; + window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX; if (!(flags & RGFW_windowNoResize)) window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX; @@ -6959,43 +9720,37 @@ RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowF wchar_t wide_name[256]; MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255); - HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0); + HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x, win->y, win->w, win->h, 0, 0, inh, 0); GetWindowRect(dummyWin, &windowRect); GetClientRect(dummyWin, &clientRect); +#ifdef RGFW_OPENGL RGFW_win32_loadOpenGLFuncs(dummyWin); +#endif + DestroyWindow(dummyWin); - win->src.hOffset = (u32)(windowRect.bottom - windowRect.top) - (u32)(clientRect.bottom - clientRect.top); - win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + (i32)win->src.hOffset, 0, 0, inh, 0); + win->src.offsetW = (i32)(windowRect.right - windowRect.left) - (i32)(clientRect.right - clientRect.left); + win->src.offsetH = (i32)(windowRect.bottom - windowRect.top) - (i32)(clientRect.bottom - clientRect.top); + win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x, win->y, win->w + (i32)win->src.offsetW, win->h + (i32)win->src.offsetH, 0, 0, inh, 0); SetPropW(win->src.window, L"RGFW", win); - RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); /* so WM_GETMINMAXINFO gets called again */ + RGFW_window_resize(win, win->w, win->h); /* so WM_GETMINMAXINFO gets called again */ if (flags & RGFW_windowAllowDND) { - win->_flags |= RGFW_windowAllowDND; + win->internal.flags |= RGFW_windowAllowDND; RGFW_window_setDND(win, 1); } win->src.hdc = GetDC(win->src.window); - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initOpenGL(win); - RGFW_window_initBuffer(win); - } - - RGFW_window_setFlags(win, flags); RGFW_win32_makeWindowTransparent(win); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - RGFW_window_show(win); - - return win; + return win; } void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { - RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); + RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); LONG style = GetWindowLong(win->src.window, GWL_STYLE); - if (border == 0) { SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); SetWindowPos( @@ -7004,8 +9759,8 @@ void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { ); } else { - style |= WS_OVERLAPPEDWINDOW; - if (win->_flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX; + if (win->internal.flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX; + SetWindowLong(win->src.window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW); SetWindowPos( win->src.window, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE @@ -7014,37 +9769,34 @@ void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { } void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { - RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow); + RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow); DragAcceptFiles(win->src.window, allow); } -RGFW_area RGFW_getScreenSize(void) { - HDC dc = GetDC(NULL); - RGFW_area area = RGFW_AREA(GetDeviceCaps(dc, HORZRES), GetDeviceCaps(dc, VERTRES)); - ReleaseDC(NULL, dc); - return area; -} - -RGFW_point RGFW_getGlobalMousePoint(void) { +RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { POINT p; GetCursorPos(&p); - - return RGFW_POINT(p.x, p.y); + if (x) *x = p.x; + if (y) *y = p.y; + return RGFW_TRUE; } -void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { +void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); - win->src.aspectRatio = a; + win->src.aspectRatioW = w; + win->src.aspectRatioH = h; } -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { +void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); - win->src.minSize = a; + win->src.minSizeW = w; + win->src.minSizeH = h; } -void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { +void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); - win->src.maxSize = a; + win->src.maxSizeW = w; + win->src.maxSizeH = h; } void RGFW_window_focus(RGFW_window* win) { @@ -7056,7 +9808,7 @@ void RGFW_window_focus(RGFW_window* win) { void RGFW_window_raise(RGFW_window* win) { RGFW_ASSERT(win); BringWindowToTop(win->src.window); - SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, win->r.w, win->r.h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, win->w, win->h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { @@ -7064,24 +9816,32 @@ void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { if (fullscreen == RGFW_FALSE) { RGFW_window_setBorder(win, 1); - SetWindowPos(win->src.window, HWND_NOTOPMOST, win->_oldRect.x, win->_oldRect.y, win->_oldRect.w, win->_oldRect.h + (i32)win->src.hOffset, + SetWindowPos(win->src.window, HWND_NOTOPMOST, win->internal.oldX, win->internal.oldY, win->internal.oldW + (i32)win->src.offsetW, win->internal.oldH + (i32)win->src.offsetH, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - win->_flags &= ~(u32)RGFW_windowFullscreen; - win->r = win->_oldRect; + win->internal.flags &= ~(u32)RGFW_windowFullscreen; + win->x = win->internal.oldX; + win->y = win->internal.oldY; + win->w = win->internal.oldW; + win->h = win->internal.oldH; return; } - win->_oldRect = win->r; - win->_flags |= RGFW_windowFullscreen; + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; + win->internal.flags |= RGFW_windowFullscreen; RGFW_monitor mon = RGFW_window_getMonitor(win); RGFW_window_setBorder(win, 0); - SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon.mode.area.w, (i32)mon.mode.area.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW); + SetWindowPos(win->src.window, HWND_TOPMOST, (i32)mon.x, (i32)mon.x, (i32)mon.mode.w, (i32)mon.mode.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW); RGFW_monitor_scaleToWindow(mon, win); - win->r = RGFW_RECT(0, 0, mon.mode.area.w, mon.mode.area.h); + win->x = mon.x; win->y = mon.x; + win->w = mon.mode.w; + win->h = mon.mode.h; } void RGFW_window_maximize(RGFW_window* win) { @@ -7112,149 +9872,16 @@ RGFW_bool RGFW_window_isFloating(RGFW_window* win) { return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; } -u8 RGFW_xinput2RGFW[] = { - RGFW_gamepadA, /* or PS X button */ - RGFW_gamepadB, /* or PS circle button */ - RGFW_gamepadX, /* or PS square button */ - RGFW_gamepadY, /* or PS triangle button */ - RGFW_gamepadR1, /* right bumper */ - RGFW_gamepadL1, /* left bump */ - RGFW_gamepadL2, /* left trigger */ - RGFW_gamepadR2, /* right trigger */ - 0, 0, 0, 0, 0, 0, 0, 0, - RGFW_gamepadUp, /* dpad up */ - RGFW_gamepadDown, /* dpad down */ - RGFW_gamepadLeft, /* dpad left */ - RGFW_gamepadRight, /* dpad right */ - RGFW_gamepadStart, /* start button */ - RGFW_gamepadSelect,/* select button */ - RGFW_gamepadL3, - RGFW_gamepadR3, -}; -i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e); -i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e) { - #ifndef RGFW_NO_XINPUT - - RGFW_UNUSED(win); - u16 i; - for (i = 0; i < 4; i++) { - XINPUT_KEYSTROKE keystroke; - - if (XInputGetKeystroke == NULL) - return 0; - - DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke); - - if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) { - if (result != ERROR_SUCCESS) - return 0; - - if (keystroke.VirtualKey > VK_PAD_RTHUMB_PRESS) - continue; - - /* gamepad + 1 = RGFW_gamepadButtonReleased */ - e->type = RGFW_gamepadButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); - e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800]; - RGFW_gamepadPressed[i][e->button].prev = RGFW_gamepadPressed[i][e->button].current; - RGFW_gamepadPressed[i][e->button].current = RGFW_BOOL(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); - - RGFW_gamepadButtonCallback(win, i, e->button, e->type == RGFW_gamepadButtonPressed); - return 1; - } - - XINPUT_STATE state; - if (XInputGetState == NULL || - XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED - ) { - if (RGFW_gamepads[i] == 0) - continue; - - RGFW_gamepads[i] = 0; - RGFW_gamepadCount--; - - win->event.type = RGFW_gamepadDisconnected; - win->event.gamepad = (u16)i; - RGFW_gamepadCallback(win, i, 0); - return 1; - } - - if (RGFW_gamepads[i] == 0) { - RGFW_gamepads[i] = 1; - RGFW_gamepadCount++; - - char str[] = "Microsoft X-Box (XInput device)"; - RGFW_MEMCPY(RGFW_gamepads_name[i], str, sizeof(str)); - RGFW_gamepads_name[i][sizeof(RGFW_gamepads_name[i]) - 1] = '\0'; - win->event.type = RGFW_gamepadConnected; - win->event.gamepad = i; - RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; - - RGFW_gamepadCallback(win, i, 1); - return 1; - } - -#define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) /* Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed. */ - - if ((state.Gamepad.sThumbLX < INPUT_DEADZONE && - state.Gamepad.sThumbLX > -INPUT_DEADZONE) && - (state.Gamepad.sThumbLY < INPUT_DEADZONE && - state.Gamepad.sThumbLY > -INPUT_DEADZONE)) - { - state.Gamepad.sThumbLX = 0; - state.Gamepad.sThumbLY = 0; - } - - if ((state.Gamepad.sThumbRX < INPUT_DEADZONE && - state.Gamepad.sThumbRX > -INPUT_DEADZONE) && - (state.Gamepad.sThumbRY < INPUT_DEADZONE && - state.Gamepad.sThumbRY > -INPUT_DEADZONE)) - { - state.Gamepad.sThumbRX = 0; - state.Gamepad.sThumbRY = 0; - } - - e->axisesCount = 2; - RGFW_point axis1 = RGFW_POINT(((float)state.Gamepad.sThumbLX / 32768.0f) * 100, ((float)state.Gamepad.sThumbLY / -32768.0f) * 100); - RGFW_point axis2 = RGFW_POINT(((float)state.Gamepad.sThumbRX / 32768.0f) * 100, ((float)state.Gamepad.sThumbRY / -32768.0f) * 100); - - if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y){ - win->event.whichAxis = 0; - - e->type = RGFW_gamepadAxisMove; - e->axis[0] = axis1; - RGFW_gamepadAxes[i][0] = e->axis[0]; - - RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis); - return 1; - } - - if (axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) { - win->event.whichAxis = 1; - e->type = RGFW_gamepadAxisMove; - e->axis[1] = axis2; - RGFW_gamepadAxes[i][1] = e->axis[1]; - - RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis); - return 1; - } - } - - #endif - - return 0; -} - void RGFW_stopCheckEvents(void) { - PostMessageW(_RGFW.root->src.window, WM_NULL, 0, 0); + PostMessageW(_RGFW->root->src.window, WM_NULL, 0, 0); } -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - RGFW_UNUSED(win); +void RGFW_waitForEvent(i32 waitMS) { MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT); } u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { - UINT vsc = RGFW_rgfwToApiKey(rgfw_keycode); // Should return a Windows VK_* code + UINT vsc = RGFW_rgfwToApiKey(rgfw_keycode); /* Should return a Windows VK_* code */ BYTE keyboardState[256] = {0}; if (!GetKeyboardState(keyboardState)) @@ -7272,273 +9899,17 @@ u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { return (u8)charBuffer[0]; } -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; - RGFW_event* ev = RGFW_window_checkEventCore(win); - if (ev) { - return ev; - } - - static HDROP drop; - if (win->event.type == RGFW_DNDInit) { - if (win->event.droppedFilesCount) { - u32 i; - for (i = 0; i < win->event.droppedFilesCount; i++) - win->event.droppedFiles[i][0] = '\0'; - } - - win->event.droppedFilesCount = 0; - win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0); - - u32 i; - for (i = 0; i < win->event.droppedFilesCount; i++) { - UINT length = DragQueryFileW(drop, i, NULL, 0); - if (length == 0) - continue; - - WCHAR buffer[RGFW_MAX_PATH * 2]; - if (length > (RGFW_MAX_PATH * 2) - 1) - length = RGFW_MAX_PATH * 2; - - DragQueryFileW(drop, i, buffer, length + 1); - - char* str = RGFW_createUTF8FromWideStringWin32(buffer); - if (str != NULL) - RGFW_MEMCPY(win->event.droppedFiles[i], str, length + 1); - - win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; - } - - DragFinish(drop); - RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); - - win->event.type = RGFW_DND; - return &win->event; - } - - if (RGFW_checkXInput(win, &win->event)) - return &win->event; - - static BYTE keyboardState[256]; - GetKeyboardState(keyboardState); - +void RGFW_pollEvents(void) { + RGFW_resetPrevState(); MSG msg; - if (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) { - if (msg.hwnd != win->src.window && msg.hwnd != NULL) { - TranslateMessage(&msg); - DispatchMessageA(&msg); - return RGFW_window_checkEvent(win); - } - } else { - return NULL; - } - - switch (msg.message) { - case WM_MOUSELEAVE: - win->event.type = RGFW_mouseLeave; - win->_flags |= RGFW_MOUSE_LEFT; - RGFW_mouseNotifyCallback(win, win->event.point, 0); - break; - case WM_SYSKEYUP: case WM_KEYUP: { - i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); - if (scancode == 0) - scancode = (i32)MapVirtualKeyW((UINT)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 = (u8)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((UINT)msg.wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL); - - win->event.keyChar = (u8)charBuffer; - - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - win->event.type = RGFW_keyReleased; - RGFW_keyboard[win->event.key].current = 0; - - RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); - break; - } - case WM_SYSKEYDOWN: case WM_KEYDOWN: { - i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); - if (scancode == 0) - scancode = (i32)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 = (u8)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((UINT)msg.wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL); - win->event.keyChar = (u8)charBuffer; - - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - - win->event.type = RGFW_keyPressed; - win->event.repeat = RGFW_isPressed(win, win->event.key); - RGFW_keyboard[win->event.key].current = 1; - RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1); - break; - } - case WM_MOUSEMOVE: { - if ((win->_flags & RGFW_HOLD_MOUSE)) - break; - - win->event.type = RGFW_mousePosChanged; - - i32 x = GET_X_LPARAM(msg.lParam); - i32 y = GET_Y_LPARAM(msg.lParam); - - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - - if (win->_flags & RGFW_MOUSE_LEFT) { - win->_flags &= ~(u32)RGFW_MOUSE_LEFT; - win->event.type = RGFW_mouseEnter; - RGFW_mouseNotifyCallback(win, win->event.point, 1); - } - - win->event.point.x = x; - win->event.point.y = y; - win->_lastMousePoint = RGFW_POINT(x, y); - - break; - } - case WM_INPUT: { - if (!(win->_flags & RGFW_HOLD_MOUSE)) - break; - - unsigned size = sizeof(RAWINPUT); - static RAWINPUT raw; - - 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, 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) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width); - pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height); - ScreenToClient(win->src.window, &pos); - - win->event.vector.x = pos.x - win->_lastMousePoint.x; - win->event.vector.y = pos.y - win->_lastMousePoint.y; - } else { - win->event.vector.x = raw.data.mouse.lLastX; - win->event.vector.y = raw.data.mouse.lLastY; - } - - win->event.type = RGFW_mousePosChanged; - win->_lastMousePoint.x += win->event.vector.x; - win->_lastMousePoint.y += win->event.vector.y; - win->event.point = win->_lastMousePoint; - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - break; - } - case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: - if (msg.message == WM_XBUTTONDOWN) - win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2); - else win->event.button = (msg.message == WM_LBUTTONDOWN) ? RGFW_mouseLeft : - (msg.message == WM_RBUTTONDOWN) ? RGFW_mouseRight : RGFW_mouseMiddle; - - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: - if (msg.message == WM_XBUTTONUP) - win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2); - else win->event.button = (msg.message == WM_LBUTTONUP) ? RGFW_mouseLeft : - (msg.message == WM_RBUTTONUP) ? RGFW_mouseRight : RGFW_mouseMiddle; - win->event.type = RGFW_mouseButtonReleased; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; - case WM_MOUSEWHEEL: - if (msg.wParam > 0) - win->event.button = RGFW_mouseScrollUp; - else - win->event.button = RGFW_mouseScrollDown; - - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - - win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA; - - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - case WM_DROPFILES: { - win->event.type = RGFW_DNDInit; - - drop = (HDROP) msg.wParam; - POINT pt; - - /* Move the mouse to the position of the drop */ - DragQueryPoint(drop, &pt); - - win->event.point.x = pt.x; - win->event.point.y = pt.y; - - RGFW_dndInitCallback(win, win->event.point); - } - break; - default: - TranslateMessage(&msg); - DispatchMessageA(&msg); - return RGFW_window_checkEvent(win); + while (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); } - - TranslateMessage(&msg); - DispatchMessageA(&msg); - - return &win->event; } RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_ASSERT(win != NULL); - return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win); } @@ -7546,9 +9917,9 @@ RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_ASSERT(win != NULL); #ifndef __cplusplus - WINDOWPLACEMENT placement = { 0 }; + WINDOWPLACEMENT placement = {0}; #else - WINDOWPLACEMENT placement = { }; + WINDOWPLACEMENT placement = {}; #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMINIMIZED; @@ -7558,9 +9929,9 @@ RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_ASSERT(win != NULL); #ifndef __cplusplus - WINDOWPLACEMENT placement = { 0 }; + WINDOWPLACEMENT placement = {0}; #else - WINDOWPLACEMENT placement = { }; + WINDOWPLACEMENT placement = {}; #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window); @@ -7568,51 +9939,49 @@ RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { typedef struct { int iIndex; HMONITOR hMonitor; RGFW_monitor* monitors; } RGFW_mInfo; #ifndef RGFW_NO_MONITOR -RGFW_monitor win32CreateMonitor(HMONITOR src); -RGFW_monitor win32CreateMonitor(HMONITOR src) { +RGFW_monitor RGFW_win32_createMonitor(HMONITOR src); +RGFW_monitor RGFW_win32_createMonitor(HMONITOR src) { RGFW_monitor monitor; - MONITORINFOEX monitorInfo; + RGFW_MEMSET(&monitor, 0, sizeof(monitor)); - monitorInfo.cbSize = sizeof(MONITORINFOEX); - GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo); + MONITORINFOEXW monitorInfo; + monitorInfo.cbSize = sizeof(MONITORINFOEXW); + GetMonitorInfoW(src, (LPMONITORINFO)&monitorInfo); /* get the monitor's index */ - DISPLAY_DEVICEA dd; + DISPLAY_DEVICEW dd; dd.cb = sizeof(dd); DWORD deviceNum; - for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) { + for (deviceNum = 0; EnumDisplayDevicesW(NULL, deviceNum, &dd, 0); deviceNum++) { if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; - DEVMODEA dm; + DEVMODEW dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); - if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { + if (EnumDisplaySettingsW(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { monitor.mode.refreshRate = dm.dmDisplayFrequency; RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode); } - DISPLAY_DEVICEA mdd; + DISPLAY_DEVICEW mdd; mdd.cb = sizeof(mdd); - if (EnumDisplayDevicesA(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) { - RGFW_STRNCPY(monitor.name, mdd.DeviceString, sizeof(monitor.name) - 1); + if (EnumDisplayDevicesW(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) { + RGFW_createUTF8FromWideStringWin32(mdd.DeviceString, monitor.name, sizeof(monitor.name)); monitor.name[sizeof(monitor.name) - 1] = '\0'; break; } } - - - monitor.x = monitorInfo.rcWork.left; monitor.y = monitorInfo.rcWork.top; - monitor.mode.area.w = (u32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left); - monitor.mode.area.h = (u32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); + monitor.mode.w = (i32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left); + monitor.mode.h = (i32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); - HDC hdc = CreateDC(monitorInfo.szDevice, NULL, NULL, NULL); + HDC hdc = CreateDCW(monitorInfo.szDevice, NULL, NULL, NULL); /* get pixels per inch */ float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX); float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX); @@ -7638,7 +10007,7 @@ RGFW_monitor win32CreateMonitor(HMONITOR src) { } #endif - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); return monitor; } #endif /* RGFW_NO_MONITOR */ @@ -7655,7 +10024,7 @@ BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMon if (info->iIndex >= 6) return FALSE; - info->monitors[info->iIndex] = win32CreateMonitor(hMonitor); + info->monitors[info->iIndex] = RGFW_win32_createMonitor(hMonitor); info->iIndex++; return TRUE; @@ -7663,9 +10032,9 @@ BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMon RGFW_monitor RGFW_getPrimaryMonitor(void) { #ifdef __cplusplus - return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + return RGFW_win32_createMonitor(MonitorFromPoint({0, 0}, MONITOR_DEFAULTTOPRIMARY)); #else - return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + return RGFW_win32_createMonitor(MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY)); #endif } @@ -7683,7 +10052,7 @@ RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY); - return win32CreateMonitor(src); + return RGFW_win32_createMonitor(src); } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { @@ -7705,7 +10074,7 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW if (strcmp(dd.DeviceName, (const char*)monitorInfo.szDevice) != 0) continue; - + DEVMODEA dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); @@ -7713,8 +10082,8 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { if (request & RGFW_monitorScale) { dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; - dm.dmPelsWidth = mode.area.w; - dm.dmPelsHeight = mode.area.h; + dm.dmPelsWidth = (u32)mode.w; + dm.dmPelsHeight = (u32)mode.h; } if (request & RGFW_monitorRefresh) { @@ -7727,8 +10096,8 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW dm.dmBitsPerPel = (DWORD)(mode.red + mode.green + mode.blue); } - if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { - if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) + if (ChangeDisplaySettingsExA(dd.DeviceName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { + if (ChangeDisplaySettingsExA(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) return RGFW_TRUE; return RGFW_FALSE; } else return RGFW_FALSE; @@ -7739,17 +10108,15 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW } #endif -HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon); -HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) { - size_t channels = (size_t)c; - +HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon); +HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon) { BITMAPV5HEADER bi; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); - bi.bV5Width = (i32)a.w; - bi.bV5Height = -((LONG) a.h); + bi.bV5Width = (i32)w; + bi.bV5Height = -((LONG) h); bi.bV5Planes = 1; - bi.bV5BitCount = (WORD)(channels * 8); + bi.bV5BitCount = (WORD)32; bi.bV5Compression = BI_RGB; HDC dc = GetDC(NULL); u8* target = NULL; @@ -7758,26 +10125,16 @@ HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) { (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target, NULL, (DWORD) 0); - size_t x, y; - for (y = 0; y < a.h; y++) { - for (x = 0; x < a.w; x++) { - size_t index = (y * 4 * (size_t)a.w) + x * channels; - target[index] = src[index + 2]; - target[index + 1] = src[index + 1]; - target[index + 2] = src[index]; - target[index + 3] = src[index + 3]; - } - } - + RGFW_copyImageData(target, w, h, RGFW_formatBGRA8, data, format); ReleaseDC(NULL, dc); - HBITMAP mask = CreateBitmap((i32)a.w, (i32)a.h, 1, 1, NULL); + HBITMAP mask = CreateBitmap((i32)w, (i32)h, 1, 1, NULL); ICONINFO ii; ZeroMemory(&ii, sizeof(ii)); ii.fIcon = icon; - ii.xHotspot = a.w / 2; - ii.yHotspot = a.h / 2; + ii.xHotspot = (u32)w / 2; + ii.yHotspot = (u32)h / 2; ii.hbmMask = mask; ii.hbmColor = color; @@ -7788,9 +10145,8 @@ HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) { return handle; } - -void* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { - HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(icon, channels, a, FALSE); +RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { + HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(data, w, h, format, FALSE); return cursor; } @@ -7828,16 +10184,12 @@ void RGFW_window_hide(RGFW_window* win) { } void RGFW_window_show(RGFW_window* win) { - if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); + if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); ShowWindow(win->src.window, SW_RESTORE); } #define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL; -void RGFW_deinit(void) { - #ifndef RGFW_NO_XINPUT - RGFW_FREE_LIBRARY(RGFW_XInput_dll); - #endif - +void RGFW_deinitPlatform(void) { #ifndef RGFW_NO_DPI RGFW_FREE_LIBRARY(RGFW_Shcore_dll); #endif @@ -7850,55 +10202,35 @@ void RGFW_deinit(void) { #endif RGFW_FREE_LIBRARY(RGFW_wgl_dll); - _RGFW.root = NULL; - RGFW_freeMouse(_RGFW.hiddenMouse); - _RGFW.windowCount = -1; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); + RGFW_freeMouse(_RGFW->hiddenMouse); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized"); } -void RGFW_window_close(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - #ifdef RGFW_BUFFER - DeleteDC(win->src.hdcMem); - DeleteObject(win->src.bitmap); - #endif - - if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); +void RGFW_window_closePlatform(RGFW_window* win) { RemovePropW(win->src.window, L"RGFW"); ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */ DestroyWindow(win->src.window); /*!< delete window */ if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall); if (win->src.hIconBig) DestroyIcon(win->src.hIconBig); - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } } -void RGFW_window_move(RGFW_window* win, RGFW_point v) { +void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); - win->r.x = v.x; - win->r.y = v.y; - SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE); + win->x = x; + win->y = y; + SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, 0, 0, SWP_NOSIZE); } -void RGFW_window_resize(RGFW_window* win, RGFW_area a) { +void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); - win->r.w = (i32)a.w; - win->r.h = (i32)a.h; - SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + (i32)win->src.hOffset, SWP_NOMOVE); + win->w = w; + win->h = h; + SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->w + (i32)win->src.offsetW, win->h + (i32)win->src.offsetH, SWP_NOMOVE); } @@ -7936,15 +10268,13 @@ void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { } #endif -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* src, RGFW_area a, i32 channels, u8 type) { +RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_ASSERT(win != NULL); #ifndef RGFW_WIN95 - RGFW_UNUSED(channels); - if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall); if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig); - if (src == NULL) { + if (data == NULL) { HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION); if (type & RGFW_iconWindow) SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon); @@ -7954,18 +10284,17 @@ RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* src, RGFW_area a, i32 chan } if (type & RGFW_iconWindow) { - win->src.hIconSmall = RGFW_loadHandleImage(src, channels, a, TRUE); + win->src.hIconSmall = RGFW_loadHandleImage(data, w, h, format, TRUE); SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall); } if (type & RGFW_iconTaskbar) { - win->src.hIconBig = RGFW_loadHandleImage(src, channels, a, TRUE); + win->src.hIconBig = RGFW_loadHandleImage(data, w, h, format, TRUE); SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig); } return RGFW_TRUE; #else - RGFW_UNUSED(src); - RGFW_UNUSED(a); - RGFW_UNUSED(channels); + RGFW_UNUSED(img); + RGFW_UNUSED(type); return RGFW_FALSE; #endif } @@ -7997,7 +10326,7 @@ RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { if (textLen > 1) wcstombs(str, wstr, (size_t)(textLen)); - str[textLen] = '\0'; + str[textLen - 1] = '\0'; } } @@ -8025,7 +10354,7 @@ void RGFW_writeClipboard(const char* text, u32 textLen) { MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen); GlobalUnlock(object); - if (!OpenClipboard(_RGFW.root->src.window)) { + if (!OpenClipboard(_RGFW->root->src.window)) { GlobalFree(object); return; } @@ -8035,94 +10364,307 @@ void RGFW_writeClipboard(const char* text, u32 textLen) { CloseClipboard(); } -void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { +void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); - win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y); - SetCursorPos(p.x, p.y); + win->internal.lastMouseX = x - win->x; + win->internal.lastMouseX = y - win->y; + SetCursorPos(x, y); } #ifdef RGFW_OPENGL -void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { +RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) { + const char* extensions = NULL; + + RGFW_proc proc = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringARB"); + RGFW_proc proc2 = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringEXT"); + + if (proc) + extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC()); + else if (proc2) + extensions = ((const char*(*)(void))proc2)(); + return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); +} + +RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { + RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname); + if (proc) + return proc; + + return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); +} + +void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) { + if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL) + return; + + HDC dummy_dc = GetDC(dummyWin); + u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + + PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0}; + + int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd); + SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd); + + HGLRC dummy_context = wglCreateContext(dummy_dc); + + HGLRC cur = wglGetCurrentContext(); + wglMakeCurrent(dummy_dc, dummy_context); + + wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB"); + wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB"); + + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT"); + if (wglSwapIntervalEXT == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function"); + } + + wglMakeCurrent(dummy_dc, cur); + wglDeleteContext(dummy_context); + ReleaseDC(dummyWin, dummy_dc); +} + +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_TYPE_RGBA_ARB 0x202b +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_ALPHA_BITS_ARB 0x201b +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_STEREO_ARB 0x2012 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_ACCUM_RED_BITS_ARB 0x201e +#define WGL_ACCUM_GREEN_BITS_ARB 0x201f +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_COLORSPACE_SRGB_EXT 0x3089 +#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_ACCESS_READ_WRITE_NV 0x00000001 +#define WGL_COVERAGE_SAMPLES_NV 0x2042 +#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 + +RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { + const char flushControl[] = "WGL_ARB_context_flush_control"; + const char noError[] = "WGL_ARB_create_context_no_error"; + const char robustness[] = "WGL_ARB_create_context_robustness"; + + win->src.ctx.native = ctx; + win->src.gfxType = RGFW_gfxNativeOpenGL; + + PIXELFORMATDESCRIPTOR pfd; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.cColorBits = 32; + pfd.cAlphaBits = 8; + pfd.cDepthBits = 24; + pfd.cStencilBits = (BYTE)hints->stencil; + pfd.cAuxBuffers = (BYTE)hints->auxBuffers; + if (hints->stereo) pfd.dwFlags |= PFD_STEREO; + + /* try to create the pixel format we want for OpenGL and then try to create an OpenGL context for the specified version */ + if (hints->renderer == RGFW_glSoftware) + pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED; + + /* get pixel format, default to a basic pixel format */ + int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd); + if (wglChoosePixelFormatARB != NULL) { + i32 pixel_format_attribs[50]; + RGFW_attribStack stack; + RGFW_attribStack_init(&stack, pixel_format_attribs, 50); + + RGFW_attribStack_pushAttribs(&stack, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB); + RGFW_attribStack_pushAttribs(&stack, WGL_DRAW_TO_WINDOW_ARB, 1); + RGFW_attribStack_pushAttribs(&stack, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); + RGFW_attribStack_pushAttribs(&stack, WGL_SUPPORT_OPENGL_ARB, 1); + RGFW_attribStack_pushAttribs(&stack, WGL_COLOR_BITS_ARB, 32); + RGFW_attribStack_pushAttribs(&stack, WGL_DOUBLE_BUFFER_ARB, 1); + RGFW_attribStack_pushAttribs(&stack, WGL_ALPHA_BITS_ARB, hints->alpha); + RGFW_attribStack_pushAttribs(&stack, WGL_DEPTH_BITS_ARB, hints->depth); + RGFW_attribStack_pushAttribs(&stack, WGL_STENCIL_BITS_ARB, hints->stencil); + RGFW_attribStack_pushAttribs(&stack, WGL_STEREO_ARB, hints->stereo); + RGFW_attribStack_pushAttribs(&stack, WGL_AUX_BUFFERS_ARB, hints->auxBuffers); + RGFW_attribStack_pushAttribs(&stack, WGL_RED_BITS_ARB, hints->red); + RGFW_attribStack_pushAttribs(&stack, WGL_GREEN_BITS_ARB, hints->blue); + RGFW_attribStack_pushAttribs(&stack, WGL_BLUE_BITS_ARB, hints->green); + RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_RED_BITS_ARB, hints->accumRed); + RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_GREEN_BITS_ARB, hints->accumGreen); + RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_BLUE_BITS_ARB, hints->accumBlue); + RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_ALPHA_BITS_ARB, hints->accumAlpha); + + if(hints->sRGB) { + if (hints->profile != RGFW_glES) + RGFW_attribStack_pushAttribs(&stack, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, 1); + else + RGFW_attribStack_pushAttribs(&stack, WGL_COLORSPACE_SRGB_EXT, hints->sRGB); + } + + RGFW_attribStack_pushAttribs(&stack, WGL_COVERAGE_SAMPLES_NV, hints->samples); + + RGFW_attribStack_pushAttribs(&stack, 0, 0); + + int new_pixel_format; + UINT num_formats; + wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats); + if (!num_formats) + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create a pixel format for WGL"); + else pixel_format = new_pixel_format; + } + + PIXELFORMATDESCRIPTOR suggested; + if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) || + !SetPixelFormat(win->src.hdc, pixel_format, &pfd)) + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format"); + + if (wglCreateContextAttribsARB != NULL) { + /* create OpenGL/WGL context for the specified version */ + i32 attribs[40]; + RGFW_attribStack stack; + RGFW_attribStack_init(&stack, attribs, 50); + + + i32 mask = 0; + switch (hints->profile) { + case RGFW_glES: mask |= WGL_CONTEXT_ES_PROFILE_BIT_EXT; break; + case RGFW_glCompatibility: mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break; + case RGFW_glCore: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break; + default: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break; + } + + RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_PROFILE_MASK_ARB, mask); + + if (hints->minor || hints->major) { + RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MAJOR_VERSION_ARB, hints->major); + RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MINOR_VERSION_ARB, hints->minor); + } + + if (RGFW_extensionSupportedPlatform_OpenGL(noError, sizeof(noError))) + RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError); + + if (RGFW_extensionSupportedPlatform_OpenGL(flushControl, sizeof(flushControl))) { + if (hints->releaseBehavior == RGFW_glReleaseFlush) { + RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); /* WGL_CONTEXT_RELEASE_BEHAVIOR_ARB */ + } else if (hints->releaseBehavior == RGFW_glReleaseNone) { + RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + } + + i32 flags = 0; + if (hints->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustness, sizeof(robustness))) flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; + if (flags) { + RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_FLAGS_ARB, flags); + } + + + RGFW_attribStack_pushAttribs(&stack, 0, 0); + + win->src.ctx.native->ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); + } + + if (wglCreateContextAttribsARB == NULL || win->src.ctx.native->ctx == NULL) { /* fall back to a default context (probably OpenGL 2 or something) */ + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an accelerated OpenGL Context."); + win->src.ctx.native->ctx = wglCreateContext(win->src.hdc); + } + + ReleaseDC(win->src.window, win->src.hdc); + win->src.hdc = GetDC(win->src.window); + + if (hints->share) { + wglShareLists((HGLRC)RGFW_getCurrentContext_OpenGL(), hints->share->ctx); + } + + wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); + return RGFW_TRUE; +} + +void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { + wglDeleteContext((HGLRC) ctx->ctx); /*!< delete OpenGL context */ + win->src.ctx.native->ctx = NULL; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); +} + +void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { if (win == NULL) wglMakeCurrent(NULL, NULL); else - wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx); + wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx); +} +void* RGFW_getCurrentContext_OpenGL(void) { + return wglGetCurrentContext(); +} +void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { + RGFW_ASSERT(win->src.ctx.native); + SwapBuffers(win->src.hdc); } -void* RGFW_getCurrent_OpenGL(void) { return wglGetCurrentContext(); } -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win){ SwapBuffers(win->src.hdc); } -#endif -#ifndef RGFW_EGL -void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { +void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_ASSERT(win != NULL); -#if defined(RGFW_OPENGL) if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set swap interval"); -#else - RGFW_UNUSED(swapInterval); -#endif + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set swap interval"); } #endif -void RGFW_window_swapBuffers_software(RGFW_window* win) { -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if (win->buffer != win->src.bitmapBits) - memcpy(win->src.bitmapBits, win->buffer, win->bufferSize.w * win->bufferSize.h * 4); - - RGFW_RGB_to_BGR(win, win->src.bitmapBits); - BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY); -#else - RGFW_UNUSED(win); -#endif -} - -char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source) { - if (source == NULL) { - return NULL; +RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* output, size_t max) { + i32 size = 0; + if (source == NULL) { + return RGFW_FALSE; } - i32 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); + size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); if (!size) { - return NULL; + return RGFW_FALSE; } - static char target[RGFW_MAX_PATH * 2]; - if (size > RGFW_MAX_PATH * 2) - size = RGFW_MAX_PATH * 2; + if (size > (i32)max) + size = (i32)max; - target[size] = 0; - - if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) { - return NULL; + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, output, size, NULL, NULL)) { + return RGFW_FALSE; } - return target; + output[size] = 0; + return RGFW_TRUE; } -u64 RGFW_getTimerFreq(void) { - static u64 frequency = 0; - if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency); +#ifdef RGFW_WEBGPU +WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { + WGPUSurfaceDescriptor surfaceDesc = {0}; + WGPUSurfaceSourceWindowsHWND fromHwnd = {0}; + fromHwnd.chain.sType = WGPUSType_SurfaceSourceWindowsHWND; + fromHwnd.hwnd = window->src.window; /* Get HWND from RGFW window source */ + if (!fromHwnd.hwnd) { + fprintf(stderr, "RGFW Error: HWND is NULL for Windows window.\n"); + return NULL; + } + fromHwnd.hinstance = GetModuleHandle(NULL); /* Get current process HINSTANCE */ - return frequency; + surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromHwnd.chain; + return wgpuInstanceCreateSurface(instance, &surfaceDesc); } - -u64 RGFW_getTimerValue(void) { - u64 value; - QueryPerformanceCounter((LARGE_INTEGER*)&value); - return value; -} - -void RGFW_sleep(u64 ms) { - Sleep((u32)ms); -} - -#ifndef RGFW_NO_THREADS - -RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); } -void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); } -void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); } -void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); } - #endif + #endif /* RGFW_WINDOWS */ /* @@ -8151,6 +10693,7 @@ void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority #include #include +#ifndef __OBJC__ typedef CGRect NSRect; typedef CGPoint NSPoint; typedef CGSize NSSize; @@ -8160,207 +10703,6 @@ typedef unsigned long NSUInteger; typedef long NSInteger; typedef NSInteger NSModalResponse; -#ifdef __arm64__ - /* ARM just uses objc_msgSend */ -#define abi_objc_msgSend_stret objc_msgSend -#define abi_objc_msgSend_fpret objc_msgSend -#else /* __i386__ */ - /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ -#define abi_objc_msgSend_stret objc_msgSend_stret -#define abi_objc_msgSend_fpret objc_msgSend_fpret -#endif - -#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) -#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z) -#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z) -#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z) -#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) -#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) -#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) -#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) -#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z) -#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y) -#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z) - -id NSApp = NULL; - -#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release")) -id NSString_stringWithUTF8String(const char* str); -id NSString_stringWithUTF8String(const char* str) { - return ((id(*)(id, SEL, const char*))objc_msgSend) - ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str); -} - -const char* NSString_to_char(id str); -const char* NSString_to_char(id str) { - return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String")); -} - -void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function); -void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) { - Class selected_class; - - if (RGFW_STRNCMP(class_name, "NSView", 6) == 0) { - selected_class = objc_getClass("ViewClass"); - } else if (RGFW_STRNCMP(class_name, "NSWindow", 8) == 0) { - selected_class = objc_getClass("WindowClass"); - } else { - selected_class = objc_getClass(class_name); - } - - class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0); -} - -/* Header for the array. */ -typedef struct siArrayHeader { - size_t count; - /* TODO(EimaMei): Add a `type_width` later on. */ -} siArrayHeader; - -/* Gets the header of the siArray. */ -#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1) -#define si_array_len(array) (SI_ARRAY_HEADER(array)->count) -#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", (void*)function) -/* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/ -#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", (void*)function) - -unsigned char* NSBitmapImageRep_bitmapData(id imageRep); -unsigned char* NSBitmapImageRep_bitmapData(id imageRep) { - return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData")); -} - -typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) { - NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */ - NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */ - NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */ - - NSBitmapFormatSixteenBitLittleEndian = (1 << 8), - NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9), - NSBitmapFormatSixteenBitBigEndian = (1 << 10), - NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11) -}; - -id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits); -id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) { - SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); - - return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend) - (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); -} - -id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); -id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { - void* nsclass = objc_getClass("NSColor"); - SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); - return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend) - ((id)nsclass, func, red, green, blue, alpha); -} - -typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) { - NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */ - NSOpenGLContextParametectxaceOrder = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */ - NSOpenGLContextParametectxaceOpacity = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */ - NSOpenGLContextParametectxaceBackingSize = 304, /* 2 params. Width/height of surface backing size */ - NSOpenGLContextParameterReclaimResources = 308, /* 0 params. */ - NSOpenGLContextParameterCurrentRendererID = 309, /* 1 param. Retrieves the current renderer ID */ - NSOpenGLContextParameterGPUVertexProcessing = 310, /* 1 param. Currently processing vertices with GPU (get) */ - NSOpenGLContextParameterGPUFragmentProcessing = 311, /* 1 param. Currently processing fragments with GPU (get) */ - NSOpenGLContextParameterHasDrawable = 314, /* 1 param. Boolean returned if drawable is attached */ - NSOpenGLContextParameterMPSwapsInFlight = 315, /* 1 param. Max number of swaps queued by the MP GL engine */ - - NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */ - NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */ - NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */ - NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */ - NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */ -}; - -typedef RGFW_ENUM(NSInteger, NSWindowButton) { - NSWindowCloseButton = 0, - NSWindowMiniaturizeButton = 1, - NSWindowZoomButton = 2, - NSWindowToolbarButton = 3, - NSWindowDocumentIconButton = 4, - NSWindowDocumentVersionsButton = 6, - NSWindowFullScreenButton = 7, -}; -void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param); -void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) { - ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend) - (context, sel_registerName("setValues:forParameter:"), vals, param); -} -void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs); -void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) { - return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend) - (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), attribs); -} - -id NSPasteboard_generalPasteboard(void); -id NSPasteboard_generalPasteboard(void) { - return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard")); -} - -id* cstrToNSStringArray(char** strs, size_t len); -id* cstrToNSStringArray(char** strs, size_t len) { - static id nstrs[6]; - size_t i; - for (i = 0; i < len; i++) - nstrs[i] = NSString_stringWithUTF8String(strs[i]); - - return nstrs; -} - -const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len); -const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) { - SEL func = sel_registerName("stringForType:"); - id nsstr = NSString_stringWithUTF8String(dataType); - id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr); - const char* str = NSString_to_char(nsString); - if (len != NULL) - *len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4); - return str; -} - -id c_array_to_NSArray(void* array, size_t len); -id c_array_to_NSArray(void* array, size_t len) { - SEL func = sel_registerName("initWithObjects:count:"); - void* nsclass = objc_getClass("NSArray"); - return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) - (NSAlloc(nsclass), func, array, len); -} - - -void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len); -void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) { - id* ntypes = cstrToNSStringArray((char**)newTypes, len); - - id array = c_array_to_NSArray(ntypes, len); - objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array); - NSRelease(array); -} - -NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner); -NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) { - id* ntypes = cstrToNSStringArray((char**)newTypes, len); - - SEL func = sel_registerName("declareTypes:owner:"); - - id array = c_array_to_NSArray(ntypes, len); - - NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend) - (pasteboard, func, array, owner); - NSRelease(array); - - return output; -} - -#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain")) - typedef enum NSApplicationActivationPolicy { NSApplicationActivationPolicyRegular, NSApplicationActivationPolicyAccessory, @@ -8389,8 +10731,7 @@ typedef RGFW_ENUM(u32, NSWindowStyleMask) { NSWindowStyleMaskHUDWindow = 1 << 13 }; -NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; /* Replaces NSStringPasteboardType */ - +#define NSPasteboardTypeString "public.utf8-plain-text" typedef RGFW_ENUM(i32, NSDragOperation) { NSDragOperationNone = 0, @@ -8403,87 +10744,331 @@ typedef RGFW_ENUM(i32, NSDragOperation) { NSDragOperationEvery = (int)ULONG_MAX }; -void* NSArray_objectAtIndex(id array, NSUInteger index) { - SEL func = sel_registerName("objectAtIndex:"); - return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index); +typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) { + NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */ + NSOpenGLContextParametectxaceOrder = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */ + NSOpenGLContextParametectxaceOpacity = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */ + NSOpenGLContextParametectxaceBackingSize = 304, /* 2 params. Width/height of surface backing size */ + NSOpenGLContextParameterReclaimResources = 308, /* 0 params. */ + NSOpenGLContextParameterCurrentRendererID = 309, /* 1 param. Retrieves the current renderer ID */ + NSOpenGLContextParameterGPUVertexProcessing = 310, /* 1 param. Currently processing vertices with GPU (get) */ + NSOpenGLContextParameterGPUFragmentProcessing = 311, /* 1 param. Currently processing fragments with GPU (get) */ + NSOpenGLContextParameterHasDrawable = 314, /* 1 param. Boolean returned if drawable is attached */ + NSOpenGLContextParameterMPSwapsInFlight = 315, /* 1 param. Max number of swaps queued by the MP GL engine */ + + NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */ + NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */ + NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */ + NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */ + NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */ +}; + +typedef RGFW_ENUM(NSInteger, NSWindowButton) { + NSWindowCloseButton = 0, + NSWindowMiniaturizeButton = 1, + NSWindowZoomButton = 2, + NSWindowToolbarButton = 3, + NSWindowDocumentIconButton = 4, + NSWindowDocumentVersionsButton = 6, + NSWindowFullScreenButton = 7, +}; + +#define NSPasteboardTypeURL "public.url" +#define NSPasteboardTypeFileURL "public.file-url" +#define NSTrackingMouseEnteredAndExited 0x01 +#define NSTrackingMouseMoved 0x02 +#define NSTrackingCursorUpdate 0x04 +#define NSTrackingActiveWhenFirstResponder 0x10 +#define NSTrackingActiveInKeyWindow 0x20 +#define NSTrackingActiveInActiveApp 0x40 +#define NSTrackingActiveAlways 0x80 +#define NSTrackingAssumeInside 0x100 +#define NSTrackingInVisibleRect 0x200 +#define NSTrackingEnabledDuringMouseDrag 0x400 +enum { + NSOpenGLPFAAllRenderers = 1, /* choose from all available renderers */ + NSOpenGLPFATripleBuffer = 3, /* choose a triple buffered pixel format */ + NSOpenGLPFADoubleBuffer = 5, /* choose a double buffered pixel format */ + NSOpenGLPFAAuxBuffers = 7, /* number of aux buffers */ + NSOpenGLPFAColorSize = 8, /* number of color buffer bits */ + NSOpenGLPFAAlphaSize = 11, /* number of alpha component bits */ + NSOpenGLPFADepthSize = 12, /* number of depth buffer bits */ + NSOpenGLPFAStencilSize = 13, /* number of stencil buffer bits */ + NSOpenGLPFAAccumSize = 14, /* number of accum buffer bits */ + NSOpenGLPFAMinimumPolicy = 51, /* never choose smaller buffers than requested */ + NSOpenGLPFAMaximumPolicy = 52, /* choose largest buffers of type requested */ + NSOpenGLPFASampleBuffers = 55, /* number of multi sample buffers */ + NSOpenGLPFASamples = 56, /* number of samples per multi sample buffer */ + NSOpenGLPFAAuxDepthStencil = 57, /* each aux buffer has its own depth stencil */ + NSOpenGLPFAColorFloat = 58, /* color buffers store floating point pixels */ + NSOpenGLPFAMultisample = 59, /* choose multisampling */ + NSOpenGLPFASupersample = 60, /* choose supersampling */ + NSOpenGLPFASampleAlpha = 61, /* request alpha filtering */ + NSOpenGLPFARendererID = 70, /* request renderer by ID */ + NSOpenGLPFANoRecovery = 72, /* disable all failure recovery systems */ + NSOpenGLPFAAccelerated = 73, /* choose a hardware accelerated renderer */ + NSOpenGLPFAClosestPolicy = 74, /* choose the closest color buffer to request */ + NSOpenGLPFABackingStore = 76, /* back buffer contents are valid after swap */ + NSOpenGLPFAScreenMask = 84, /* bit mask of supported physical screens */ + NSOpenGLPFAAllowOfflineRenderers = 96, /* allow use of offline renderers */ + NSOpenGLPFAAcceleratedCompute = 97, /* choose a hardware accelerated compute device */ + NSOpenGLPFAOpenGLProfile = 99, /* specify an OpenGL Profile to use */ + NSOpenGLProfileVersionLegacy = 0x1000, /* The requested profile is a legacy (pre-OpenGL 3.0) profile. */ + NSOpenGLProfileVersion3_2Core = 0x3200, /* The 3.2 Profile of OpenGL */ + NSOpenGLProfileVersion4_1Core = 0x3200, /* The 4.1 profile of OpenGL */ + NSOpenGLPFAVirtualScreenCount = 128, /* number of virtual screens in this format */ + NSOpenGLPFAStereo = 6, + NSOpenGLPFAOffScreen = 53, + NSOpenGLPFAFullScreen = 54, + NSOpenGLPFASingleRenderer = 71, + NSOpenGLPFARobust = 75, + NSOpenGLPFAMPSafe = 78, + NSOpenGLPFAWindow = 80, + NSOpenGLPFAMultiScreen = 81, + NSOpenGLPFACompliant = 83, + NSOpenGLPFAPixelBuffer = 90, + NSOpenGLPFARemotePixelBuffer = 91, +}; + +typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */ + NSEventTypeApplicationDefined = 15, +}; +typedef unsigned long long NSEventMask; + +typedef enum NSEventModifierFlags { + NSEventModifierFlagCapsLock = 1 << 16, + NSEventModifierFlagShift = 1 << 17, + NSEventModifierFlagControl = 1 << 18, + NSEventModifierFlagOption = 1 << 19, + NSEventModifierFlagCommand = 1 << 20, + NSEventModifierFlagNumericPad = 1 << 21 +} NSEventModifierFlags; + +typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) { + NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */ + NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */ + NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */ + + NSBitmapFormatSixteenBitLittleEndian = (1 << 8), + NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9), + NSBitmapFormatSixteenBitBigEndian = (1 << 10), + NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11) +}; + +#else +#import +#include +#endif /* notdef __OBJC__ */ + +#ifdef __arm64__ + /* ARM just uses objc_msgSend */ +#define abi_objc_msgSend_stret objc_msgSend +#define abi_objc_msgSend_fpret objc_msgSend +#else /* __i386__ */ + /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ +#define abi_objc_msgSend_stret objc_msgSend_stret +#define abi_objc_msgSend_fpret objc_msgSend_fpret +#endif + +#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) +#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z) +#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z) +#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z) +#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) +#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) +#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) +#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) +#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z) +#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y) +#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z) + +#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release")) +RGFWDEF id NSString_stringWithUTF8String(const char* str); +id NSString_stringWithUTF8String(const char* str) { + return ((id(*)(id, SEL, const char*))objc_msgSend) ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str); } -id NSWindow_contentView(id window) { - SEL func = sel_registerName("contentView"); - return objc_msgSend_id(window, func); +const char* NSString_to_char(id str); +const char* NSString_to_char(id str) { + return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String")); } +unsigned char* NSBitmapImageRep_bitmapData(id imageRep); +unsigned char* NSBitmapImageRep_bitmapData(id imageRep) { + return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData")); +} + +id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits); +id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) { + SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); + + return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend) + (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); +} + +id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); +id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { + Class nsclass = objc_getClass("NSColor"); + SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); + return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend) + ((id)nsclass, func, red, green, blue, alpha); +} + +id NSPasteboard_generalPasteboard(void); +id NSPasteboard_generalPasteboard(void) { + return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard")); +} + +id* cstrToNSStringArray(char** strs, size_t len); +id* cstrToNSStringArray(char** strs, size_t len) { + static id nstrs[6]; + size_t i; + for (i = 0; i < len; i++) + nstrs[i] = NSString_stringWithUTF8String(strs[i]); + + return nstrs; +} + +const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len); +const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) { + SEL func = sel_registerName("stringForType:"); + id nsstr = NSString_stringWithUTF8String((const char*)dataType); + id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr); + const char* str = NSString_to_char(nsString); + if (len != NULL) + *len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4); + return str; +} + +id c_array_to_NSArray(void* array, size_t len); +id c_array_to_NSArray(void* array, size_t len) { + return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) (NSAlloc(objc_getClass("NSArray")), sel_registerName("initWithObjects:count:"), array, len); +} + + +void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len); +void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) { + id* ntypes = cstrToNSStringArray((char**)newTypes, len); + + id array = c_array_to_NSArray(ntypes, len); + objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array); + NSRelease(array); +} + +NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner); +NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) { + id* ntypes = cstrToNSStringArray((char**)newTypes, len); + + SEL func = sel_registerName("declareTypes:owner:"); + + id array = c_array_to_NSArray(ntypes, len); + + NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend) + (pasteboard, func, array, owner); + NSRelease(array); + + return output; +} + +#define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain")) + /* End of cocoa wrapper */ -#ifdef RGFW_OPENGL -/* MacOS opengl API spares us yet again (there are no extensions) */ -RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; } -CFBundleRef RGFWnsglFramework = NULL; +static id RGFW__osxCustomInitWithRGFWWindow(id self, SEL _cmd, RGFW_window* win) { + RGFW_UNUSED(_cmd); + struct objc_super s = { self, class_getSuperclass(object_getClass(self)) }; + self = ((id (*)(struct objc_super*, SEL))objc_msgSendSuper)(&s, sel_registerName("init")); -RGFW_proc RGFW_getProcAddress(const char* procname) { - if (RGFWnsglFramework == NULL) - RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (self != nil) { + object_setInstanceVariable(self, "RGFW_window", win); + object_setInstanceVariable(self, "trackingArea", nil); - CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII); + object_setInstanceVariable( + self, "markedText", + ((id (*)(id, SEL))objc_msgSend)( + ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSMutableAttributedString"), sel_registerName("alloc")), + sel_registerName("init") + ) + ); - RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName); + ((void (*)(id, SEL))objc_msgSend)(self, sel_registerName("updateTrackingAreas")); - CFRelease(symbolName); + ((void (*)(id, SEL, id))objc_msgSend)( + self, sel_registerName("registerForDraggedTypes:"), + ((id (*)(Class, SEL, id))objc_msgSend)( + objc_getClass("NSArray"), + sel_registerName("arrayWithObject:"), + ((id (*)(Class, SEL, const char*))objc_msgSend)( + objc_getClass("NSString"), + sel_registerName("stringWithUTF8String:"), + "public.url" + ) + ) + ); + } - return symbol; -} -#endif - -id NSWindow_delegate(RGFW_window* win) { - return (id) objc_msgSend_id((id)win->src.window, sel_registerName("delegate")); + return self; } -u32 RGFW_OnClose(id self) { +static u32 RGFW_OnClose(id self) { RGFW_window* win = NULL; object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win); if (win == NULL) return true; - RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); + RGFW_window_setShouldClose(win, RGFW_TRUE); + RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); RGFW_windowQuitCallback(win); return false; } /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */ -bool acceptsFirstResponder(void) { return true; } -bool performKeyEquivalent(id event) { RGFW_UNUSED(event); return true; } +static bool RGFW__osxAcceptsFirstResponder(void) { return true; } +static bool RGFW__osxPerformKeyEquivalent(id event) { RGFW_UNUSED(event); return true; } -NSDragOperation draggingEntered(id self, SEL sel, id sender) { +static NSDragOperation RGFW__osxDraggingEntered(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return NSDragOperationCopy; } -NSDragOperation draggingUpdated(id self, SEL sel, id sender) { +static NSDragOperation RGFW__osxDraggingUpdated(id self, SEL sel, id sender) { RGFW_UNUSED(sel); RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || (!(win->_flags & RGFW_windowAllowDND))) + if (win == NULL || (!(win->internal.flags & RGFW_windowAllowDND))) return 0; + if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return NSDragOperationCopy; NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); - RGFW_eventQueuePushEx(e.type = RGFW_DNDInit; - e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); - e._win = win); + RGFW_eventQueuePushEx(e.type = RGFW_dataDrag; + e.mouse.x = (i32)p.x; e.mouse.y = (i32)(win->h - p.y); + e.common.win = win); - RGFW_dndInitCallback(win, win->event.point); + _RGFW->windowState.win = win; + _RGFW->windowState.dataDragging = RGFW_TRUE; + _RGFW->windowState.dropX = (i32)p.x; + _RGFW->windowState.dropY = (i32)(win->h - p.y); + + RGFW_dataDragCallback(win, (i32) p.x, (i32) (win->h - p.y)); return NSDragOperationCopy; } -bool prepareForDragOperation(id self) { +static bool RGFW__osxPrepareForDragOperation(id self) { RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) + if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag))) return true; - if (!(win->_flags & RGFW_windowAllowDND)) { + if (!(win->internal.flags & RGFW_windowAllowDND)) { return false; } @@ -8493,14 +11078,13 @@ bool prepareForDragOperation(id self) { void RGFW__osxDraggingEnded(id self, SEL sel, id sender); void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; } -/* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */ -bool performDragOperation(id self, SEL sel, id sender) { +static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) + if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag))) return false; /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */ @@ -8515,7 +11099,7 @@ bool performDragOperation(id self, SEL sel, id sender) { /* Check if the pasteboard contains file URLs */ if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(win, 0), "No files found on the pasteboard."); + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "No files found on the pasteboard."); return 0; } @@ -8525,49 +11109,54 @@ bool performDragOperation(id self, SEL sel, id sender) { if (count == 0) return 0; - int i; - for (i = 0; i < count; i++) { + RGFW_event event; + event.drop.files = (char**)(void*)_RGFW->files; + + u32 i; + for (i = 0; i < (u32)count; i++) { id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i); const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String")); - RGFW_STRNCPY(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH - 1); - win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; + RGFW_STRNCPY(event.drop.files[i], filePath, RGFW_MAX_PATH - 1); + event.drop.files[i][RGFW_MAX_PATH - 1] = '\0'; } - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); - - win->event.droppedFilesCount = (size_t)count; - RGFW_eventQueuePushEx(e.type = RGFW_DND; - e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); - e.droppedFilesCount = (size_t)count; - e._win = win); - - RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); + + event.drop.count = (size_t)count; + RGFW_eventQueuePushEx(e.type = RGFW_dataDrop; + e.drop.count = (size_t)count; + e.drop.files = event.drop.files; + e.common.win = win); + + _RGFW->windowState.win = win; + _RGFW->windowState.dataDrop = RGFW_TRUE; + _RGFW->windowState.filesCount = event.drop.count; + RGFW_dataDropCallback(win, event.drop.files, event.drop.count); return false; } #ifndef RGFW_NO_IOKIT #include -#include +u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID); u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) { u32 refreshRate = 0; io_iterator_t it; io_service_t service; CFNumberRef indexRef, clockRef, countRef; - uint32_t clock, count; + u32 clock, count; -#ifdef kIOMainPortDefault +#ifdef kIOMainPortDefault if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) -#elif defined(kIOMasterPortDefault) +#elif defined(kIOMasterPortDefault) if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) #endif return RGFW_FALSE; while ((service = IOIteratorNext(it)) != 0) { - uint32_t index; + u32 index; indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions); if (indexRef == 0) continue; - + if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) { CFRelease(indexRef); break; @@ -8582,7 +11171,8 @@ u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) { if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) { countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions); if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) { - refreshRate = (u32)RGFW_ROUND(clock / (double) count); + float rate = (float)((double)clock / (double) count); + refreshRate = (u32)RGFW_ROUND(rate); CFRelease(countRef); } } @@ -8593,201 +11183,6 @@ u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) { IOObjectRelease(it); return refreshRate; } - -IOHIDDeviceRef RGFW_osxControllers[4] = {NULL}; - -size_t findControllerIndex(IOHIDDeviceRef device) { - size_t i; - for (i = 0; i < 4; i++) - if (RGFW_osxControllers[i] == device) - return i; - return (size_t)-1; -} - -void RGFW__osxInputValueChangedCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) { - RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); - IOHIDElementRef element = IOHIDValueGetElement(value); - - IOHIDDeviceRef device = IOHIDElementGetDevice(element); - size_t index = findControllerIndex(device); - if (index == (size_t)-1) return; - - uint32_t usagePage = IOHIDElementGetUsagePage(element); - uint32_t usage = IOHIDElementGetUsage(element); - - CFIndex intValue = IOHIDValueGetIntegerValue(value); - - u8 RGFW_osx2RGFWSrc[2][RGFW_gamepadFinal] = {{ - 0, RGFW_gamepadSelect, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadStart, - RGFW_gamepadUp, RGFW_gamepadRight, RGFW_gamepadDown, RGFW_gamepadLeft, - RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadL1, RGFW_gamepadR1, - RGFW_gamepadY, RGFW_gamepadB, RGFW_gamepadA, RGFW_gamepadX, RGFW_gamepadHome}, - {0, RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadR3, RGFW_gamepadX, - RGFW_gamepadY, RGFW_gamepadRight, RGFW_gamepadL1, RGFW_gamepadR1, - RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadDown, RGFW_gamepadStart, - RGFW_gamepadUp, RGFW_gamepadL3, RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome} - }; - - u8* RGFW_osx2RGFW = RGFW_osx2RGFWSrc[0]; - if (RGFW_gamepads_type[index] == RGFW_gamepadMicrosoft) - RGFW_osx2RGFW = RGFW_osx2RGFWSrc[1]; - - switch (usagePage) { - case kHIDPage_Button: { - u8 button = 0; - if (usage < sizeof(RGFW_osx2RGFW)) - button = RGFW_osx2RGFW[usage]; - - RGFW_gamepadButtonCallback(_RGFW.root, (u16)index, button, (u8)intValue); - RGFW_gamepadPressed[index][button].prev = RGFW_gamepadPressed[index][button].current; - RGFW_gamepadPressed[index][button].current = RGFW_BOOL(intValue); - RGFW_eventQueuePushEx(e.type = intValue ? RGFW_gamepadButtonPressed: RGFW_gamepadButtonReleased; - e.button = button; - e.gamepad = (u16)index; - e._win = _RGFW.root); - break; - } - case kHIDPage_GenericDesktop: { - CFIndex logicalMin = IOHIDElementGetLogicalMin(element); - CFIndex logicalMax = IOHIDElementGetLogicalMax(element); - - if (logicalMax <= logicalMin) return; - if (intValue < logicalMin) intValue = logicalMin; - if (intValue > logicalMax) intValue = logicalMax; - - i8 axisValue = (i8)(-100.0 + ((intValue - logicalMin) * 200.0) / (logicalMax - logicalMin)); - - u8 whichAxis = 0; - switch (usage) { - case kHIDUsage_GD_X: RGFW_gamepadAxes[index][0].x = axisValue; whichAxis = 0; break; - case kHIDUsage_GD_Y: RGFW_gamepadAxes[index][0].y = axisValue; whichAxis = 0; break; - case kHIDUsage_GD_Z: RGFW_gamepadAxes[index][1].x = axisValue; whichAxis = 1; break; - case kHIDUsage_GD_Rz: RGFW_gamepadAxes[index][1].y = axisValue; whichAxis = 1; break; - default: return; - } - - RGFW_event e; - e.type = RGFW_gamepadAxisMove; - e.gamepad = (u16)index; - e.whichAxis = whichAxis; - e._win = _RGFW.root; - for (size_t i = 0; i < 4; i++) - e.axis[i] = RGFW_gamepadAxes[index][i]; - - RGFW_eventQueuePush(e); - - RGFW_gamepadAxisCallback(_RGFW.root, (u16)index, RGFW_gamepadAxes[index], 2, whichAxis); - } - } -} - -void RGFW__osxDeviceAddedCallback(void* context, IOReturn result, void *sender, IOHIDDeviceRef device) { - RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); - CFTypeRef usageRef = (CFTypeRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey)); - int usage = 0; - if (usageRef) - CFNumberGetValue((CFNumberRef)usageRef, kCFNumberIntType, (void*)&usage); - - if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) { - return; - } - - size_t i; - for (i = 0; i < 4; i++) { - if (RGFW_osxControllers[i] != NULL) - continue; - - RGFW_osxControllers[i] = device; - - IOHIDDeviceRegisterInputValueCallback(device, RGFW__osxInputValueChangedCallback, NULL); - - CFStringRef deviceName = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); - if (deviceName) - CFStringGetCString(deviceName, RGFW_gamepads_name[i], sizeof(RGFW_gamepads_name[i]), kCFStringEncodingUTF8); - - RGFW_gamepads_type[i] = RGFW_gamepadUnknown; - if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box") || RGFW_STRSTR(RGFW_gamepads_name[i], "Xbox")) - RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5")) - RGFW_gamepads_type[i] = RGFW_gamepadSony; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo")) - RGFW_gamepads_type[i] = RGFW_gamepadNintendo; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech")) - RGFW_gamepads_type[i] = RGFW_gamepadLogitech; - - RGFW_gamepads[i] = (u16)i; - RGFW_gamepadCount++; - - RGFW_eventQueuePushEx(e.type = RGFW_gamepadConnected; - e.gamepad = (u16)i; - e._win = _RGFW.root); - - RGFW_gamepadCallback(_RGFW.root, (u16)i, 1); - break; - } -} - -void RGFW__osxDeviceRemovedCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) { - RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); RGFW_UNUSED(device); - CFNumberRef usageRef = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey)); - int usage = 0; - if (usageRef) - CFNumberGetValue(usageRef, kCFNumberIntType, &usage); - - if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) { - return; - } - - size_t index = findControllerIndex(device); - if (index != (size_t)-1) - RGFW_osxControllers[index] = NULL; - - RGFW_eventQueuePushEx(e.type = RGFW_gamepadDisconnected; - e.gamepad = (u16)index; - e._win = _RGFW.root); - RGFW_gamepadCallback(_RGFW.root, (u16)index, 0); - - RGFW_gamepadCount--; -} - -RGFWDEF void RGFW_osxInitIOKit(void); -void RGFW_osxInitIOKit(void) { - IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); - if (!hidManager) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create IOHIDManager."); - return; - } - - CFMutableDictionaryRef matchingDictionary = CFDictionaryCreateMutable( - kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks - ); - if (!matchingDictionary) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create matching dictionary for IOKit."); - CFRelease(hidManager); - return; - } - - CFDictionarySetValue( - matchingDictionary, - CFSTR(kIOHIDDeviceUsagePageKey), - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (int[]){kHIDPage_GenericDesktop}) - ); - - IOHIDManagerSetDeviceMatching(hidManager, matchingDictionary); - - IOHIDManagerRegisterDeviceMatchingCallback(hidManager, RGFW__osxDeviceAddedCallback, NULL); - IOHIDManagerRegisterDeviceRemovalCallback(hidManager, RGFW__osxDeviceRemovedCallback, NULL); - - IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - - IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone); - - /* Execute the run loop once in order to register any initially-attached joysticks */ - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); -} #endif void RGFW_moveToMacOSResourceDir(void) { @@ -8816,83 +11211,94 @@ void RGFW_moveToMacOSResourceDir(void) { } -void RGFW__osxWindowDeminiaturize(id self, SEL sel) { +static void RGFW__osxWindowDeminiaturize(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; - win->_flags |= RGFW_windowMinimize; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); - RGFW_windowRestoredCallback(win, win->r); + win->internal.flags |= RGFW_windowMinimize; + if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return; + RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); + RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); } -void RGFW__osxWindowMiniaturize(id self, SEL sel) { +static void RGFW__osxWindowMiniaturize(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; - win->_flags &= ~(u32)RGFW_windowMinimize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e._win = win); - RGFW_windowMinimizedCallback(win, win->r); + win->internal.flags &= ~(u32)RGFW_windowMinimize; + if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return; + RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); + RGFW_windowMinimizedCallback(win); } -void RGFW__osxWindowBecameKey(id self, SEL sel) { +static void RGFW__osxWindowBecameKey(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; - win->_flags |= RGFW_windowFocus; - RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = win); + win->internal.inFocus = RGFW_TRUE; + if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); + if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; + + RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = win); RGFW_focusCallback(win, RGFW_TRUE); - - if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h)); } -void RGFW__osxWindowResignKey(id self, SEL sel) { +static void RGFW__osxWindowResignKey(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; RGFW_window_focusLost(win); - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win); + if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; + + RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = win); RGFW_focusCallback(win, RGFW_FALSE); } -NSSize RGFW__osxWindowResize(id self, SEL sel, NSSize frameSize) { - RGFW_UNUSED(sel); - +static void RGFW__osxDidWindowResize(id self, SEL _cmd, id notification) { + RGFW_UNUSED(_cmd); RGFW_UNUSED(notification); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return frameSize; + if (win == NULL) return; - win->r.w = (i32)frameSize.width; - win->r.h = (i32)frameSize.height; + NSRect frame; + if (win->src.view) frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); + else return; + + if (frame.size.width == 0 || frame.size.height == 0) return; + win->w = (i32)frame.size.width; + win->h = (i32)frame.size.height; RGFW_monitor mon = RGFW_window_getMonitor(win); - if ((i32)mon.mode.area.w == win->r.w && (i32)mon.mode.area.h - 102 <= win->r.h) { - win->_flags |= RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win); - RGFW_windowMaximizedCallback(win, win->r); - } else if (win->_flags & RGFW_windowMaximize) { - win->_flags &= ~(u32)RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); - RGFW_windowRestoredCallback(win, win->r); + if ((i32)mon.mode.w == win->w && (i32)mon.mode.h - 102 <= win->h) { + win->internal.flags |= RGFW_windowMaximize; + if (!(win->internal.enabledEvents & RGFW_windowMaximizedFlag)) return; + RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); + RGFW_windowMaximizedCallback(win, 0, 0, win->w, win->h); + } else if (win->internal.flags & RGFW_windowMaximize) { + win->internal.flags &= ~(u32)RGFW_windowMaximize; + if (!(win->internal.enabledEvents & RGFW_windowRestoredFlag)) return; + RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); + RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); } + if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win); - RGFW_windowResizedCallback(win, win->r); - return frameSize; + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); + RGFW_windowResizedCallback(win, win->w, win->h); } -void RGFW__osxWindowMove(id self, SEL sel) { +static void RGFW__osxWindowMove(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; @@ -8900,289 +11306,601 @@ void RGFW__osxWindowMove(id self, SEL sel) { if (win == NULL) return; NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); - win->r.x = (i32) frame.origin.x; - win->r.y = (i32) frame.origin.y; + win->x = (i32) frame.origin.x; + win->y = (i32) frame.origin.y; - RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win); - RGFW_windowMovedCallback(win, win->r); + if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; + RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e.common.win = win); + RGFW_windowMovedCallback(win, win->x, win->y); } -void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) { +static void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) { RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return; RGFW_monitor mon = RGFW_window_getMonitor(win); RGFW_scaleUpdatedCallback(win, mon.scaleX, mon.scaleY); - RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = mon.scaleX; e.scaleY = mon.scaleY ; e._win = win); + RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scale.x = mon.scaleX; e.scale.y = mon.scaleY ; e.common.win = win); } -void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) { +static BOOL RGFW__osxWantsUpdateLayer(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); return YES; } + +static void RGFW__osxUpdateLayer(id self, SEL _cmd) { + RGFW_UNUSED(self); RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return; + RGFW_windowRefreshCallback(win); +} + +static void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) { RGFW_UNUSED(rect); RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win); - RGFW_windowRefreshCallback(win); + RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e.common.win = win); + RGFW_windowRefreshCallback(win); } -void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) { - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - win->buffer = buffer; - win->bufferSize = area; - win->_flags |= RGFW_BUFFER_ALLOC; - #ifdef RGFW_OSMESA - win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - #else - RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ - #endif +static void RGFW__osxMouseEntered(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; + + win->internal.mouseInside = RGFW_TRUE; + _RGFW->windowState.win = win; + _RGFW->windowState.mouseEnter = RGFW_TRUE; + + RGFW_event e; + e.type = RGFW_mouseEnter; + NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow")); + e.mouse.x = (i32)p.x; + e.mouse.y = (i32)(win->h - p.y); + e.common.win = win; + + RGFW_eventQueuePush(&e); + RGFW_mouseNotifyCallback(win, e.mouse.x, e.mouse.y, 1); } -void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) { +static void RGFW__osxMouseExited(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); RGFW_UNUSED(event); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; + + + win->internal.mouseInside = RGFW_FALSE; + _RGFW->windowState.winLeave = win; + _RGFW->windowState.mouseLeave = RGFW_TRUE; + + RGFW_event e; + e.type = RGFW_mouseLeave; + e.mouse.x = 0; + e.mouse.y = 0; + e.common.win = win; + + RGFW_eventQueuePush(&e); + RGFW_mouseNotifyCallback(win, e.mouse.x, e.mouse.y, 0); +} + +static void RGFW__osxKeyDown(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_keyPressedFlag)) return; + + RGFW_event e; + u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); + u32 mappedKey = (u32)*(((char*)(const char*)NSString_to_char(((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("charactersIgnoringModifiers"))))); + if ((u8)mappedKey == 239) mappedKey = 0; + + e.key.sym = (u8)mappedKey; + e.key.value = (u8)RGFW_apiKeyToRGFW(key); + _RGFW->keyboard[e.key.value].prev = _RGFW->keyboard[e.key.value].current; + e.type = RGFW_keyPressed; + e.key.repeat = RGFW_window_isKeyPressed(win, e.key.value); + _RGFW->keyboard[e.key.value].current = 1; + e.common.win = win; + + RGFW_eventQueuePush(&e); + RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, 1); +} + +static void RGFW__osxKeyUp(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return; + + RGFW_event e; + u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); + u32 mappedKey = (u32)*(((char*)(const char*)NSString_to_char(((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("charactersIgnoringModifiers"))))); + if ((u8)mappedKey == 239) mappedKey = 0; + + e.key.sym = (u8)mappedKey; + e.key.value = (u8)RGFW_apiKeyToRGFW(key); + _RGFW->keyboard[e.key.value].prev = _RGFW->keyboard[e.key.value].current; + e.type = RGFW_keyReleased; + e.key.repeat = RGFW_window_isKeyDown(win, (u8)e.key.value); + _RGFW->keyboard[e.key.value].current = 0; + e.common.win = win; + + RGFW_eventQueuePush(&e); + RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, 0); +} + +static void RGFW__osxFlagsChanged(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL) return; + + RGFW_event e; + u32 flags = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")); + RGFW_updateKeyModsEx(win, + ((u32)(flags & NSEventModifierFlagCapsLock) % 255), + ((flags & NSEventModifierFlagNumericPad) % 255), + ((flags & NSEventModifierFlagControl) % 255), + ((flags & NSEventModifierFlagOption) % 255), + ((flags & NSEventModifierFlagShift) % 255), + ((flags & NSEventModifierFlagCommand) % 255), 0); + u8 i; + for (i = 0; i < 9; i++) + _RGFW->keyboard[i + RGFW_capsLock].prev = _RGFW->keyboard[i + RGFW_capsLock].current; + + for (i = 0; i < 5; i++) { + u32 shift = (1 << (i + 16)); + u32 key = i + RGFW_capsLock; + if ((flags & shift) && !RGFW_window_isKeyDown(win, (u8)key)) { + _RGFW->keyboard[key].current = 1; + if (key != RGFW_capsLock) + _RGFW->keyboard[key + 4].current = 1; + e.type = RGFW_keyPressed; + e.key.value = (u8)key; + break; + } + if (!(flags & shift) && RGFW_window_isKeyDown(win, (u8)key)) { + _RGFW->keyboard[key].current = 0; + if (key != RGFW_capsLock) + _RGFW->keyboard[key + 4].current = 0; + e.type = RGFW_keyReleased; + e.key.value = (u8)key; + break; + } + } + e.key.repeat = RGFW_window_isKeyDown(win, (u8)e.key.value); + e.common.win = win; + + if (!(win->internal.enabledEvents & (RGFW_BIT(e.type)))) return; + RGFW_eventQueuePush(&e); + RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, e.type == RGFW_keyPressed); +} + +static void RGFW__osxMouseMoved(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; + + RGFW_event e; + e.type = RGFW_mousePosChanged; + NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow")); + e.mouse.x = (i32)p.x; + e.mouse.y = (i32)(win->h - p.y); + p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX")); + p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY")); + e.mouse.vecX = (float)p.x; + e.mouse.vecY = (float)p.y; + _RGFW->vectorX = e.mouse.vecX; + _RGFW->vectorY = e.mouse.vecY; + win->internal.lastMouseX = e.mouse.x; + win->internal.lastMouseY = e.mouse.y; + e.common.win = win; + + RGFW_eventQueuePush(&e); + RGFW_mousePosCallback(win, e.mouse.x, e.mouse.y, e.mouse.vecX, e.mouse.vecY); +} + +static void RGFW__osxMouseDown(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return; + + RGFW_event e; + u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber")); + switch (buttonNumber) { + case 0: e.button.value = RGFW_mouseLeft; break; + case 1: e.button.value = RGFW_mouseRight; break; + case 2: e.button.value = RGFW_mouseMiddle; break; + default: e.button.value = (u8)buttonNumber; + } + e.type = RGFW_mouseButtonPressed; + _RGFW->mouseButtons[e.button.value].prev = _RGFW->mouseButtons[e.button.value].current; + _RGFW->mouseButtons[e.button.value].current = 1; + e.common.win = win; + + RGFW_eventQueuePush(&e); + RGFW_mouseButtonCallback(win, e.button.value, 1); +} + +static void RGFW__osxMouseUp(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL|| !(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return; + + RGFW_event e; + u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber")); + switch (buttonNumber) { + case 0: e.button.value = RGFW_mouseLeft; break; + case 1: e.button.value = RGFW_mouseRight; break; + case 2: e.button.value = RGFW_mouseMiddle; break; + default: e.button.value = (u8)buttonNumber; + } + e.type = RGFW_mouseButtonReleased; + _RGFW->mouseButtons[e.button.value].prev = _RGFW->mouseButtons[e.button.value].current; + _RGFW->mouseButtons[e.button.value].current = 0; + e.common.win = win; + + RGFW_eventQueuePush(&e); + RGFW_mouseButtonCallback(win, e.button.value, 0); +} + +static void RGFW__osxScrollWheel(id self, SEL _cmd, id event) { + RGFW_UNUSED(_cmd); + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL|| !(win->internal.enabledEvents & RGFW_mouseScroll)) return; + + RGFW_event e; + float deltaX = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX")); + float deltaY = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY")); + + e.type = RGFW_mouseScroll; + e.scroll.x = deltaX; + e.scroll.y = deltaY; + e.common.win = win; + _RGFW->scrollX = e.scroll.x; + _RGFW->scrollY = e.scroll.y; + + RGFW_eventQueuePush(&e); + RGFW_mouseScrollCallback(win, deltaX, deltaY); +} + +RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { + surface->data = data; + surface->w = w; + surface->h = h; + surface->format = format; + surface->native.format = RGFW_formatRGBA8; + return RGFW_TRUE; +} + +void RGFW_surface_freePtr(RGFW_surface* surface) { RGFW_UNUSED(surface); } + +void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { + RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); + + size_t depth = (surface->format >= RGFW_formatRGBA8) ? 4 : 3; + id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc")); + NSSize size = (NSSize){(double)surface->w, (double)surface->h}; + image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size); + + int minX = RGFW_MIN(win->w, surface->w); + int minY = RGFW_MIN(win->h, surface->h); + + id rep = NSBitmapImageRep_initWithBitmapData(&surface->data, minX, minY, 8, (i32)depth, (depth == 4), false, "NSDeviceRGBColorSpace", 1 << 1, (u32)surface->w * (u32)depth, 8 * (u32)depth); + RGFW_copyImageData(NSBitmapImageRep_bitmapData(rep), minX, minY , RGFW_formatRGBA8, surface->data, surface->format); + ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep); + + id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView")); + ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES); + id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer")); + + ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image); + ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES); + + NSRelease(rep); + NSRelease(image); +} + +void* RGFW_window_getView_OSX(RGFW_window* win) { return win->src.view; } + +void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) { objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer"), (id)layer); } -void* RGFW_cocoaGetLayer(void) { +void* RGFW_getLayer_OSX(void) { return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer")); } +void* RGFW_window_getWindow_OSX(RGFW_window* win) { return win->src.window; } -NSPasteboardType const NSPasteboardTypeURL = "public.url"; -NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url"; - -id RGFW__osx_generateViewClass(const char* subclass, RGFW_window* win) { - Class customViewClass; - customViewClass = objc_allocateClassPair(objc_getClass(subclass), "RGFWCustomView", 0); - - class_addIvar( customViewClass, "RGFW_window", sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), "L"); - class_addMethod(customViewClass, sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}"); - class_addMethod(customViewClass, sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, ""); - - id customView = objc_msgSend_id(NSAlloc(customViewClass), sel_registerName("init")); - object_setInstanceVariable(customView, "RGFW_window", win); - - return customView; +void RGFW_initKeycodesPlatform(void) { + _RGFW->keycodes[0x1D] = RGFW_0; + _RGFW->keycodes[0x12] = RGFW_1; + _RGFW->keycodes[0x13] = RGFW_2; + _RGFW->keycodes[0x14] = RGFW_3; + _RGFW->keycodes[0x15] = RGFW_4; + _RGFW->keycodes[0x17] = RGFW_5; + _RGFW->keycodes[0x16] = RGFW_6; + _RGFW->keycodes[0x1A] = RGFW_7; + _RGFW->keycodes[0x1C] = RGFW_8; + _RGFW->keycodes[0x19] = RGFW_9; + _RGFW->keycodes[0x00] = RGFW_a; + _RGFW->keycodes[0x0B] = RGFW_b; + _RGFW->keycodes[0x08] = RGFW_c; + _RGFW->keycodes[0x02] = RGFW_d; + _RGFW->keycodes[0x0E] = RGFW_e; + _RGFW->keycodes[0x03] = RGFW_f; + _RGFW->keycodes[0x05] = RGFW_g; + _RGFW->keycodes[0x04] = RGFW_h; + _RGFW->keycodes[0x22] = RGFW_i; + _RGFW->keycodes[0x26] = RGFW_j; + _RGFW->keycodes[0x28] = RGFW_k; + _RGFW->keycodes[0x25] = RGFW_l; + _RGFW->keycodes[0x2E] = RGFW_m; + _RGFW->keycodes[0x2D] = RGFW_n; + _RGFW->keycodes[0x1F] = RGFW_o; + _RGFW->keycodes[0x23] = RGFW_p; + _RGFW->keycodes[0x0C] = RGFW_q; + _RGFW->keycodes[0x0F] = RGFW_r; + _RGFW->keycodes[0x01] = RGFW_s; + _RGFW->keycodes[0x11] = RGFW_t; + _RGFW->keycodes[0x20] = RGFW_u; + _RGFW->keycodes[0x09] = RGFW_v; + _RGFW->keycodes[0x0D] = RGFW_w; + _RGFW->keycodes[0x07] = RGFW_x; + _RGFW->keycodes[0x10] = RGFW_y; + _RGFW->keycodes[0x06] = RGFW_z; + _RGFW->keycodes[0x27] = RGFW_apostrophe; + _RGFW->keycodes[0x2A] = RGFW_backSlash; + _RGFW->keycodes[0x2B] = RGFW_comma; + _RGFW->keycodes[0x18] = RGFW_equals; + _RGFW->keycodes[0x32] = RGFW_backtick; + _RGFW->keycodes[0x21] = RGFW_bracket; + _RGFW->keycodes[0x1B] = RGFW_minus; + _RGFW->keycodes[0x2F] = RGFW_period; + _RGFW->keycodes[0x1E] = RGFW_closeBracket; + _RGFW->keycodes[0x29] = RGFW_semicolon; + _RGFW->keycodes[0x2C] = RGFW_slash; + _RGFW->keycodes[0x0A] = RGFW_world1; + _RGFW->keycodes[0x33] = RGFW_backSpace; + _RGFW->keycodes[0x39] = RGFW_capsLock; + _RGFW->keycodes[0x75] = RGFW_delete; + _RGFW->keycodes[0x7D] = RGFW_down; + _RGFW->keycodes[0x77] = RGFW_end; + _RGFW->keycodes[0x24] = RGFW_enter; + _RGFW->keycodes[0x35] = RGFW_escape; + _RGFW->keycodes[0x7A] = RGFW_F1; + _RGFW->keycodes[0x78] = RGFW_F2; + _RGFW->keycodes[0x63] = RGFW_F3; + _RGFW->keycodes[0x76] = RGFW_F4; + _RGFW->keycodes[0x60] = RGFW_F5; + _RGFW->keycodes[0x61] = RGFW_F6; + _RGFW->keycodes[0x62] = RGFW_F7; + _RGFW->keycodes[0x64] = RGFW_F8; + _RGFW->keycodes[0x65] = RGFW_F9; + _RGFW->keycodes[0x6D] = RGFW_F10; + _RGFW->keycodes[0x67] = RGFW_F11; + _RGFW->keycodes[0x6F] = RGFW_F12; + _RGFW->keycodes[0x69] = RGFW_printScreen; + _RGFW->keycodes[0x6B] = RGFW_F14; + _RGFW->keycodes[0x71] = RGFW_F15; + _RGFW->keycodes[0x6A] = RGFW_F16; + _RGFW->keycodes[0x40] = RGFW_F17; + _RGFW->keycodes[0x4F] = RGFW_F18; + _RGFW->keycodes[0x50] = RGFW_F19; + _RGFW->keycodes[0x5A] = RGFW_F20; + _RGFW->keycodes[0x73] = RGFW_home; + _RGFW->keycodes[0x72] = RGFW_insert; + _RGFW->keycodes[0x7B] = RGFW_left; + _RGFW->keycodes[0x3A] = RGFW_altL; + _RGFW->keycodes[0x3B] = RGFW_controlL; + _RGFW->keycodes[0x38] = RGFW_shiftL; + _RGFW->keycodes[0x37] = RGFW_superL; + _RGFW->keycodes[0x6E] = RGFW_menu; + _RGFW->keycodes[0x47] = RGFW_numLock; + _RGFW->keycodes[0x79] = RGFW_pageDown; + _RGFW->keycodes[0x74] = RGFW_pageUp; + _RGFW->keycodes[0x7C] = RGFW_right; + _RGFW->keycodes[0x3D] = RGFW_altR; + _RGFW->keycodes[0x3E] = RGFW_controlR; + _RGFW->keycodes[0x3C] = RGFW_shiftR; + _RGFW->keycodes[0x36] = RGFW_superR; + _RGFW->keycodes[0x31] = RGFW_space; + _RGFW->keycodes[0x30] = RGFW_tab; + _RGFW->keycodes[0x7E] = RGFW_up; + _RGFW->keycodes[0x52] = RGFW_kp0; + _RGFW->keycodes[0x53] = RGFW_kp1; + _RGFW->keycodes[0x54] = RGFW_kp2; + _RGFW->keycodes[0x55] = RGFW_kp3; + _RGFW->keycodes[0x56] = RGFW_kp4; + _RGFW->keycodes[0x57] = RGFW_kp5; + _RGFW->keycodes[0x58] = RGFW_kp6; + _RGFW->keycodes[0x59] = RGFW_kp7; + _RGFW->keycodes[0x5B] = RGFW_kp8; + _RGFW->keycodes[0x5C] = RGFW_kp9; + _RGFW->keycodes[0x45] = RGFW_kpSlash; + _RGFW->keycodes[0x41] = RGFW_kpPeriod; + _RGFW->keycodes[0x4B] = RGFW_kpSlash; + _RGFW->keycodes[0x4C] = RGFW_kpReturn; + _RGFW->keycodes[0x51] = RGFW_kpEqual; + _RGFW->keycodes[0x43] = RGFW_kpMultiply; + _RGFW->keycodes[0x4E] = RGFW_kpMinus; } -#ifndef RGFW_EGL -void RGFW_window_initOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - void* attrs = RGFW_initFormatAttribs(); - void* format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)attrs); - - if (format == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to load pixel format for OpenGL"); - win->_flags |= RGFW_windowOpenglSoftware; - void* subAttrs = RGFW_initFormatAttribs(); - format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)subAttrs); - - if (format == NULL) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "and loading software rendering OpenGL failed"); - else - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Switching to software rendering"); - } - - /* the pixel format can be passed directly to opengl context creation to create a context - this is because the format also includes information about the opengl version (which may be a bad thing) */ - - win->src.view = (id) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) (RGFW__osx_generateViewClass("NSOpenGLView", win), - sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {win->r.w, win->r.h}}, (uint32_t*)format); - - objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL")); - win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext")); - - if (win->_flags & RGFW_windowTransparent) { - i32 opacity = 0; - #define NSOpenGLCPSurfaceOpacity 236 - NSOpenGLContext_setValues((id)win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity); - } - - objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); -#else - RGFW_UNUSED(win); -#endif -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { -#ifdef RGFW_OPENGL - if (win->src.ctx == NULL) return; - objc_msgSend_void(win->src.ctx, sel_registerName("release")); - win->src.ctx = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); -#else - RGFW_UNUSED(win); -#endif -} -#endif - - -i32 RGFW_init(void) { -#if defined(RGFW_C89) || defined(__cplusplus) - if (_RGFW_init) return 0; - _RGFW_init = RGFW_TRUE; - _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; -#endif - - /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea??? - Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance). - */ - si_func_to_SEL_with_name("NSObject", "windowShouldClose", (void*)RGFW_OnClose); +i32 RGFW_initPlatform(void) { + class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP)(void*)RGFW_OnClose, 0); /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */ - si_func_to_SEL("NSWindow", acceptsFirstResponder); - si_func_to_SEL("NSWindow", performKeyEquivalent); + class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("acceptsFirstResponder:"), (IMP)(void*)RGFW__osxAcceptsFirstResponder, 0); + class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("performKeyEquivalent:"), (IMP)(void*)RGFW__osxPerformKeyEquivalent, 0); - if (NSApp == NULL) { - NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); + _RGFW->NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); - ((void (*)(id, SEL, NSUInteger))objc_msgSend) - (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); + ((void (*)(id, SEL, NSUInteger))objc_msgSend) + ((id)_RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); - #ifndef RGFW_NO_IOKIT - RGFW_osxInitIOKit(); - #endif + _RGFW->customViewClasses[0] = objc_allocateClassPair(objc_getClass("NSView"), "RGFWCustomView", 0); + _RGFW->customViewClasses[1] = objc_allocateClassPair(objc_getClass("NSOpenGLView"), "RGFWOpenGLCustomView", 0); + for (size_t i = 0; i < 2; i++) { + class_addIvar((Class)_RGFW->customViewClasses[i], "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "v@:"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("scrollWheel:"), (IMP)RGFW__osxScrollWheel, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyDown:"), (IMP)RGFW__osxKeyDown, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyUp:"), (IMP)RGFW__osxKeyUp, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseMoved:"), (IMP)RGFW__osxMouseMoved, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseEntered:"), (IMP)RGFW__osxMouseEntered, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseExited:"), (IMP)RGFW__osxMouseExited, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("flagsChanged:"), (IMP)RGFW__osxFlagsChanged, "v@:@"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_getUid("acceptsFirstResponder"), (IMP)RGFW__osxAcceptsFirstResponder, "B@:"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("initWithRGFWWindow:"), (IMP)RGFW__osxCustomInitWithRGFWWindow, "@@:{CGRect={CGPoint=dd}{CGSize=dd}}"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("wantsUpdateLayer"), (IMP)RGFW__osxWantsUpdateLayer, "B@:"); + class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("updateLayer"), (IMP)RGFW__osxUpdateLayer, "v@:"); + objc_registerClassPair((Class)_RGFW->customViewClasses[i]); } - - _RGFW.windowCount = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); - return 0; + _RGFW->customWindowDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWWindowDelegate", 0); + class_addIvar((Class)_RGFW->customWindowDelegateClass, "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResize:"), (IMP)RGFW__osxDidWindowResize, "v@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, ""); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, ""); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, ""); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, ""); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, ""); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEntered:"), (IMP)RGFW__osxDraggingEntered, "l@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingUpdated:"), (IMP)RGFW__osxDraggingUpdated, "l@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("prepareForDragOperation:"), (IMP)RGFW__osxPrepareForDragOperation, "B@:@"); + class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("performDragOperation:"), (IMP)RGFW__osxPerformDragOperation, "B@:@"); + objc_registerClassPair((Class)_RGFW->customWindowDelegateClass); + return 0; } -RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { - static u8 RGFW_loaded = 0; - RGFW_window_basic_init(win, rect, flags); +void RGFW_osx_initView(RGFW_window* win) { + NSRect contentRect; + contentRect.origin.x = 0; + contentRect.origin.y = 0; + contentRect.size.width = (double)win->w; + contentRect.size.height = (double)win->h; + ((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), contentRect); - /* RR Create an autorelease pool */ + + if (RGFW_COCOA_FRAME_NAME) + objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME); + + object_setInstanceVariable((id)win->src.view, "RGFW_window", win); + objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view); + objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true); + objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); + + id trackingArea = objc_msgSend_id(objc_getClass("NSTrackingArea"), sel_registerName("alloc")); + trackingArea = ((id (*)(id, SEL, NSRect, NSUInteger, id, id))objc_msgSend)( + trackingArea, + sel_registerName("initWithRect:options:owner:userInfo:"), + contentRect, + NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect, + (id)win->src.view, + nil + ); + + ((void (*)(id, SEL, id))objc_msgSend)((id)win->src.view, sel_registerName("addTrackingArea:"), trackingArea); + ((void (*)(id, SEL))objc_msgSend)(trackingArea, sel_registerName("release")); +} + +RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { + /* RR Create an autorelease pool */ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); pool = objc_msgSend_id(pool, sel_registerName("init")); RGFW_window_setMouseDefault(win); NSRect windowRect; - windowRect.origin.x = win->r.x; - windowRect.origin.y = win->r.y; - windowRect.size.width = win->r.w; - windowRect.size.height = win->r.h; - - NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled; + windowRect.origin.x = (double)win->x; + windowRect.origin.y = (double)win->y; + windowRect.size.width = (double)win->w; + windowRect.size.height = (double)win->h; + NSBackingStoreType macArgs = (NSBackingStoreType)(NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled); if (!(flags & RGFW_windowNoResize)) - macArgs |= NSWindowStyleMaskResizable; + macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskResizable); if (!(flags & RGFW_windowNoBorder)) - macArgs |= NSWindowStyleMaskTitled; + macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskTitled); { void* nsclass = objc_getClass("NSWindow"); SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend) - (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false); + (NSAlloc(nsclass), func, windowRect, (NSWindowStyleMask)macArgs, macArgs, false); } id str = NSString_stringWithUTF8String(name); objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str); - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initOpenGL(win); - RGFW_window_initBuffer(win); - } - - #ifdef RGFW_OPENGL - else - #endif - { - NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}}; - win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) (NSAlloc(objc_getClass("NSView")), sel_registerName("initWithFrame:"), contentRect); - } - - void* contentView = NSWindow_contentView((id)win->src.window); - objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true); - objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); - objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view); - - if (flags & RGFW_windowTransparent) { - objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); - - objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), - NSColor_colorWithSRGB(0, 0, 0, 0)); - } - - Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0); - - class_addIvar( - delegateClass, "RGFW_window", - sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), - "L" - ); - - class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}"); - class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, ""); - class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, ""); - class_addMethod(delegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, ""); - class_addMethod(delegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, ""); - class_addMethod(delegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, ""); - class_addMethod(delegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, ""); - class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@"); - class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@"); - class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); - class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); - class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@"); - class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@"); - - id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init")); - - if (RGFW_COCOA_FRAME_NAME) - objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME); - + id delegate = objc_msgSend_id(NSAlloc((Class)_RGFW->customWindowDelegateClass), sel_registerName("init")); object_setInstanceVariable(delegate, "RGFW_window", win); objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate); if (flags & RGFW_windowAllowDND) { - win->_flags |= RGFW_windowAllowDND; + win->internal.flags |= RGFW_windowAllowDND; NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString}; NSregisterForDraggedTypes((id)win->src.window, types, 3); } - RGFW_window_setFlags(win, flags); + objc_msgSend_void_bool((id)win->src.window, sel_registerName("setAcceptsMouseMovedEvents:"), true); - /* Show the window */ - objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); - ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); - RGFW_window_show(win); + if (flags & RGFW_windowTransparent) { + objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); - if (!RGFW_loaded) { + objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), + NSColor_colorWithSRGB(0, 0, 0, 0)); + } + + /* Show the window */ + objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true); + + if (_RGFW->root == NULL) { objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow")); - - RGFW_loaded = 1; } objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow")); - objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); + objc_msgSend_void((id)_RGFW->NSApp, sel_registerName("finishLaunching")); NSRetain(win->src.window); - NSRetain(NSApp); + NSRetain(_RGFW->NSApp); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); + win->src.view = ((id(*)(id, SEL, RGFW_window*))objc_msgSend) (NSAlloc((Class)_RGFW->customViewClasses[0]), sel_registerName("initWithRGFWWindow:"), win); return win; } void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); - float offset = 0; + double offset = 0; - RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); - NSBackingStoreType storeType = NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView; + RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); + NSBackingStoreType storeType = (NSBackingStoreType)(NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView); if (border) - storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; - if (!(win->_flags & RGFW_windowNoResize)) { - storeType |= NSWindowStyleMaskResizable; + storeType = (NSBackingStoreType)(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable); + if (!(win->internal.flags & RGFW_windowNoResize)) { + storeType = (NSBackingStoreType)(storeType | (NSBackingStoreType)NSWindowStyleMaskResizable); } ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType); @@ -9192,84 +11910,25 @@ void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview")); objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true); - offset = (float)(frame.size.height - content.size.height); + offset = (double)(frame.size.height - content.size.height); } - RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h + offset)); - win->r.h -= (i32)offset; + RGFW_window_resize(win, win->w, win->h + (i32)offset); + win->h -= (i32)offset; } -RGFW_area RGFW_getScreenSize(void) { - static CGDirectDisplayID display = 0; - - if (display == 0) - display = CGMainDisplayID(); - - return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display)); -} - -RGFW_point RGFW_getGlobalMousePoint(void) { - RGFW_ASSERT(_RGFW.root != NULL); +RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { + RGFW_ASSERT(_RGFW->root != NULL); CGEventRef e = CGEventCreate(NULL); CGPoint point = CGEventGetLocation(e); CFRelease(e); - return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */ + if (x) *x = (i32)point.x; + if (y) *y = (i32)point.y; + return RGFW_TRUE; } -typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */ - NSEventTypeLeftMouseDown = 1, - NSEventTypeLeftMouseUp = 2, - NSEventTypeRightMouseDown = 3, - NSEventTypeRightMouseUp = 4, - NSEventTypeMouseMoved = 5, - NSEventTypeLeftMouseDragged = 6, - NSEventTypeRightMouseDragged = 7, - NSEventTypeMouseEntered = 8, - NSEventTypeMouseExited = 9, - NSEventTypeKeyDown = 10, - NSEventTypeKeyUp = 11, - NSEventTypeFlagsChanged = 12, - NSEventTypeAppKitDefined = 13, - NSEventTypeSystemDefined = 14, - NSEventTypeApplicationDefined = 15, - NSEventTypePeriodic = 16, - NSEventTypeCursorUpdate = 17, - NSEventTypeScrollWheel = 22, - NSEventTypeTabletPoint = 23, - NSEventTypeTabletProximity = 24, - NSEventTypeOtherMouseDown = 25, - NSEventTypeOtherMouseUp = 26, - NSEventTypeOtherMouseDragged = 27, - /* The following event types are available on some hardware on 10.5.2 and later */ - NSEventTypeGesture = 29, - NSEventTypeMagnify = 30, - NSEventTypeSwipe = 31, - NSEventTypeRotate = 18, - NSEventTypeBeginGesture = 19, - NSEventTypeEndGesture = 20, - - NSEventTypeSmartMagnify = 32, - NSEventTypeQuickLook = 33, - - NSEventTypePressure = 34, - NSEventTypeDirectTouch = 37, - - NSEventTypeChangeMode = 38, -}; - -typedef unsigned long long NSEventMask; - -typedef enum NSEventModifierFlags { - NSEventModifierFlagCapsLock = 1 << 16, - NSEventModifierFlagShift = 1 << 17, - NSEventModifierFlagControl = 1 << 18, - NSEventModifierFlagOption = 1 << 19, - NSEventModifierFlagCommand = 1 << 20, - NSEventModifierFlagNumericPad = 1 << 21 -} NSEventModifierFlags; - void RGFW_stopCheckEvents(void) { id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); @@ -9279,14 +11938,12 @@ void RGFW_stopCheckEvents(void) { NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0); ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 1); + ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1); objc_msgSend_bool_void(eventPool, sel_registerName("drain")); } -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - RGFW_UNUSED(win); - +void RGFW_waitForEvent(i32 waitMS) { id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); @@ -9295,12 +11952,12 @@ void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) - (NSApp, eventFunc, + ((id)_RGFW->NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); if (e) { ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 1); + ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1); } objc_msgSend_bool_void(eventPool, sel_registerName("drain")); @@ -9310,251 +11967,66 @@ u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { return (u8)rgfw_keycode; /* TODO */ } -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; +void RGFW_pollEvents(void) { + /* + * TODO look to see if all these events can be replaced with callbacks + * callbacks seem to give better info on mac's api + */ - objc_msgSend_void((id)win->src.mouse, sel_registerName("set")); - RGFW_event* ev = RGFW_window_checkEventCore(win); - if (ev) { - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return ev; - } + RGFW_resetPrevState(); id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); - SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); - void* date = NULL; + while (1) { + void* date = NULL; + id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) + ((id)_RGFW->NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); - id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) - (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); + if (e == NULL) { + objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("sendEvent:"), e); + ((void(*)(id, SEL))objc_msgSend)((id)_RGFW->NSApp, sel_registerName("updateWindows")); + break; + } - if (e == NULL) { - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return NULL; + RGFW_event event; + RGFW_MEMSET(&event, 0, sizeof(event)); + objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("sendEvent:"), e); + ((void(*)(id, SEL))objc_msgSend)((id)_RGFW->NSApp, sel_registerName("updateWindows")); } - if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) { - ((void (*)(id, SEL, id, bool))objc_msgSend) - (NSApp, sel_registerName("postEvent:atStart:"), e, 0); - - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return NULL; - } - - if (win->event.droppedFilesCount) { - u32 i; - for (i = 0; i < win->event.droppedFilesCount; i++) - win->event.droppedFiles[i][0] = '\0'; - } - - win->event.droppedFilesCount = 0; - win->event.type = 0; - - u32 type = (u32)objc_msgSend_uint(e, sel_registerName("type")); - switch (type) { - case NSEventTypeMouseEntered: { - win->event.type = RGFW_mouseEnter; - 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); - break; - } - - case NSEventTypeMouseExited: - win->event.type = RGFW_mouseLeave; - RGFW_mouseNotifyCallback(win, win->event.point, 0); - break; - - case NSEventTypeKeyDown: { - 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"))))); - if (((u8)mappedKey) == 239) - mappedKey = 0; - - win->event.keyChar = (u8)mappedKey; - - win->event.key = (u8)RGFW_apiKeyToRGFW(key); - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - - win->event.type = RGFW_keyPressed; - 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.keyMod, 1); - break; - } - - case NSEventTypeKeyUp: { - 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"))))); - if (((u8)mappedKey) == 239) - mappedKey = 0; - - win->event.keyChar = (u8)mappedKey; - - win->event.key = (u8)RGFW_apiKeyToRGFW(key); - - RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; - - win->event.type = RGFW_keyReleased; - - RGFW_keyboard[win->event.key].current = 0; - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); - break; - } - - case NSEventTypeFlagsChanged: { - u32 flags = (u32)objc_msgSend_uint(e, sel_registerName("modifierFlags")); - RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255), - ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255), - ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0); - u8 i; - for (i = 0; i < 9; i++) - RGFW_keyboard[i + RGFW_capsLock].prev = 0; - - for (i = 0; i < 5; i++) { - u32 shift = (1 << (i + 16)); - u32 key = i + RGFW_capsLock; - - if ((flags & shift) && !RGFW_wasPressed(win, (u8)key)) { - RGFW_keyboard[key].current = 1; - - if (key != RGFW_capsLock) - RGFW_keyboard[key+ 4].current = 1; - - win->event.type = RGFW_keyPressed; - win->event.key = (u8)key; - break; - } - - if (!(flags & shift) && RGFW_wasPressed(win, (u8)key)) { - RGFW_keyboard[key].current = 0; - - if (key != RGFW_capsLock) - RGFW_keyboard[key + 4].current = 0; - - win->event.type = RGFW_keyReleased; - win->event.key = (u8)key; - break; - } - } - - RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed); - - break; - } - case NSEventTypeLeftMouseDragged: - case NSEventTypeOtherMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeMouseMoved: { - win->event.type = RGFW_mousePosChanged; - NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); - win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); - - p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX")); - p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); - win->event.vector = RGFW_POINT((i32)p.x, (i32)p.y); - - win->_lastMousePoint = win->event.point; - RGFW_mousePosCallback(win, win->event.point, win->event.vector); - break; - } - case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: { - u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber")); - switch (buttonNumber) { - case 0: win->event.button = RGFW_mouseLeft; break; - case 1: win->event.button = RGFW_mouseRight; break; - case 2: win->event.button = RGFW_mouseMiddle; break; - default: win->event.button = (u8)buttonNumber; - } - - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - } - case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: { - u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber")); - switch (buttonNumber) { - case 0: win->event.button = RGFW_mouseLeft; break; - case 1: win->event.button = RGFW_mouseRight; break; - case 2: win->event.button = RGFW_mouseMiddle; break; - default: win->event.button = (u8)buttonNumber; - } - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 0; - win->event.type = RGFW_mouseButtonReleased; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); - break; - } - case NSEventTypeScrollWheel: { - double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); - - if (deltaY > 0) { - win->event.button = RGFW_mouseScrollUp; - } - else if (deltaY < 0) { - win->event.button = RGFW_mouseScrollDown; - } - - RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; - RGFW_mouseButtons[win->event.button].current = 1; - - win->event.scroll = deltaY; - - win->event.type = RGFW_mouseButtonPressed; - RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); - break; - } - - default: - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); - return RGFW_window_checkEvent(win); - } - - objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); objc_msgSend_bool_void(eventPool, sel_registerName("drain")); - return &win->event; } -void RGFW_window_move(RGFW_window* win, RGFW_point v) { +void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_ASSERT(win != NULL); - win->r.x = v.x; - win->r.y = v.y; - ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); + win->x = x; + win->y = y; + ((void(*)(id,SEL,NSPoint))objc_msgSend)((id)win->src.window, sel_registerName("setFrameOrigin:"), (NSPoint){(double)x, (double)y}); } -void RGFW_window_resize(RGFW_window* win, RGFW_area a) { +void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { RGFW_ASSERT(win != NULL); NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); float offset = (float)(frame.size.height - content.size.height); - win->r.w = (i32)a.w; - win->r.h = (i32)a.h; + win->w = w; + win->h = h; + + ((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}}); ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h + offset}}, true, true); + ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{(double)win->x, (double)win->y}, {(double)win->w, (double)win->h + (double)offset}}, true, true); } void RGFW_window_focus(RGFW_window* win) { RGFW_ASSERT(win); - objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); + objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true); ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow")); } @@ -9566,25 +12038,38 @@ void RGFW_window_raise(RGFW_window* win) { void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); - if (fullscreen && (win->_flags & RGFW_windowFullscreen)) return; - if (!fullscreen && !(win->_flags & RGFW_windowFullscreen)) return; + if (fullscreen && (win->internal.flags & RGFW_windowFullscreen)) return; + if (!fullscreen && !(win->internal.flags & RGFW_windowFullscreen)) return; if (fullscreen) { - win->_oldRect = win->r; + if (!(win->internal.flags & RGFW_windowFullscreen)) { + return; + } + + win->internal.oldX = win->x; + win->internal.oldY = win->y; + win->internal.oldW = win->w; + win->internal.oldH = win->h; RGFW_monitor mon = RGFW_window_getMonitor(win); - win->r = RGFW_RECT(0, 0, mon.x, mon.y); - win->_flags |= RGFW_windowFullscreen; - RGFW_window_resize(win, RGFW_AREA(mon.mode.area.w, mon.mode.area.h)); - RGFW_window_move(win, RGFW_POINT(0, 0)); + win->x = mon.x; + win->y = mon.y; + win->w = mon.mode.w; + win->h = mon.mode.h; + win->internal.flags |= RGFW_windowFullscreen; + RGFW_window_resize(win, mon.mode.w, mon.mode.h); + RGFW_window_move(win, mon.x, mon.y); } objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL); if (!fullscreen) { - win->r = win->_oldRect; - win->_flags &= ~(u32)RGFW_windowFullscreen; + win->x = win->internal.oldX; + win->y = win->internal.oldY; + win->w = win->internal.oldW; + win->h = win->internal.oldH; + win->internal.flags &= ~(u32)RGFW_windowFullscreen; - RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); - RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y)); + RGFW_window_resize(win, win->w, win->h); + RGFW_window_move(win, win->x, win->y); } } @@ -9592,7 +12077,7 @@ void RGFW_window_maximize(RGFW_window* win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) return; - win->_flags |= RGFW_windowMaximize; + win->internal.flags |= RGFW_windowMaximize; objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); } @@ -9645,81 +12130,75 @@ void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { } #endif -void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { - if (a.w == 0 && a.h == 0) a = RGFW_AREA(1, 1); +void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { + if (w == 0 && h == 0) { w = 1; h = 1; }; ((void (*)(id, SEL, NSSize))objc_msgSend) - ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){a.w, a.h}); + ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){(CGFloat)w, (CGFloat)h}); } -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { - ((void (*)(id, SEL, NSSize))objc_msgSend) - ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h}); +void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { + ((void (*)(id, SEL, NSSize))objc_msgSend) ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){(CGFloat)w, (CGFloat)h}); } -void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { - if (a.w == 0 && a.h == 0) { - a = RGFW_getScreenSize(); +void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { + if (w == 0 && h == 0) { + RGFW_monitor mon = RGFW_window_getMonitor(win); + w = mon.mode.w; + h = mon.mode.h; } ((void (*)(id, SEL, NSSize))objc_msgSend) - ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h}); + ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){(CGFloat)w, (CGFloat)h}); } -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, RGFW_area area, i32 channels, u8 type) { +RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_ASSERT(win != NULL); RGFW_UNUSED(type); if (data == NULL) { - objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), NULL); + objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), NULL); return RGFW_TRUE; } - /* code by EimaMei: Make a bitmap representation, then copy the loaded image into it. */ - id representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * (u32)channels, 8 * (u32)channels); - RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * (u32)channels); + id representation = NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32); + RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format); - /* Add ze representation. */ - id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){area.w, area.h})); + id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h})); objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation); - /* Finally, set the dock image to it. */ - objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image); - /* Free the garbage. */ + objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), dock_image); + NSRelease(dock_image); NSRelease(representation); return RGFW_TRUE; } +id NSCursor_arrowStr(const char* str); id NSCursor_arrowStr(const char* str) { void* nclass = objc_getClass("NSCursor"); SEL func = sel_registerName(str); return (id) objc_msgSend_id(nclass, func); } -RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { - if (icon == NULL) { +RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { + if (data == NULL) { objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set")); return NULL; } - /* NOTE(EimaMei): Code by yours truly. */ - /* Make a bitmap representation, then copy the loaded image into it. */ - id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * (u32)channels, 8 * (u32)channels); - RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), icon, a.w * a.h * (u32)channels); + id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32); + RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format); - /* Add ze representation. */ - id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){a.w, a.h})); + id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h})); objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation); - /* Finally, set the cursor image. */ id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend) (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0}); - /* Free the garbage. */ NSRelease(cursor_image); NSRelease(representation); @@ -9772,18 +12251,19 @@ void RGFW_releaseCursor(RGFW_window* win) { CGAssociateMouseAndMouseCursorPosition(1); } -void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { +void RGFW_captureCursor(RGFW_window* win) { RGFW_UNUSED(win); - CGWarpMouseCursorPosition((CGPoint){r.x + (r.w / 2), r.y + (r.h / 2)}); + CGWarpMouseCursorPosition((CGPoint){(CGFloat)(win->x + (win->w / 2)), (CGFloat)(win->y + (win->h / 2))}); CGAssociateMouseAndMouseCursorPosition(0); } -void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { +void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); - win->_lastMousePoint = RGFW_POINT(v.x - win->r.x, v.y - win->r.y); - CGWarpMouseCursorPosition((CGPoint){v.x, v.y}); + win->internal.lastMouseX = x - win->x; + win->internal.lastMouseY = y - win->y; + CGWarpMouseCursorPosition((CGPoint){(CGFloat)x, (CGFloat)y}); } @@ -9792,7 +12272,7 @@ void RGFW_window_hide(RGFW_window* win) { } void RGFW_window_show(RGFW_window* win) { - if (win->_flags & RGFW_windowFocusOnShow) + if (win->internal.flags & RGFW_windowFocusOnShow) ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL); @@ -9818,6 +12298,7 @@ RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { return b; } +id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display); id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) { Class NSScreenClass = objc_getClass("NSScreen"); @@ -9839,8 +12320,7 @@ id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) { return NULL; } -u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID); - +u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode); u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) { if (mode) { u32 refreshRate = (u32)CGDisplayModeGetRefreshRate(mode); @@ -9856,6 +12336,7 @@ u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) { return 60; } +RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen); RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { RGFW_monitor monitor; @@ -9865,7 +12346,8 @@ RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { CGRect bounds = CGDisplayBounds(display); monitor.x = (i32)bounds.origin.x; monitor.y = (i32)bounds.origin.y; - monitor.mode.area = RGFW_AREA((int) bounds.size.width, (int) bounds.size.height); + monitor.mode.w = (i32) bounds.size.width; + monitor.mode.h = (i32) bounds.size.height; monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8; @@ -9877,8 +12359,8 @@ RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { monitor.physW = (float)screenSizeMM.width / 25.4f; monitor.physH = (float)screenSizeMM.height / 25.4f; - float ppi_width = (monitor.mode.area.w/monitor.physW); - float ppi_height = (monitor.mode.area.h/monitor.physH); + float ppi_width = (monitor.mode.w/monitor.physW); + float ppi_height = (monitor.mode.h/monitor.physH); monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor")); float dpi = 96.0f * monitor.pixelRatio; @@ -9886,7 +12368,7 @@ RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { monitor.scaleX = ((i32)(((float) (ppi_width) / dpi) * 10.0f)) / 10.0f; monitor.scaleY = ((i32)(((float) (ppi_height) / dpi) * 10.0f)) / 10.0f; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); return monitor; } @@ -9911,10 +12393,10 @@ RGFW_monitor* RGFW_getMonitors(size_t* len) { } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { - CGPoint point = { mon.x, mon.y }; + CGPoint point = { (CGFloat)mon.x, (CGFloat)mon.y }; CGDirectDisplayID display; - uint32_t displayCount = 0; + u32 displayCount = 0; CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount); if (err != kCGErrorSuccess || displayCount != 1) return RGFW_FALSE; @@ -9929,7 +12411,8 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i); RGFW_monitorMode foundMode; - foundMode.area = RGFW_AREA(CGDisplayModeGetWidth(cmode), CGDisplayModeGetHeight(cmode)); + foundMode.w = (i32)CGDisplayModeGetWidth(cmode); + foundMode.h = (i32)CGDisplayModeGetHeight(cmode); foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode); foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8; @@ -9988,104 +12471,203 @@ void RGFW_writeClipboard(const char* text, u32 textLen) { SEL func = sel_registerName("setString:forType:"); ((bool (*)(id, SEL, id, id))objc_msgSend) - (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String(NSPasteboardTypeString)); + (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String((const char*)NSPasteboardTypeString)); } - #ifdef RGFW_OPENGL - void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { - if (win != NULL) - objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); - else - objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext")); - } - void* RGFW_getCurrent_OpenGL(void) { - return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext")); - } +#ifdef RGFW_OPENGL +void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param); +void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) { + ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend) + (context, sel_registerName("setValues:forParameter:"), vals, param); +} - void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { - objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer")); - } - #endif - #if !defined(RGFW_EGL) +/* MacOS OpenGL API spares us yet again (there are no extensions) */ +RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; } - void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { - RGFW_ASSERT(win != NULL); - #if defined(RGFW_OPENGL) +RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { + static CFBundleRef RGFWnsglFramework = NULL; + if (RGFWnsglFramework == NULL) + RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - NSOpenGLContext_setValues((id)win->src.ctx, &swapInterval, 222); - #else - RGFW_UNUSED(swapInterval); + CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII); + + RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName); + + CFRelease(symbolName); + + return symbol; +} + +RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { + win->src.ctx.native = ctx; + win->src.gfxType = RGFW_gfxNativeOpenGL; + + i32 attribs[40]; + size_t render_type_index = 0; + { + RGFW_attribStack stack; + RGFW_attribStack_init(&stack, attribs, 40); + + i32 colorBits = (i32)(hints->red + hints->green + hints->blue + hints->alpha) / 4; + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAColorSize, colorBits); + + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAlphaSize, hints->alpha); + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFADepthSize, hints->depth); + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAStencilSize, hints->stencil); + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAuxBuffers, hints->auxBuffers); + RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAClosestPolicy); + if (hints->samples) { + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 1); + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASamples, hints->samples); + } else RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 0); + + if (hints->doubleBuffer) + RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFADoubleBuffer); + + #ifdef RGFW_COCOA_GRAPHICS_SWITCHING + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAllowOfflineRenderers, kCGLPFASupportsAutomaticGraphicsSwitching) #endif + #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 + if (hints->stereo]) RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAStereo); + #endif + + /* macOS has the surface attribs and the OpenGL attribs connected for some reason maybe this is to give macOS more control to limit openGL/the OpenGL version? */ + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAOpenGLProfile, + (hints->major >= 4) ? NSOpenGLProfileVersion4_1Core : (hints->major >= 3) ? + NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy); + + if (hints->major <= 2) { + i32 accumSize = (i32)(hints->accumRed + hints->accumGreen + hints->accumBlue + hints->accumAlpha) / 4; + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAccumSize, accumSize); + } + + if (hints->renderer == RGFW_glSoftware) { + RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFARendererID, kCGLRendererGenericFloatID); + } else { + RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAAccelerated); + } + render_type_index = stack.count - 1; + + RGFW_attribStack_pushAttribs(&stack, 0, 0); } - #endif + void* format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs); + if (format == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load pixel format for OpenGL"); -void RGFW_window_swapBuffers_software(RGFW_window* win) { -#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - RGFW_RGB_to_BGR(win, win->buffer); - i32 channels = 4; - id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc")); - NSSize size = (NSSize){win->bufferSize.w, win->bufferSize.h}; - image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size); + assert(render_type_index + 3 < (sizeof(attribs) / sizeof(attribs[0]))); + attribs[render_type_index] = NSOpenGLPFARendererID; + attribs[render_type_index + 1] = kCGLRendererGenericFloatID; + attribs[render_type_index + 3] = 0; - id rep = NSBitmapImageRep_initWithBitmapData(&win->buffer, win->r.w, win->r.h , 8, channels, (channels == 4), false, - "NSDeviceRGBColorSpace", 1 << 1, (u32)win->bufferSize.w * (u32)channels, 8 * (u32)channels); - ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep); + format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs); + if (format == NULL) + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "and loading software rendering OpenGL failed"); + else + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Switching to software rendering"); + } - id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView")); - ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES); - id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer")); + /* the pixel format can be passed directly to OpenGL context creation to create a context + this is because the format also includes information about the OpenGL version (which may be a bad thing) */ - ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image); - ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES); + if (win->src.view) + NSRelease(win->src.view); + win->src.view = (id) ((id(*)(id, SEL, NSRect, u32*))objc_msgSend) (NSAlloc(_RGFW->customViewClasses[1]), + sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}}, (u32*)format); - NSRelease(rep); - NSRelease(image); -#else - RGFW_UNUSED(win); + id share = NULL; + if (hints->share) { + share = (id)hints->share->ctx; + } + + win->src.ctx.native->ctx = ((id (*)(id, SEL, id, id))objc_msgSend)(NSAlloc(objc_getClass("NSOpenGLContext")), + sel_registerName("initWithFormat:shareContext:"), + (id)format, share); + + objc_msgSend_void_id(win->src.view, sel_registerName("setOpenGLContext:"), win->src.ctx.native->ctx); + if (win->internal.flags & RGFW_windowTransparent) { + i32 opacity = 0; + #define NSOpenGLCPSurfaceOpacity 236 + NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &opacity, (NSOpenGLContextParameter)NSOpenGLCPSurfaceOpacity); + + } + + objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext")); + + objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view); + objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true); + objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); + return RGFW_TRUE; +} + +void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { + objc_msgSend_void(ctx->ctx, sel_registerName("release")); + win->src.ctx.native->ctx = NULL; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); +} + +void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { + if (win) RGFW_ASSERT(win->src.ctx.native); + if (win != NULL) + objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext")); + else + objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext")); +} +void* RGFW_getCurrentContext_OpenGL(void) { + return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext")); +} + +void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { + RGFW_ASSERT(win && win->src.ctx.native); + objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("flushBuffer")); +} +void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { + RGFW_ASSERT(win != NULL && win->src.ctx.native != NULL); + NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &swapInterval, (NSOpenGLContextParameter)222); +} #endif -} -void RGFW_deinit(void) { - _RGFW.windowCount = -1; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); -} +void RGFW_deinitPlatform(void) { } -void RGFW_window_close(RGFW_window* win) { - RGFW_ASSERT(win != NULL); +void RGFW_window_closePlatform(RGFW_window* win) { NSRelease(win->src.view); - if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); +} - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if ((win->_flags & RGFW_BUFFER_ALLOC)) - RGFW_FREE(win->buffer); - #endif - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; +#ifdef RGFW_WEBGPU +WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { + WGPUSurfaceDescriptor surfaceDesc = {0}; + id* nsView = (id*)window->src.view; + if (!nsView) { + fprintf(stderr, "RGFW Error: NSView is NULL for macOS window.\n"); + return NULL; } -} -u64 RGFW_getTimerFreq(void) { - static u64 freq = 0; - if (freq == 0) { - mach_timebase_info_data_t info; - mach_timebase_info(&info); - freq = (u64)((info.denom * 1e9) / info.numer); + ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES); + id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer")); + + void* metalLayer = RGFW_getLayer_OSX(); + if (metalLayer == NULL) { + return NULL; } + ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer); + layer = metalLayer; /* Use the newly created layer */ - return freq; + /* At this point, 'layer' should be a valid CAMetalLayer* */ + WGPUSurfaceSourceMetalLayer fromMetal = {0}; + fromMetal.chain.sType = WGPUSType_SurfaceSourceMetalLayer; +#ifdef __OBJC__ + fromMetal.layer = (__bridge CAMetalLayer*)layer; /* Use __bridge for ARC compatibility if mixing C/Obj-C */ +#else + fromMetal.layer = layer; +#endif + + surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromMetal.chain; + return wgpuInstanceCreateSurface(instance, &surfaceDesc); } - -u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); } +#endif #endif /* RGFW_MACOS */ @@ -10101,33 +12683,40 @@ u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); } EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root); - RGFW_windowResizedCallback(_RGFW.root, RGFW_RECT(0, 0, E->windowInnerWidth, E->windowInnerHeight)); + if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE; + + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = _RGFW->root); + RGFW_windowResizedCallback(_RGFW->root, E->windowInnerWidth, E->windowInnerHeight); return EM_TRUE; } EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + + if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE; + static u8 fullscreen = RGFW_FALSE; - static RGFW_rect ogRect; + static i32 originalW, originalH; if (fullscreen == RGFW_FALSE) { - ogRect = _RGFW.root->r; + originalW = _RGFW->root->w; + originalH = _RGFW->root->h; } fullscreen = !fullscreen; - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root); - _RGFW.root->r = RGFW_RECT(0, 0, E->screenWidth, E->screenHeight); + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = _RGFW->root); + _RGFW->root->w = E->screenWidth; + _RGFW->root->h = 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); */ + _RGFW->root->w = originalW; + _RGFW->root->h = originalH; } else { #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0 EmscriptenFullscreenStrategy FSStrat = {0}; - FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; /* EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; */ + FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF; FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat); @@ -10136,97 +12725,111 @@ EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreen #endif } - emscripten_set_canvas_element_size("#canvas", _RGFW.root->r.w, _RGFW.root->r.h); - - RGFW_windowResizedCallback(_RGFW.root, _RGFW.root->r); + emscripten_set_canvas_element_size("#canvas", _RGFW->root->w, _RGFW->root->h); + RGFW_windowResizedCallback(_RGFW->root, _RGFW->root->w, _RGFW->root->h); return EM_TRUE; } - - EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E); - RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = _RGFW.root); - _RGFW.root->_flags |= RGFW_windowFocus; - RGFW_focusCallback(_RGFW.root, 1); + if (!(_RGFW->root->internal.enabledEvents & RGFW_focusInFlag)) return EM_TRUE; - if ((_RGFW.root->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(_RGFW.root, RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h)); + RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = _RGFW->root); + _RGFW->root->internal.inFocus = RGFW_TRUE; + RGFW_focusCallback(_RGFW->root, 1); + + if ((_RGFW->root->internal.holdMouse)) RGFW_window_holdMouse(_RGFW->root); return EM_TRUE; } EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E); - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = _RGFW.root); - RGFW_window_focusLost(_RGFW.root); - RGFW_focusCallback(_RGFW.root, 0); + if (!(_RGFW->root->internal.enabledEvents & RGFW_focusOutFlag)) return EM_TRUE; + + RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = _RGFW->root); + RGFW_window_focusLost(_RGFW->root); + RGFW_focusCallback(_RGFW->root, 0); return EM_TRUE; } EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.point = RGFW_POINT(E->targetX, E->targetY); - e.vector = RGFW_POINT(E->movementX, E->movementY); - e._win = _RGFW.root); - _RGFW.root->_lastMousePoint = RGFW_POINT(E->targetX, E->targetY); - RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->targetX, E->targetY), RGFW_POINT(E->movementX, E->movementY)); + if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE; + + RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; + e.mouse.x = E->targetX; e.mouse.y = E->targetY; + e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; + e.common.win = _RGFW->root); + + _RGFW->vectorX = E->movementX; + _RGFW->vectorY = E->movementY; + _RGFW->root->internal.lastMouseX = E->targetX; + _RGFW->root->internal.lastMouseY = E->targetY; + RGFW_mousePosCallback(_RGFW->root, E->targetX, E->targetY, E->movementX, E->movementY); return EM_TRUE; } EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE; + int button = E->button; if (button > 2) button += 2; RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.point = RGFW_POINT(E->targetX, E->targetY); - e.vector = RGFW_POINT(E->movementX, E->movementY); - e.button = (u8)button; - e.scroll = 0; - e._win = _RGFW.root); - RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; - RGFW_mouseButtons[button].current = 1; + e.mouse.x = E->targetX; e.mouse.y = E->targetY; + e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; + e.button.value = (u8)button; + e.common.win = _RGFW->root); + _RGFW->vectorX = E->movementX; + _RGFW->vectorY = E->movementY; + _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current; + _RGFW->mouseButtons[button].current = 1; - RGFW_mouseButtonCallback(_RGFW.root, button, 0, 1); + RGFW_mouseButtonCallback(_RGFW->root, button, 1); return EM_TRUE; } EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE; + int button = E->button; if (button > 2) button += 2; RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased; - e.point = RGFW_POINT(E->targetX, E->targetY); - e.vector = RGFW_POINT(E->movementX, E->movementY); - e.button = (u8)button; - e.scroll = 0; - e._win = _RGFW.root); - RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; - RGFW_mouseButtons[button].current = 0; + e.mouse.x = E->targetX; e.mouse.y = E->targetY; + e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; + e.button.value = (u8)button; + e.common.win = _RGFW->root); + _RGFW->vectorX = E->movementX; + _RGFW->vectorY = E->movementY; + _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current; + _RGFW->mouseButtons[button].current = 0; - RGFW_mouseButtonCallback(_RGFW.root, button, 0, 0); + RGFW_mouseButtonCallback(_RGFW->root, button, 0); return EM_TRUE; } EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - int button = RGFW_mouseScrollUp + (E->deltaY < 0); + if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseScrollFlag)) return EM_TRUE; + + _RGFW->scrollX = E->deltaX; + _RGFW->scrollY = E->deltaY; RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.button = (u8)button; - e.scroll = (double)(E->deltaY < 0 ? 1 : -1); - e._win = _RGFW.root); - RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; - RGFW_mouseButtons[button].current = 1; - RGFW_mouseButtonCallback(_RGFW.root, button, E->deltaY < 0 ? 1 : -1, 1); + e.scroll.x = E->deltaX; + e.scroll.y = E->deltaY; + ); + RGFW_mouseScrollCallback(_RGFW->root, E->deltaX, E->deltaY); return EM_TRUE; } @@ -10234,35 +12837,44 @@ EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE; + size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - e.button = RGFW_mouseLeft; - e._win = _RGFW.root); + e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; + e.button.value = RGFW_mouseLeft; + e.common.win = _RGFW->root); - RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current; - RGFW_mouseButtons[RGFW_mouseLeft].current = 1; + _RGFW->mouseButtons[RGFW_mouseLeft].prev = _RGFW->mouseButtons[RGFW_mouseLeft].current; + _RGFW->mouseButtons[RGFW_mouseLeft].current = 1; - _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); - RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 1); + _RGFW->root->internal.lastMouseX = E->touches[i].targetX; + _RGFW->root->internal.lastMouseX = E->touches[i].targetY; + RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); + RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 1); } return EM_TRUE; } + EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE; + size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - e.button = RGFW_mouseLeft; - e._win = _RGFW.root); + e.mouse.x = E->touches[i].targetX; + e.mouse.y = E->touches[i].targetY; + e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; + e.button.value = RGFW_mouseLeft; + e.common.win = _RGFW->root); - _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); + _RGFW->root->internal.lastMouseX = E->touches[i].targetX; + _RGFW->root->internal.lastMouseX = E->touches[i].targetY; + RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); } return EM_TRUE; } @@ -10270,60 +12882,563 @@ EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, vo EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); + if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE; + size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased; - e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - e.button = RGFW_mouseLeft; - e._win = _RGFW.root); + e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; + e.button.value = RGFW_mouseLeft; + e.common.win = _RGFW->root); - RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current; - RGFW_mouseButtons[RGFW_mouseLeft].current = 0; + _RGFW->mouseButtons[RGFW_mouseLeft].prev = _RGFW->mouseButtons[RGFW_mouseLeft].current; + _RGFW->mouseButtons[RGFW_mouseLeft].current = 0; - _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); - RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); - RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 0); + _RGFW->root->internal.lastMouseX = E->touches[i].targetX; + _RGFW->root->internal.lastMouseY = E->touches[i].targetY; + RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); + RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 0); } return EM_TRUE; } EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; } -EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) { - RGFW_UNUSED(eventType); RGFW_UNUSED(userData); +u32 RGFW_WASMPhysicalToRGFW(u32 hash); - if (gamepadEvent->index >= 4) - return 0; +void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) { + const char* iCode = code; - size_t i = gamepadEvent->index; - if (gamepadEvent->connected) { - RGFW_STRNCPY(RGFW_gamepads_name[gamepadEvent->index], gamepadEvent->id, sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1); - RGFW_gamepads_name[gamepadEvent->index][sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1] = '\0'; - RGFW_gamepads_type[i] = RGFW_gamepadUnknown; - if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box")) - RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5")) - RGFW_gamepads_type[i] = RGFW_gamepadSony; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo")) - RGFW_gamepads_type[i] = RGFW_gamepadNintendo; - else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech")) - RGFW_gamepads_type[i] = RGFW_gamepadLogitech; - RGFW_gamepadCount++; - } else { - RGFW_gamepadCount--; + u32 hash = 0; + while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++; + + u32 physicalKey = RGFW_WASMPhysicalToRGFW(hash); + + u8 mappedKey = (u8)(*((u32*)key)); + + if (*((u16*)key) != mappedKey) { + mappedKey = 0; + if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab; } - RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(gamepadEvent->connected ? RGFW_gamepadConnected : RGFW_gamepadConnected); - e.gamepad = (u16)gamepadEvent->index; - e._win = _RGFW.root); + if (!(press ? (_RGFW->root->internal.enabledEvents & RGFW_keyPressedFlag) : (_RGFW->root->internal.enabledEvents & RGFW_keyReleasedFlag))) return; - RGFW_gamepadCallback(_RGFW.root, gamepadEvent->index, gamepadEvent->connected); - RGFW_gamepads[gamepadEvent->index] = gamepadEvent->connected; + RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased); + e.key.value = (u8)physicalKey; + e.key.sym = (u8)mappedKey; + e.key.mod = _RGFW->root->internal.mod; + e.key.repeat = RGFW_window_isKeyDown(_RGFW->root, (u8)physicalKey); + e.common.win = _RGFW->root); - return 1; /* The event was consumed by the callback handler */ + _RGFW->keyboard[physicalKey].prev = _RGFW->keyboard[physicalKey].current; + _RGFW->keyboard[physicalKey].current = press; + + RGFW_keyCallback(_RGFW->root, physicalKey, mappedKey, _RGFW->root->internal.mod, RGFW_window_isKeyDown(_RGFW->root, (u8)physicalKey), press); } -u32 RGFW_wASMPhysicalToRGFW(u32 hash) { +void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { + RGFW_updateKeyModsEx(_RGFW->root, capital, numlock, control, alt, shift, super, scroll); +} + +void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { + if (!(_RGFW->root->internal.flags & RGFW_windowAllowDND)) + return; + + if (!(_RGFW->root->internal.enabledEvents & RGFW_dataDropFlag)) return; + + RGFW_eventQueuePushEx(e.type = RGFW_dataDrop; + e.drop.count = count; + e.common.win = _RGFW->root); + + _RGFW->windowState.win = _RGFW->root; + _RGFW->windowState.dataDrop = RGFW_TRUE; + _RGFW->windowState.filesCount = count; + RGFW_dataDropCallback(_RGFW->root, _RGFW->files, count); +} + +void RGFW_stopCheckEvents(void) { + _RGFW->stopCheckEvents_bool = RGFW_TRUE; +} + +RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { + surface->data = data; + surface->w = w; + surface->h = h; + surface->format = format; + return RGFW_TRUE; +} + +void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { + /* TODO: Needs fixing. */ + RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), RGFW_formatRGBA8, surface->data, surface->format); + EM_ASM_({ + var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); + let context = document.getElementById("canvas").getContext("2d"); + let image = context.getImageData(0, 0, $1, $2); + image.data.set(data); + context.putImageData(image, 0, $4 - $2); + }, surface->data, surface->w, surface->h, RGFW_MIN(win->h, surface->w), RGFW_MIN(win->h, surface->h)); +} + +void RGFW_surface_freePtr(RGFW_surface* surface) { } + +void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) { + /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */ + /* TODO: find a better way to do this + */ + RGFW_STRNCPY((char*)_RGFW->files[index], file, RGFW_MAX_PATH - 1); + _RGFW->files[index][RGFW_MAX_PATH - 1] = '\0'; +} + +#include +#include +#include +#include + +void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); } + +void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) { + FILE* file = fopen(path, "w+"); + if (file == NULL) + return; + + fwrite(data, sizeof(char), len, file); + fclose(file); +} + +void RGFW_initKeycodesPlatform(void) { + _RGFW->keycodes[DOM_VK_BACK_QUOTE] = RGFW_backtick; + _RGFW->keycodes[DOM_VK_0] = RGFW_0; + _RGFW->keycodes[DOM_VK_1] = RGFW_1; + _RGFW->keycodes[DOM_VK_2] = RGFW_2; + _RGFW->keycodes[DOM_VK_3] = RGFW_3; + _RGFW->keycodes[DOM_VK_4] = RGFW_4; + _RGFW->keycodes[DOM_VK_5] = RGFW_5; + _RGFW->keycodes[DOM_VK_6] = RGFW_6; + _RGFW->keycodes[DOM_VK_7] = RGFW_7; + _RGFW->keycodes[DOM_VK_8] = RGFW_8; + _RGFW->keycodes[DOM_VK_9] = RGFW_9; + _RGFW->keycodes[DOM_VK_SPACE] = RGFW_space; + _RGFW->keycodes[DOM_VK_A] = RGFW_a; + _RGFW->keycodes[DOM_VK_B] = RGFW_b; + _RGFW->keycodes[DOM_VK_C] = RGFW_c; + _RGFW->keycodes[DOM_VK_D] = RGFW_d; + _RGFW->keycodes[DOM_VK_E] = RGFW_e; + _RGFW->keycodes[DOM_VK_F] = RGFW_f; + _RGFW->keycodes[DOM_VK_G] = RGFW_g; + _RGFW->keycodes[DOM_VK_H] = RGFW_h; + _RGFW->keycodes[DOM_VK_I] = RGFW_i; + _RGFW->keycodes[DOM_VK_J] = RGFW_j; + _RGFW->keycodes[DOM_VK_K] = RGFW_k; + _RGFW->keycodes[DOM_VK_L] = RGFW_l; + _RGFW->keycodes[DOM_VK_M] = RGFW_m; + _RGFW->keycodes[DOM_VK_N] = RGFW_n; + _RGFW->keycodes[DOM_VK_O] = RGFW_o; + _RGFW->keycodes[DOM_VK_P] = RGFW_p; + _RGFW->keycodes[DOM_VK_Q] = RGFW_q; + _RGFW->keycodes[DOM_VK_R] = RGFW_r; + _RGFW->keycodes[DOM_VK_S] = RGFW_s; + _RGFW->keycodes[DOM_VK_T] = RGFW_t; + _RGFW->keycodes[DOM_VK_U] = RGFW_u; + _RGFW->keycodes[DOM_VK_V] = RGFW_v; + _RGFW->keycodes[DOM_VK_W] = RGFW_w; + _RGFW->keycodes[DOM_VK_X] = RGFW_x; + _RGFW->keycodes[DOM_VK_Y] = RGFW_y; + _RGFW->keycodes[DOM_VK_Z] = RGFW_z; + _RGFW->keycodes[DOM_VK_PERIOD] = RGFW_period; + _RGFW->keycodes[DOM_VK_COMMA] = RGFW_comma; + _RGFW->keycodes[DOM_VK_SLASH] = RGFW_slash; + _RGFW->keycodes[DOM_VK_OPEN_BRACKET] = RGFW_bracket; + _RGFW->keycodes[DOM_VK_CLOSE_BRACKET] = RGFW_closeBracket; + _RGFW->keycodes[DOM_VK_SEMICOLON] = RGFW_semicolon; + _RGFW->keycodes[DOM_VK_QUOTE] = RGFW_apostrophe; + _RGFW->keycodes[DOM_VK_BACK_SLASH] = RGFW_backSlash; + _RGFW->keycodes[DOM_VK_RETURN] = RGFW_return; + _RGFW->keycodes[DOM_VK_DELETE] = RGFW_delete; + _RGFW->keycodes[DOM_VK_NUM_LOCK] = RGFW_numLock; + _RGFW->keycodes[DOM_VK_DIVIDE] = RGFW_kpSlash; + _RGFW->keycodes[DOM_VK_MULTIPLY] = RGFW_kpMultiply; + _RGFW->keycodes[DOM_VK_SUBTRACT] = RGFW_kpMinus; + _RGFW->keycodes[DOM_VK_NUMPAD1] = RGFW_kp1; + _RGFW->keycodes[DOM_VK_NUMPAD2] = RGFW_kp2; + _RGFW->keycodes[DOM_VK_NUMPAD3] = RGFW_kp3; + _RGFW->keycodes[DOM_VK_NUMPAD4] = RGFW_kp4; + _RGFW->keycodes[DOM_VK_NUMPAD5] = RGFW_kp5; + _RGFW->keycodes[DOM_VK_NUMPAD6] = RGFW_kp6; + _RGFW->keycodes[DOM_VK_NUMPAD9] = RGFW_kp9; + _RGFW->keycodes[DOM_VK_NUMPAD0] = RGFW_kp0; + _RGFW->keycodes[DOM_VK_DECIMAL] = RGFW_kpPeriod; + _RGFW->keycodes[DOM_VK_RETURN] = RGFW_kpReturn; + _RGFW->keycodes[DOM_VK_HYPHEN_MINUS] = RGFW_minus; + _RGFW->keycodes[DOM_VK_EQUALS] = RGFW_equals; + _RGFW->keycodes[DOM_VK_BACK_SPACE] = RGFW_backSpace; + _RGFW->keycodes[DOM_VK_TAB] = RGFW_tab; + _RGFW->keycodes[DOM_VK_CAPS_LOCK] = RGFW_capsLock; + _RGFW->keycodes[DOM_VK_SHIFT] = RGFW_shiftL; + _RGFW->keycodes[DOM_VK_CONTROL] = RGFW_controlL; + _RGFW->keycodes[DOM_VK_ALT] = RGFW_altL; + _RGFW->keycodes[DOM_VK_META] = RGFW_superL; + _RGFW->keycodes[DOM_VK_F1] = RGFW_F1; + _RGFW->keycodes[DOM_VK_F2] = RGFW_F2; + _RGFW->keycodes[DOM_VK_F3] = RGFW_F3; + _RGFW->keycodes[DOM_VK_F4] = RGFW_F4; + _RGFW->keycodes[DOM_VK_F5] = RGFW_F5; + _RGFW->keycodes[DOM_VK_F6] = RGFW_F6; + _RGFW->keycodes[DOM_VK_F7] = RGFW_F7; + _RGFW->keycodes[DOM_VK_F8] = RGFW_F8; + _RGFW->keycodes[DOM_VK_F9] = RGFW_F9; + _RGFW->keycodes[DOM_VK_F10] = RGFW_F10; + _RGFW->keycodes[DOM_VK_F11] = RGFW_F11; + _RGFW->keycodes[DOM_VK_F12] = RGFW_F12; + _RGFW->keycodes[DOM_VK_UP] = RGFW_up; + _RGFW->keycodes[DOM_VK_DOWN] = RGFW_down; + _RGFW->keycodes[DOM_VK_LEFT] = RGFW_left; + _RGFW->keycodes[DOM_VK_RIGHT] = RGFW_right; + _RGFW->keycodes[DOM_VK_INSERT] = RGFW_insert; + _RGFW->keycodes[DOM_VK_END] = RGFW_end; + _RGFW->keycodes[DOM_VK_PAGE_UP] = RGFW_pageUp; + _RGFW->keycodes[DOM_VK_PAGE_DOWN] = RGFW_pageDown; + _RGFW->keycodes[DOM_VK_ESCAPE] = RGFW_escape; + _RGFW->keycodes[DOM_VK_HOME] = RGFW_home; + _RGFW->keycodes[DOM_VK_SCROLL_LOCK] = RGFW_scrollLock; + _RGFW->keycodes[DOM_VK_PRINTSCREEN] = RGFW_printScreen; + _RGFW->keycodes[DOM_VK_PAUSE] = RGFW_pause; + _RGFW->keycodes[DOM_VK_F13] = RGFW_F13; + _RGFW->keycodes[DOM_VK_F14] = RGFW_F14; + _RGFW->keycodes[DOM_VK_F15] = RGFW_F15; + _RGFW->keycodes[DOM_VK_F16] = RGFW_F16; + _RGFW->keycodes[DOM_VK_F17] = RGFW_F17; + _RGFW->keycodes[DOM_VK_F18] = RGFW_F18; + _RGFW->keycodes[DOM_VK_F19] = RGFW_F19; + _RGFW->keycodes[DOM_VK_F20] = RGFW_F20; + _RGFW->keycodes[DOM_VK_F21] = RGFW_F21; + _RGFW->keycodes[DOM_VK_F22] = RGFW_F22; + _RGFW->keycodes[DOM_VK_F23] = RGFW_F23; + _RGFW->keycodes[DOM_VK_F24] = RGFW_F24; +} + +i32 RGFW_initPlatform(void) { return 0; } + +RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { + emscripten_set_canvas_element_size("#canvas", win->w, win->h); + emscripten_set_window_title(name); + + /* load callbacks */ + 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); + emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart); + emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend); + emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove); + emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel); + emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown); + emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup); + emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel); + emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin); + emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout); + + if (flags & RGFW_windowAllowDND) { + win->internal.flags |= RGFW_windowAllowDND; + } + + EM_ASM({ + window.addEventListener("keydown", + (event) => { + var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); + Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); + Module._RGFW_handleKeyEvent(key, code, 1); + _free(key); _free(code); + }, + true); + window.addEventListener("keyup", + (event) => { + var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); + Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); + Module._RGFW_handleKeyEvent(key, code, 0); + _free(key); _free(code); + }, + true); + }); + + EM_ASM({ + var canvas = document.getElementById('canvas'); + canvas.addEventListener('drop', function(e) { + e.preventDefault(); + if (e.dataTransfer.file < 0) + return; + + var filenamesArray = []; + var count = e.dataTransfer.files.length; + + /* Read and save the files to emscripten's files */ + var drop_dir = '.rgfw_dropped_files'; + Module._RGFW_mkdir(drop_dir); + + for (var i = 0; i < count; i++) { + var file = e.dataTransfer.files[i]; + + var path = '/' + drop_dir + '/' + file.name.replace("//", '_'); + var reader = new FileReader(); + + reader.onloadend = (e) => { + if (reader.readyState != 2) { + out('failed to read dropped file: '+file.name+': '+reader.error); + } + else { + var data = e.target.result; + + Module._RGFW_writeFile(path, new Uint8Array(data), file.size); + } + }; + + reader.readAsArrayBuffer(file); + /* This works weird on modern OpenGL */ + var filename = stringToNewUTF8(path); + + filenamesArray.push(filename); + + Module._RGFW_makeSetValue(i, filename); + } + + Module._Emscripten_onDrop(count); + + for (var i = 0; i < count; ++i) { + _free(filenamesArray[i]); + } + }, true); + + canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true); + }); + + return win; +} + +u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { + return (u8)rgfw_keycode; /* TODO */ +} + +void RGFW_pollEvents(void) { + emscripten_sleep(0); + RGFW_resetPrevState(); +} + +void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { + RGFW_UNUSED(win); + emscripten_set_canvas_element_size("#canvas", w, h); +} + +/* NOTE: I don't know if this is possible */ +void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); } +/* this one might be possible but it looks iffy */ +RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); return NULL; } + +void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); } +void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); } + +RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { + static const char cursors[16][16] = { + "default", "default", "text", "crosshair", + "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize", + "move", "not-allowed" + }; + + RGFW_UNUSED(win); + EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]); + return RGFW_TRUE; +} + +RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { + return RGFW_window_setMouseStandard(win, RGFW_mouseNormal); +} + +void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { + RGFW_window_showMouseFlags(win, show); + if (show) + RGFW_window_setMouseDefault(win); + else + EM_ASM(document.getElementById('canvas').style.cursor = 'none';); +} + +RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { + if(x) *x = EM_ASM_INT({ + return window.mouseX || 0; + }); + if (y) *y = EM_ASM_INT({ + return window.mouseY || 0; + }); + return RGFW_TRUE; +} + +void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { + RGFW_UNUSED(win); + + EM_ASM_({ + var canvas = document.getElementById('canvas'); + if ($0) { + canvas.style.pointerEvents = 'none'; + } else { + canvas.style.pointerEvents = 'auto'; + } + }, passthrough); +} + +void RGFW_writeClipboard(const char* text, u32 textLen) { + RGFW_UNUSED(textLen); + EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text); +} + + +RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { + RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); + /* + placeholder code for later + I'm not sure if this is possible do the the async stuff + */ + return 0; +} + +#ifdef RGFW_OPENGL +RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { + win->src.ctx.native = ctx; + win->src.gfxType = RGFW_gfxNativeOpenGL; + + EmscriptenWebGLContextAttributes attrs; + attrs.alpha = hints->alpha; + attrs.depth = hints->depth; + attrs.stencil = hints->stencil; + attrs.antialias = hints->samples; + attrs.premultipliedAlpha = EM_TRUE; + attrs.preserveDrawingBuffer = EM_FALSE; + + if (hints->doubleBuffer == 0) + attrs.renderViaOffscreenBackBuffer = 0; + else + attrs.renderViaOffscreenBackBuffer = hints->auxBuffers; + + attrs.failIfMajorPerformanceCaveat = EM_FALSE; + attrs.majorVersion = (hints->major == 0) ? 1 : hints->major; + attrs.minorVersion = hints->minor; + + attrs.enableExtensionsByDefault = EM_TRUE; + attrs.explicitSwapControl = EM_TRUE; + + emscripten_webgl_init_context_attributes(&attrs); + win->src.ctx.native->ctx = emscripten_webgl_create_context("#canvas", &attrs); + emscripten_webgl_make_context_current(win->src.ctx.native->ctx); + + #ifdef LEGACY_GL_EMULATION + EM_ASM("Module.useWebGL = true; GLImmediate.init();"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); + #endif + return RGFW_TRUE; +} + +void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { + emscripten_webgl_destroy_context(ctx->ctx); + win->src.ctx.native->ctx = 0; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); +} + +void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { + if (win) RGFW_ASSERT(win->src.ctx.native); + if (win == NULL) + emscripten_webgl_make_context_current(0); + else + emscripten_webgl_make_context_current(win->src.ctx.native->ctx); +} + +void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { + RGFW_ASSERT(win && win->src.ctx.native); + emscripten_webgl_commit_frame(); +} +void* RGFW_getCurrentContext_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); } + +RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) { + return EM_ASM_INT({ + var ext = UTF8ToString($0, $1); + var canvas = document.querySelector('canvas'); + var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + if (!gl) return 0; + + var supported = gl.getSupportedExtensions(); + return supported && supported.includes(ext) ? 1 : 0; + }, extension, len); + return RGFW_FALSE; +} + +RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { + return (RGFW_proc)emscripten_webgl_get_proc_address(procname); + return NULL; +} + +#endif + +void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } + +void RGFW_deinitPlatform(void) { } + +void RGFW_window_closePlatform(RGFW_window* win) { } + +int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); } +int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); } + +void RGFW_releaseCursor(RGFW_window* win) { + RGFW_UNUSED(win); + emscripten_exit_pointerlock(); +} + +void RGFW_captureCursor(RGFW_window* win) { + RGFW_UNUSED(win); + emscripten_request_pointerlock("#canvas", 1); +} + + +void RGFW_window_setName(RGFW_window* win, const char* name) { + RGFW_UNUSED(win); + emscripten_set_window_title(name); +} + +void RGFW_window_maximize(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + + RGFW_monitor mon = RGFW_window_getMonitor(win); + RGFW_window_move(win, 0, 0); + RGFW_window_resize(win, mon.mode.w, mon.mode.h); +} + +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { + RGFW_ASSERT(win != NULL); + if (fullscreen) { + win->internal.flags |= RGFW_windowFullscreen; + EM_ASM( Module.requestFullscreen(false, true); ); + return; + } + win->internal.flags &= ~(u32)RGFW_windowFullscreen; + EM_ASM( Module.exitFullscreen(false, true); ); +} + +void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { + RGFW_UNUSED(win); + EM_ASM({ + var element = document.getElementById("canvas"); + if (element) + element.style.opacity = $1; + }, "elementId", opacity); +} + +#ifdef RGFW_WEBGPU +WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { + WGPUSurfaceDescriptor surfaceDesc = {0}; + WGPUEmscriptenSurfaceSourceCanvasHTMLSelector canvasDesc = {0}; + canvasDesc.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector; + canvasDesc.selector = (WGPUStringView){.data = "#canvas", .length = 7}; + + surfaceDesc.nextInChain = &canvasDesc.chain; + return wgpuInstanceCreateSurface(instance, &surfaceDesc); +} +#endif + +u32 RGFW_WASMPhysicalToRGFW(u32 hash) { switch(hash) { /* 0x0000 */ case 0x67243A2DU /* Escape */: return RGFW_escape; /* 0x0001 */ case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */ @@ -10378,7 +13493,7 @@ u32 RGFW_wASMPhysicalToRGFW(u32 hash) { 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 0x5D64DA91U /* NumpadMultiply */: return RGFW_kpMultiply; case 0xC914958CU /* AltLeft */: return RGFW_altL; /* 0x0038 */ case 0x92E09CB5U /* Space */: return RGFW_space; /* 0x0039 */ case 0xB8FAE73BU /* CapsLock */: return RGFW_capsLock; /* 0x003A */ @@ -10392,21 +13507,32 @@ u32 RGFW_wASMPhysicalToRGFW(u32 hash) { 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 0xC925FCDFU /* Numpad7 */: return RGFW_kpMultiply; /* 0x0047 */ + case 0xC925FCD0U /* Numpad8 */: return RGFW_kp8; /* 0x0048 */ + case 0xC925FCD1U /* Numpad9 */: return RGFW_kp9; /* 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 0xC925FCDCU /* Numpad4 */: return RGFW_kp4; /* 0x004B */ + case 0xC925FCDDU /* Numpad5 */: return RGFW_kp5; /* 0x004C */ + case 0xC925FCDEU /* Numpad6 */: return RGFW_kp6; /* 0x004D */ + case 0xC925FCD9U /* Numpad1 */: return RGFW_kp1; /* 0x004F */ + case 0xC925FCDAU /* Numpad2 */: return RGFW_kp2; /* 0x0050 */ + case 0xC925FCDBU /* Numpad3 */: return RGFW_kp3; /* 0x0051 */ + case 0xC925FCD8U /* Numpad0 */: return RGFW_kp0; /* 0x0052 */ case 0x95852DACU /* NumpadDecimal */: return RGFW_period; /* 0x0053 */ case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */ case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */ - case 0x7393FBACU /* NumpadEqual */: return RGFW_KP_Return; + case 0x7B8E57B3U /* F13 */: return DOM_PK_F13; /* 0x0064 */ + case 0x7B8E57B4U /* F14 */: return DOM_PK_F14; /* 0x0065 */ + case 0x7B8E57B5U /* F15 */: return DOM_PK_F15; /* 0x0066 */ + case 0x7B8E57B6U /* F16 */: return DOM_PK_F16; /* 0x0067 */ + case 0x7B8E57B7U /* F17 */: return DOM_PK_F17; /* 0x0068 */ + case 0x7B8E57B8U /* F18 */: return DOM_PK_F18; /* 0x0069 */ + case 0x7B8E57B9U /* F19 */: return DOM_PK_F19; /* 0x006A */ + case 0x7B8E57A8U /* F20 */: return DOM_PK_F20; /* 0x006B */ + case 0x7B8E57A9U /* F21 */: return DOM_PK_F21; /* 0x006C */ + case 0x7B8E57AAU /* F22 */: return DOM_PK_F22; /* 0x006D */ + case 0x7B8E57ABU /* F23 */: return DOM_PK_F23; /* 0x006E */ + case 0x7393FBACU /* NumpadEqual */: return RGFW_kpReturn; case 0xB88EBF7CU /* AltRight */: return RGFW_altR; /* 0xE038 */ case 0xC925873BU /* NumLock */: return RGFW_numLock; /* 0xE045 */ case 0x2C595F45U /* Home */: return RGFW_home; /* 0xE047 */ @@ -10421,602 +13547,28 @@ u32 RGFW_wASMPhysicalToRGFW(u32 hash) { case 0x6725C50DU /* Delete */: return RGFW_delete; /* 0xE053 */ case 0x6723658CU /* OSLeft */: return RGFW_superL; /* 0xE05B */ case 0x39643F7CU /* MetaRight */: return RGFW_superR; /* 0xE05C */ + case 0x380B9C8CU /* NumpadAdd */: return DOM_PK_NUMPAD_ADD; /* 0x004E */ + default: return DOM_PK_UNKNOWN; } return 0; } -void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) { - const char* iCode = code; - - u32 hash = 0; - while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++; - - u32 physicalKey = RGFW_wASMPhysicalToRGFW(hash); - - u8 mappedKey = (u8)(*((u32*)key)); - - if (*((u16*)key) != mappedKey) { - mappedKey = 0; - if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab; - } - - RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased); - e.key = (u8)physicalKey; - e.keyChar = (u8)mappedKey; - e.keyMod = _RGFW.root->event.keyMod; - e._win = _RGFW.root); - - RGFW_keyboard[physicalKey].prev = RGFW_keyboard[physicalKey].current; - RGFW_keyboard[physicalKey].current = press; - - RGFW_keyCallback(_RGFW.root, physicalKey, mappedKey, _RGFW.root->event.keyMod, press); -} - -void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { - RGFW_updateKeyModsPro(_RGFW.root, capital, numlock, control, alt, shift, super, scroll); -} - -void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { - if (!(_RGFW.root->_flags & RGFW_windowAllowDND)) - return; - - _RGFW.root->event.droppedFilesCount = count; - RGFW_eventQueuePushEx(e.type = RGFW_DND; - e.droppedFilesCount = count; - e._win = _RGFW.root); - RGFW_dndCallback(_RGFW.root, _RGFW.root->event.droppedFiles, count); -} - -RGFW_bool RGFW_stopCheckEvents_bool = RGFW_FALSE; -void RGFW_stopCheckEvents(void) { - RGFW_stopCheckEvents_bool = RGFW_TRUE; -} - -void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { - RGFW_UNUSED(win); - if (waitMS == 0) return; - - u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6); - - while ((_RGFW.eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && (RGFW_getTimeNS() / 1e+6) - start < waitMS) - emscripten_sleep(0); - - RGFW_stopCheckEvents_bool = RGFW_FALSE; -} - -void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){ - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - win->buffer = buffer; - win->bufferSize = area; - #ifdef RGFW_OSMESA - win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); - OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); - OSMesaPixelStore(OSMESA_Y_UP, 0); - #endif - #else - RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ - #endif -} - -void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) { - /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */ - /* TODO: find a better way to do this - */ - RGFW_STRNCPY((char*)_RGFW.root->event.droppedFiles[index], file, RGFW_MAX_PATH - 1); - _RGFW.root->event.droppedFiles[index][RGFW_MAX_PATH - 1] = '\0'; -} - -#include -#include -#include -#include - -void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); } - -void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) { - FILE* file = fopen(path, "w+"); - if (file == NULL) - return; - - fwrite(data, sizeof(char), len, file); - fclose(file); -} - -void RGFW_window_initOpenGL(RGFW_window* win) { -#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_BUFFER) - EmscriptenWebGLContextAttributes attrs; - attrs.alpha = RGFW_GL_HINTS[RGFW_glDepth]; - attrs.depth = RGFW_GL_HINTS[RGFW_glAlpha]; - attrs.stencil = RGFW_GL_HINTS[RGFW_glStencil]; - attrs.antialias = RGFW_GL_HINTS[RGFW_glSamples]; - attrs.premultipliedAlpha = EM_TRUE; - attrs.preserveDrawingBuffer = EM_FALSE; - - if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0) - attrs.renderViaOffscreenBackBuffer = 0; - else - attrs.renderViaOffscreenBackBuffer = RGFW_GL_HINTS[RGFW_glAuxBuffers]; - - attrs.failIfMajorPerformanceCaveat = EM_FALSE; - attrs.majorVersion = (RGFW_GL_HINTS[RGFW_glMajor] == 0) ? 1 : RGFW_GL_HINTS[RGFW_glMajor]; - attrs.minorVersion = RGFW_GL_HINTS[RGFW_glMinor]; - - attrs.enableExtensionsByDefault = EM_TRUE; - attrs.explicitSwapControl = EM_TRUE; - - emscripten_webgl_init_context_attributes(&attrs); - win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs); - emscripten_webgl_make_context_current(win->src.ctx); - - #ifdef LEGACY_GL_EMULATION - EM_ASM("Module.useWebGL = true; GLImmediate.init();"); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); - #endif - glViewport(0, 0, win->r.w, win->r.h); -#endif -} - -void RGFW_window_freeOpenGL(RGFW_window* win) { -#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_OSMESA) - if (win->src.ctx == 0) return; - emscripten_webgl_destroy_context(win->src.ctx); - win->src.ctx = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); -#elif defined(RGFW_OPENGL) && defined(RGFW_OSMESA) - if(win->src.ctx == 0) return; - OSMesaDestroyContext(win->src.ctx); - win->src.ctx = 0; -#else - RGFW_UNUSED(win); -#endif -} - -i32 RGFW_init(void) { -#if defined(RGFW_C89) || defined(__cplusplus) - if (_RGFW_init) return 0; - _RGFW_init = RGFW_TRUE; - _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -2; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; -#endif - - _RGFW.windowCount = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); - return 0; -} - -RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { - RGFW_window_basic_init(win, rect, flags); - RGFW_window_initOpenGL(win); - - #if defined(RGFW_WEBGPU) - win->src.ctx = wgpuCreateInstance(NULL); - win->src.device = emscripten_webgpu_get_device(); - win->src.queue = wgpuDeviceGetQueue(win->src.device); - #endif - - emscripten_set_canvas_element_size("#canvas", rect.w, rect.h); - emscripten_set_window_title(name); - - /* load callbacks */ - 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); - emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart); - emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend); - emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove); - emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel); - emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown); - emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup); - emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel); - emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin); - emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout); - emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad); - emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad); - - if (flags & RGFW_windowAllowDND) { - win->_flags |= RGFW_windowAllowDND; - } - - EM_ASM({ - window.addEventListener("keydown", - (event) => { - var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); - Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); - Module._RGFW_handleKeyEvent(key, code, 1); - _free(key); _free(code); - }, - true); - window.addEventListener("keyup", - (event) => { - var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); - Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); - Module._RGFW_handleKeyEvent(key, code, 0); - _free(key); _free(code); - }, - true); - }); - - EM_ASM({ - var canvas = document.getElementById('canvas'); - canvas.addEventListener('drop', function(e) { - e.preventDefault(); - if (e.dataTransfer.file < 0) - return; - - var filenamesArray = []; - var count = e.dataTransfer.files.length; - - /* Read and save the files to emscripten's files */ - var drop_dir = '.rgfw_dropped_files'; - Module._RGFW_mkdir(drop_dir); - - for (var i = 0; i < count; i++) { - var file = e.dataTransfer.files[i]; - - var path = '/' + drop_dir + '/' + file.name.replace("//", '_'); - var reader = new FileReader(); - - reader.onloadend = (e) => { - if (reader.readyState != 2) { - out('failed to read dropped file: '+file.name+': '+reader.error); - } - else { - var data = e.target.result; - - _RGFW_writeFile(path, new Uint8Array(data), file.size); - } - }; - - reader.readAsArrayBuffer(file); - /* This works weird on modern opengl */ - var filename = stringToNewUTF8(path); - - filenamesArray.push(filename); - - Module._RGFW_makeSetValue(i, filename); - } - - Module._Emscripten_onDrop(count); - - for (var i = 0; i < count; ++i) { - _free(filenamesArray[i]); - } - }, true); - - canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true); - }); - - RGFW_window_setFlags(win, flags); - - if ((flags & RGFW_windowNoInitAPI) == 0) { - RGFW_window_initBuffer(win); - } - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); - return win; -} - -u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { - return (u8)rgfw_keycode; /* TODO */ -} - -RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { - if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; - RGFW_event* ev = RGFW_window_checkEventCore(win); - if (ev) return ev; - - emscripten_sample_gamepad_data(); - /* check gamepads */ - int i; - for (i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) { - if (RGFW_gamepads[i] == 0) - continue; - EmscriptenGamepadEvent gamepadState; - - if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS) - break; - - /* Register buttons data for every connected gamepad */ - int j; - for (j = 0; (j < gamepadState.numButtons) && (j < 16); j++) { - u32 map[] = { - RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, - RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, - RGFW_gamepadSelect, RGFW_gamepadStart, - RGFW_gamepadL3, RGFW_gamepadR3, - RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, RGFW_gamepadHome - }; - - - u32 button = map[j]; - if (button == 404) - continue; - - if (RGFW_gamepadPressed[i][button].current != gamepadState.digitalButton[j]) { - if (gamepadState.digitalButton[j]) - win->event.type = RGFW_gamepadButtonPressed; - else - win->event.type = RGFW_gamepadButtonReleased; - - win->event.gamepad = i; - win->event.button = map[j]; - - RGFW_gamepadPressed[i][button].prev = RGFW_gamepadPressed[i][button].current; - RGFW_gamepadPressed[i][button].current = gamepadState.digitalButton[j]; - - RGFW_gamepadButtonCallback(win, win->event.gamepad, win->event.button, gamepadState.digitalButton[j]); - return &win->event; - } - } - - for (j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) { - win->event.axisesCount = gamepadState.numAxes / 2; - if (RGFW_gamepadAxes[i][(size_t)(j / 2)].x != (i8)(gamepadState.axis[j] * 100.0f) || - RGFW_gamepadAxes[i][(size_t)(j / 2)].y != (i8)(gamepadState.axis[j + 1] * 100.0f) - ) { - - RGFW_gamepadAxes[i][(size_t)(j / 2)].x = (i8)(gamepadState.axis[j] * 100.0f); - RGFW_gamepadAxes[i][(size_t)(j / 2)].y = (i8)(gamepadState.axis[j + 1] * 100.0f); - win->event.axis[(size_t)(j / 2)] = RGFW_gamepadAxes[i][(size_t)(j / 2)]; - - win->event.type = RGFW_gamepadAxisMove; - win->event.gamepad = i; - win->event.whichAxis = j / 2; - - RGFW_gamepadAxisCallback(win, win->event.gamepad, win->event.axis, win->event.axisesCount, win->event.whichAxis); - return &win->event; - } - } - } - - return NULL; -} - -void RGFW_window_resize(RGFW_window* win, RGFW_area a) { - RGFW_UNUSED(win); - emscripten_set_canvas_element_size("#canvas", a.w, a.h); -} - -/* NOTE: I don't know if this is possible */ -void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } -/* this one might be possible but it looks iffy */ -RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(channels); RGFW_UNUSED(a); RGFW_UNUSED(icon); return NULL; } - -void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); } -void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); } - -RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { - static const char cursors[16][16] = { - "default", "default", "text", "crosshair", - "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize", - "move", "not-allowed" - }; - - RGFW_UNUSED(win); - EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]); - return RGFW_TRUE; -} - -RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { - return RGFW_window_setMouseStandard(win, RGFW_mouseNormal); -} - -void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { - RGFW_window_showMouseFlags(win, show); - if (show) - RGFW_window_setMouseDefault(win); - else - EM_ASM(document.getElementById('canvas').style.cursor = 'none';); -} - -RGFW_point RGFW_getGlobalMousePoint(void) { - RGFW_point point; - point.x = EM_ASM_INT({ - return window.mouseX || 0; - }); - point.y = EM_ASM_INT({ - return window.mouseY || 0; - }); - return point; -} - -void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { - RGFW_UNUSED(win); - - EM_ASM_({ - var canvas = document.getElementById('canvas'); - if ($0) { - canvas.style.pointerEvents = 'none'; - } else { - canvas.style.pointerEvents = 'auto'; - } - }, passthrough); -} - -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_UNUSED(textLen); - EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text); -} - - -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { - RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); - /* - placeholder code for later - I'm not sure if this is possible do the the async stuff - */ - return 0; -} - -void RGFW_window_swapBuffers_software(RGFW_window* win) { -#if defined(RGFW_OSMESA) - EM_ASM_({ - var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); - let context = document.getElementById("canvas").getContext("2d"); - let image = context.getImageData(0, 0, $1, $2); - image.data.set(data); - context.putImageData(image, 0, $4 - $2); - }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h); -#elif defined(RGFW_BUFFER) - EM_ASM_({ - var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); - let context = document.getElementById("canvas").getContext("2d"); - let image = context.getImageData(0, 0, $1, $2); - image.data.set(data); - context.putImageData(image, 0, 0); - }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h); - emscripten_sleep(0); -#else - RGFW_UNUSED(win); -#endif -} - -void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { -#if !defined(RGFW_WEBGPU) && !(defined(RGFW_OSMESA) || defined(RGFW_BUFFER)) - if (win == NULL) - emscripten_webgl_make_context_current(0); - else - emscripten_webgl_make_context_current(win->src.ctx); -#endif -} - - -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { -#ifndef RGFW_WEBGPU - emscripten_webgl_commit_frame(); - -#endif - emscripten_sleep(0); -} - -#ifndef RGFW_WEBGPU -void* RGFW_getCurrent_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); } -#endif - -#ifndef RGFW_EGL -void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } -#endif - -void RGFW_deinit(void) { _RGFW.windowCount = -1; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); } - -void RGFW_window_close(RGFW_window* win) { - if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); - - #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) - if ((win->_flags & RGFW_BUFFER_ALLOC)) - RGFW_FREE(win->buffer); - #endif - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); - _RGFW.windowCount--; - if (_RGFW.windowCount == 0) RGFW_deinit(); - - RGFW_clipboard_switch(NULL); - RGFW_FREE(win->event.droppedFiles); - if ((win->_flags & RGFW_WINDOW_ALLOC)) { - RGFW_FREE(win); - win = NULL; - } -} - -int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); } -int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); } - -RGFW_area RGFW_getScreenSize(void) { - return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight()); -} - -RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) { -#ifdef RGFW_OPENGL - return EM_ASM_INT({ - var ext = UTF8ToString($0, $1); - var canvas = document.querySelector('canvas'); - var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - if (!gl) return 0; - - var supported = gl.getSupportedExtensions(); - return supported && supported.includes(ext) ? 1 : 0; - }, extension, len); -#else - return RGFW_FALSE; -#endif -} - -RGFW_proc RGFW_getProcAddress(const char* procname) { -#ifdef RGFW_OPENGL - return (RGFW_proc)emscripten_webgl_get_proc_address(procname); -#else - return NULL -#endif -} - -void RGFW_sleep(u64 milisecond) { - emscripten_sleep(milisecond); -} - -u64 RGFW_getTimerFreq(void) { return (u64)1000; } -u64 RGFW_getTimerValue(void) { return emscripten_get_now() * 1e+6; } - -void RGFW_releaseCursor(RGFW_window* win) { - RGFW_UNUSED(win); - emscripten_exit_pointerlock(); -} - -void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { - RGFW_UNUSED(win); RGFW_UNUSED(r); - - emscripten_request_pointerlock("#canvas", 1); -} - - -void RGFW_window_setName(RGFW_window* win, const char* name) { - RGFW_UNUSED(win); - emscripten_set_window_title(name); -} - -void RGFW_window_maximize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - RGFW_area screen = RGFW_getScreenSize(); - RGFW_window_move(win, RGFW_POINT(0, 0)); - RGFW_window_resize(win, screen); -} - -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); - if (fullscreen) { - win->_flags |= RGFW_windowFullscreen; - EM_ASM( Module.requestFullscreen(false, true); ); - return; - } - win->_flags &= ~(u32)RGFW_windowFullscreen; - EM_ASM( Module.exitFullscreen(false, true); ); -} - -void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { - RGFW_UNUSED(win); - EM_ASM({ - var element = document.getElementById("canvas"); - if (element) - element.style.opacity = $1; - }, "elementId", opacity); -} - /* unsupported functions */ void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; } RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_UNUSED(len); return NULL; } RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; } -void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } -void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } -void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } -void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } +void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); } +void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } +void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } +void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); } void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); } -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); return RGFW_FALSE; } +RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_UNUSED(win); RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); RGFW_UNUSED(type); return RGFW_FALSE; } void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); } RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } @@ -11024,43 +13576,338 @@ RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return R RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return (RGFW_monitor){}; } +void RGFW_waitForEvent(i32 waitMS) { RGFW_UNUSED(waitMS); } #endif /* end of web asm defines */ -/* unix (macOS, linux, web asm) only stuff */ -#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) -#ifndef RGFW_NO_THREADS -#include +/* + * RGFW function pointer backend, made to allow you to compile for Wayland but fallback to X11 +*/ +#ifdef RGFW_DYNAMIC +typedef RGFW_window* (*RGFW_createWindowPlatform_ptr)(const char* name, RGFW_windowFlags flags, RGFW_window* win); +typedef RGFW_bool (*RGFW_getMouse_ptr)(i32* x, i32* y); +typedef u8 (*RGFW_rgfwToKeyChar_ptr)(u32 key); +typedef void (*RGFW_pollEvents_ptr)(void); +typedef void (*RGFW_window_move_ptr)(RGFW_window* win, i32 x, i32 y); +typedef void (*RGFW_window_resize_ptr)(RGFW_window* win, i32 w, i32 h); +typedef void (*RGFW_window_setAspectRatio_ptr)(RGFW_window* win, i32 w, i32 h); +typedef void (*RGFW_window_setMinSize_ptr)(RGFW_window* win, i32 w, i32 h); +typedef void (*RGFW_window_setMaxSize_ptr)(RGFW_window* win, i32 w, i32 h); +typedef void (*RGFW_window_maximize_ptr)(RGFW_window* win); +typedef void (*RGFW_window_focus_ptr)(RGFW_window* win); +typedef void (*RGFW_window_raise_ptr)(RGFW_window* win); +typedef void (*RGFW_window_setFullscreen_ptr)(RGFW_window* win, RGFW_bool fullscreen); +typedef void (*RGFW_window_setFloating_ptr)(RGFW_window* win, RGFW_bool floating); +typedef void (*RGFW_window_setOpacity_ptr)(RGFW_window* win, u8 opacity); +typedef void (*RGFW_window_minimize_ptr)(RGFW_window* win); +typedef void (*RGFW_window_restore_ptr)(RGFW_window* win); +typedef RGFW_bool (*RGFW_window_isFloating_ptr)(RGFW_window* win); +typedef void (*RGFW_window_setName_ptr)(RGFW_window* win, const char* name); +typedef void (*RGFW_window_setMousePassthrough_ptr)(RGFW_window* win, RGFW_bool passthrough); +typedef RGFW_bool (*RGFW_window_setIconEx_ptr)(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type); +typedef RGFW_mouse* (*RGFW_loadMouse_ptr)(u8* data, i32 w, i32 h, RGFW_format format); +typedef void (*RGFW_window_setMouse_ptr)(RGFW_window* win, RGFW_mouse* mouse); +typedef void (*RGFW_window_moveMouse_ptr)(RGFW_window* win, i32 x, i32 y); +typedef RGFW_bool (*RGFW_window_setMouseDefault_ptr)(RGFW_window* win); +typedef RGFW_bool (*RGFW_window_setMouseStandard_ptr)(RGFW_window* win, u8 mouse); +typedef void (*RGFW_window_hide_ptr)(RGFW_window* win); +typedef void (*RGFW_window_show_ptr)(RGFW_window* win); +typedef RGFW_ssize_t (*RGFW_readClipboardPtr_ptr)(char* str, size_t strCapacity); +typedef void (*RGFW_writeClipboard_ptr)(const char* text, u32 textLen); +typedef RGFW_bool (*RGFW_window_isHidden_ptr)(RGFW_window* win); +typedef RGFW_bool (*RGFW_window_isMinimized_ptr)(RGFW_window* win); +typedef RGFW_bool (*RGFW_window_isMaximized_ptr)(RGFW_window* win); +typedef RGFW_monitor* (*RGFW_getMonitors_ptr)(size_t* len); +typedef RGFW_monitor (*RGFW_getPrimaryMonitor_ptr)(void); +typedef RGFW_bool (*RGFW_monitor_requestMode_ptr)(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); +typedef RGFW_monitor (*RGFW_window_getMonitor_ptr)(RGFW_window* win); +typedef void (*RGFW_window_closePlatform_ptr)(RGFW_window* win); +typedef RGFW_bool (*RGFW_createSurfacePtr_ptr)(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface); +typedef void (*RGFW_window_blitSurface_ptr)(RGFW_window* win, RGFW_surface* surface); +typedef void (*RGFW_surface_freePtr_ptr)(RGFW_surface* surface); +typedef void (*RGFW_freeMouse_ptr)(RGFW_mouse* mouse); +typedef void (*RGFW_window_setBorder_ptr)(RGFW_window* win, RGFW_bool border); +typedef void (*RGFW_releaseCursor_ptr)(RGFW_window* win); +typedef void (*RGFW_captureCursor_ptr)(RGFW_window* win); +#ifdef RGFW_OPENGL +typedef void (*RGFW_window_makeCurrentContext_OpenGL_ptr)(RGFW_window* win); +typedef void* (*RGFW_getCurrentContext_OpenGL_ptr)(void); +typedef void (*RGFW_window_swapBuffers_OpenGL_ptr)(RGFW_window* win); +typedef void (*RGFW_window_swapInterval_OpenGL_ptr)(RGFW_window* win, i32 swapInterval); +typedef RGFW_bool (*RGFW_extensionSupportedPlatform_OpenGL_ptr)(const char* extension, size_t len); +typedef RGFW_proc (*RGFW_getProcAddress_OpenGL_ptr)(const char* procname); +typedef RGFW_bool (*RGFW_window_createContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints); +typedef void (*RGFW_window_deleteContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx); +#endif +#ifdef RGFW_WEBGPU +typedef WGPUSurface (*RGFW_window_createSurface_WebGPU_ptr)(RGFW_window* window, WGPUInstance instance); +#endif -RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { - RGFW_thread t; - pthread_create((pthread_t*) &t, NULL, *ptr, args); - return t; +/* Structure to hold all function pointers */ +typedef struct RGFW_FunctionPointers { + RGFW_createSurfacePtr_ptr createSurfacePtr; + RGFW_window_blitSurface_ptr window_blitSurface; + RGFW_surface_freePtr_ptr surface_freePtr; + RGFW_freeMouse_ptr freeMouse; + RGFW_window_setBorder_ptr window_setBorder; + RGFW_releaseCursor_ptr releaseCursor; + RGFW_captureCursor_ptr captureCursor; + RGFW_createWindowPlatform_ptr createWindowPlatform; + RGFW_getMouse_ptr getGlobalMouse; + RGFW_rgfwToKeyChar_ptr rgfwToKeyChar; + RGFW_pollEvents_ptr pollEvents; + RGFW_window_move_ptr window_move; + RGFW_window_resize_ptr window_resize; + RGFW_window_setAspectRatio_ptr window_setAspectRatio; + RGFW_window_setMinSize_ptr window_setMinSize; + RGFW_window_setMaxSize_ptr window_setMaxSize; + RGFW_window_maximize_ptr window_maximize; + RGFW_window_focus_ptr window_focus; + RGFW_window_raise_ptr window_raise; + RGFW_window_setFullscreen_ptr window_setFullscreen; + RGFW_window_setFloating_ptr window_setFloating; + RGFW_window_setOpacity_ptr window_setOpacity; + RGFW_window_minimize_ptr window_minimize; + RGFW_window_restore_ptr window_restore; + RGFW_window_isFloating_ptr window_isFloating; + RGFW_window_setName_ptr window_setName; + RGFW_window_setMousePassthrough_ptr window_setMousePassthrough; + RGFW_window_setIconEx_ptr window_setIconEx; + RGFW_loadMouse_ptr loadMouse; + RGFW_window_setMouse_ptr window_setMouse; + RGFW_window_moveMouse_ptr window_moveMouse; + RGFW_window_setMouseDefault_ptr window_setMouseDefault; + RGFW_window_setMouseStandard_ptr window_setMouseStandard; + RGFW_window_hide_ptr window_hide; + RGFW_window_show_ptr window_show; + RGFW_readClipboardPtr_ptr readClipboardPtr; + RGFW_writeClipboard_ptr writeClipboard; + RGFW_window_isHidden_ptr window_isHidden; + RGFW_window_isMinimized_ptr window_isMinimized; + RGFW_window_isMaximized_ptr window_isMaximized; + RGFW_getMonitors_ptr getMonitors; + RGFW_getPrimaryMonitor_ptr getPrimaryMonitor; + RGFW_monitor_requestMode_ptr monitor_requestMode; + RGFW_window_getMonitor_ptr window_getMonitor; + RGFW_window_closePlatform_ptr window_closePlatform; +#ifdef RGFW_OPENGL + RGFW_extensionSupportedPlatform_OpenGL_ptr extensionSupportedPlatform_OpenGL; + RGFW_getProcAddress_OpenGL_ptr getProcAddress_OpenGL; + RGFW_window_createContextPtr_OpenGL_ptr window_createContextPtr_OpenGL; + RGFW_window_deleteContextPtr_OpenGL_ptr window_deleteContextPtr_OpenGL; + RGFW_window_makeCurrentContext_OpenGL_ptr window_makeCurrentContext_OpenGL; + RGFW_getCurrentContext_OpenGL_ptr getCurrentContext_OpenGL; + RGFW_window_swapBuffers_OpenGL_ptr window_swapBuffers_OpenGL; + RGFW_window_swapInterval_OpenGL_ptr window_swapInterval_OpenGL; +#endif +#ifdef RGFW_WEBGPU + RGFW_window_createSurface_WebGPU_ptr window_createSurface_WebGPU; +#endif +} RGFW_functionPointers; + +RGFW_functionPointers RGFW_api; + +RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { return RGFW_api.createSurfacePtr(data, w, h, format, surface); } +void RGFW_surface_freePtr(RGFW_surface* surface) { RGFW_api.surface_freePtr(surface); } +void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_api.freeMouse(mouse); } +void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { RGFW_api.window_blitSurface(win, surface); } +void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_api.window_setBorder(win, border); } +void RGFW_releaseCursor(RGFW_window* win) { RGFW_api.releaseCursor(win); } +void RGFW_captureCursor(RGFW_window* win) { RGFW_api.captureCursor(win); } +RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { RGFW_init(); return RGFW_api.createWindowPlatform(name, flags, win); } +RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { return RGFW_api.getGlobalMouse(x, y); } +u8 RGFW_rgfwToKeyChar(u32 key) { return RGFW_api.rgfwToKeyChar(key); } +void RGFW_pollEvents(void) { RGFW_api.pollEvents(); } +void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_move(win, x, y); } +void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_resize(win, w, h); } +void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setAspectRatio(win, w, h); } +void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMinSize(win, w, h); } +void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMaxSize(win, w, h); } +void RGFW_window_maximize(RGFW_window* win) { RGFW_api.window_maximize(win); } +void RGFW_window_focus(RGFW_window* win) { RGFW_api.window_focus(win); } +void RGFW_window_raise(RGFW_window* win) { RGFW_api.window_raise(win); } +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_api.window_setFullscreen(win, fullscreen); } +void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_api.window_setFloating(win, floating); } +void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { RGFW_api.window_setOpacity(win, opacity); } +void RGFW_window_minimize(RGFW_window* win) { RGFW_api.window_minimize(win); } +void RGFW_window_restore(RGFW_window* win) { RGFW_api.window_restore(win); } +RGFW_bool RGFW_window_isFloating(RGFW_window* win) { return RGFW_api.window_isFloating(win); } +void RGFW_window_setName(RGFW_window* win, const char* name) { RGFW_api.window_setName(win, name); } + +#ifndef RGFW_NO_PASSTHROUGH +void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_api.window_setMousePassthrough(win, passthrough); } +#endif + +RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type) { return RGFW_api.window_setIconEx(win, data, w, h, format, type); } +RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { return RGFW_api.loadMouse(data, w, h, format); } +void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_api.window_setMouse(win, mouse); } +void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_moveMouse(win, x, y); } +RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { return RGFW_api.window_setMouseDefault(win); } +RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { return RGFW_api.window_setMouseStandard(win, mouse); } +void RGFW_window_hide(RGFW_window* win) { RGFW_api.window_hide(win); } +void RGFW_window_show(RGFW_window* win) { RGFW_api.window_show(win); } +RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { return RGFW_api.readClipboardPtr(str, strCapacity); } +void RGFW_writeClipboard(const char* text, u32 textLen) { RGFW_api.writeClipboard(text, textLen); } +RGFW_bool RGFW_window_isHidden(RGFW_window* win) { return RGFW_api.window_isHidden(win); } +RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { return RGFW_api.window_isMinimized(win); } +RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { return RGFW_api.window_isMaximized(win); } +RGFW_monitor* RGFW_getMonitors(size_t* len) { return RGFW_api.getMonitors(len); } +RGFW_monitor RGFW_getPrimaryMonitor(void) { return RGFW_api.getPrimaryMonitor(); } +RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { return RGFW_api.monitor_requestMode(mon, mode, request); } +RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { return RGFW_api.window_getMonitor(win); } +void RGFW_window_closePlatform(RGFW_window* win) { RGFW_api.window_closePlatform(win); } + +#ifdef RGFW_OPENGL +RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) { return RGFW_api.extensionSupportedPlatform_OpenGL(extension, len); } +RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { return RGFW_api.getProcAddress_OpenGL(procname); } +RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { return RGFW_api.window_createContextPtr_OpenGL(win, ctx, hints); } +void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { RGFW_api.window_deleteContextPtr_OpenGL(win, ctx); } +void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { RGFW_api.window_makeCurrentContext_OpenGL(win); } +void* RGFW_getCurrentContext_OpenGL(void) { return RGFW_api.getCurrentContext_OpenGL(); } +void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { RGFW_api.window_swapBuffers_OpenGL(win); } +void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_api.window_swapInterval_OpenGL(win, swapInterval); } +#endif + +#ifdef RGFW_WEBGPU +WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { return RGFW_api.window_createSurface_WebGPU(window, instance); } +#endif +#endif /* RGFW_DYNAMIC */ + +/* + * start of X11 AND wayland defines + * this allows a single executable to support x11 AND wayland + * falling back to x11 if wayland fails to initalize +*/ +#if defined(RGFW_WAYLAND) && defined(RGFW_X11) +void RGFW_load_X11(void) { + RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_X11; + RGFW_api.window_blitSurface = RGFW_window_blitSurface_X11; + RGFW_api.surface_freePtr = RGFW_surface_freePtr_X11; + RGFW_api.freeMouse = RGFW_freeMouse_X11; + RGFW_api.window_setBorder = RGFW_window_setBorder_X11; + RGFW_api.releaseCursor = RGFW_releaseCursor_X11; + RGFW_api.captureCursor = RGFW_captureCursor_X11; + RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_X11; + RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_X11; + RGFW_api.rgfwToKeyChar = RGFW_rgfwToKeyChar_X11; + RGFW_api.pollEvents = RGFW_pollEvents_X11; + RGFW_api.window_move = RGFW_window_move_X11; + RGFW_api.window_resize = RGFW_window_resize_X11; + RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_X11; + RGFW_api.window_setMinSize = RGFW_window_setMinSize_X11; + RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_X11; + RGFW_api.window_maximize = RGFW_window_maximize_X11; + RGFW_api.window_focus = RGFW_window_focus_X11; + RGFW_api.window_raise = RGFW_window_raise_X11; + RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_X11; + RGFW_api.window_setFloating = RGFW_window_setFloating_X11; + RGFW_api.window_setOpacity = RGFW_window_setOpacity_X11; + RGFW_api.window_minimize = RGFW_window_minimize_X11; + RGFW_api.window_restore = RGFW_window_restore_X11; + RGFW_api.window_isFloating = RGFW_window_isFloating_X11; + RGFW_api.window_setName = RGFW_window_setName_X11; +#ifndef RGFW_NO_PASSTHROUGH + RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_X11; +#endif + RGFW_api.window_setIconEx = RGFW_window_setIconEx_X11; + RGFW_api.loadMouse = RGFW_loadMouse_X11; + RGFW_api.window_setMouse = RGFW_window_setMouse_X11; + RGFW_api.window_moveMouse = RGFW_window_moveMouse_X11; + RGFW_api.window_setMouseDefault = RGFW_window_setMouseDefault_X11; + RGFW_api.window_setMouseStandard = RGFW_window_setMouseStandard_X11; + RGFW_api.window_hide = RGFW_window_hide_X11; + RGFW_api.window_show = RGFW_window_show_X11; + RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_X11; + RGFW_api.writeClipboard = RGFW_writeClipboard_X11; + RGFW_api.window_isHidden = RGFW_window_isHidden_X11; + RGFW_api.window_isMinimized = RGFW_window_isMinimized_X11; + RGFW_api.window_isMaximized = RGFW_window_isMaximized_X11; + RGFW_api.getMonitors = RGFW_getMonitors_X11; + RGFW_api.getPrimaryMonitor = RGFW_getPrimaryMonitor_X11; + RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_X11; + RGFW_api.window_getMonitor = RGFW_window_getMonitor_X11; + RGFW_api.window_closePlatform = RGFW_window_closePlatform_X11; +#ifdef RGFW_OPENGL + RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_X11; + RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_X11; + RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_X11; + RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_X11; + RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_X11; + RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_X11; + RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_X11; + RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_X11; +#endif +#ifdef RGFW_WEBGPU + RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_X11; +#endif } -void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); } -void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); } -#if defined(__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); } +void RGFW_load_Wayland(void) { + RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_Wayland; + RGFW_api.window_blitSurface = RGFW_window_blitSurface_Wayland; + RGFW_api.surface_freePtr = RGFW_surface_freePtr_Wayland; + RGFW_api.freeMouse = RGFW_freeMouse_Wayland; + RGFW_api.window_setBorder = RGFW_window_setBorder_Wayland; + RGFW_api.releaseCursor = RGFW_releaseCursor_Wayland; + RGFW_api.captureCursor = RGFW_captureCursor_Wayland; + RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_Wayland; + RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_Wayland; + RGFW_api.rgfwToKeyChar = RGFW_rgfwToKeyChar_Wayland; + RGFW_api.pollEvents = RGFW_pollEvents_Wayland; + RGFW_api.window_move = RGFW_window_move_Wayland; + RGFW_api.window_resize = RGFW_window_resize_Wayland; + RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_Wayland; + RGFW_api.window_setMinSize = RGFW_window_setMinSize_Wayland; + RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_Wayland; + RGFW_api.window_maximize = RGFW_window_maximize_Wayland; + RGFW_api.window_focus = RGFW_window_focus_Wayland; + RGFW_api.window_raise = RGFW_window_raise_Wayland; + RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_Wayland; + RGFW_api.window_setFloating = RGFW_window_setFloating_Wayland; + RGFW_api.window_setOpacity = RGFW_window_setOpacity_Wayland; + RGFW_api.window_minimize = RGFW_window_minimize_Wayland; + RGFW_api.window_restore = RGFW_window_restore_Wayland; + RGFW_api.window_isFloating = RGFW_window_isFloating_Wayland; + RGFW_api.window_setName = RGFW_window_setName_Wayland; +#ifndef RGFW_NO_PASSTHROUGH + RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_Wayland; #endif + RGFW_api.window_setIconEx = RGFW_window_setIconEx_Wayland; + RGFW_api.loadMouse = RGFW_loadMouse_Wayland; + RGFW_api.window_setMouse = RGFW_window_setMouse_Wayland; + RGFW_api.window_moveMouse = RGFW_window_moveMouse_Wayland; + RGFW_api.window_setMouseDefault = RGFW_window_setMouseDefault_Wayland; + RGFW_api.window_setMouseStandard = RGFW_window_setMouseStandard_Wayland; + RGFW_api.window_hide = RGFW_window_hide_Wayland; + RGFW_api.window_show = RGFW_window_show_Wayland; + RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_Wayland; + RGFW_api.writeClipboard = RGFW_writeClipboard_Wayland; + RGFW_api.window_isHidden = RGFW_window_isHidden_Wayland; + RGFW_api.window_isMinimized = RGFW_window_isMinimized_Wayland; + RGFW_api.window_isMaximized = RGFW_window_isMaximized_Wayland; + RGFW_api.getMonitors = RGFW_getMonitors_Wayland; + RGFW_api.getPrimaryMonitor = RGFW_getPrimaryMonitor_Wayland; + RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_Wayland; + RGFW_api.window_getMonitor = RGFW_window_getMonitor_Wayland; + RGFW_api.window_closePlatform = RGFW_window_closePlatform_Wayland; +#ifdef RGFW_OPENGL + RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_Wayland; + RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_Wayland; + RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_Wayland; + RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_Wayland; + RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_Wayland; + RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_Wayland; + RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_Wayland; + RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_Wayland; +#endif +#ifdef RGFW_WEBGPU + RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_Wayland; #endif - -#ifndef RGFW_WASM -void RGFW_sleep(u64 ms) { - struct timespec time; - time.tv_sec = 0; - time.tv_nsec = (long int)((double)ms * 1e+6); - - #ifndef RGFW_NO_UNIX_CLOCK - nanosleep(&time, NULL); - #endif } -#endif +#endif /* wayland AND x11 */ +/* end of X11 AND wayland defines */ -#endif /* end of unix / mac stuff */ #endif /* RGFW_IMPLEMENTATION */ #if defined(__cplusplus) && !defined(__EMSCRIPTEN__) @@ -11070,3 +13917,4 @@ void RGFW_sleep(u64 ms) { #if _MSC_VER #pragma warning( pop ) #endif + diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index a1b13856b..2671538d8 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -48,11 +48,6 @@ * **********************************************************************************************/ -#ifndef RAYLIB_H /* this should never actually happen, it's only here for IDEs */ -#include "raylib.h" -#include "../rcore.c" -#endif - #if defined(PLATFORM_WEB_RGFW) #define RGFW_NO_GL_HEADER #endif From 1c7240a01d75e80e49a4019aace0d7132dd06207 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Dec 2025 18:18:42 +0100 Subject: [PATCH 36/57] Revert "REVIEWED: Alignment with other platforms" This reverts commit cf0d6fc664f1d0775c6b21ed79feaa1e38b2ddb4. --- src/external/RGFW.h | 17500 +++++++++++---------------- src/platforms/rcore_desktop_rgfw.c | 5 + 2 files changed, 7331 insertions(+), 10174 deletions(-) diff --git a/src/external/RGFW.h b/src/external/RGFW.h index b913d4f2d..7205bf9d8 100644 --- a/src/external/RGFW.h +++ b/src/external/RGFW.h @@ -1,8 +1,8 @@ /* * -* RGFW 1.8.1 +* RGFW 1.7.5-dev -* Copyright (C) 2022-25 Riley Mabb (@ColleagueRiley) +* Copyright (C) 2022-25 ColleagueRiley * * libpng license * @@ -33,12 +33,19 @@ /* #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included #define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found - #define RGFW_EGL - (optional) compile with OpenGL functions, allowing you to use to use EGL instead of the native OpenGL functions + #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl) + #define RGFW_BUFFER - (optional) 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) + #define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api) + This version doesn't work for desktops (I'm pretty sure) + #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2) + #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3) #define RGFW_DIRECTX - (optional) include integration directX functions (windows only) #define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros - #define RGFW_WEBGPU - (optional) use WebGPU for rendering - #define RGFW_NATIVE - (optional) define native RGFW types that use native API structures + #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY) + #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX) + #define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress) #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS #define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11) #define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland @@ -55,9 +62,8 @@ #define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU) #define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name #define RGFW_NO_DPI - do not calculate DPI (no XRM nor libShcore included) + #define RGFW_BUFFER_BGR - use the BGR format for bufffers instead of RGB, saves processing time #define RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may result in a spike in memory usage or worse performance) (eg. WM_TIMER and XSyncValue) - #define RGFW_NO_INFO - do not define the RGFW_info struct (without RGFW_IMPLEMENTATION) - #define RGFW_NO_GLXWINDOW - do not use GLXWindow #define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc) #define RGFW_FREE x - choose the default deallocation function (defaults to standard free) @@ -83,17 +89,20 @@ macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -fram u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF}; int main() { - RGFW_window* win = RGFW_createWindow("name", 100, 100, 500, 500, (u64)0); - RGFW_event event; + RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(100, 100, 500, 500), (u64)0); - RGFW_window_setExitKey(win, RGFW_escape); - RGFW_window_setIcon(win, icon, 3, 3, RGFW_formatRGBA8); + RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4); while (RGFW_window_shouldClose(win) == RGFW_FALSE) { - while (RGFW_window_checkEvent(win, &event)) { - if (event.type == RGFW_quit) - break; - } + while (RGFW_window_checkEvent(win)) { + if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_escape)) + break; + } + + RGFW_window_swapBuffers(win); + + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); } RGFW_window_close(win); @@ -134,40 +143,25 @@ int main() { /* Credits : - EimaMei/Sacode : Code review, helped with X11, MacOS and Windows support, Silicon, siliapp.h -> referencing + EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing - stb : This project is heavily inspired by the stb single header files + stb - This project is heavily inspired by the stb single header files - SDL, GLFW and other online resources : reference implementations + GLFW: + certain parts of winapi and X11 are very poorly documented, + GLFW's source code was referenced and used throughout the project. contributors : (feel free to put yourself here if you contribute) - krisvers (@krisvers) -> code review - EimaMei (@SaCode) -> code review - Nycticebus (@Code-Nycticebus) -> bug fixes - Rob Rohan (@robrohan) -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs + krisvers -> code review + EimaMei (SaCode) -> code review + Code-Nycticebus -> bug fixes + Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs AICDG (@THISISAGOODNAME) -> vulkan support (example) @Easymode -> support, testing/debugging, bug fixes and reviews Joshua Rowe (omnisci3nce) - bug fix, review (macOS) @lesleyrs -> bug fix, review (OpenGL) - Nick Porcino (@meshula) - testing, organization, review (MacOS, examples) - @therealmarrakesh -> documentation - @DarekParodia -> code review (X11) (C++) - @NishiOwO -> fix BSD support, fix OSMesa example - @BaynariKattu -> code review and documentation - Miguel Pinto (@konopimi) -> code review, fix vulkan example - @m-doescode -> code review (wayland) - Robert Gonzalez (@uni-dos) -> code review (wayland) - @TheLastVoyager -> code review - @yehoravramenko -> code review (winapi) - @halocupcake -> code review (OpenGL) - @GideonSerf -> documentation - Alexandre Almeida (@M374LX) -> code review (keycodes) - Vũ Xuân Trường (@wanwanvxt) -> code review (winapi) - Lucas (@lightspeedlucas) -> code review (msvc++) - Jeffery Myers (@JeffM2501) -> code review (msvc) - Zeni (@zenitsuyo) -> documentation - TheYahton (@TheYahton) -> documentation - nonexistant_object (@DiarrheaMcgee + Nick Porcino (meshula) - testing, organization, review (MacOS, examples) + @DarekParodia -> code review (X11) (C++) */ #if _MSC_VER @@ -185,74 +179,6 @@ int main() { #endif #endif -#if defined(RGFW_EGL) && !defined(RGFW_OPENGL) - #define RGFW_OPENGL -#endif - -/* these OS macros look better & are standardized */ -/* plus it helps with cross-compiling */ - -#ifdef __EMSCRIPTEN__ - #define RGFW_WASM -#endif - -#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS_X11 - #define RGFW_UNIX -#endif - -#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */ - #define RGFW_WINDOWS -#endif -#if defined(RGFW_WAYLAND) - #define RGFW_DEBUG /* wayland will be in debug mode by default for now */ - #define RGFW_UNIX - #ifdef RGFW_OPENGL - #define RGFW_EGL - #endif - #ifdef RGFW_X11 - #define RGFW_DYNAMIC - #endif -#endif -#if (!defined(RGFW_WAYLAND) && !defined(RGFW_X11)) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS_X11 - #define RGFW_X11 - #define RGFW_UNIX -#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) - #define RGFW_MACOS -#endif - -#ifndef RGFW_ASSERT - #include - #define RGFW_ASSERT assert -#endif - -#if !defined(__STDC_VERSION__) - #define RGFW_C89 -#endif - -#if !defined(RGFW_SNPRINTF) && (defined(RGFW_X11) || defined(RGFW_WAYLAND)) - - /* required for X11 errors */ - #include - - #ifdef RGFW_C89 - #include - static int RGFW_c89_snprintf(char *dst, size_t size, const char *format, ...) { - va_list args; - size_t count = 0; - va_start(args, format); - count = (size_t)vsprintf(dst, format, args); - RGFW_ASSERT(count + 1 < size && "Buffer overflow"); - va_end(args); - return (int)count; - } - #define RGFW_SNPRINTF RGFW_c89_snprintf - #else - #define RGFW_SNPRINTF snprintf - #endif /*RGFW_C89*/ -#endif - #ifndef RGFW_USERPTR #define RGFW_USERPTR NULL #endif @@ -265,16 +191,17 @@ int main() { #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f) #endif -#ifndef RGFW_MIN - #define RGFW_MIN(x, y) ((x < y) ? x : y) -#endif - #ifndef RGFW_ALLOC #include #define RGFW_ALLOC malloc #define RGFW_FREE free #endif +#ifndef RGFW_ASSERT + #include + #define RGFW_ASSERT assert +#endif + #if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY) || !defined(RGFW_MEMSET) #include #endif @@ -306,31 +233,6 @@ int main() { #define RGFW_ATOF(num) atof(num) #endif -#if !defined(RGFW_PRINTF) && ( defined(RGFW_DEBUG) || defined(RGFW_WAYLAND) ) - /* required when using RGFW_DEBUG */ - #include - #define RGFW_PRINTF printf -#endif - -#ifndef RGFW_MAX_PATH - #define RGFW_MAX_PATH 260 /* max length of a path (for drag andn drop) */ -#endif -#ifndef RGFW_MAX_DROPS - #define RGFW_MAX_DROPS 260 /* max items you can drop at once */ -#endif - -#ifndef RGFW_MAX_EVENTS - #define RGFW_MAX_EVENTS 32 -#endif - -#ifndef RGFW_MAX_MONITORS - #define RGFW_MAX_MONITORS 6 -#endif - -#ifndef RGFW_COCOA_FRAME_NAME - #define RGFW_COCOA_FRAME_NAME NULL -#endif - #ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */ #define RGFW_NO_MONITOR #define RGFW_NO_PASSTHROUGH @@ -365,11 +267,16 @@ int main() { #endif #endif +#ifndef RGFW_ENUM + #define RGFW_ENUM(type, name) type name; enum +#endif + + #if defined(__cplusplus) && !defined(__EMSCRIPTEN__) extern "C" { #endif -/* makes sure the header file part is only defined once by default */ + /* makes sure the header file part is only defined once by default */ #ifndef RGFW_HEADER #define RGFW_HEADER @@ -400,31 +307,1023 @@ int main() { #define RGFW_INT_DEFINED #endif -typedef ptrdiff_t RGFW_ssize_t; - #ifndef RGFW_BOOL_DEFINED #define RGFW_BOOL_DEFINED typedef u8 RGFW_bool; #endif -#define RGFW_BOOL(x) (RGFW_bool)((x) != 0) /* force a value to be 0 or 1 */ +#define RGFW_BOOL(x) (RGFW_bool)((x) ? RGFW_TRUE : RGFW_FALSE) /* force an value to be 0 or 1 */ #define RGFW_TRUE (RGFW_bool)1 #define RGFW_FALSE (RGFW_bool)0 -#define RGFW_ENUM(type, name) type name; enum -#define RGFW_BIT(x) (1 << (x)) +/* these OS macros look better & are standardized */ +/* plus it helps with cross-compiling */ +#ifdef __EMSCRIPTEN__ + #define RGFW_WASM + + #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU) + #define RGFW_OPENGL + #endif + + #ifdef RGFW_EGL + #undef RGFW_EGL + #endif + + #include + #include + + #ifdef RGFW_WEBGPU + #include + #endif +#endif + +#if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND) + #define RGFW_MACOS_X11 + #define RGFW_UNIX + #undef __APPLE__ +#endif + +#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */ + #define RGFW_WINDOWS + /* make sure the correct architecture is defined */ + #if defined(_WIN64) + #define _AMD64_ + #undef _X86_ + #else + #undef _AMD64_ + #ifndef _X86_ + #define _X86_ + #endif + #endif + + #ifndef RGFW_NO_XINPUT + #ifdef __MINGW32__ /* try to find the right header */ + #include + #else + #include + #endif + #endif +#endif +#if defined(RGFW_WAYLAND) + #define RGFW_DEBUG /* wayland will be in debug mode by default for now */ + #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) + #define RGFW_EGL + #define RGFW_OPENGL + #include + #endif + + #define RGFW_UNIX + #include +#endif +#if !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) + #define RGFW_MACOS_X11 + #define RGFW_X11 + #define RGFW_UNIX + #include + #include +#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) + #define RGFW_MACOS + #if !defined(RGFW_BUFFER_BGR) + #define RGFW_BUFFER_BGR + #else + #undef RGFW_BUFFER_BGR + #endif +#endif + +#if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL) + #define RGFW_EGL +#endif + +#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API) + #define RGFW_OPENGL +#endif + +#ifdef RGFW_EGL + #include +#elif defined(RGFW_OSMESA) + #ifdef RGFW_WINDOWS + #define OEMRESOURCE + #include + #ifndef GLAPIENTRY + #define GLAPIENTRY APIENTRY + #endif + #ifndef GLAPI + #define GLAPI WINGDIAPI + #endif + #endif + + #ifndef __APPLE__ + #include + #else + #include + #endif +#endif + +#if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER) + #pragma comment(lib, "opengl32") +#endif + +#if defined(RGFW_OPENGL) && defined(RGFW_X11) + #ifndef GLX_MESA_swap_control + #define GLX_MESA_swap_control + #endif + #include /* GLX defs, xlib.h, gl.h */ +#endif + +#define RGFW_COCOA_FRAME_NAME NULL + +/*! (unix) Toggle use of wayland. This will be on by default if you use `RGFW_WAYLAND` (if you don't use RGFW_WAYLAND, you don't expose WAYLAND functions) + this is mostly used to allow you to force the use of XWayland +*/ +RGFWDEF void RGFW_useWayland(RGFW_bool wayland); +RGFWDEF RGFW_bool RGFW_usingWayland(void); +/* + regular RGFW stuff +*/ + +#define RGFW_key u8 + +typedef RGFW_ENUM(u8, RGFW_eventType) { + /*! event codes */ + RGFW_eventNone = 0, /*!< no event has been sent */ + RGFW_keyPressed, /* a key has been pressed */ + RGFW_keyReleased, /*!< a key has been released */ + /*! key event note + the code of the key pressed is stored in + RGFW_event.key + !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! + + while a string version is stored in + RGFW_event.KeyString + + RGFW_event.keyMod holds the current keyMod + this means if CapsLock, NumLock are active or not + */ + RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */ + RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */ + RGFW_mousePosChanged, /*!< the position of the mouse has been changed */ + /*! mouse event note + the x and y of the mouse can be found in the vector, RGFW_event.point + + RGFW_event.button holds which mouse button was pressed + */ + RGFW_gamepadConnected, /*!< a gamepad was connected */ + RGFW_gamepadDisconnected, /*!< a gamepad was disconnected */ + RGFW_gamepadButtonPressed, /*!< a gamepad button was pressed */ + RGFW_gamepadButtonReleased, /*!< a gamepad button was released */ + RGFW_gamepadAxisMove, /*!< an axis of a gamepad was moved */ + /*! gamepad event note + RGFW_event.gamepad holds which gamepad was altered, if any + RGFW_event.button holds which gamepad button was pressed + + RGFW_event.axis holds the data of all the axises + RGFW_event.axisesCount says how many axises there are + */ + RGFW_windowMoved, /*!< the window was moved (by the user) */ + RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */ + RGFW_focusIn, /*!< window is in focus now */ + RGFW_focusOut, /*!< window is out of focus now */ + RGFW_mouseEnter, /* mouse entered the window */ + RGFW_mouseLeave, /* mouse left the window */ + RGFW_windowRefresh, /* The window content needs to be refreshed */ + + /* attribs change event note + The event data is sent straight to the window structure + with win->r.x, win->r.y, win->r.w and win->r.h + */ + RGFW_quit, /*!< the user clicked the quit button */ + RGFW_DND, /*!< a file has been dropped into the window */ + RGFW_DNDInit, /*!< the start of a dnd event, when the place where the file drop is known */ + /* dnd data note + The x and y coords of the drop are stored in the vector RGFW_event.point + + RGFW_event.droppedFilesCount holds how many files were dropped + + This is also the size of the array which stores all the dropped file string, + RGFW_event.droppedFiles + */ + RGFW_windowMaximized, /*!< the window was maximized */ + RGFW_windowMinimized, /*!< the window was minimized */ + RGFW_windowRestored, /*!< the window was restored */ + RGFW_scaleUpdated /*!< content scale factor changed */ +}; + +/*! mouse button codes (RGFW_event.button) */ +typedef RGFW_ENUM(u8, RGFW_mouseButton) { + RGFW_mouseLeft = 0, /*!< left mouse button is pressed */ + RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */ + RGFW_mouseRight, /*!< right mouse button is pressed */ + RGFW_mouseScrollUp, /*!< mouse wheel is scrolling up */ + RGFW_mouseScrollDown, /*!< mouse wheel is scrolling down */ + RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5, + RGFW_mouseFinal +}; + +#ifndef RGFW_MAX_PATH +#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */ +#endif +#ifndef RGFW_MAX_DROPS +#define RGFW_MAX_DROPS 260 /* max items you can drop at once */ +#endif + +#define RGFW_BIT(x) (1 << x) + +/* for RGFW_event.lockstate */ +typedef RGFW_ENUM(u8, RGFW_keymod) { + RGFW_modCapsLock = RGFW_BIT(0), + RGFW_modNumLock = RGFW_BIT(1), + RGFW_modControl = RGFW_BIT(2), + RGFW_modAlt = RGFW_BIT(3), + RGFW_modShift = RGFW_BIT(4), + RGFW_modSuper = RGFW_BIT(5), + RGFW_modScrollLock = RGFW_BIT(6) +}; + +/*! gamepad button codes (based on xbox/playstation), you may need to change these values per controller */ +typedef RGFW_ENUM(u8, RGFW_gamepadCodes) { + RGFW_gamepadNone = 0, /*!< or PS X button */ + RGFW_gamepadA, /*!< or PS X button */ + RGFW_gamepadB, /*!< or PS circle button */ + RGFW_gamepadY, /*!< or PS triangle button */ + RGFW_gamepadX, /*!< or PS square button */ + RGFW_gamepadStart, /*!< start button */ + RGFW_gamepadSelect, /*!< select button */ + RGFW_gamepadHome, /*!< home button */ + RGFW_gamepadUp, /*!< dpad up */ + RGFW_gamepadDown, /*!< dpad down */ + RGFW_gamepadLeft, /*!< dpad left */ + RGFW_gamepadRight, /*!< dpad right */ + RGFW_gamepadL1, /*!< left bump */ + RGFW_gamepadL2, /*!< left trigger */ + RGFW_gamepadR1, /*!< right bumper */ + RGFW_gamepadR2, /*!< right trigger */ + RGFW_gamepadL3, /* left thumb stick */ + RGFW_gamepadR3, /*!< right thumb stick */ + RGFW_gamepadFinal +}; + +/*! basic vector type, if there's not already a point/vector type of choice */ +#ifndef RGFW_point + typedef struct RGFW_point { i32 x, y; } RGFW_point; +#endif + +/*! basic rect type, if there's not already a rect type of choice */ +#ifndef RGFW_rect + typedef struct RGFW_rect { i32 x, y, w, h; } RGFW_rect; +#endif + +/*! basic area type, if there's not already a area type of choice */ +#ifndef RGFW_area + typedef struct RGFW_area { u32 w, h; } RGFW_area; +#endif + +#if defined(__cplusplus) && !defined(__APPLE__) +#define RGFW_POINT(x, y) {(i32)x, (i32)y} +#define RGFW_RECT(x, y, w, h) {(i32)x, (i32)y, (i32)w, (i32)h} +#define RGFW_AREA(w, h) {(u32)w, (u32)h} +#else +#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)} +#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)} +#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)} +#endif + +#ifndef RGFW_NO_MONITOR + /* monitor mode data | can be changed by the user (with functions)*/ + typedef struct RGFW_monitorMode { + RGFW_area area; /*!< monitor workarea size */ + u32 refreshRate; /*!< monitor refresh rate */ + u8 red, blue, green; + } RGFW_monitorMode; + + /*! structure for monitor data */ + typedef struct RGFW_monitor { + i32 x, y; /*!< x - y of the monitor workarea */ + char name[128]; /*!< monitor name */ + float scaleX, scaleY; /*!< monitor content scale */ + float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */ + float physW, physH; /*!< monitor physical size in inches */ + + RGFW_monitorMode mode; + } RGFW_monitor; + + /*! get an array of all the monitors (max 6) */ + RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len); + /*! get the primary monitor */ + RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); + + typedef RGFW_ENUM(u8, RGFW_modeRequest) { + RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */ + RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */ + RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */ + RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB + }; + + /*! request a specific mode */ + RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); + /*! check if 2 monitor modes are the same */ + RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request); +#endif + +/* RGFW mouse loading */ +typedef void RGFW_mouse; + +/*!< loads mouse icon from bitmap (similar to RGFW_window_setIcon). Icon NOT resized by default */ +RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels); +/*!< frees RGFW_mouse data */ +RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse); + +/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_event struct) */ +/*! Event structure for checking/getting events */ +typedef struct RGFW_event { + RGFW_eventType type; /*!< which event has been sent?*/ + RGFW_point point; /*!< mouse x, y of event (or drop point) */ + RGFW_point vector; /*!< raw mouse movement */ + float scaleX, scaleY; /*!< DPI scaling */ + + RGFW_key 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 */ + + RGFW_bool repeat; /*!< key press event repeated (the key is being held) */ + RGFW_keymod keyMod; + + u8 button; /* !< which mouse (or gamepad) button was pressed */ + double scroll; /*!< the raw mouse scroll value */ + + u16 gamepad; /*! which gamepad this event applies to (if applicable to any) */ + u8 axisesCount; /*!< number of axises */ + + u8 whichAxis; /* which axis was effected */ + RGFW_point axis[4]; /*!< x, y of axises (-100 to 100) */ + + /*! drag and drop data */ + /* 260 max paths with a max length of 260 */ + char** droppedFiles; /*!< dropped files */ + size_t droppedFilesCount; /*!< house many files were dropped */ + + void* _win; /*!< the window this event applies too (for event queue events) */ +} RGFW_event; + +/*! source data for the window (used by the APIs) */ +#ifdef RGFW_WINDOWS +typedef struct RGFW_window_src { + HWND window; /*!< source window */ + HDC hdc; /*!< source HDC */ + u32 hOffset; /*!< height offset for window */ + HICON hIconSmall, hIconBig; /*!< source window icons */ + #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) + HGLRC ctx; /*!< source graphics context */ + #elif defined(RGFW_OSMESA) + OSMesaContext ctx; + #elif defined(RGFW_EGL) + EGLSurface EGL_surface; + EGLDisplay EGL_display; + EGLContext EGL_context; + #endif + + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + HDC hdcMem; + HBITMAP bitmap; + u8* bitmapBits; + #endif + RGFW_area maxSize, minSize, aspectRatio; /*!< for setting max/min resize (RGFW_WINDOWS) */ +} RGFW_window_src; +#elif defined(RGFW_UNIX) +typedef struct RGFW_window_src { +#if defined(RGFW_X11) + Display* display; /*!< source display */ + Window window; /*!< source window */ + #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) + GLXContext ctx; /*!< source graphics context */ + GLXFBConfig bestFbc; + #elif defined(RGFW_OSMESA) + OSMesaContext ctx; + #elif defined(RGFW_EGL) + EGLSurface EGL_surface; + EGLDisplay EGL_display; + EGLContext EGL_context; + #endif + + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + XImage* bitmap; + #endif + GC gc; + XVisualInfo visual; + #ifdef RGFW_ADVANCED_SMOOTH_RESIZE + i64 counter_value; + XID counter; + #endif + RGFW_rect r; +#endif /* RGFW_X11 */ +#if defined(RGFW_WAYLAND) + struct wl_display* wl_display; + struct wl_surface* surface; + struct wl_buffer* wl_buffer; + struct wl_keyboard* keyboard; + + struct wl_compositor* compositor; + struct xdg_surface* xdg_surface; + struct xdg_toplevel* xdg_toplevel; + struct zxdg_toplevel_decoration_v1* decoration; + struct xdg_wm_base* xdg_wm_base; + struct wl_shm* shm; + struct wl_seat *seat; + u8* buffer; + #if defined(RGFW_EGL) + struct wl_egl_window* eglWindow; + #endif + #if defined(RGFW_EGL) && !defined(RGFW_X11) + EGLSurface EGL_surface; + EGLDisplay EGL_display; + EGLContext EGL_context; + #elif defined(RGFW_OSMESA) && !defined(RGFW_X11) + OSMesaContext ctx; + #endif +#endif /* RGFW_WAYLAND */ +} RGFW_window_src; +#endif /* RGFW_UNIX */ +#if defined(RGFW_MACOS) +typedef struct RGFW_window_src { + void* window; +#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) + void* ctx; /*!< source graphics context */ +#elif defined(RGFW_OSMESA) + OSMesaContext ctx; +#elif defined(RGFW_EGL) + EGLSurface EGL_surface; + EGLDisplay EGL_display; + EGLContext EGL_context; +#endif + + void* view; /* apple viewpoint thingy */ + void* mouse; +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) +#endif +} RGFW_window_src; +#elif defined(RGFW_WASM) +typedef struct RGFW_window_src { + #if defined(RGFW_WEBGPU) + WGPUInstance ctx; + WGPUDevice device; + WGPUQueue queue; + #elif defined(RGFW_OSMESA) + OSMesaContext ctx; + #else + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; + #endif +} RGFW_window_src; +#endif + +/*! Optional arguments for making a windows */ +typedef RGFW_ENUM(u32, RGFW_windowFlags) { + RGFW_windowNoInitAPI = RGFW_BIT(0), /* do NOT init an API (including the software rendering buffer) (mostly for bindings. you can also use `#define RGFW_NO_API`) */ + RGFW_windowNoBorder = RGFW_BIT(1), /*!< the window doesn't have a border */ + RGFW_windowNoResize = RGFW_BIT(2), /*!< the window cannot be resized by the user */ + RGFW_windowAllowDND = RGFW_BIT(3), /*!< the window supports drag and drop */ + RGFW_windowHideMouse = RGFW_BIT(4), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_mouseShow`) */ + RGFW_windowFullscreen = RGFW_BIT(5), /*!< the window is fullscreen by default */ + RGFW_windowTransparent = RGFW_BIT(6), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */ + RGFW_windowCenter = RGFW_BIT(7), /*! center the window on the screen */ + RGFW_windowOpenglSoftware = RGFW_BIT(8), /*! use OpenGL software rendering */ + RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /*! (cocoa only), change directory to resource folder */ + RGFW_windowScaleToMonitor = RGFW_BIT(10), /*! scale the window to the screen */ + RGFW_windowHide = RGFW_BIT(11), /*! the window is hidden */ + RGFW_windowMaximize = RGFW_BIT(12), + RGFW_windowCenterCursor = RGFW_BIT(13), + RGFW_windowFloating = RGFW_BIT(14), /*!< create a floating window */ + RGFW_windowFreeOnClose = RGFW_BIT(15), /*!< free (RGFW_window_close) the RGFW_window struct when the window is closed (by the end user) */ + RGFW_windowFocusOnShow = RGFW_BIT(16), /*!< focus the window when it's shown */ + RGFW_windowMinimize = RGFW_BIT(17), /*!< focus the window when it's shown */ + RGFW_windowFocus = RGFW_BIT(18), /*!< if the window is in focus */ + RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize +}; + +typedef struct RGFW_window { + RGFW_window_src src; /*!< src window data */ + +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */ + /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */ + RGFW_area bufferSize; +#endif + void* userPtr; /* ptr for usr data */ + + RGFW_event event; /*!< current event */ + + RGFW_rect r; /*!< the x, y, w and h of the struct */ + + /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */ + RGFW_key exitKey; + RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */ + + u32 _flags; /*!< windows flags (for RGFW to check) */ + RGFW_rect _oldRect; /*!< rect before fullscreen */ +} RGFW_window; /*!< window structure for managing the window */ + +#if defined(RGFW_X11) || defined(RGFW_MACOS) + typedef u64 RGFW_thread; /*!< thread type unix */ +#else + typedef void* RGFW_thread; /*!< thread type for windows */ +#endif + +/*! scale monitor to window size */ +RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win); + +/** * @defgroup Window_management +* @{ */ + + +/*! + * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM + * by default the class name will == the root window's name +*/ +RGFWDEF void RGFW_setClassName(const char* name); +RGFWDEF void RGFW_setXInstName(const char* name); /*!< X11 instance name (window name will by used by default) */ + +/*! (cocoa only) change directory to resource folder */ +RGFWDEF void RGFW_moveToMacOSResourceDir(void); + +/* NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window */ + +RGFWDEF RGFW_window* RGFW_createWindow( + const char* name, /* name of the window */ + RGFW_rect rect, /* rect of window */ + RGFW_windowFlags flags /* extra arguments ((u32)0 means no flags used)*/ +); /*!< function to create a window and struct */ + +RGFWDEF RGFW_window* RGFW_createWindowPtr( + const char* name, /* name of the window */ + RGFW_rect rect, /* rect of window */ + RGFW_windowFlags flags, /* extra arguments (NULL / (u32)0 means no flags used) */ + RGFW_window* win /* ptr to the window struct you want to use */ +); /*!< function to create a window (without allocating a window struct) */ + +RGFWDEF void RGFW_window_initBuffer(RGFW_window* win); +RGFWDEF void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area); +RGFWDEF void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area); + +/*! set the window flags (will undo flags if they don't match the old ones) */ +RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags); + +/*! get the size of the screen to an area struct */ +RGFWDEF RGFW_area RGFW_getScreenSize(void); + + +/*! + this function checks an *individual* event (and updates window structure attributes) + this means, using this function without a while loop may cause event lag + + ex. + + while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one] + + this function is optional if you choose to use event callbacks, + although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents` +*/ + +RGFWDEF RGFW_event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/ + +/*! + for RGFW_window_eventWait and RGFW_window_checkEvents + waitMS -> Allows the function to keep checking for events even after `RGFW_window_checkEvent == NULL` + if waitMS == 0, the loop will not wait for events + if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns + if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event +*/ +typedef RGFW_ENUM(i32, RGFW_eventWait) { + RGFW_eventNoWait = 0, + RGFW_eventWaitNext = -1 +}; + +/*! sleep until RGFW gets an event or the timer ends (defined by OS) */ +RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS); + +/*! + check all the events until there are none left. + This should only be used if you're using callbacks only +*/ +RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS); + +/*! + tell RGFW_window_eventWait to stop waiting (to be ran from another thread) +*/ +RGFWDEF void RGFW_stopCheckEvents(void); + +/*! window managment functions */ +RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */ + +/*! move a window to a given point */ +RGFWDEF void RGFW_window_move(RGFW_window* win, + RGFW_point v /*!< new pos */ +); + +#ifndef RGFW_NO_MONITOR + /*! move window to a specific monitor */ + RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */); +#endif + +/*! resize window to a current size/area */ +RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */ + RGFW_area a /*!< new size */ +); + +/*! set window aspect ratio */ +RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a); +/*! set the minimum dimensions of a window */ +RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a); +/*! set the maximum dimensions of a window */ +RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a); + +RGFWDEF void RGFW_window_focus(RGFW_window* win); /*!< sets the focus to this window */ +RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); /*!< checks the focus to this window */ +RGFWDEF void RGFW_window_raise(RGFW_window* win); /*!< raise the window (to the top) */ +RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window */ +RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); /*!< turn fullscreen on / off for a window */ +RGFWDEF void RGFW_window_center(RGFW_window* win); /*!< center the window */ +RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/ +RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/ +RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); /*!< make the window a floating window */ +RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); /*!< sets the opacity of a window */ + +RGFWDEF RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win); + +/*! if the window should have a border or not (borderless) based on bool value of `border` */ +RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border); +RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win); + +/*! turn on / off dnd (RGFW_windowAllowDND stil must be passed to the window)*/ +RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow); +/*! check if DND is allowed */ +RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win); + + +#ifndef RGFW_NO_PASSTHROUGH + /*! turn on / off mouse passthrough */ + RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough); +#endif + +/*! rename window to a given string */ +RGFWDEF void RGFW_window_setName(RGFW_window* win, + const char* name +); + +RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, /*!< source window */ + u8* icon /*!< icon bitmap */, + RGFW_area a /*!< width and height of the bitmap */, + i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */ +); /*!< image MAY be resized by default, set both the taskbar and window icon */ + +typedef RGFW_ENUM(u8, RGFW_icon) { + RGFW_iconTaskbar = RGFW_BIT(0), + RGFW_iconWindow = RGFW_BIT(1), + RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow +}; +RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type); + +/*!< sets mouse to RGFW_mouse icon (loaded from a bitmap struct) */ +RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse); + +/*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */ +RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse); + +RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */ +/* + Locks cursor at the center of the window + win->event.point becomes raw mouse movement data + + this is useful for a 3D camera +*/ +RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area); +/*! if the mouse is held by RGFW */ +RGFWDEF RGFW_bool RGFW_window_mouseHeld(RGFW_window* win); +/*! stop holding the mouse and let it move freely */ +RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win); + +/*! hide the window */ +RGFWDEF void RGFW_window_hide(RGFW_window* win); +/*! show the window */ +RGFWDEF void RGFW_window_show(RGFW_window* win); + +/* + makes it so `RGFW_window_shouldClose` returns true or overrides a window close + by modifying window flags +*/ +RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose); + +/*! where the mouse is on the screen */ +RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void); + +/*! where the mouse is on the window */ +RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win); + +/*! show the mouse or hide the mouse */ +RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show); +/*! if the mouse is hidden */ +RGFWDEF RGFW_bool RGFW_window_mouseHidden(RGFW_window* win); +/*! move the mouse to a given point */ +RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v); + +/*! if the window should close (RGFW_close was sent or escape was pressed) */ +RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win); +/*! if the window is fullscreen */ +RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win); +/*! if the window is hidden */ +RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win); +/*! if the window is minimized */ +RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win); +/*! if the window is maximized */ +RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win); +/*! if the window is floating */ +RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win); +/** @} */ + +/** * @defgroup Monitor +* @{ */ + +#ifndef RGFW_NO_MONITOR +/* + scale the window to the monitor. + This is run by default if the user uses the arg `RGFW_scaleToMonitor` during window creation +*/ +RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win); +/*! get the struct of the window's monitor */ +RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); +#endif + +/** @} */ + +/** * @defgroup Input +* @{ */ + +/*! 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 RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/ + +RGFWDEF RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code) */ + +RGFWDEF RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code) */ +RGFWDEF RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code) */ + +/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */ +RGFWDEF RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code */); + +/*! if a mouse button is pressed */ +RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); +/*! if a mouse button is held */ +RGFWDEF RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); +/*! if a mouse button was released */ +RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); +/*! if a mouse button was pressed (checks previous state only) */ +RGFWDEF RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ ); +/** @} */ + +/** * @defgroup Clipboard +* @{ */ +typedef ptrdiff_t RGFW_ssize_t; + +RGFWDEF const char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */ +/*! read clipboard data or send a NULL str to just get the length of the clipboard data */ +RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity); +RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */ +/** @} */ + + + +/** * @defgroup error handling +* @{ */ +typedef RGFW_ENUM(u8, RGFW_debugType) { + RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo +}; + +typedef RGFW_ENUM(u8, RGFW_errorCode) { + RGFW_noError = 0, /*!< no error */ + RGFW_errOpenglContext, RGFW_errEGLContext, /*!< error with the OpenGL context */ + RGFW_errWayland, + RGFW_errDirectXContext, + RGFW_errIOKit, + RGFW_errClipboard, + RGFW_errFailedFuncLoad, + RGFW_errBuffer, + RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL, + RGFW_warningWayland, RGFW_warningOpenGL +}; + +typedef struct RGFW_debugContext { RGFW_window* win; RGFW_monitor* monitor; u32 srcError; } RGFW_debugContext; + +#if defined(__cplusplus) && !defined(__APPLE__) +#define RGFW_DEBUG_CTX(win, err) {win, NULL, err} +#define RGFW_DEBUG_CTX_MON(monitor) {_RGFW.root, &monitor, 0} +#else +#define RGFW_DEBUG_CTX(win, err) (RGFW_debugContext){win, NULL, err} +#define RGFW_DEBUG_CTX_MON(monitor) (RGFW_debugContext){_RGFW.root, &monitor, 0} +#endif + +typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg); +RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func); +RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg); +/** @} */ + +/** + + + event callbacks. + These are completely optional, so you can use the normal + RGFW_checkEvent() method if you prefer that + +* @defgroup Callbacks +* @{ +*/ + +/*! RGFW_windowMoved, the window and its new rect value */ +typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, RGFW_rect r); +/*! RGFW_windowResized, the window and its new rect value */ +typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, RGFW_rect r); +/*! RGFW_windowRestored, the window and its new rect value */ +typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, RGFW_rect r); +/*! RGFW_windowMaximized, the window and its new rect value */ +typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, RGFW_rect r); +/*! RGFW_windowMinimized, the window and its new rect value */ +typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win, RGFW_rect r); +/*! RGFW_quit, the window that was closed */ +typedef void (* RGFW_windowQuitfunc)(RGFW_window* win); +/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */ +typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus); +/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */ +typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, RGFW_bool status); +/*! RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */ +typedef void (* RGFW_mousePosfunc)(RGFW_window* win, RGFW_point point, RGFW_point vector); +/*! RGFW_DNDInit, the window, the point of the drop on the windows */ +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 mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */ +typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool 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, RGFW_mouseButton button, double scroll, RGFW_bool pressed); +/*! RGFW_gamepadButtonPressed, 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_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed); +/*! RGFW_gamepadAxisMove, the window that got the event, the gamepad in question, the axis values and the axis count */ +typedef void (* RGFW_gamepadAxisfunc)(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis); +/*! RGFW_gamepadConnected / RGFW_gamepadDisconnected, the window that got the event, the gamepad in question, if the controller was connected (else it was disconnected) */ +typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, RGFW_bool connected); +/*! RGFW_dnd, the window that had the drop, the drop data and the number of files dropped */ +typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount); +/*! RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */ +typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY); + +/*! set callback for a window move event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func); +/*! set callback for a window resize event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func); +/*! set callback for a window quit event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func); +/*! set callback for a mouse move event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func); +/*! set callback for a window refresh event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func); +/*! set callback for a window focus change event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func); +/*! set callback for a mouse notify event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func); +/*! set callback for a drop event event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func); +/*! set callback for a start of a drop event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func); +/*! set callback for a key (press / release) event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func); +/*! set callback for a mouse button (press / release) event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func); +/*! set callback for a controller button (press / release) event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_gamepadButtonfunc RGFW_setGamepadButtonCallback(RGFW_gamepadButtonfunc func); +/*! set callback for a gamepad axis move event. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_gamepadAxisfunc RGFW_setGamepadAxisCallback(RGFW_gamepadAxisfunc func); +/*! set callback for when a controller is connected or disconnected. Returns the previous callback function (if it was set) */ +RGFWDEF RGFW_gamepadfunc RGFW_setGamepadCallback(RGFW_gamepadfunc func); +/*! set call back for when window is maximized. Returns the previous callback function (if it was set) */ +RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowResizedfunc func); +/*! set call back for when window is minimized. Returns the previous callback function (if it was set) */ +RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowResizedfunc func); +/*! set call back for when window is restored. Returns the previous callback function (if it was set) */ +RGFWDEF RGFW_windowResizedfunc RGFW_setWindowRestoredCallback(RGFW_windowResizedfunc func); +/*! set callback for when the DPI changes. Returns previous callback function (if it was set) */ +RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func); +/** @} */ + +/** * @defgroup Threads +* @{ */ + +#ifndef RGFW_NO_THREADS +/*! threading functions */ + +/*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */ +/* + I'd suggest you use sili's threading functions instead + if you're going to use sili + which is a good idea generally +*/ + +#if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WASM) || defined(RGFW_CUSTOM_BACKEND) + typedef void* (* RGFW_threadFunc_ptr)(void*); +#else + typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter); +#endif + +RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread */ +RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread */ +RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */ +RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */ +#endif + +/** @} */ + +/** * @defgroup gamepad +* @{ */ + +typedef RGFW_ENUM(u8, RGFW_gamepadType) { + RGFW_gamepadMicrosoft = 0, RGFW_gamepadSony, RGFW_gamepadNintendo, RGFW_gamepadLogitech, RGFW_gamepadUnknown +}; + +/*! gamepad count starts at 0*/ +RGFWDEF u32 RGFW_isPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); +RGFWDEF u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); +RGFWDEF u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); +RGFWDEF u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button); +RGFWDEF RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis); +RGFWDEF const char* RGFW_getGamepadName(RGFW_window* win, u16 controller); +RGFWDEF size_t RGFW_getGamepadCount(RGFW_window* win); +RGFWDEF RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller); + +/** @} */ + +/** * @defgroup graphics_API +* @{ */ + +/*!< make the window the current opengl drawing context + + NOTE: + if you want to switch the graphics context's thread, + you have to run RGFW_window_makeCurrent(NULL); on the old thread + then RGFW_window_makeCurrent(valid_window) on the new thread +*/ +RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win); + +/*! get current RGFW window graphics context */ +RGFWDEF RGFW_window* RGFW_getCurrent(void); + +/* supports openGL, directX, OSMesa, EGL and software rendering */ +RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */ +RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval); +/*!< render the software rendering buffer (this is called by RGFW_window_swapInterval) */ +RGFWDEF void RGFW_window_swapBuffers_software(RGFW_window* win); + +typedef void (*RGFW_proc)(void); /* function pointer equivalent of void* */ + +/*! native API functions */ +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) +/*!< create an opengl context for the RGFW window, run by createWindow by default (unless the RGFW_windowNoInitAPI is included) */ +RGFWDEF void RGFW_window_initOpenGL(RGFW_window* win); +/*!< called by `RGFW_window_close` by default (unless the RGFW_windowNoInitAPI is set) */ +RGFWDEF void RGFW_window_freeOpenGL(RGFW_window* win); + +/*! OpenGL init hints */ +typedef RGFW_ENUM(u8, RGFW_glHints) { + RGFW_glStencil = 0, /*!< set stencil buffer bit size (8 by default) */ + RGFW_glSamples, /*!< set number of sampiling buffers (4 by default) */ + RGFW_glStereo, /*!< use GL_STEREO (GL_FALSE by default) */ + RGFW_glAuxBuffers, /*!< number of aux buffers (0 by default) */ + RGFW_glDoubleBuffer, /*!< request double buffering */ + RGFW_glRed, RGFW_glGreen, RGFW_glBlue, RGFW_glAlpha, /*!< set RGBA bit sizes */ + RGFW_glDepth, + RGFW_glAccumRed, RGFW_glAccumGreen, RGFW_glAccumBlue,RGFW_glAccumAlpha, /*!< set accumulated RGBA bit sizes */ + RGFW_glSRGB, /*!< request sRGA */ + RGFW_glRobustness, /*!< request a robust context */ + RGFW_glDebug, /*!< request opengl debugging */ + RGFW_glNoError, /*!< request no opengl errors */ + RGFW_glReleaseBehavior, + RGFW_glProfile, + RGFW_glMajor, RGFW_glMinor, + RGFW_glFinalHint = 32, /*!< the final hint (not for setting) */ + RGFW_releaseFlush = 0, RGFW_glReleaseNone, /* RGFW_glReleaseBehavior options */ + RGFW_glCore = 0, RGFW_glCompatibility /*!< RGFW_glProfile options */ +}; +RGFWDEF void RGFW_setGLHint(RGFW_glHints hint, i32 value); +RGFWDEF RGFW_bool RGFW_extensionSupported(const char* extension, size_t len); /*!< check if whether the specified API extension is supported by the current OpenGL or OpenGL ES context */ +RGFWDEF RGFW_proc RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */ +RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */ +RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); /*!< swap opengl buffer (only) called by RGFW_window_swapInterval */ +void* RGFW_getCurrent_OpenGL(void); /*!< get the current context (OpenGL backend (GLX) (WGL) (EGL) (cocoa) (webgl))*/ + +RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len); /*!< check if whether the specified platform-specific API extension is supported by the current OpenGL or OpenGL ES context */ +#endif #ifdef RGFW_VULKAN - #if defined(RGFW_WAYLAND) && defined(RGFW_X11) + #define VK_USE_PLATFORM_WAYLAND_KHR + #define VK_USE_PLATFORM_XLIB_KHR + #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface")) + #elif defined(RGFW_WAYLAND) #define VK_USE_PLATFORM_WAYLAND_KHR #define VK_USE_PLATFORM_XLIB_KHR - #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface")) - #elif defined(RGFW_WAYLAND) - #define VK_USE_PLATFORM_WAYLAND_KHR - #define VK_USE_PLATFORM_XLIB_KHR - #define RGFW_VK_SURFACE "VK_KHR_wayland_surface" - #elif defined(RGFW_X11) + #define RGFW_VK_SURFACE "VK_KHR_wayland_surface" + #elif defined(RGFW_X11) #define VK_USE_PLATFORM_XLIB_KHR #define RGFW_VK_SURFACE "VK_KHR_xlib_surface" #elif defined(RGFW_WINDOWS) @@ -438,39 +1337,63 @@ typedef ptrdiff_t RGFW_ssize_t; #define RGFW_VK_SURFACE NULL #endif +/* if you don't want to use the above macros */ +RGFWDEF const char** RGFW_getVKRequiredInstanceExtensions(size_t* count); /*!< gets (static) extension array (and size (which will be 2)) */ + +#include + +RGFWDEF VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface); +RGFWDEF RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex); +#endif +#ifdef RGFW_DIRECTX +#ifndef RGFW_WINDOWS + #undef RGFW_DIRECTX +#else + #define OEMRESOURCE + #include + + #ifndef __cplusplus + #define __uuidof(T) IID_##T + #endif +RGFWDEF int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain); +#endif #endif +/** @} */ -/*! @brief The stucture that contains information about the current RGFW instance */ -typedef struct RGFW_info RGFW_info; +/** * @defgroup Supporting +* @{ */ -/*! @brief The window stucture for interfacing with the window */ -typedef struct RGFW_window RGFW_window; +/*! optional init/deinit function */ +RGFWDEF i32 RGFW_init(void); /*!< is called by default when the first window is created by default */ +RGFWDEF void RGFW_deinit(void); /*!< is called by default when the last open window is closed */ -/*! @brief The source window stucture for interfacing with the underlying windowing API (e.g. winapi, wayland, cocoa, etc) */ -typedef struct RGFW_window_src RGFW_window_src; +RGFWDEF double RGFW_getTime(void); /*!< get time in seconds since RGFW_setTime, which ran when the first window is open */ +RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds RGFW_setTime, which ran when the first window is open */ +RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */ +RGFWDEF void RGFW_setTime(double time); /*!< set timer in seconds */ +RGFWDEF u64 RGFW_getTimerValue(void); /*!< get API timer value */ +RGFWDEF u64 RGFW_getTimerFreq(void); /*!< get API time freq */ -/*! @brief The color format for pixel data */ -typedef RGFW_ENUM(u8, RGFW_format) { - RGFW_formatRGB8 = 0, /*!< 8-bit RGB (3 channels) */ - RGFW_formatBGR8, /*!< 8-bit BGR (3 channels) */ - RGFW_formatRGBA8, /*!< 8-bit RGBA (4 channels) */ - RGFW_formatARGB8, /*!< 8-bit RGBA (4 channels) */ - RGFW_formatBGRA8, /*!< 8-bit BGRA (4 channels) */ - RGFW_formatABGR8, /*!< 8-bit BGRA (4 channels) */ - RGFW_formatCount -}; +/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */ +RGFWDEF u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap); -/*! @brief a stucture for interfacing with the underlying native image (e.g. XImage, HBITMAP, etc) */ -typedef struct RGFW_nativeImage RGFW_nativeImage; +/*!< change which window is the root window */ +RGFWDEF void RGFW_setRootWindow(RGFW_window* win); +RGFWDEF RGFW_window* RGFW_getRootWindow(void); -/*! @brief a stucture for interfacing with pixel data as a renderable surface */ -typedef struct RGFW_surface RGFW_surface; +/*! standard event queue, used for injecting events and returning source API callback events like any other queue check */ +/* these are all used internally by RGFW */ +void RGFW_eventQueuePush(RGFW_event event); +RGFW_event* RGFW_eventQueuePop(RGFW_window* win); -/*! a raw pointer to the underlying mouse handle for setting and creating custom mouse icons */ -typedef void RGFW_mouse; +/* for C++ / C89 */ +#define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(e); } -/*! @brief RGFW's abstract keycodes */ +/*! + key codes and mouse icon enums +*/ +#undef RGFW_key typedef RGFW_ENUM(u8, RGFW_key) { RGFW_keyNULL = 0, RGFW_escape = '\033', @@ -485,11 +1408,13 @@ typedef RGFW_ENUM(u8, RGFW_key) { 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', @@ -516,17 +1441,20 @@ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_x = 'x', RGFW_y = 'y', RGFW_z = 'z', + RGFW_period = '.', RGFW_comma = ',', RGFW_slash = '/', RGFW_bracket = '[', - RGFW_closeBracket = ']', + RGFW_closeBracket = ']', RGFW_semicolon = ';', RGFW_apostrophe = '\'', RGFW_backSlash = '\\', RGFW_return = '\n', RGFW_enter = RGFW_return, + RGFW_delete = '\177', /* 127 */ + RGFW_F1, RGFW_F2, RGFW_F3, @@ -539,19 +1467,7 @@ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_F10, RGFW_F11, RGFW_F12, - RGFW_F13, - RGFW_F14, - RGFW_F15, - RGFW_F16, - RGFW_F17, - RGFW_F18, - RGFW_F19, - RGFW_F20, - RGFW_F21, - RGFW_F22, - RGFW_F23, - RGFW_F24, - RGFW_F25, + RGFW_capsLock, RGFW_shiftL, RGFW_controlL, @@ -566,262 +1482,41 @@ typedef RGFW_ENUM(u8, RGFW_key) { RGFW_left, RGFW_right, RGFW_insert, - RGFW_menu, RGFW_end, RGFW_home, RGFW_pageUp, RGFW_pageDown, + RGFW_numLock, - RGFW_kpSlash, - RGFW_kpMultiply, - RGFW_kpPlus, - RGFW_kpMinus, - RGFW_kpEqual, - RGFW_kp1, - RGFW_kp2, - RGFW_kp3, - RGFW_kp4, - RGFW_kp5, - RGFW_kp6, - RGFW_kp7, - RGFW_kp8, - RGFW_kp9, - RGFW_kp0, - RGFW_kpPeriod, - RGFW_kpReturn, + RGFW_KP_Slash, + RGFW_multiply, + RGFW_KP_Minus, + RGFW_KP_1, + RGFW_KP_2, + RGFW_KP_3, + RGFW_KP_4, + RGFW_KP_5, + RGFW_KP_6, + RGFW_KP_7, + RGFW_KP_8, + RGFW_KP_9, + RGFW_KP_0, + RGFW_KP_Period, + RGFW_KP_Return, RGFW_scrollLock, RGFW_printScreen, RGFW_pause, - RGFW_world1, - RGFW_world2, RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */ -}; - -/*! @brief abstract mouse button codes */ -typedef RGFW_ENUM(u8, RGFW_mouseButton) { - RGFW_mouseLeft = 0, /*!< left mouse button is pressed */ - RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */ - RGFW_mouseRight, /*!< right mouse button is pressed */ - RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5, - RGFW_mouseFinal -}; - -/*! abstract key modifier codes */ -typedef RGFW_ENUM(u8, RGFW_keymod) { - RGFW_modCapsLock = RGFW_BIT(0), - RGFW_modNumLock = RGFW_BIT(1), - RGFW_modControl = RGFW_BIT(2), - RGFW_modAlt = RGFW_BIT(3), - RGFW_modShift = RGFW_BIT(4), - RGFW_modSuper = RGFW_BIT(5), - RGFW_modScrollLock = RGFW_BIT(6) -}; - -/*! @brief codes for the event types that can be sent */ -typedef RGFW_ENUM(u8, RGFW_eventType) { - RGFW_eventNone = 0, /*!< no event has been sent */ - RGFW_keyPressed, /* a key has been pressed */ - RGFW_keyReleased, /*!< a key has been released */ - /*! key event note - the code of the key pressed is stored in - RGFW_event.key.value - !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! - - while a string version is stored in - RGFW_event.key.valueString - - RGFW_event.key.mod holds the current mod - this means if CapsLock, NumLock are active or not - */ - RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */ - RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */ - RGFW_mouseScroll, /*!< a mouse scroll event */ - RGFW_mousePosChanged, /*!< the position of the mouse has been changed */ - /*! mouse event note - the x and y of the mouse can be found in the vector, RGFW_x, y - - RGFW_event.button.value holds which mouse button was pressed - */ - RGFW_windowMoved, /*!< the window was moved (by the user) */ - RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */ - RGFW_focusIn, /*!< window is in focus now */ - RGFW_focusOut, /*!< window is out of focus now */ - RGFW_mouseEnter, /* mouse entered the window */ - RGFW_mouseLeave, /* mouse left the window */ - RGFW_windowRefresh, /* The window content needs to be refreshed */ - - /* attribs change event note - The event data is sent straight to the window structure - with win->x, win->y, win->w and win->h - */ - RGFW_quit, /*!< the user clicked the quit button */ - RGFW_dataDrop, /*!< a file has been dropped into the window */ - RGFW_dataDrag, /*!< the start of a drag and drop event, when the file is being dragged */ - /* drop data note - The x and y coords of the drop are stored in the vector RGFW_x, y - - RGFW_event.drop.count holds how many files were dropped - - This is also the size of the array which stores all the dropped file string, - RGFW_event.drop.files - */ - RGFW_windowMaximized, /*!< the window was maximized */ - RGFW_windowMinimized, /*!< the window was minimized */ - RGFW_windowRestored, /*!< the window was restored */ - RGFW_scaleUpdated /*!< content scale factor changed */ -}; - -/*! @brief flags for toggling wether or not an event should be processed */ -typedef RGFW_ENUM(u32, RGFW_eventFlag) { - RGFW_keyPressedFlag = RGFW_BIT(RGFW_keyPressed), - RGFW_keyReleasedFlag = RGFW_BIT(RGFW_keyReleased), - RGFW_mouseScrollFlag = RGFW_BIT(RGFW_mouseScroll), - RGFW_mouseButtonPressedFlag = RGFW_BIT(RGFW_mouseButtonPressed), - RGFW_mouseButtonReleasedFlag = RGFW_BIT(RGFW_mouseButtonReleased), - RGFW_mousePosChangedFlag = RGFW_BIT(RGFW_mousePosChanged), - RGFW_mouseEnterFlag = RGFW_BIT(RGFW_mouseEnter), - RGFW_mouseLeaveFlag = RGFW_BIT(RGFW_mouseLeave), - RGFW_windowMovedFlag = RGFW_BIT(RGFW_windowMoved), - RGFW_windowResizedFlag = RGFW_BIT(RGFW_windowResized), - RGFW_focusInFlag = RGFW_BIT(RGFW_focusIn), - RGFW_focusOutFlag = RGFW_BIT(RGFW_focusOut), - RGFW_windowRefreshFlag = RGFW_BIT(RGFW_windowRefresh), - RGFW_windowMaximizedFlag = RGFW_BIT(RGFW_windowMaximized), - RGFW_windowMinimizedFlag = RGFW_BIT(RGFW_windowMinimized), - RGFW_windowRestoredFlag = RGFW_BIT(RGFW_windowRestored), - RGFW_scaleUpdatedFlag = RGFW_BIT(RGFW_scaleUpdated), - RGFW_quitFlag = RGFW_BIT(RGFW_quit), - RGFW_dataDropFlag = RGFW_BIT(RGFW_dataDrop), - RGFW_dataDragFlag = RGFW_BIT(RGFW_dataDrag), - - RGFW_keyEventsFlag = RGFW_keyPressedFlag | RGFW_keyReleasedFlag, - RGFW_mouseEventsFlag = RGFW_mouseButtonPressedFlag | RGFW_mouseButtonReleasedFlag | RGFW_mousePosChangedFlag | RGFW_mouseEnterFlag | RGFW_mouseLeaveFlag | RGFW_mouseScrollFlag , - RGFW_windowEventsFlag = RGFW_windowMovedFlag | RGFW_windowResizedFlag | RGFW_windowRefreshFlag | RGFW_windowMaximizedFlag | RGFW_windowMinimizedFlag | RGFW_windowRestoredFlag | RGFW_scaleUpdatedFlag, - RGFW_focusEventsFlag = RGFW_focusInFlag | RGFW_focusOutFlag, - RGFW_dataDropEventsFlag = RGFW_dataDropFlag | RGFW_dataDragFlag, - RGFW_allEventFlags = RGFW_keyEventsFlag | RGFW_mouseEventsFlag | RGFW_windowEventsFlag | RGFW_focusEventsFlag | RGFW_dataDropEventsFlag | RGFW_quitFlag -}; - -/*! Event structure(s) and union for checking/getting events */ - -/*! @brief common event data across all events */ -typedef struct RGFW_commonEvent { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_window* win; /*!< the window this event applies too (for event queue events) */ -} RGFW_commonEvent; - -/*! @brief event data for any mouse button event (press/release) */ -typedef struct RGFW_mouseButtonEvent { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_window* win; /*!< the window this event applies too (for event queue events) */ - u8 value; /* !< which mouse button was pressed */ -} RGFW_mouseButtonEvent; - -/*! @brief event data for any mouse scroll event */ -typedef struct RGFW_mouseScrollEvent { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_window* win; /*!< the window this event applies too (for event queue events) */ - float x, y; /*!< the raw mouse scroll value */ -} RGFW_mouseScrollEvent; - -/*! @brief event data for any mouse position event (RGFW_mousePosChanged) */ -typedef struct RGFW_mousePosEvent { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_window* win; /*!< the window this event applies too (for event queue events) */ - i32 x, y; /*!< mouse x, y of event (or drop point) */ - float vecX, vecY; /*!< raw mouse movement */ -} RGFW_mousePosEvent; - -/*! @brief event data for any key event (press/release) */ -typedef struct RGFW_keyEvent { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_window* win; /*!< the window this event applies too (for event queue events) */ - RGFW_key value; /*!< 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 sym; /*!< mapped key char of the event */ - RGFW_bool repeat; /*!< key press event repeated (the key is being held) */ - RGFW_keymod mod; -} RGFW_keyEvent; - -/*! @brief event data for any data drop event */ -typedef struct RGFW_dataDropEvent { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_window* win; /*!< the window this event applies too (for event queue events) */ - /* 260 max paths with a max length of 260 */ - char** files; /*!< dropped files */ - size_t count; /*!< how many files were dropped */ -} RGFW_dataDropEvent; - -/*! @brief event data for any data drag event */ -typedef struct RGFW_dataDragEvent { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_window* win; /*!< the window this event applies too (for event queue events) */ - i32 x, y; /*!< mouse x, y of event (or drop point) */ -} RGFW_dataDragEvent; - -/*! @brief event data for when the window scale (DPI) is updated */ -typedef struct RGFW_scaleUpdatedEvent { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_window* win; /*!< the window this event applies too (for event queue events) */ - float x, y; /*!< DPI scaling */ -} RGFW_scaleUpdatedEvent; - -/*! @brief union for all of the event stucture types */ -typedef union RGFW_event { - RGFW_eventType type; /*!< which event has been sent?*/ - RGFW_commonEvent common; /*!< common event data (e.g.) type and win */ - RGFW_mouseButtonEvent button; /*!< data for a button press/release */ - RGFW_mouseScrollEvent scroll; /*!< data for a mouse scroll */ - RGFW_mousePosEvent mouse; /*!< data for mouse motion events */ - RGFW_keyEvent key; /*!< data for key press/release/hold events */ - RGFW_dataDropEvent drop; /*!< dropping a file events */ - RGFW_dataDragEvent drag; /* data for dragging a file events */ - RGFW_scaleUpdatedEvent scale; /* data for monitor scaling events */ -} RGFW_event; - -/*! - @!brief codes for for RGFW_the code is stupid and C++ waitForEvent - waitMS -> Allows the function to keep checking for events even after there are no more events - if waitMS == 0, the loop will not wait for events - if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns - if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event -*/ -typedef RGFW_ENUM(i32, RGFW_eventWait) { - RGFW_eventNoWait = 0, - RGFW_eventWaitNext = -1 -}; + }; +/*! converts api keycode to the RGFW unmapped/physical key */ +RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode); +/*! converts RGFW keycode to the unmapped/physical api key */ +RGFWDEF u32 RGFW_rgfwToApiKey(u32 keycode); +/*! converts RGFW keycode to the mapped keychar */ +RGFWDEF u8 RGFW_rgfwToKeyChar(u32 keycode); -/*! @brief optional bitwise arguments for making a windows, these can be OR'd together */ -typedef RGFW_ENUM(u32, RGFW_windowFlags) { - RGFW_windowNoBorder = RGFW_BIT(0), /*!< the window doesn't have a border */ - RGFW_windowNoResize = RGFW_BIT(1), /*!< the window cannot be resized by the user */ - RGFW_windowAllowDND = RGFW_BIT(2), /*!< the window supports drag and drop */ - RGFW_windowHideMouse = RGFW_BIT(3), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_showMouse`) */ - RGFW_windowFullscreen = RGFW_BIT(4), /*!< the window is fullscreen by default */ - RGFW_windowTransparent = RGFW_BIT(5), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */ - RGFW_windowCenter = RGFW_BIT(6), /*! center the window on the screen */ - RGFW_windowScaleToMonitor = RGFW_BIT(8), /*! scale the window to the screen */ - RGFW_windowHide = RGFW_BIT(9), /*! the window is hidden */ - RGFW_windowMaximize = RGFW_BIT(10), /*!< maximize the window on creation */ - RGFW_windowCenterCursor = RGFW_BIT(11), /*!< center the cursor to the window on creation */ - RGFW_windowFloating = RGFW_BIT(12), /*!< create a floating window */ - RGFW_windowFocusOnShow = RGFW_BIT(13), /*!< focus the window when it's shown */ - RGFW_windowMinimize = RGFW_BIT(14), /*!< focus the window when it's shown */ - RGFW_windowFocus = RGFW_BIT(15), /*!< if the window is in focus */ - RGFW_windowOpenGL = RGFW_BIT(17), /*!< create an OpenGL context (you can also do this manually with RGFW_window_createContext_OpenGL) */ - RGFW_windowEGL = RGFW_BIT(18), /*!< create an EGL context (you can also do this manually with RGFW_window_createContext_EGL) */ - RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize -}; - -/*! @brief the types of icon to set */ -typedef RGFW_ENUM(u8, RGFW_icon) { - RGFW_iconTaskbar = RGFW_BIT(0), - RGFW_iconWindow = RGFW_BIT(1), - RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow -}; - -/*! @brief standard mouse icons */ typedef RGFW_ENUM(u8, RGFW_mouseIcons) { RGFW_mouseNormal = 0, RGFW_mouseArrow, @@ -834,2188 +1529,46 @@ typedef RGFW_ENUM(u8, RGFW_mouseIcons) { RGFW_mouseResizeNESW, RGFW_mouseResizeAll, RGFW_mouseNotAllowed, - RGFW_mouseIconCount, RGFW_mouseIconFinal = 16 /* padding for alignment */ }; - -/*! @brief the type of debug message */ -typedef RGFW_ENUM(u8, RGFW_debugType) { - RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo -}; - -/*! @brief error codes for known failure types */ -typedef RGFW_ENUM(u8, RGFW_errorCode) { - RGFW_noError = 0, /*!< no error */ - RGFW_errOutOfMemory, - RGFW_errOpenGLContext, RGFW_errEGLContext, /*!< error with the OpenGL context */ - RGFW_errWayland, RGFW_errX11, - RGFW_errDirectXContext, - RGFW_errIOKit, - RGFW_errClipboard, - RGFW_errFailedFuncLoad, - RGFW_errBuffer, - RGFW_errEventQueue, - RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL, - RGFW_warningWayland, RGFW_warningOpenGL -}; - -/*! @brief callback function type for debug messags */ -typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, const char* msg); - -/*! @brief RGFW_windowMoved, the window and its new rect value */ -typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, i32 x, i32 y); -/*! @brief RGFW_windowResized, the window and its new rect value */ -typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, i32 w, i32 h); -/*! @brief RGFW_windowRestored, the window and its new rect value */ -typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, i32 x, i32 y, i32 w, i32 h); -/*! @brief RGFW_windowMaximized, the window and its new rect value */ -typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, i32 x, i32 y, i32 w, i32 h); -/*! @brief RGFW_windowMinimized, the window and its new rect value */ -typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win); -/*! @brief RGFW_quit, the window that was closed */ -typedef void (* RGFW_windowQuitfunc)(RGFW_window* win); -/*! @brief RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */ -typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus); -/*! @brief RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */ -typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, i32 x, i32 y, RGFW_bool status); -/*! @brief RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */ -typedef void (* RGFW_mousePosfunc)(RGFW_window* win, i32 x, i32 y, float vecX, float vecY); -/*! @brief RGFW_dataDrag, the window, the point of the drop on the windows */ -typedef void (* RGFW_dataDragfunc)(RGFW_window* win, i32 x, i32 y); -/*! @brief RGFW_windowRefresh, the window that needs to be refreshed */ -typedef void (* RGFW_windowRefreshfunc)(RGFW_window* win); -/*! @brief RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */ -typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 sym, RGFW_keymod mod, RGFW_bool repeat, RGFW_bool pressed); -/*! @brief 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, RGFW_mouseButton button, RGFW_bool pressed); -/*! @brief RGFW_mouseScroll, the window that got the event, the x scroll value, the y scroll value */ -typedef void (* RGFW_mouseScrollfunc)(RGFW_window* win, float x, float y); -/*! @brief RGFW_dataDrop the window that had the drop, the drop data and the number of files dropped */ -typedef void (* RGFW_dataDropfunc)(RGFW_window* win, char** files, size_t count); -/*! @brief RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */ -typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY); - -/*! @brief function pointer equivalent of void* */ -typedef void (*RGFW_proc)(void); - -#ifndef RGFW_NO_MONITOR - -/*! @brief monitor mode data | can be changed by the user (with functions)*/ -typedef struct RGFW_monitorMode { - i32 w, h; /*!< monitor workarea size */ - u32 refreshRate; /*!< monitor refresh rate */ - u8 red, blue, green; -} RGFW_monitorMode; - -/*! @brief structure for monitor data */ -typedef struct RGFW_monitor { - i32 x, y; /*!< x - y of the monitor workarea */ - char name[128]; /*!< monitor name */ - float scaleX, scaleY; /*!< monitor content scale */ - float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */ - float physW, physH; /*!< monitor physical size in inches */ - RGFW_monitorMode mode; -} RGFW_monitor; - -/*! @brief what type of request you are making for the monitor */ -typedef RGFW_ENUM(u8, RGFW_modeRequest) { - RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */ - RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */ - RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */ - RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB -}; - -#endif - -#if defined(RGFW_OPENGL) - -/*! @brief abstract structure for interfacing with the underlying OpenGL API */ -typedef struct RGFW_glContext RGFW_glContext; - -/*! @brief abstract structure for interfacing with the underlying EGL API */ -typedef struct RGFW_eglContext RGFW_eglContext; - -/*! values for the releaseBehavior hint */ -typedef RGFW_ENUM(i32, RGFW_glReleaseBehavior) { - RGFW_glReleaseFlush = 0, /*!< flush the pipeline will be flushed when the context is release */ - RGFW_glReleaseNone /*!< do nothing on release */ -}; - -/*! values for the profile hint */ -typedef RGFW_ENUM(i32, RGFW_glProfile) { - RGFW_glCore = 0, /*!< the core OpenGL version, e.g. just support for that version */ - RGFW_glCompatibility, /*!< allow compatibility for older versions of RGFW as well as the requested version */ - RGFW_glES /*!< use OpenGL ES */ -}; - -/*! values for the renderer hint */ -typedef RGFW_ENUM(i32, RGFW_glRenderer) { - RGFW_glAccelerated = 0, /*!< hardware accelerated (GPU) */ - RGFW_glSoftware /*!< software rendered (CPU) */ -}; - -/*! OpenGL initalization hints */ -typedef struct RGFW_glHints { - i32 stencil; /*!< set stencil buffer bit size (0 by default) */ - i32 samples; /*!< set number of sample buffers (0 by default) */ - i32 stereo; /*!< hint the context to use stereoscopic frame buffers for 3D (false by default) */ - i32 auxBuffers; /*!< number of aux buffers (0 by default) */ - i32 doubleBuffer; /*!< request double buffering (true by default) */ - i32 red, green, blue, alpha; /*!< set color bit sizes (all 8 by default) */ - i32 depth; /*!< set depth buffer bit size (24 by default) */ - i32 accumRed, accumGreen, accumBlue, accumAlpha; /*!< set accumulated RGBA bit sizes (all 0 by default) */ - RGFW_bool sRGB; /*!< request sRGA format (false by default) */ - RGFW_bool robustness; /*!< request a "robust" (as in memory-safe) context (false by default). For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_robustness.txt */ - RGFW_bool debug; /*!< request OpenGL debugging (false by default). */ - RGFW_bool noError; /*!< request no OpenGL errors (false by default). This causes OpenGL errors to be undefined behavior. For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_no_error.txt */ - RGFW_glReleaseBehavior releaseBehavior; /*!< hint how the OpenGL driver should behave when changing contexts (RGFW_glReleaseNone by default). For more information check the overview section: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_context_flush_control.txt */ - RGFW_glProfile profile; /*!< set OpenGL API profile (RGFW_glCore by default) */ - i32 major, minor; /*!< set the OpenGL API profile version (by default RGFW_glMajor is 1, RGFW_glMinor is 0) */ - RGFW_glContext* share; /*!< Share this OpenGL context with newly created OpenGL contexts; defaults to NULL. */ - RGFW_eglContext* shareEGL; /*!< Share this EGL context with newly created OpenGL contexts; defaults to NULL. */ - RGFW_glRenderer renderer; /*!< renderer to use e.g. accelerated or software defaults to accelerated */ -} RGFW_glHints; - -#endif - -/**! - * @brief Allocates memory using the allocator defined by RGFW_ALLOC at compile time. - * @param size The size (in bytes) of the memory block to allocate. - * @return A pointer to the allocated memory block. -*/ -RGFWDEF void* RGFW_alloc(size_t size); - -/**! - * @brief Frees memory using the deallocator defined by RGFW_FREE at compile time. - * @param ptr A pointer to the memory block to free. -*/ -RGFWDEF void RGFW_free(void* ptr); - -/**! - * @brief Returns the size (in bytes) of the RGFW_window structure. - * @return The size of the RGFW_window structure. -*/ -RGFWDEF size_t RGFW_sizeofWindow(void); - -/**! - * @brief Returns the size (in bytes) of the RGFW_window_src structure. - * @return The size of the RGFW_window_src structure. -*/ -RGFWDEF size_t RGFW_sizeofWindowSrc(void); - -/**! - * @brief (Unix) Toggles the use of Wayland. - * This is enabled by default when compiled with `RGFW_WAYLAND`. - * If not using `RGFW_WAYLAND`, Wayland functions are not exposed. - * This function can be used to force the use of XWayland. - * @param wayland A boolean value indicating whether to use Wayland (true) or not (false). -*/ -RGFWDEF void RGFW_useWayland(RGFW_bool wayland); - -/**! - * @brief Checks if Wayland is currently being used. - * @return RGFW_TRUE if using Wayland, RGFW_FALSE otherwise. -*/ -RGFWDEF RGFW_bool RGFW_usingWayland(void); - -/**! - * @brief Retrieves the current Cocoa layer (macOS only). - * @return A pointer to the Cocoa layer, or NULL if the platform is not in use. -*/ -RGFWDEF void* RGFW_getLayer_OSX(void); - -/**! - * @brief Retrieves the current X11 display connection. - * @return A pointer to the X11 display, or NULL if the platform is not in use. -*/ -RGFWDEF void* RGFW_getDisplay_X11(void); - -/**! - * @brief Retrieves the current Wayland display connection. - * @return A pointer to the Wayland display (`struct wl_display*`), or NULL if the platform is not in use. -*/ -RGFWDEF struct wl_display* RGFW_getDisplay_Wayland(void); - -/**! - * @brief Sets the class name for X11 and WinAPI windows. - * Windows with the same class name will be grouped by the window manager. - * By default, the class name matches the root window’s name. - * @param name The class name to assign. -*/ -RGFWDEF void RGFW_setClassName(const char* name); - -/**! - * @brief Sets the X11 instance name. - * By default, the window name will be used as the instance name. - * @param name The X11 instance name to set. -*/ -RGFWDEF void RGFW_setXInstName(const char* name); - -/**! - * @brief (macOS only) Changes the current working directory to the application’s resource folder. -*/ -RGFWDEF void RGFW_moveToMacOSResourceDir(void); - -/*! copy image to another image, respecting each image's format */ -RGFWDEF void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format); - -/**! - * @brief Returns the size (in bytes) of the RGFW_nativeImage structure. - * @return The size of the RGFW_nativeImage structure. -*/ -RGFWDEF size_t RGFW_sizeofNativeImage(void); - -/**! - * @brief Returns the size (in bytes) of the RGFW_surface structure. - * @return The size of the RGFW_surface structure. -*/ -RGFWDEF size_t RGFW_sizeofSurface(void); - -/**! - * @brief Creates a new surface from raw pixel data. - * @param data A pointer to the pixel data buffer. - * @param w The width of the surface in pixels. - * @param h The height of the surface in pixels. - * @param format The pixel format of the data. - * @return A pointer to the newly created RGFW_surface. - * - * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual - * this means it may fail to render on any other window if the visual does not match - * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues - * Of course, you can also manually set the root window with RGFW_setRootWindow -*/ -RGFWDEF RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format); - -/**! - * @brief Creates a surface using a pre-allocated RGFW_surface structure. - * @param data A pointer to the pixel data buffer. - * @param w The width of the surface in pixels. - * @param h The height of the surface in pixels. - * @param format The pixel format of the data. - * @param surface A pointer to a pre-allocated RGFW_surface structure. - * @return RGFW_TRUE if successful, RGFW_FALSE otherwise. -*/ -RGFWDEF RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface); - -/**! - * @brief Retrieves the native image associated with a surface. - * @param surface A pointer to the RGFW_surface. - * @return A pointer to the native RGFW_nativeImage associated with the surface. -*/ -RGFWDEF RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface); - -/**! - * @brief Frees the surface pointer and any buffers used for software rendering. - * @param surface A pointer to the RGFW_surface to free. -*/ -RGFWDEF void RGFW_surface_free(RGFW_surface* surface); - -/**! - * @brief Frees only the internal buffers used for software rendering, leaving the surface struct intact. - * @param surface A pointer to the RGFW_surface whose buffers should be freed. -*/ -RGFWDEF void RGFW_surface_freePtr(RGFW_surface* surface); - - -/**! - * @brief Loads a mouse icon from bitmap data (similar to RGFW_window_setIcon). - * @param data A pointer to the bitmap pixel data. - * @param w The width of the mouse icon in pixels. - * @param h The height of the mouse icon in pixels. - * @param format The pixel format of the data. - * @return A pointer to the newly loaded RGFW_mouse structure. - * - * @note The icon is not resized by default. -*/ -RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format); - -/**! - * @brief Frees the data associated with an RGFW_mouse structure. - * @param mouse A pointer to the RGFW_mouse to free. -*/ -RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse); - -#ifndef RGFW_NO_MONITOR - -/**! - * @brief Retrieves an array of all available monitors. - * @param len [OUTPUT] A pointer to store the number of monitors found (maximum of 6). - * @return A pointer to an array of RGFW_monitor structures. -*/ -RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len); - -/**! - * @brief Retrieves the primary monitor. - * @return The RGFW_monitor structure representing the primary monitor. -*/ -RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); - -/**! - * @brief Requests a specific display mode for a monitor. - * @param mon The monitor to apply the mode change to. - * @param mode The desired RGFW_monitorMode. - * @param request The RGFW_modeRequest describing how to handle the mode change. - * @return RGFW_TRUE if the mode was successfully applied, otherwise RGFW_FALSE. -*/ -RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); - -/**! - * @brief Compares two monitor modes to check if they are equivalent. - * @param mon The first monitor mode. - * @param mon2 The second monitor mode. - * @param request The RGFW_modeRequest that defines the comparison parameters. - * @return RGFW_TRUE if both modes are equivalent, otherwise RGFW_FALSE. -*/ -RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request); - -/**! - * @brief Scales a monitor’s mode to match a window’s size. - * @param mon The monitor to be scaled. - * @param win The window whose size should be used as a reference. - * @return RGFW_TRUE if the scaling was successful, otherwise RGFW_FALSE. -*/ -RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, struct RGFW_window* win); - -#endif - -/**! -* @brief sleep until RGFW gets an event or the timer ends (defined by OS) -* @param waitMS how long to wait for the next event (in miliseconds) -*/ -RGFWDEF void RGFW_waitForEvent(i32 waitMS); - -/**! -* @brief Set if events should be queued or not (enabled by default if the event queue is checked) -* @param queue boolean value if RGFW should queue events or not -*/ -RGFWDEF void RGFW_setQueueEvents(RGFW_bool queue); - -/**! -* @brief check all the events until there are none left and updates window structure attributes -*/ -RGFWDEF void RGFW_pollEvents(void); - -/**! -* @brief check all the events until there are none left and updates window structure attributes -* queues events if the queue is checked and/or requested -*/ -RGFWDEF void RGFW_stopCheckEvents(void); - -/** * @defgroup Input -* @{ */ - -/**! - * @brief returns true if the key is pressed during the current frame - * @param key the key code of the key you want to check - * @return The boolean value if the key is pressed or not -*/ -RGFWDEF RGFW_bool RGFW_isKeyPressed(RGFW_key key); - -/**! - * @brief returns true if the key was released during the current frame - * @param key the key code of the key you want to check - * @return The boolean value if the key is released or not -*/ -RGFWDEF RGFW_bool RGFW_isKeyReleased(RGFW_key key); - -/**! - * @brief returns true if the key is down - * @param key the key code of the key you want to check - * @return The boolean value if the key is down or not -*/ -RGFWDEF RGFW_bool RGFW_isKeyDown(RGFW_key key); - -/**! - * @brief returns true if the mouse button is pressed during the current frame - * @param button the mouse button code of the button you want to check - * @return The boolean value if the button is pressed or not -*/ -RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button); - -/**! - * @brief returns true if the mouse button is released during the current frame - * @param button the mouse button code of the button you want to check - * @return The boolean value if the button is released or not -*/ -RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button); - -/**! - * @brief returns true if the mouse button is down - * @param button the mouse button code of the button you want to check - * @return The boolean value if the button is down or not -*/ -RGFWDEF RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button); - -/**! - * @brief outputs the current x, y position of the mouse - * @param X [OUTPUT] a pointer for the output X value - * @param Y [OUTPUT] a pointer for the output Y value -*/ -RGFWDEF void RGFW_getMouseScroll(float* x, float* y); - -/**! - * @brief outputs the current x, y movement vector of the mouse - * @param X [OUTPUT] a pointer for the output X vector value - * @param Y [OUTPUT] a pointer for the output Y vector value -*/ -RGFWDEF void RGFW_getMouseVector(float* x, float* y); /** @} */ -/**! - * @brief creates a new window - * @param name the requested title of the window - * @param x the requested x position of the window - * @param y the requested y position of the window - * @param w the requested width of the window - * @param h the requested height of the window - * @param flags extra arguments ((u32)0 means no flags used) - * @return A pointer to the newly created window structure - * - * NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window -*/ -RGFWDEF RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags); - -/**! - * @brief creates a new window using a pre-allocated window structure - * @param name the requested title of the window - * @param x the requested x position of the window - * @param y the requested y position of the window - * @param w the requested width of the window - * @param h the requested height of the window - * @param flags extra arguments ((u32)0 means no flags used) - * @param win a pointer the pre-allocated window structure - * @return A pointer to the newly created window structure -*/ -RGFWDEF RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win); - -/**! - * @brief creates a new surface structure - * @param win the source window of the surface - * @param data a pointer to the raw data of the structure (you allocate this) - * @param w the width the data - * @param h the height of the data - * @return A pointer to the newly created surface structure - * - * NOTE: when you create a surface using RGFW_createSurface / ptr, on X11 it uses the root window's visual - * this means it may fail to render on any other window if the visual does not match - * RGFW_window_createSurface and RGFW_window_createSurfacePtr exist only for X11 to address this issues - * Of course, you can also manually set the root window with RGFW_setRootWindow - */ -RGFWDEF RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format); - -/**! - * @brief creates a new surface structure using a pre-allocated surface structure - * @param win the source window of the surface - * @param data a pointer to the raw data of the structure (you allocate this) - * @param w the width the data - * @param h the height of the data - * @param a pointer to the pre-allocated surface structure - * @return a bool if the creation was successful or not -*/ -RGFWDEF RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface); - -/**! - * @brief blits a surface stucture to the window - * @param win a pointer the window to blit to - * @param surface a pointer to the surface -*/ -RGFWDEF void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface); - -/**! - * @brief gets the position of the window | with RGFW_window.x and window.y - * @param x [OUTPUT] the x position of the window - * @param y [OUTPUT] the y position of the window - * @return a bool if the function was successful -*/ -RGFWDEF RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y); /*!< */ - -/**! - * @brief gets the size of the window | with RGFW_window.w and window.h - * @param win a pointer to the window - * @param w [OUTPUT] the width of the window - * @param h [OUTPUT] the height of the window - * @return a bool if the function was successful -*/ -RGFWDEF RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h); - -/**! - * @brief gets the flags of the window | returns RGFW_window._flags - * @param win a pointer to the window - * @return the window flags -*/ -RGFWDEF u32 RGFW_window_getFlags(RGFW_window* win); - -/**! - * @brief returns the exit key assigned to the window - * @param win a pointer to the target window - * @return The key code assigned as the exit key -*/ -RGFWDEF RGFW_key RGFW_window_getExitKey(RGFW_window* win); - -/**! - * @brief sets the exit key for the window - * @param win a pointer to the target window - * @param key the key code to assign as the exit key -*/ -RGFWDEF void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key); - -/**! - * @brief sets the types of events you want the window to receive - * @param win a pointer to the target window - * @param events the event flags to enable (use RGFW_allEventFlags for all) -*/ -RGFWDEF void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events); - -/**! - * @brief gets the currently enabled events for the window - * @param win a pointer to the target window - * @return The enabled event flags for the window -*/ -RGFWDEF RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win); - -/**! - * @brief enables all events and disables selected ones - * @param win a pointer to the target window - * @param events the event flags to disable -*/ -RGFWDEF void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events); - -/**! - * @brief directly enables or disables a specific event or group of events - * @param win a pointer to the target window - * @param event the event flag or group of flags to modify - * @param state RGFW_TRUE to enable, RGFW_FALSE to disable -*/ -RGFWDEF void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state); - -/**! - * @brief gets the user pointer associated with the window - * @param win a pointer to the target window - * @return The user-defined pointer stored in the window -*/ -RGFWDEF void* RGFW_window_getUserPtr(RGFW_window* win); - -/**! - * @brief sets a user pointer for the window - * @param win a pointer to the target window - * @param ptr a pointer to associate with the window -*/ -RGFWDEF void RGFW_window_setUserPtr(RGFW_window* win, void* ptr); - -/**! - * @brief retrieves the platform-specific window source pointer - * @param win a pointer to the target window - * @return A pointer to the internal RGFW_window_src structure -*/ -RGFWDEF RGFW_window_src* RGFW_window_getSrc(RGFW_window* win); - -/**! - * @brief sets the macOS layer object associated with the window - * @param win a pointer to the target window - * @param layer a pointer to the macOS layer object - * @note Only available on macOS platforms -*/ -RGFWDEF void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer); - -/**! - * @brief retrieves the macOS view object associated with the window - * @param win a pointer to the target window - * @return A pointer to the macOS view object, or NULL if not on macOS -*/ -RGFWDEF void* RGFW_window_getView_OSX(RGFW_window* win); - -/**! - * @brief retrieves the macOS window object - * @param win a pointer to the target window - * @return A pointer to the macOS window object, or NULL if not on macOS -*/ -RGFWDEF void* RGFW_window_getWindow_OSX(RGFW_window* win); - -/**! - * @brief retrieves the HWND handle for the window - * @param win a pointer to the target window - * @return A pointer to the Windows HWND handle, or NULL if not on Windows -*/ -RGFWDEF void* RGFW_window_getHWND(RGFW_window* win); - -/**! - * @brief retrieves the HDC handle for the window - * @param win a pointer to the target window - * @return A pointer to the Windows HDC handle, or NULL if not on Windows -*/ -RGFWDEF void* RGFW_window_getHDC(RGFW_window* win); - -/**! - * @brief retrieves the X11 Window handle for the window - * @param win a pointer to the target window - * @return The X11 Window handle, or 0 if not on X11 -*/ -RGFWDEF u64 RGFW_window_getWindow_X11(RGFW_window* win); - -/**! - * @brief retrieves the Wayland surface handle for the window - * @param win a pointer to the target window - * @return A pointer to the Wayland wl_surface, or NULL if not on Wayland -*/ -RGFWDEF struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win); - -/** * @defgroup Window_management -* @{ */ - -/*! set the window flags (will undo flags if they don't match the old ones) */ -RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags); - -/**! - * @brief polls and pops the next event from the window's event queue - * @param win a pointer to the target window - * @param event [OUTPUT] a pointer to store the retrieved event - * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise - * - * NOTE: Using this function without a loop may cause event lag. - * For multi-threaded systems, use RGFW_pollEvents combined with RGFW_window_checkQueuedEvent. - * - * Example: - * RGFW_event event; - * while (RGFW_window_checkEvent(win, &event)) { - * // handle event - * } -*/ -RGFWDEF RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event); - -/**! - * @brief pops the first queued event for the window - * @param win a pointer to the target window - * @param event [OUTPUT] a pointer to store the retrieved event - * @return RGFW_TRUE if an event was found, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event); - -/**! - * @brief checks if a key was pressed while the window is in focus - * @param win a pointer to the target window - * @param key the key code to check - * @return RGFW_TRUE if the key was pressed, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key); - -/**! - * @brief checks if a key is currently being held down - * @param win a pointer to the target window - * @param key the key code to check - * @return RGFW_TRUE if the key is held down, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key); - -/**! - * @brief checks if a key was released - * @param win a pointer to the target window - * @param key the key code to check - * @return RGFW_TRUE if the key was released, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key); - -/**! - * @brief checks if a mouse button was pressed - * @param win a pointer to the target window - * @param button the mouse button code to check - * @return RGFW_TRUE if the mouse button was pressed, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button); - -/**! - * @brief checks if a mouse button is currently held down - * @param win a pointer to the target window - * @param button the mouse button code to check - * @return RGFW_TRUE if the mouse button is down, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button); - -/**! - * @brief checks if a mouse button was released - * @param win a pointer to the target window - * @param button the mouse button code to check - * @return RGFW_TRUE if the mouse button was released, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button); - -/**! - * @brief checks if the mouse left the window (true only for the first frame) - * @param win a pointer to the target window - * @return RGFW_TRUE if the mouse left, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win); - -/**! - * @brief checks if the mouse entered the window (true only for the first frame) - * @param win a pointer to the target window - * @return RGFW_TRUE if the mouse entered, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win); - -/**! - * @brief checks if the mouse is currently inside the window bounds - * @param win a pointer to the target window - * @return RGFW_TRUE if the mouse is inside, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isMouseInside(RGFW_window* win); - -/**! - * @brief checks if there is data being dragged into or within the window - * @param win a pointer to the target window - * @return RGFW_TRUE if data is being dragged, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isDataDragging(RGFW_window* win); - -/**! - * @brief gets the position of a data drag - * @param win a pointer to the target window - * @param x [OUTPUT] pointer to store the x position - * @param y [OUTPUT] pointer to store the y position - * @return RGFW_TRUE if there is an active drag, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y); - -/**! - * @brief checks if a data drop occurred in the window (first frame only) - * @param win a pointer to the target window - * @return RGFW_TRUE if data was dropped, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_didDataDrop(RGFW_window* win); - -/**! - * @brief retrieves files from a data drop (drag and drop) - * @param win a pointer to the target window - * @param files [OUTPUT] a pointer to the array of file paths - * @param count [OUTPUT] the number of dropped files - * @return RGFW_TRUE if a data drop occurred, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_getDataDrop(RGFW_window* win, const char*** files, size_t* count); - -/**! - * @brief closes the window and frees its associated structure - * @param win a pointer to the target window -*/ -RGFWDEF void RGFW_window_close(RGFW_window* win); - -/**! - * @brief closes the window without freeing its structure - * @param win a pointer to the target window -*/ -RGFWDEF void RGFW_window_closePtr(RGFW_window* win); - -/**! - * @brief moves the window to a new position on the screen - * @param win a pointer to the target window - * @param x the new x position - * @param y the new y position -*/ -RGFWDEF void RGFW_window_move(RGFW_window* win, i32 x, i32 y); - -#ifndef RGFW_NO_MONITOR -/**! - * @brief moves the window to a specific monitor - * @param win a pointer to the target window - * @param m the target monitor -*/ -RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m); -#endif - -/**! - * @brief resizes the window to the given dimensions - * @param win a pointer to the target window - * @param w the new width - * @param h the new height -*/ -RGFWDEF void RGFW_window_resize(RGFW_window* win, i32 w, i32 h); - -/**! - * @brief sets the aspect ratio of the window - * @param win a pointer to the target window - * @param w the width ratio - * @param h the height ratio -*/ -RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h); - -/**! - * @brief sets the minimum size of the window - * @param win a pointer to the target window - * @param w the minimum width - * @param h the minimum height -*/ -RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h); - -/**! - * @brief sets the maximum size of the window - * @param win a pointer to the target window - * @param w the maximum width - * @param h the maximum height -*/ -RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h); - -/**! - * @brief sets focus to the window - * @param win a pointer to the target window -*/ -RGFWDEF void RGFW_window_focus(RGFW_window* win); - -/**! - * @brief checks if the window is currently in focus - * @param win a pointer to the target window - * @return RGFW_TRUE if the window is in focus, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); - -/**! - * @brief raises the window to the top of the stack - * @param win a pointer to the target window -*/ -RGFWDEF void RGFW_window_raise(RGFW_window* win); - -/**! - * @brief maximizes the window - * @param win a pointer to the target window -*/ -RGFWDEF void RGFW_window_maximize(RGFW_window* win); - -/**! - * @brief toggles fullscreen mode for the window - * @param win a pointer to the target window - * @param fullscreen RGFW_TRUE to enable fullscreen, RGFW_FALSE to disable -*/ -RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); - -/**! - * @brief centers the window on the screen - * @param win a pointer to the target window -*/ -RGFWDEF void RGFW_window_center(RGFW_window* win); - -/**! - * @brief minimizes the window - * @param win a pointer to the target window -*/ -RGFWDEF void RGFW_window_minimize(RGFW_window* win); - -/**! - * @brief restores the window from minimized state - * @param win a pointer to the target window -*/ -RGFWDEF void RGFW_window_restore(RGFW_window* win); - -/**! - * @brief makes the window a floating window - * @param win a pointer to the target window - * @param floating RGFW_TRUE to float, RGFW_FALSE to disable -*/ -RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); - -/**! - * @brief sets the opacity level of the window - * @param win a pointer to the target window - * @param opacity the opacity level (0–255) -*/ -RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); - -/**! - * @brief toggles window borders - * @param win a pointer to the target window - * @param border RGFW_TRUE for bordered, RGFW_FALSE for borderless -*/ -RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border); - -/**! - * @brief checks if the window is borderless - * @param win a pointer to the target window - * @return RGFW_TRUE if borderless, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win); - -/**! - * @brief toggles drag-and-drop (DND) support for the window - * @param win a pointer to the target window - * @param allow RGFW_TRUE to allow DND, RGFW_FALSE to disable - * @note RGFW_windowAllowDND must still be passed when creating the window -*/ -RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow); - -/**! - * @brief checks if drag-and-drop (DND) is allowed - * @param win a pointer to the target window - * @return RGFW_TRUE if DND is enabled, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win); - -#ifndef RGFW_NO_PASSTHROUGH -/**! - * @brief toggles mouse passthrough for the window - * @param win a pointer to the target window - * @param passthrough RGFW_TRUE to enable passthrough, RGFW_FALSE to disable -*/ -RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough); -#endif - -/**! - * @brief renames the window - * @param win a pointer to the target window - * @param name the new title string for the window -*/ -RGFWDEF void RGFW_window_setName(RGFW_window* win, const char* name); - -/**! - * @brief sets the icon for the window and taskbar - * @param win a pointer to the target window - * @param data the image data - * @param w the width of the icon - * @param h the height of the icon - * @param format the image format - * @return RGFW_TRUE if successful, RGFW_FALSE otherwise - * - * NOTE: The image may be resized by default. -*/ -RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format); - -/**! - * @brief sets the icon for the window and/or taskbar - * @param win a pointer to the target window - * @param data the image data - * @param w the width of the icon - * @param h the height of the icon - * @param format the image format - * @param type the target icon type (taskbar, window, or both) - * @return RGFW_TRUE if successful, RGFW_FALSE otherwise -*/ -RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type); - -/**! - * @brief sets the mouse icon for the window using a loaded bitmap - * @param win a pointer to the target window - * @param mouse a pointer to the RGFW_mouse struct containing the icon -*/ -RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse); - -/**! - * @brief Sets the mouse to a standard system cursor. - * @param win The target window. - * @param mouse The standard cursor type (see RGFW_MOUSE enum). - * @return True if the standard cursor was successfully applied. -*/ -RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, RGFW_mouseIcons mouse); - -/**! - * @brief Sets the mouse to the default cursor icon. - * @param win The target window. - * @return True if the default cursor was successfully set. -*/ -RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); - -/**! - * @brief Locks the cursor to the center of the window. - * @param win The target window. - * - * While the cursor is held, X and Y report raw mouse movement data. - * Useful for 3D camera or first-person movement systems. -*/ -RGFWDEF void RGFW_window_holdMouse(RGFW_window* win); - -/**! - * @brief Returns true if the mouse is currently held by RGFW. - * @param win The target window. - * @return True if the mouse is being held. -*/ -RGFWDEF RGFW_bool RGFW_window_isHoldingMouse(RGFW_window* win); - -/**! - * @brief Releases the mouse so it can move freely again. - * @param win The target window. -*/ -RGFWDEF void RGFW_window_unholdMouse(RGFW_window* win); - -/**! - * @brief Hides the window from view. - * @param win The target window. -*/ -RGFWDEF void RGFW_window_hide(RGFW_window* win); - -/**! - * @brief Shows the window if it was hidden. - * @param win The target window. -*/ -RGFWDEF void RGFW_window_show(RGFW_window* win); - -/**! - * @brief Sets whether the window should close. - * @param win The target window. - * @param shouldClose True to signal the window should close, false to keep it open. - * - * This can override or trigger the `RGFW_window_shouldClose` state by modifying window flags. -*/ -RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose); - -/**! - * @brief Retrieves the current global mouse position. - * @param x [OUTPUT] Pointer to store the X position of the mouse on the screen. - * @param y [OUTPUT] Pointer to store the Y position of the mouse on the screen. - * @return True if the position was successfully retrieved. -*/ -RGFWDEF RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y); - -/**! - * @brief Retrieves the mouse position relative to the window. - * @param win The target window. - * @param x [OUTPUT] Pointer to store the X position within the window. - * @param y [OUTPUT] Pointer to store the Y position within the window. - * @return True if the position was successfully retrieved. -*/ -RGFWDEF RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y); - -/**! - * @brief Shows or hides the mouse cursor for the window. - * @param win The target window. - * @param show True to show the mouse, false to hide it. -*/ -RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show); - -/**! - * @brief Checks if the mouse is currently hidden in the window. - * @param win The target window. - * @return True if the mouse is hidden. -*/ -RGFWDEF RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win); - -/**! - * @brief Moves the mouse to the specified position within the window. - * @param win The target window. - * @param x The new X position. - * @param y The new Y position. -*/ -RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y); - -/**! - * @brief Checks if the window should close. - * @param win The target window. - * @return True if the window should close (for example, if ESC was pressed or a close event occurred). -*/ -RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win); - -/**! - * @brief Checks if the window is currently fullscreen. - * @param win The target window. - * @return True if the window is fullscreen. -*/ -RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win); - -/**! - * @brief Checks if the window is currently hidden. - * @param win The target window. - * @return True if the window is hidden. -*/ -RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win); - -/**! - * @brief Checks if the window is minimized. - * @param win The target window. - * @return True if the window is minimized. -*/ -RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win); - -/**! - * @brief Checks if the window is maximized. - * @param win The target window. - * @return True if the window is maximized. -*/ -RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win); - -/**! - * @brief Checks if the window is floating. - * @param win The target window. - * @return True if the window is floating. -*/ -RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win); -/** @} */ - -/** * @defgroup Monitor -* @{ */ - -#ifndef RGFW_NO_MONITOR -/**! - * @brief Scales the window to match its monitor’s resolution. - * @param win The target window. - * - * This function is automatically called when the flag `RGFW_scaleToMonitor` - * is used during window creation. -*/ -RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win); - -/**! - * @brief Retrieves the monitor structure associated with the window. - * @param win The target window. - * @return The monitor structure of the window. -*/ -RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); -#endif - -/** @} */ - -/** * @defgroup Clipboard -* @{ */ - -/**! - * @brief Reads clipboard data. - * @param size [OUTPUT] A pointer that will be filled with the size of the clipboard data. - * @return A pointer to the clipboard data as a string. -*/ -RGFWDEF const char* RGFW_readClipboard(size_t* size); - -/**! - * @brief Reads clipboard data into a provided buffer, or returns the required length if str is NULL. - * @param str [OUTPUT] A pointer to the buffer that will receive the clipboard data (or NULL to get required size). - * @param strCapacity The capacity of the provided buffer. - * @return The number of bytes read or required length of clipboard data. -*/ -RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity); - -/**! - * @brief Writes text to the clipboard. - * @param text The text to be written to the clipboard. - * @param textLen The length of the text being written. -*/ -RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); -/** @} */ - - - -/** * @defgroup error handling -* @{ */ -/**! - * @brief Sets the callback function to handle debug messages from RGFW. - * @param func The function pointer to be used as the debug callback. - * @return The previously set debug callback function. -*/ -RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func); - -/**! - * @brief Sends a debug message manually through the currently set debug callback. - * @param type The type of debug message being sent. - * @param err The associated error code. - * @param msg The debug message text. -*/ -RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char* msg); -/** @} */ - -/** - - - event callbacks. - These are completely optional, so you can use the normal - RGFW_checkEvent() method if you prefer that - -* @defgroup Callbacks -* @{ -*/ - -/**! - * @brief Sets the callback function for window move events. - * @param func The function to be called when the window is moved. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func); - -/**! - * @brief Sets the callback function for window resize events. - * @param func The function to be called when the window is resized. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func); - -/**! - * @brief Sets the callback function for window quit events. - * @param func The function to be called when the window receives a quit signal. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func); - -/**! - * @brief Sets the callback function for mouse move events. - * @param func The function to be called when the mouse moves within the window. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func); - -/**! - * @brief Sets the callback function for window refresh events. - * @param func The function to be called when the window needs to be refreshed. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func); - -/**! - * @brief Sets the callback function for focus change events. - * @param func The function to be called when the window gains or loses focus. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func); - -/**! - * @brief Sets the callback function for mouse notification events. - * @param func The function to be called when a mouse notification event occurs. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func); - -/**! - * @brief Sets the callback function for data drop events. - * @param func The function to be called when data is dropped into the window. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_dataDropfunc RGFW_setDataDropCallback(RGFW_dataDropfunc func); - -/**! - * @brief Sets the callback function for the start of a data drag event. - * @param func The function to be called when data dragging begins. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_dataDragfunc RGFW_setDataDragCallback(RGFW_dataDragfunc func); - -/**! - * @brief Sets the callback function for key press and release events. - * @param func The function to be called when a key is pressed or released. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func); - -/**! - * @brief Sets the callback function for mouse button press and release events. - * @param func The function to be called when a mouse button is pressed or released. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func); - -/**! - * @brief Sets the callback function for mouse scroll events. - * @param func The function to be called when the mouse wheel is scrolled. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_mouseScrollfunc RGFW_setMouseScrollCallback(RGFW_mouseScrollfunc func); - -/**! - * @brief Sets the callback function for window maximize events. - * @param func The function to be called when the window is maximized. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_windowMaximizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowMaximizedfunc func); - -/**! - * @brief Sets the callback function for window minimize events. - * @param func The function to be called when the window is minimized. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_windowMinimizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowMinimizedfunc func); - -/**! - * @brief Sets the callback function for window restore events. - * @param func The function to be called when the window is restored from a minimized or maximized state. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_windowRestoredfunc RGFW_setWindowRestoredCallback(RGFW_windowRestoredfunc func); - -/**! - * @brief Sets the callback function for DPI (scale) update events. - * @param func The function to be called when the window’s DPI or scale changes. - * @return The previously set callback function, if any. -*/ -RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func); -/** @} */ - -/** * @defgroup graphics_API -* @{ */ - -/*! native rendering API functions */ -#if defined(RGFW_OPENGL) -/* these are native opengl specific functions and will NOT work with EGL */ - -/*!< make the window the current OpenGL drawing context - - NOTE: - if you want to switch the graphics context's thread, - you have to run RGFW_window_makeCurrentContext_OpenGL(NULL); on the old thread - then RGFW_window_makeCurrentContext_OpenGL(valid_window) on the new thread -*/ - -/**! - * @brief Sets the global OpenGL hints to the specified pointer. - * @param hints A pointer to the RGFW_glHints structure containing the desired OpenGL settings. -*/ -RGFWDEF void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints); - -/**! - * @brief Resets the global OpenGL hints to their default values. -*/ -RGFWDEF void RGFW_resetGlobalHints_OpenGL(void); - -/**! - * @brief Gets the current global OpenGL hints pointer. - * @return A pointer to the currently active RGFW_glHints structure. -*/ -RGFWDEF RGFW_glHints* RGFW_getGlobalHints_OpenGL(void); - -/**! - * @brief Creates and allocates an OpenGL context for the specified window. - * @param win A pointer to the target RGFW_window. - * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. - * @return A pointer to the newly created RGFW_glContext. -*/ -RGFWDEF RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints); - -/**! - * @brief Creates an OpenGL context for the specified window using a preallocated context structure. - * @param win A pointer to the target RGFW_window. - * @param ctx A pointer to an already allocated RGFW_glContext structure. - * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. - * @return RGFW_TRUE on success, RGFW_FALSE on failure. -*/ -RGFWDEF RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints); - -/**! - * @brief Retrieves the OpenGL context associated with a window. - * @param win A pointer to the RGFW_window. - * @return A pointer to the associated RGFW_glContext, or NULL if none exists or if the context is EGL-based. -*/ -RGFWDEF RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win); - -/**! - * @brief Deletes and frees the OpenGL context. - * @param win A pointer to the RGFW_window. - * @param ctx A pointer to the RGFW_glContext to delete. - * - * @note This is automatically called by RGFW_window_close if the window’s context is not NULL. -*/ -RGFWDEF void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx); - -/**! - * @brief Deletes the OpenGL context without freeing its memory. - * @param win A pointer to the RGFW_window. - * @param ctx A pointer to the RGFW_glContext to delete. - * - * @note This is automatically called by RGFW_window_close if the window’s context is not NULL. -*/ -RGFWDEF void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx); - -/**! - * @brief Retrieves the native source context from an RGFW_glContext. - * @param ctx A pointer to the RGFW_glContext. - * @return A pointer to the native OpenGL context handle. -*/ -RGFWDEF void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx); - -/**! - * @brief Makes the specified window the current OpenGL rendering target. - * @param win A pointer to the RGFW_window to make current. - * - * @note This is typically called internally by RGFW_window_makeCurrent. -*/ -RGFWDEF void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win); - -/**! - * @brief Makes the OpenGL context of the specified window current. - * @param win A pointer to the RGFW_window whose context should be made current. - * - * @note To move a context between threads, call RGFW_window_makeCurrentContext_OpenGL(NULL) - * on the old thread before making it current on the new one. -*/ -RGFWDEF void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win); - -/**! - * @brief Swaps the OpenGL buffers for the specified window. - * @param win A pointer to the RGFW_window whose buffers should be swapped. - * - * @note Typically called by RGFW_window_swapInterval. -*/ -RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); - -/**! - * @brief Retrieves the current OpenGL context. - * @return A pointer to the currently active OpenGL context (GLX, WGL, Cocoa, or WebGL backend). -*/ -RGFWDEF void* RGFW_getCurrentContext_OpenGL(void); - -/**! - * @brief Retrieves the current OpenGL window. - * @return A pointer to the RGFW_window currently bound as the OpenGL context target. -*/ -RGFWDEF RGFW_window* RGFW_getCurrentWindow_OpenGL(void); - -/**! - * @brief Sets the OpenGL swap interval (vsync). - * @param win A pointer to the RGFW_window. - * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable). -*/ -RGFWDEF void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval); - -/**! - * @brief Retrieves the address of a native OpenGL procedure. - * @param procname The name of the OpenGL function to look up. - * @return A pointer to the function, or NULL if not found. -*/ -RGFWDEF RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname); - -/**! - * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported. - * @param extension The name of the extension to check. - * @param len The length of the extension string. - * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. -*/ -RGFWDEF RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len); - -/**! - * @brief Checks whether a specific platform-dependent OpenGL extension is supported. - * @param extension The name of the extension to check. - * @param len The length of the extension string. - * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. -*/ -RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len); - -/* these are EGL specific functions, they may fallback to OpenGL */ -#ifdef RGFW_EGL -/**! - * @brief Creates and allocates an OpenGL/EGL context for the specified window. - * @param win A pointer to the target RGFW_window. - * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. - * @return A pointer to the newly created RGFW_eglContext. -*/ -RGFWDEF RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints); - -/**! - * @brief Creates an OpenGL/EGL context for the specified window using a preallocated context structure. - * @param win A pointer to the target RGFW_window. - * @param ctx A pointer to an already allocated RGFW_eglContext structure. - * @param hints A pointer to an RGFW_glHints structure defining context creation parameters. - * @return RGFW_TRUE on success, RGFW_FALSE on failure. -*/ -RGFWDEF RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints); - -/**! - * @brief Frees and deletes an OpenGL/EGL context. - * @param win A pointer to the RGFW_window. - * @param ctx A pointer to the RGFW_eglContext to delete. - * - * @note Automatically called by RGFW_window_close if RGFW owns the context. -*/ -RGFWDEF void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx); - -/**! - * @brief Deletes an OpenGL/EGL context without freeing its memory. - * @param win A pointer to the RGFW_window. - * @param ctx A pointer to the RGFW_eglContext to delete. - * - * @note Automatically called by RGFW_window_close if RGFW owns the context. -*/ -RGFWDEF void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx); - -/**! - * @brief Retrieves the OpenGL/EGL context associated with a window. - * @param win A pointer to the RGFW_window. - * @return A pointer to the associated RGFW_eglContext, or NULL if none exists or if the context is a native OpenGL context. -*/ -RGFWDEF RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win); - -/**! - * @brief Retrieves the EGL display handle. - * @return A pointer to the native EGLDisplay. -*/ -RGFWDEF void* RGFW_getDisplay_EGL(void); - -/**! - * @brief Retrieves the native source context from an RGFW_eglContext. - * @param ctx A pointer to the RGFW_eglContext. - * @return A pointer to the native EGLContext handle. -*/ -RGFWDEF void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx); - -/**! - * @brief Retrieves the EGL surface handle from an RGFW_eglContext. - * @param ctx A pointer to the RGFW_eglContext. - * @return A pointer to the EGLSurface associated with the context. -*/ -RGFWDEF void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx); - -/**! - * @brief Retrieves the Wayland EGL window handle from an RGFW_eglContext. - * @param ctx A pointer to the RGFW_eglContext. - * @return A pointer to the wl_egl_window associated with the EGL context. -*/ -RGFWDEF struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx); - -/**! - * @brief Swaps the EGL buffers for the specified window. - * @param win A pointer to the RGFW_window whose buffers should be swapped. - * - * @note Typically called by RGFW_window_swapInterval. -*/ -RGFWDEF void RGFW_window_swapBuffers_EGL(RGFW_window* win); - -/**! - * @brief Makes the specified window the current EGL rendering target. - * @param win A pointer to the RGFW_window to make current. - * - * @note This is typically called internally by RGFW_window_makeCurrent. -*/ -RGFWDEF void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win); - -/**! - * @brief Makes the EGL context of the specified window current. - * @param win A pointer to the RGFW_window whose context should be made current. - * - * @note To move a context between threads, call RGFW_window_makeCurrentContext_EGL(NULL) - * on the old thread before making it current on the new one. -*/ -RGFWDEF void RGFW_window_makeCurrentContext_EGL(RGFW_window* win); - -/**! - * @brief Retrieves the current EGL context. - * @return A pointer to the currently active EGLContext. -*/ -RGFWDEF void* RGFW_getCurrentContext_EGL(void); - -/**! - * @brief Retrieves the current EGL window. - * @return A pointer to the RGFW_window currently bound as the EGL context target. -*/ -RGFWDEF RGFW_window* RGFW_getCurrentWindow_EGL(void); - -/**! - * @brief Sets the EGL swap interval (vsync). - * @param win A pointer to the RGFW_window. - * @param swapInterval The desired swap interval value (0 to disable vsync, 1 to enable). -*/ -RGFWDEF void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval); - -/**! - * @brief Retrieves the address of a native OpenGL or OpenGL ES procedure in an EGL context. - * @param procname The name of the OpenGL function to look up. - * @return A pointer to the function, or NULL if not found. -*/ -RGFWDEF RGFW_proc RGFW_getProcAddress_EGL(const char* procname); - -/**! - * @brief Checks whether a specific OpenGL or OpenGL ES API extension is supported in the current EGL context. - * @param extension The name of the extension to check. - * @param len The length of the extension string. - * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. -*/ -RGFWDEF RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len); - -/**! - * @brief Checks whether a specific platform-dependent EGL extension is supported in the current context. - * @param extension The name of the extension to check. - * @param len The length of the extension string. - * @return RGFW_TRUE if supported, RGFW_FALSE otherwise. -*/ -RGFWDEF RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len); -#endif -#endif - -#ifdef RGFW_VULKAN -#include - -/* if you don't want to use the above macros */ - -/**! - * @brief Retrieves the Vulkan instance extensions required by RGFW. - * @param count [OUTPUT] A pointer that will receive the number of required extensions (typically 2). - * @return A pointer to a static array of required Vulkan instance extension names. -*/ -RGFWDEF const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count); - -/**! - * @brief Creates a Vulkan surface for the specified window. - * @param win A pointer to the RGFW_window for which to create the Vulkan surface. - * @param instance The Vulkan instance used to create the surface. - * @param surface [OUTPUT] A pointer to a VkSurfaceKHR handle that will receive the created surface. - * @return A VkResult indicating success or failure. -*/ -RGFWDEF VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface); - -/**! - * @brief Checks whether the specified Vulkan physical device and queue family support presentation for RGFW. - * @param instance The Vulkan instance. - * @param physicalDevice The Vulkan physical device to check. - * @param queueFamilyIndex The index of the queue family to query for presentation support. - * @return RGFW_TRUE if presentation is supported, RGFW_FALSE otherwise. -*/ -RGFWDEF RGFW_bool RGFW_getPresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex); -#endif - -#ifdef RGFW_DIRECTX -#ifndef RGFW_WINDOWS - #undef RGFW_DIRECTX -#else - #define OEMRESOURCE - #include - - #ifndef __cplusplus - #define __uuidof(T) IID_##T - #endif -/**! - * @brief Creates a DirectX swap chain for the specified RGFW window. - * @param win A pointer to the RGFW_window for which to create the swap chain. - * @param pFactory A pointer to the IDXGIFactory used to create the swap chain. - * @param pDevice A pointer to the DirectX device (e.g., ID3D11Device or ID3D12Device). - * @param swapchain [OUTPUT] A pointer to an IDXGISwapChain pointer that will receive the created swap chain. - * @return An integer result code (0 on success, or a DirectX error code on failure). -*/ -RGFWDEF int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain); -#endif -#endif - -#ifdef RGFW_WEBGPU - #include - /**! - * @brief Creates a WebGPU surface for the specified RGFW window. - * @param window A pointer to the RGFW_window for which to create the surface. - * @param instance The WebGPU instance used to create the surface. - * @return The created WGPUSurface handle. - */ - RGFWDEF WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance); -#endif - -/** @} */ - -/** * @defgroup Supporting -* @{ */ - -/**! - * @brief Sets the root (main) RGFW window. - * @param win A pointer to the RGFW_window to set as the root window. -*/ -RGFWDEF void RGFW_setRootWindow(RGFW_window* win); - -/**! - * @brief Retrieves the current root RGFW window. - * @return A pointer to the current root RGFW_window. -*/ -RGFWDEF RGFW_window* RGFW_getRootWindow(void); - -/**! - * @brief Pushes an event into the standard RGFW event queue. - * @param event A pointer to the RGFW_event to be added to the queue. -*/ -RGFWDEF void RGFW_eventQueuePush(const RGFW_event* event); - -/**! - * @brief Clears all events from the RGFW event queue without processing them. -*/ -RGFWDEF void RGFW_eventQueueFlush(void); - -/**! - * @brief Pops the next event from the RGFW event queue for the specified window. - * @param win A pointer to the RGFW_window to retrieve an event for. - * @return A pointer to the popped RGFW_event, or NULL if the queue is empty. -*/ -RGFWDEF RGFW_event* RGFW_eventQueuePop(RGFW_window* win); - -/**! - * @brief Converts an API keycode to the RGFW unmapped (physical) key. - * @param keycode The platform-specific keycode. - * @return The corresponding RGFW keycode. -*/ -RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode); - -/**! - * @brief Converts an RGFW keycode to the unmapped (physical) API key. - * @param keycode The RGFW keycode. - * @return The corresponding platform-specific keycode. -*/ -RGFWDEF u32 RGFW_rgfwToApiKey(u32 keycode); - -/**! - * @brief Converts an RGFW keycode to the mapped character representation. - * @param keycode The RGFW keycode. - * @return The corresponding key character. -*/ -RGFWDEF u8 RGFW_rgfwToKeyChar(u32 keycode); - -/**! - * @brief Retrieves the size of the RGFW_info structure. - * @return The size (in bytes) of RGFW_info. -*/ -RGFWDEF size_t RGFW_sizeofInfo(void); - -/**! - * @brief Initializes the RGFW library. - * @return 0 on success, or a negative error code on failure. - * @note This is automatically called when the first window is created. -*/ -RGFWDEF i32 RGFW_init(void); - -/**! - * @brief Deinitializes the RGFW library. - * @note This is automatically called when the last open window is closed. -*/ -RGFWDEF void RGFW_deinit(void); - -/**! - * @brief Initializes RGFW using a user-provided RGFW_info structure. - * @param info A pointer to an RGFW_info structure to be used for initialization. - * @return 0 on success, or a negative error code on failure. -*/ -RGFWDEF i32 RGFW_init_ptr(RGFW_info* info); - -/**! - * @brief Deinitializes a specific RGFW instance stored in the provided RGFW_info pointer. - * @param info A pointer to the RGFW_info structure representing the instance to deinitialize. -*/ -RGFWDEF void RGFW_deinit_ptr(RGFW_info* info); - -/**! - * @brief Sets the global RGFW_info structure pointer. - * @param info A pointer to the RGFW_info structure to set. -*/ -RGFWDEF void RGFW_setInfo(RGFW_info* info); - -/**! - * @brief Retrieves the global RGFW_info structure pointer. - * @return A pointer to the current RGFW_info structure. -*/ -RGFWDEF RGFW_info* RGFW_getInfo(void); - -/** @} */ #endif /* RGFW_HEADER */ - -#if !defined(RGFW_NATIVE_HEADER) && (defined(RGFW_NATIVE) || defined(RGFW_IMPLEMENTATION)) -#define RGFW_NATIVE_HEADER - #if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER) - #pragma comment(lib, "opengl32") - #endif - - #ifdef RGFW_OPENGL - struct RGFW_eglContext { - void* ctx; - void* surface; - struct wl_egl_window* eglWindow; - }; - - typedef union RGFW_gfxContext { - RGFW_glContext* native; - RGFW_eglContext* egl; - } RGFW_gfxContext; - - typedef RGFW_ENUM(u32, RGFW_gfxContextType) { - RGFW_gfxNativeOpenGL = RGFW_BIT(0), - RGFW_gfxEGL = RGFW_BIT(1), - RGFW_gfxOwnedByRGFW = RGFW_BIT(2) - }; - #endif - - /*! source data for the window (used by the APIs) */ - #ifdef RGFW_WINDOWS - - #define WIN32_LEAN_AND_MEAN - #define OEMRESOURCE - #include - - struct RGFW_nativeImage { - HBITMAP bitmap; - u8* bitmapBits; - RGFW_format format; - HDC hdcMem; - }; - - #ifdef RGFW_OPENGL - struct RGFW_glContext { HGLRC ctx; }; - #endif - - struct RGFW_window_src { - HWND window; /*!< source window */ - HDC hdc; /*!< source HDC */ - i32 offsetW, offsetH; /*!< width and height offset for window */ - HICON hIconSmall, hIconBig; /*!< source window icons */ - i32 maxSizeW, maxSizeH, minSizeW, minSizeH, aspectRatioW, aspectRatioH; /*!< for setting max/min resize (RGFW_WINDOWS) */ - #ifdef RGFW_OPENGL - RGFW_gfxContext ctx; - RGFW_gfxContextType gfxType; - #endif - }; - -#elif defined(RGFW_UNIX) - #ifdef RGFW_X11 - #include - #include - #endif - - #ifdef RGFW_WAYLAND - #ifdef RGFW_LIBDECOR - #include - #endif - - #include - #include - #endif - - struct RGFW_nativeImage { - #ifdef RGFW_X11 - XImage* bitmap; - #endif - #ifdef RGFW_WAYLAND - struct wl_buffer* wl_buffer; - #endif - u8* buffer; - RGFW_format format; - }; - - #ifdef RGFW_OPENGL - struct RGFW_glContext { - #ifdef RGFW_X11 - struct __GLXcontextRec* ctx; /*!< source graphics context */ - Window window; - #endif - #ifdef RGFW_WAYLAND - RGFW_eglContext egl; - #endif - }; - #endif - - struct RGFW_window_src { - i32 x, y, w, h; - #ifdef RGFW_OPENGL - RGFW_gfxContext ctx; - RGFW_gfxContextType gfxType; - #endif -#ifdef RGFW_X11 - Window window; /*!< source window */ - Window parent; /*!< parent window */ - GC gc; - #ifdef RGFW_ADVANCED_SMOOTH_RESIZE - i64 counter_value; - XID counter; - #endif -#endif /* RGFW_X11 */ - -#if defined(RGFW_WAYLAND) - struct wl_surface* surface; - struct xdg_surface* xdg_surface; - struct xdg_toplevel* xdg_toplevel; - struct zxdg_toplevel_decoration_v1* decoration; - struct zwp_locked_pointer_v1 *locked_pointer; - struct xdg_toplevel_icon_v1 *icon; - u32 decoration_mode; - /* State flags to configure the window */ - RGFW_bool pending_activated; - RGFW_bool activated; - RGFW_bool resizing; - RGFW_bool pending_maximized; - RGFW_bool maximized; - RGFW_bool minimized; - - RGFW_bool using_custom_cursor; - struct wl_surface* custom_cursor_surface; - - RGFW_monitor active_monitor; - - struct wl_data_source *data_source; // offer data to other clients - - #ifdef RGFW_LIBDECOR - struct libdecor* decorContext; - #endif -#endif /* RGFW_WAYLAND */ - }; - +#if defined(RGFW_X11) || defined(RGFW_WAYLAND) + #define RGFW_OS_BASED_VALUE(l, w, m, h) l +#elif defined(RGFW_WINDOWS) + #define RGFW_OS_BASED_VALUE(l, w, m, h) w #elif defined(RGFW_MACOS) - - struct RGFW_nativeImage { - RGFW_format format; - }; - - #ifdef RGFW_OPENGL - struct RGFW_glContext { void* ctx; }; - #endif - - struct RGFW_window_src { - void* window; - void* view; /* apple viewpoint thingy */ - void* mouse; - #ifdef RGFW_OPENGL - RGFW_gfxContext ctx; - RGFW_gfxContextType gfxType; - #endif - }; - + #define RGFW_OS_BASED_VALUE(l, w, m, h) m #elif defined(RGFW_WASM) - - #include - #include - - struct RGFW_nativeImage { - RGFW_format format; - }; - - #ifdef RGFW_OPENGL - struct RGFW_glContext { - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; - }; - #endif - - struct RGFW_window_src { - #ifdef RGFW_OPENGL - RGFW_gfxContext ctx; - RGFW_gfxContextType gfxType; - #endif - }; - + #define RGFW_OS_BASED_VALUE(l, w, m, h) h #endif -struct RGFW_surface { - u8* data; - i32 w, h; - RGFW_format format; - RGFW_nativeImage native; -}; - -/*! internal window data that is not specific to the OS */ -typedef struct RGFW_windowInternal { - /*! which key RGFW_window_shouldClose checks. Settting this to RGFW_keyNULL disables the feature. */ - RGFW_key exitKey; - i32 lastMouseX, lastMouseY; /*!< last cusor point (for raw mouse data) */ - - RGFW_bool shouldClose; - RGFW_bool holdMouse; - RGFW_bool inFocus; - RGFW_bool mouseInside; - RGFW_keymod mod; - RGFW_eventFlag enabledEvents; - u32 flags; /*!< windows flags (for RGFW to check and modify) */ - i32 oldX, oldY, oldW, oldH; -} RGFW_windowInternal; - -struct RGFW_window { - RGFW_window_src src; /*!< src window data */ - RGFW_windowInternal internal; /*!< internal window data that is not specific to the OS */ - void* userPtr; /* ptr for usr data */ - i32 x, y, w, h; /*!< position and size of the window */ -}; /*!< window structure for the window */ - -typedef struct RGFW_windowState { - RGFW_bool mouseEnter; - RGFW_bool dataDragging; - RGFW_bool dataDrop; - size_t filesCount; - i32 dropX, dropY; - RGFW_window* win; /*!< it's not possible for one of these events to happen in the frame that the other event happened */ - - RGFW_bool mouseLeave; - RGFW_window* winLeave; /*!< if a mouse leaves one widow and enters the next */ -} RGFW_windowState; - -typedef struct { - RGFW_bool current; - RGFW_bool prev; -} RGFW_keyState; - -#ifndef RGFW_NO_MONITOR - typedef struct RGFW_monitorNode { - RGFW_monitor mon; - struct RGFW_monitorNode* next; -#ifdef RGFW_WAYLAND - u32 id; /* Add id so wl_outputs can be removed */ - struct wl_output *output; - struct zxdg_output_v1 *xdg_output; -#endif - } RGFW_monitorNode; - - typedef struct RGFW_monitorList { - RGFW_monitorNode* head; - RGFW_monitorNode* cur; - } RGFW_monitorList; - - typedef struct RGFW_monitors { - RGFW_monitorList list; - RGFW_monitorList freeList; - size_t count; - RGFW_monitorNode data[RGFW_MAX_MONITORS]; - } RGFW_monitors; - - RGFWDEF RGFW_monitorNode* RGFW_monitors_add(RGFW_monitor mon); - RGFWDEF void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev); -#endif - -struct RGFW_info { - RGFW_window* root; - i32 windowCount; - - RGFW_mouse* hiddenMouse; - - RGFW_event events[RGFW_MAX_EVENTS]; /* A circular buffer (FIFO), using eventBottom/Len */ - - i32 eventBottom; - i32 eventLen; - RGFW_bool queueEvents; - RGFW_bool polledEvents; - - u32 apiKeycodes[RGFW_keyLast]; - #if defined(RGFW_X11) || defined(RGFW_WAYLAND) - u8 keycodes[256]; - #elif defined(RGFW_WINDOWS) - u8 keycodes[512]; - #elif defined(RGFW_MACOS) - u8 keycodes[128]; - #elif defined(RGFW_WASM) - u8 keycodes[256]; - #endif - - const char* className; - RGFW_bool useWaylandBool; - RGFW_bool stopCheckEvents_bool ; - u64 timerOffset; - - char* clipboard_data; - char* clipboard; /* for writing to the clipboard selection */ - size_t clipboard_len; - char filesSrc[RGFW_MAX_PATH * RGFW_MAX_DROPS]; - char** files; - #ifdef RGFW_X11 - Display* display; - XContext context; - Window helperWindow; - const char* instName; - XErrorEvent* x11Error; - #endif - #ifdef RGFW_WAYLAND - struct wl_display* wl_display; - struct xkb_context *xkb_context; - struct xkb_keymap *keymap; - struct xkb_state *xkb_state; - struct zxdg_decoration_manager_v1 *decoration_manager; - struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; - struct zwp_relative_pointer_v1 *relative_pointer; - struct zwp_pointer_constraints_v1 *constraint_manager; - struct xdg_toplevel_icon_manager_v1 *icon_manager; - - struct zxdg_output_manager_v1 *xdg_output_manager; - - struct wl_data_device_manager *data_device_manager; - struct wl_data_device *data_device; // supports clipboard and DND - - struct wl_keyboard* wl_keyboard; - struct wl_pointer* wl_pointer; - struct wl_compositor* compositor; - struct xdg_wm_base* xdg_wm_base; - struct wl_shm* shm; - struct wl_seat *seat; - struct wl_registry *registry; - u32 mouse_enter_serial; - struct wl_cursor_theme* wl_cursor_theme; - struct wl_surface* cursor_surface; - - RGFW_window* kbOwner; - - #endif - - RGFW_monitors monitors; - - #ifdef RGFW_UNIX - int eventWait_forceStop[3]; - #endif - - #ifdef RGFW_MACOS - void* NSApp; - void* customViewClasses[2]; /* NSView and NSOpenGLView */ - void* customWindowDelegateClass; - #endif - - #ifdef RGFW_OPENGL - RGFW_window* current; - #endif - #ifdef RGFW_EGL - void* EGL_display; - #endif - - RGFW_window* mouseOwner; - RGFW_windowState windowState; /*! for checking window state events */ - - RGFW_keyState mouseButtons[RGFW_mouseFinal]; - RGFW_keyState keyboard[RGFW_keyLast]; - float scrollX, scrollY; - float vectorX, vectorY; -}; -#endif /* RGFW_NATIVE_HEADER */ #ifdef RGFW_IMPLEMENTATION +RGFW_bool RGFW_useWaylandBool = 1; +void RGFW_useWayland(RGFW_bool wayland) { RGFW_useWaylandBool = wayland; } +RGFW_bool RGFW_usingWayland(void) { return RGFW_useWaylandBool; } -/* global private API */ - -/* for C++ / C89 */ -#define RGFW_eventQueuePushEx(eventInit) { RGFW_event e; eventInit; RGFW_eventQueuePush(&e); } - -RGFWDEF RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win); -RGFWDEF void RGFW_window_closePlatform(RGFW_window* win); - -RGFWDEF void RGFW_window_focusLost(RGFW_window* win); -RGFWDEF void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags); - -RGFWDEF void RGFW_initKeycodes(void); -RGFWDEF void RGFW_initKeycodesPlatform(void); -RGFWDEF void RGFW_resetPrevState(void); -RGFWDEF void RGFW_resetKey(void); -RGFWDEF void RGFW_unloadEGL(void); -RGFWDEF void RGFW_updateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll); -RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll); -RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show); -RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value); - -RGFWDEF void RGFW_setBit(u32* var, u32 mask, RGFW_bool set); -RGFWDEF void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode); - -RGFWDEF void RGFW_captureCursor(RGFW_window* win); -RGFWDEF void RGFW_releaseCursor(RGFW_window* win); - -RGFWDEF void RGFW_copyImageData64(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, - u8* src_data, RGFW_format src_format, RGFW_bool is64bit); - -RGFWDEF RGFW_bool RGFW_loadEGL(void); - -#ifdef RGFW_OPENGL -typedef struct RGFW_attribStack { - i32* attribs; - size_t count; - size_t max; -} RGFW_attribStack; -RGFWDEF void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max); -RGFWDEF void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib); -RGFWDEF void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2); - -RGFWDEF RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len); +#if !defined(RGFW_NO_X11) && defined(RGFW_WAYLAND) +#define RGFW_GOTO_WAYLAND(fallback) if (RGFW_useWaylandBool && fallback == 0) goto wayland +#define RGFW_WAYLAND_LABEL wayland:; +#else +#define RGFW_GOTO_WAYLAND(fallback) +#define RGFW_WAYLAND_LABEL #endif -typedef struct RGFW_colorLayout { i32 r, g, b, a; } RGFW_colorLayout; - -#ifdef RGFW_X11 -RGFWDEF void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win); -#endif -#ifdef RGFW_MACOS -RGFWDEF void RGFW_osx_initView(RGFW_window* win); -#endif -/* end of global private API defs */ - -RGFW_info* _RGFW = NULL; -void RGFW_setInfo(RGFW_info* info) { _RGFW = info; } -RGFW_info* RGFW_getInfo(void) { return _RGFW; } - - -void* RGFW_alloc(size_t size) { return RGFW_ALLOC(size); } -void RGFW_free(void* ptr) { RGFW_FREE(ptr); } - -void RGFW_useWayland(RGFW_bool wayland) { RGFW_init(); _RGFW->useWaylandBool = RGFW_BOOL(wayland); } -RGFW_bool RGFW_usingWayland(void) { return _RGFW->useWaylandBool; } - +char* RGFW_clipboard_data; void RGFW_clipboard_switch(char* newstr); void RGFW_clipboard_switch(char* newstr) { - if (_RGFW->clipboard_data != NULL) - RGFW_FREE(_RGFW->clipboard_data); - _RGFW->clipboard_data = newstr; + if (RGFW_clipboard_data != NULL) + RGFW_FREE(RGFW_clipboard_data); + RGFW_clipboard_data = newstr; } #define RGFW_CHECK_CLIPBOARD() \ - if (size <= 0 && _RGFW->clipboard_data != NULL) \ - return (const char*)_RGFW->clipboard_data; \ + if (size <= 0 && RGFW_clipboard_data != NULL) \ + return (const char*)RGFW_clipboard_data; \ else if (size <= 0) \ return "\0"; @@ -3036,6 +1589,52 @@ const char* RGFW_readClipboard(size_t* len) { return (const char*)str; } +RGFW_debugfunc RGFW_debugCallback = NULL; +RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func) { + RGFW_debugfunc RGFW_debugCallbackPrev = RGFW_debugCallback; + RGFW_debugCallback = func; + return RGFW_debugCallbackPrev; +} + +#ifdef RGFW_DEBUG +#include +#endif + +void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg) { + if (RGFW_debugCallback) RGFW_debugCallback(type, err, ctx, msg); + #ifdef RGFW_DEBUG + switch (type) { + case RGFW_typeInfo: printf("RGFW INFO (%i %i): %s", type, err, msg); break; + case RGFW_typeError: printf("RGFW DEBUG (%i %i): %s", type, err, msg); break; + case RGFW_typeWarning: printf("RGFW WARNING (%i %i): %s", type, err, msg); break; + default: break; + } + + switch (err) { + #ifdef RGFW_BUFFER + case RGFW_errBuffer: case RGFW_infoBuffer: printf(" buffer size: %i %i\n", ctx.win->bufferSize.w, ctx.win->bufferSize.h); break; + #endif + case RGFW_infoMonitor: printf(": scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", ctx.monitor->name, ctx.monitor->x, ctx.monitor->y, ctx.monitor->mode.area.w, ctx.monitor->mode.area.h, ctx.monitor->physW, ctx.monitor->physH, ctx.monitor->scaleX, ctx.monitor->scaleY, ctx.monitor->pixelRatio, ctx.monitor->mode.refreshRate, ctx.monitor->mode.red + ctx.monitor->mode.green + ctx.monitor->mode.blue); break; + case RGFW_infoWindow: printf(" with rect of {%i, %i, %i, %i} \n", ctx.win->r.x, ctx.win->r.y,ctx. win->r.w, ctx.win->r.h); break; + case RGFW_errDirectXContext: printf(" srcError %i\n", ctx.srcError); break; + default: printf("\n"); + } + #endif +} + +u64 RGFW_timerOffset = 0; +void RGFW_setTime(double time) { + RGFW_timerOffset = RGFW_getTimerValue() - (u64)(time * (double)RGFW_getTimerFreq()); +} + +double RGFW_getTime(void) { + return (double) ((double)(RGFW_getTimerValue() - RGFW_timerOffset) / (double)RGFW_getTimerFreq()); +} + +u64 RGFW_getTimeNS(void) { + return (u64)(((double)((RGFW_getTimerValue() - RGFW_timerOffset)) * 1e9) / (double)RGFW_getTimerFreq()); +} + /* RGFW_IMPLEMENTATION starts with generic RGFW defines @@ -3044,44 +1643,205 @@ This is the start of keycode data -void RGFW_initKeycodes(void) { - RGFW_MEMSET(_RGFW->keycodes, 0, sizeof(_RGFW->keycodes)); - RGFW_initKeycodesPlatform(); - u32 i, y; - for (i = 0; i < RGFW_keyLast; i++) { - for (y = 0; y < sizeof(_RGFW->keycodes); y++) { - if (_RGFW->keycodes[y] == i) { - _RGFW->apiKeycodes[i] = y; - break; +/* + the c++ compiler doesn't support setting up an array like, + we'll have to do it during runtime using a function & this messy setup +*/ + +#ifndef RGFW_CUSTOM_BACKEND + +#if !defined(__cplusplus) && !defined(RGFW_C89) +#define RGFW_NEXT , +#define RGFW_MAP +#else +#define RGFW_NEXT ; +#define RGFW_MAP RGFW_keycodes +#endif + +u32 RGFW_apiKeycodes[RGFW_keyLast] = { 0 }; + +u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(256, 512, 128, 256)] = { +#if defined(__cplusplus) || defined(RGFW_C89) + 0 +}; +void RGFW_init_keys(void); +void RGFW_init_keys(void) { +#endif + RGFW_MAP [RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] = RGFW_backtick RGFW_NEXT + + RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x00B, 29, DOM_VK_0)] = RGFW_0 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x002, 18, DOM_VK_1)] = RGFW_1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x003, 19, DOM_VK_2)] = RGFW_2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x004, 20, DOM_VK_3)] = RGFW_3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x005, 21, DOM_VK_4)] = RGFW_4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x006, 23, DOM_VK_5)] = RGFW_5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x007, 22, DOM_VK_6)] = RGFW_6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x008, 26, DOM_VK_7)] = RGFW_7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x009, 28, DOM_VK_8)] = RGFW_8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x00A, 25, DOM_VK_9)] = RGFW_9, + RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x039, 49, DOM_VK_SPACE)] = RGFW_space, + RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x01E, 0, DOM_VK_A)] = RGFW_a RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x030, 11, DOM_VK_B)] = RGFW_b RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x02E, 8, DOM_VK_C)] = RGFW_c RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x020, 2, DOM_VK_D)] = RGFW_d RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x012, 14, DOM_VK_E)] = RGFW_e RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x021, 3, DOM_VK_F)] = RGFW_f RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x022, 5, DOM_VK_G)] = RGFW_g RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x023, 4, DOM_VK_H)] = RGFW_h RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x017, 34, DOM_VK_I)] = RGFW_i RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x024, 38, DOM_VK_J)] = RGFW_j RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x025, 40, DOM_VK_K)] = RGFW_k RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x026, 37, DOM_VK_L)] = RGFW_l RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x032, 46, DOM_VK_M)] = RGFW_m RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x031, 45, DOM_VK_N)] = RGFW_n RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x018, 31, DOM_VK_O)] = RGFW_o RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x019, 35, DOM_VK_P)] = RGFW_p RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x010, 12, DOM_VK_Q)] = RGFW_q RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x013, 15, DOM_VK_R)] = RGFW_r RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x01F, 1, DOM_VK_S)] = RGFW_s RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x014, 17, DOM_VK_T)] = RGFW_t RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x016, 32, DOM_VK_U)] = RGFW_u RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x02F, 9, DOM_VK_V)] = RGFW_v RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x011, 13, DOM_VK_W)] = RGFW_w RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x02D, 7, DOM_VK_X)] = RGFW_x RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x015, 16, DOM_VK_Y)] = RGFW_y RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x02C, 6, DOM_VK_Z)] = RGFW_z, + RGFW_MAP [RGFW_OS_BASED_VALUE(60, 0x034, 47, DOM_VK_PERIOD)] = RGFW_period RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(59, 0x033, 43, DOM_VK_COMMA)] = RGFW_comma RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(61, 0x035, 44, DOM_VK_SLASH)] = RGFW_slash RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(34, 0x01A, 33, DOM_VK_OPEN_BRACKET)] = RGFW_bracket RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(35, 0x01B, 30, DOM_VK_CLOSE_BRACKET)] = RGFW_closeBracket RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(47, 0x027, 41, DOM_VK_SEMICOLON)] = RGFW_semicolon RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(48, 0x028, 39, DOM_VK_QUOTE)] = RGFW_apostrophe RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(51, 0x02B, 42, DOM_VK_BACK_SLASH)] = RGFW_backSlash, + RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x01C, 36, DOM_VK_RETURN)] = RGFW_return RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x153, 118, DOM_VK_DELETE)] = RGFW_delete RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x145, 72, DOM_VK_NUM_LOCK)] = RGFW_numLock RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x135, 82, DOM_VK_DIVIDE)] = RGFW_KP_Slash RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x037, 76, DOM_VK_MULTIPLY)] = RGFW_multiply RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x04A, 67, DOM_VK_SUBTRACT)] = RGFW_KP_Minus RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x04F, 84, DOM_VK_NUMPAD1)] = RGFW_KP_1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x050, 85, DOM_VK_NUMPAD2)] = RGFW_KP_2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x051, 86, DOM_VK_NUMPAD3)] = RGFW_KP_3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x04B, 87, DOM_VK_NUMPAD4)] = RGFW_KP_4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x04C, 88, DOM_VK_NUMPAD5)] = RGFW_KP_5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x04D, 89, DOM_VK_NUMPAD6)] = RGFW_KP_6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x047, 90, DOM_VK_NUMPAD7)] = RGFW_KP_7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x048, 92, DOM_VK_NUMPAD8)] = RGFW_KP_8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x049, 93, DOM_VK_NUMPAD9)] = RGFW_KP_9 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x052, 83, DOM_VK_NUMPAD0)] = RGFW_KP_0 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x053, 65, DOM_VK_DECIMAL)] = RGFW_KP_Period RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x11C, 77, 0)] = RGFW_KP_Return, + RGFW_MAP [RGFW_OS_BASED_VALUE(20, 0x00C, 27, DOM_VK_HYPHEN_MINUS)] = RGFW_minus RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(21, 0x00D, 24, DOM_VK_EQUALS)] = RGFW_equals RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(22, 0x00E, 51, DOM_VK_BACK_SPACE)] = RGFW_backSpace RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x00F, 48, DOM_VK_TAB)] = RGFW_tab RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(66, 0x03A, 57, DOM_VK_CAPS_LOCK)] = RGFW_capsLock RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x02A, 56, DOM_VK_SHIFT)] = RGFW_shiftL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL)] = RGFW_controlL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT)] = RGFW_altL RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN)] = RGFW_superL, + #if !defined(RGFW_MACOS) && !defined(RGFW_WASM) + RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0)] = RGFW_controlR RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(134, 0x15C, 55, 0)] = RGFW_superR, + RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0)] = RGFW_shiftR RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(108, 0x138, 58, 0)] = RGFW_altR, + #endif + RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x03B, 127, DOM_VK_F1)] = RGFW_F1 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x03C, 121, DOM_VK_F2)] = RGFW_F2 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x03D, 100, DOM_VK_F3)] = RGFW_F3 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x03E, 119, DOM_VK_F4)] = RGFW_F4 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x03F, 97, DOM_VK_F5)] = RGFW_F5 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x040, 98, DOM_VK_F6)] = RGFW_F6 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x041, 99, DOM_VK_F7)] = RGFW_F7 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x042, 101, DOM_VK_F8)] = RGFW_F8 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x043, 102, DOM_VK_F9)] = RGFW_F9 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x044, 110, DOM_VK_F10)] = RGFW_F10 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x057, 104, DOM_VK_F11)] = RGFW_F11 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x058, 111, DOM_VK_F12)] = RGFW_F12 RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x148, 126, DOM_VK_UP)] = RGFW_up RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x150, 125, DOM_VK_DOWN)] = RGFW_down RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x14B, 123, DOM_VK_LEFT)] = RGFW_left RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x14D, 124, DOM_VK_RIGHT)] = RGFW_right RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x152, 115, DOM_VK_INSERT)] = RGFW_insert RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x14F, 120, DOM_VK_END)] = RGFW_end RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(112, 0x149, 117, DOM_VK_PAGE_UP)] = RGFW_pageUp RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN)] = RGFW_pageDown RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE)] = RGFW_escape RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME)] = RGFW_home RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(78, 0x046, 107, DOM_VK_SCROLL_LOCK)] = RGFW_scrollLock RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(107, 0x137, 105, DOM_VK_PRINTSCREEN)] = RGFW_printScreen RGFW_NEXT + RGFW_MAP [RGFW_OS_BASED_VALUE(128, 0x045, 113, DOM_VK_PAUSE)] = RGFW_pause RGFW_NEXT +#if defined(__cplusplus) || defined(RGFW_C89) +} +#else +}; +#endif + +#undef RGFW_NEXT +#undef RGFW_MAP + +u32 RGFW_apiKeyToRGFW(u32 keycode) { + #if defined(__cplusplus) || defined(RGFW_C89) + if (RGFW_keycodes[RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] != RGFW_backtick) { + RGFW_init_keys(); + } + #endif + + /* make sure the key isn't out of bounds */ + if (keycode > sizeof(RGFW_keycodes) / sizeof(u8)) + return 0; + + return RGFW_keycodes[keycode]; +} + +u32 RGFW_rgfwToApiKey(u32 keycode) { + if (RGFW_apiKeycodes[RGFW_backtick] != RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)) { + for (u32 i = 0; i < RGFW_keyLast; i++) { + for (u32 y = 0; y < sizeof(RGFW_keycodes); y++) { + if (RGFW_keycodes[y] == i) { + RGFW_apiKeycodes[i] = y; + break; + } } } } - - RGFW_resetKey(); -} - -u32 RGFW_apiKeyToRGFW(u32 keycode) { - /* make sure the key isn't out of bounds */ - if (keycode > sizeof(_RGFW->keycodes) / sizeof(u8)) - return 0; - - return _RGFW->keycodes[keycode]; -} - -u32 RGFW_rgfwToApiKey(u32 keycode) { /* make sure the key isn't out of bounds */ - if (keycode > sizeof(_RGFW->apiKeycodes) / sizeof(u32)) + if (keycode > sizeof(RGFW_apiKeycodes) / sizeof(u32)) return 0; - return _RGFW->apiKeycodes[keycode]; + return RGFW_apiKeycodes[keycode]; } +#endif /* RGFW_CUSTOM_BACKEND */ -void RGFW_resetKey(void) { RGFW_MEMSET(_RGFW->keyboard, 0, sizeof(_RGFW->keyboard)); } +typedef struct { + RGFW_bool current : 1; + RGFW_bool prev : 1; +} RGFW_keyState; + +RGFW_keyState RGFW_keyboard[RGFW_keyLast] = { {0, 0} }; + +RGFWDEF void RGFW_resetKeyPrev(void); +void RGFW_resetKeyPrev(void) { + size_t i; /*!< reset each previous state */ + for (i = 0; i < RGFW_keyLast; i++) RGFW_keyboard[i].prev = 0; +} +RGFWDEF void RGFW_resetKey(void); +void RGFW_resetKey(void) { RGFW_MEMSET(RGFW_keyboard, 0, sizeof(RGFW_keyboard)); } /* this is the end of keycode data */ +/* gamepad data */ +RGFW_keyState RGFW_gamepadPressed[4][32]; /*!< if a key is currently pressed or not (per gamepad) */ +RGFW_point RGFW_gamepadAxes[4][4]; /*!< if a key is currently pressed or not (per gamepad) */ + +RGFW_gamepadType RGFW_gamepads_type[4]; /*!< if a key is currently pressed or not (per gamepad) */ +i32 RGFW_gamepads[4] = {0, 0, 0, 0}; /*!< limit of 4 gamepads at a time */ +char RGFW_gamepads_name[4][128]; /*!< gamepad names */ +u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */ + /* event callback defines start here */ @@ -3094,101 +1854,79 @@ void RGFW_resetKey(void) { RGFW_MEMSET(_RGFW->keyboard, 0, sizeof(_RGFW->keyboar RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning */ +static void RGFW_windowMovedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } +static void RGFW_windowResizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } +static void RGFW_windowRestoredfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } +static void RGFW_windowMinimizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } +static void RGFW_windowMaximizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } +static void RGFW_windowQuitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); } +static void RGFW_focusfuncEMPTY(RGFW_window* win, RGFW_bool inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);} +static void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_bool status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);} +static void RGFW_mousePosfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_point vector) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(vector);} +static void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} +static void RGFW_windowRefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); } +static void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);} +static void RGFW_mouseButtonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);} +static void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); } +static void RGFW_gamepadAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); RGFW_UNUSED(whichAxis); } +static void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_bool connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);} +static void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} +static void RGFW_scaleUpdatedfuncEMPTY(RGFW_window* win, float scaleX, float scaleY) {RGFW_UNUSED(win); RGFW_UNUSED(scaleX); RGFW_UNUSED(scaleY); } + #define RGFW_CALLBACK_DEFINE(x, x2) \ -RGFW_##x##func RGFW_##x##CallbackSrc = NULL; \ +RGFW_##x##func RGFW_##x##Callback = RGFW_##x##funcEMPTY; \ RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \ - RGFW_##x##func prev = RGFW_##x##CallbackSrc; \ - RGFW_##x##CallbackSrc = func; \ + RGFW_##x##func prev = RGFW_##x##Callback; \ + RGFW_##x##Callback = func; \ return prev; \ } - RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized) -#define RGFW_windowMaximizedCallback(win, x, y, w, h) if (RGFW_windowMaximizedCallbackSrc) RGFW_windowMaximizedCallbackSrc(win, x, y, w, h); - RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized) -#define RGFW_windowMinimizedCallback(w) if (RGFW_windowMinimizedCallbackSrc) RGFW_windowMinimizedCallbackSrc(w); - RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored) -#define RGFW_windowRestoredCallback(win, x, y, w, h) if (RGFW_windowRestoredCallbackSrc) RGFW_windowRestoredCallbackSrc(win, x, y, w, h); - RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved) -#define RGFW_windowMovedCallback(w, x, y) if (RGFW_windowMovedCallbackSrc) RGFW_windowMovedCallbackSrc(w, x, y); - RGFW_CALLBACK_DEFINE(windowResized, WindowResized) -#define RGFW_windowResizedCallback(win, w, h) if (RGFW_windowResizedCallbackSrc) RGFW_windowResizedCallbackSrc(win, w, h); - RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit) -#define RGFW_windowQuitCallback(w) if (RGFW_windowQuitCallbackSrc) RGFW_windowQuitCallbackSrc(w); - RGFW_CALLBACK_DEFINE(mousePos, MousePos) -#define RGFW_mousePosCallback(w, x, y, vecX, vecY) if (RGFW_mousePosCallbackSrc) RGFW_mousePosCallbackSrc(w, x, y, vecX, vecY); - RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh) -#define RGFW_windowRefreshCallback(w) if (RGFW_windowRefreshCallbackSrc) RGFW_windowRefreshCallbackSrc(w); - RGFW_CALLBACK_DEFINE(focus, Focus) -#define RGFW_focusCallback(w, inFocus) if (RGFW_focusCallbackSrc) RGFW_focusCallbackSrc(w, inFocus); - RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify) -#define RGFW_mouseNotifyCallback(w, x, y, status) if (RGFW_mouseNotifyCallbackSrc) RGFW_mouseNotifyCallbackSrc(w, x, y, status); - -RGFW_CALLBACK_DEFINE(dataDrop, DataDrop) -#define RGFW_dataDropCallback(w, files, count) if (RGFW_dataDropCallbackSrc) RGFW_dataDropCallbackSrc(w, files, count); - -RGFW_CALLBACK_DEFINE(dataDrag, DataDrag) -#define RGFW_dataDragCallback(w, x, y) if (RGFW_dataDragCallbackSrc) RGFW_dataDragCallbackSrc(w, x, y); - +RGFW_CALLBACK_DEFINE(dnd, Dnd) +RGFW_CALLBACK_DEFINE(dndInit, DndInit) RGFW_CALLBACK_DEFINE(key, Key) -#define RGFW_keyCallback(w, key, sym, mod, repeat, press) if (RGFW_keyCallbackSrc) RGFW_keyCallbackSrc(w, key, sym, mod, repeat, press); - RGFW_CALLBACK_DEFINE(mouseButton, MouseButton) -#define RGFW_mouseButtonCallback(w, button, press) if (RGFW_mouseButtonCallbackSrc) RGFW_mouseButtonCallbackSrc(w, button, press); - -RGFW_CALLBACK_DEFINE(mouseScroll, MouseScroll) -#define RGFW_mouseScrollCallback(w, x, y) if (RGFW_mouseScrollCallbackSrc) RGFW_mouseScrollCallbackSrc(w, x, y); - +RGFW_CALLBACK_DEFINE(gamepadButton, GamepadButton) +RGFW_CALLBACK_DEFINE(gamepadAxis, GamepadAxis) +RGFW_CALLBACK_DEFINE(gamepad, Gamepad) RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated) -#define RGFW_scaleUpdatedCallback(w, scaleX, scaleY) if (RGFW_scaleUpdatedCallbackSrc) RGFW_scaleUpdatedCallbackSrc(w, scaleX, scaleY); - -RGFW_CALLBACK_DEFINE(debug, Debug) -#define RGFW_debugCallback(type, err, msg) if (RGFW_debugCallbackSrc) RGFW_debugCallbackSrc(type, err, msg); #undef RGFW_CALLBACK_DEFINE -#ifdef RGFW_DEBUG -#include -#endif +void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) { + RGFW_window_eventWait(win, waitMS); -void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, const char* msg) { - RGFW_debugCallback(type, err, msg); - - #ifdef RGFW_DEBUG - switch (type) { - case RGFW_typeInfo: RGFW_PRINTF("RGFW INFO (%i %i): %s", type, err, msg); break; - case RGFW_typeError: RGFW_PRINTF("RGFW DEBUG (%i %i): %s", type, err, msg); break; - case RGFW_typeWarning: RGFW_PRINTF("RGFW WARNING (%i %i): %s", type, err, msg); break; - default: break; + while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) { + if (win->event.type == RGFW_quit) return; } - RGFW_PRINTF("\n"); + #ifdef RGFW_WASM /* WASM needs to run the sleep function for asyncify */ + RGFW_sleep(0); #endif } void RGFW_window_checkMode(RGFW_window* win); void RGFW_window_checkMode(RGFW_window* win) { - if (RGFW_window_isMinimized(win) && (win->internal.enabledEvents & RGFW_windowMinimizedFlag)) { - win->internal.flags |= RGFW_windowMinimize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); - RGFW_windowMinimizedCallback(win); - } else if (RGFW_window_isMaximized(win) && (win->internal.enabledEvents & RGFW_windowMaximizedFlag)) { - win->internal.flags |= RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); - RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h); - } else if ((((win->internal.flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) || - (win->internal.flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) && (win->internal.enabledEvents & RGFW_windowRestoredFlag)) { - win->internal.flags &= ~(u32)RGFW_windowMinimize; - if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->internal.flags &= ~(u32)RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); - RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); + if (RGFW_window_isMinimized(win)) { + win->_flags |= RGFW_windowMinimize; + RGFW_windowMinimizedCallback(win, win->r); + } else if (RGFW_window_isMaximized(win)) { + win->_flags |= RGFW_windowMaximize; + RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win); + RGFW_windowMaximizedCallback(win, win->r); + } else if (((win->_flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) || + (win->_flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) { + win->_flags &= ~(u32)RGFW_windowMinimize; + if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->_flags &= ~(u32)RGFW_windowMaximize; + RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); + RGFW_windowRestoredCallback(win, win->r); } } @@ -3196,359 +1934,173 @@ void RGFW_window_checkMode(RGFW_window* win) { no more event call back defines */ -size_t RGFW_sizeofInfo(void) { return sizeof(RGFW_info); } -size_t RGFW_sizeofNativeImage(void) { return sizeof(RGFW_nativeImage); } -size_t RGFW_sizeofSurface(void) { return sizeof(RGFW_surface); } -size_t RGFW_sizeofWindow(void) { return sizeof(RGFW_window); } -size_t RGFW_sizeofWindowSrc(void) { return sizeof(RGFW_window_src); } +#define SET_ATTRIB(a, v) { \ + RGFW_ASSERT(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ + attribs[index++] = a; \ + attribs[index++] = v; \ +} -RGFW_window_src* RGFW_window_getSrc(RGFW_window* win) { return &win->src; } -RGFW_bool RGFW_window_getPosition(RGFW_window* win, i32* x, i32* y) { if (x) *x = win->x; if (y) *y = win->y; return RGFW_TRUE; } -RGFW_bool RGFW_window_getSize(RGFW_window* win, i32* w, i32* h) { if (w) *w = win->w; if (h) *h = win->h; return RGFW_TRUE; } -u32 RGFW_window_getFlags(RGFW_window* win) { return win->internal.flags; } -RGFW_key RGFW_window_getExitKey(RGFW_window* win) { return win->internal.exitKey; } -void RGFW_window_setExitKey(RGFW_window* win, RGFW_key key) { win->internal.exitKey = key; } -void RGFW_window_setEnabledEvents(RGFW_window* win, RGFW_eventFlag events) { win->internal.enabledEvents = events; } -RGFW_eventFlag RGFW_window_getEnabledEvents(RGFW_window* win) { return win->internal.enabledEvents; } -void RGFW_window_setDisabledEvents(RGFW_window* win, RGFW_eventFlag events) { RGFW_window_setEnabledEvents(win, (RGFW_allEventFlags) & ~(u32)events); } -void RGFW_window_setEventState(RGFW_window* win, RGFW_eventFlag event, RGFW_bool state) { RGFW_setBit(&win->internal.enabledEvents, event, state); } -void* RGFW_window_getUserPtr(RGFW_window* win) { return win->userPtr; } -void RGFW_window_setUserPtr(RGFW_window* win, void* ptr) { win->userPtr = ptr; } +#define RGFW_EVENT_PASSED RGFW_BIT(24) /* if a queued event was passed */ +#define RGFW_EVENT_QUIT RGFW_BIT(25) /* the window close button was pressed */ +#define RGFW_HOLD_MOUSE RGFW_BIT(26) /*!< hold the moues still */ +#define RGFW_MOUSE_LEFT RGFW_BIT(27) /* if mouse left the window */ +#define RGFW_WINDOW_ALLOC RGFW_BIT(28) /* if window was allocated by RGFW */ +#define RGFW_BUFFER_ALLOC RGFW_BIT(29) /* if window.buffer was allocated by RGFW */ +#define RGFW_WINDOW_INIT RGFW_BIT(30) /* if window.buffer was allocated by RGFW */ +#define RGFW_INTERNAL_FLAGS (RGFW_EVENT_QUIT | RGFW_EVENT_PASSED | RGFW_HOLD_MOUSE | RGFW_MOUSE_LEFT | RGFW_WINDOW_ALLOC | RGFW_BUFFER_ALLOC | RGFW_windowFocus) +RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlags flags) { + RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window)); + RGFW_ASSERT(win != NULL); + win->_flags = RGFW_WINDOW_ALLOC; + return RGFW_createWindowPtr(name, rect, flags, win); +} #if defined(RGFW_USE_XDL) && defined(RGFW_X11) #define XDL_IMPLEMENTATION #include "XDL.h" #endif -#ifndef RGFW_FORCE_INIT -RGFW_info _rgfwGlobal; +#define RGFW_MAX_EVENTS 32 +typedef struct RGFW_globalStruct { + RGFW_window* root; + RGFW_window* current; + i32 windowCount; + i32 eventLen; + i32 eventIndex; + + #ifdef RGFW_X11 + Display* display; + Window helperWindow; + char* clipboard; /* for writing to the clipboard selection */ + size_t clipboard_len; + #endif + #ifdef RGFW_WAYLAND + struct wl_display* wl_display; + #endif + #if defined(RGFW_X11) || defined(RGFW_WINDOWS) || defined(RGFW_WAYLAND) + RGFW_mouse* hiddenMouse; + #endif + RGFW_event events[RGFW_MAX_EVENTS]; + +} RGFW_globalStruct; +#if !defined(RGFW_C89) && !defined(__cplusplus) +RGFW_globalStruct _RGFW = {.root = NULL, .current = NULL, .windowCount = -1, .eventLen = 0, .eventIndex = 0}; +#define _RGFW_init RGFW_TRUE +#else +RGFW_bool _RGFW_init = RGFW_FALSE; +RGFW_globalStruct _RGFW; #endif -i32 RGFW_init(void) { return RGFW_init_ptr(&_rgfwGlobal); } -void RGFW_deinit(void) { RGFW_deinit_ptr(&_rgfwGlobal); } - -i32 RGFW_initPlatform(void); -void RGFW_deinitPlatform(void); - -i32 RGFW_init_ptr(RGFW_info* info) { - if (info == _RGFW || info == NULL) return 1; - - RGFW_setInfo(info); - RGFW_MEMSET(_RGFW, 0, sizeof(RGFW_info)); - _RGFW->queueEvents = RGFW_FALSE; - _RGFW->polledEvents = RGFW_FALSE; -#ifdef RGFW_WAYLAND - _RGFW->useWaylandBool = RGFW_TRUE; -#endif - - _RGFW->files = (char**)(void*)_RGFW->filesSrc; - u32 i; - for (i = 0; i < RGFW_MAX_DROPS; i++) - _RGFW->files[i] = (char*)(_RGFW->filesSrc + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH)); - - _RGFW->monitors.freeList.head = &_RGFW->monitors.data[0]; - _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.head; - - for (i = 1; i < RGFW_MAX_MONITORS; i++) { - RGFW_monitorNode* newNode = &_RGFW->monitors.data[i]; - _RGFW->monitors.freeList.cur->next = newNode; - _RGFW->monitors.freeList.cur = _RGFW->monitors.freeList.cur->next; - } - - RGFW_initKeycodes(); - i32 out = RGFW_initPlatform(); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context initialized"); - - return out; -} - -#ifndef RGFW_EGL -void RGFW_unloadEGL(void) { } -#endif - -void RGFW_deinit_ptr(RGFW_info* info) { - if (info == NULL) return; - - RGFW_setInfo(info); - RGFW_unloadEGL(); - RGFW_deinitPlatform(); - - _RGFW->root = NULL; - _RGFW->windowCount = 0; - RGFW_setInfo(NULL); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized"); -} - -RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags) { - RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window)); - RGFW_ASSERT(win != NULL); - return RGFW_createWindowPtr(name, x, y, w, h, flags, win); -} - -void RGFW_window_close(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_window_closePtr(win); - RGFW_FREE(win); -} - -RGFW_window* RGFW_createWindowPtr(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags, RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_MEMSET(win, 0, sizeof(RGFW_window)); - if (_RGFW == NULL) RGFW_init(); - _RGFW->windowCount++; - - /* rect based the requested flags */ - if (_RGFW->root == NULL) { - RGFW_setRootWindow(win); - } - - /* set and init the new window's data */ - win->x = x; - win->y = y; - win->w = w; - win->h = h; - win->internal.flags = flags; - win->internal.enabledEvents = RGFW_allEventFlags; - - RGFW_window* ret = RGFW_createWindowPlatform(name, flags, win); - -#ifndef RGFW_X11 - RGFW_window_setFlagsInternal(win, flags, 0); -#endif - -#ifdef RGFW_OPENGL - win->src.gfxType = 0; - if (flags & RGFW_windowOpenGL) - RGFW_window_createContext_OpenGL(win, RGFW_getGlobalHints_OpenGL()); -#endif - -#ifdef RGFW_EGL - if (flags & RGFW_windowEGL) - RGFW_window_createContext_EGL(win, RGFW_getGlobalHints_OpenGL()); -#endif - - /* X11 creates the window after the OpenGL context is created (because of visual garbage), - * so we have to wait to set the flags - * This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used - * if a window is crated, CreateContext will delete the window and create a new one - * */ -#ifdef RGFW_X11 - RGFW_window_setFlagsInternal(win, flags, 0); -#endif - -#ifdef RGFW_MACOS - /*NOTE: another OpenGL/setFlags related hack, this because OSX the 'view' class must be setup after the NSOpenGL view is made AND after setFlags happens */ - RGFW_osx_initView(win); -#endif - -#ifdef RGFW_WAYLAND - /* recieve all events needed to configure the surface */ - /* also gets the wl_outputs */ - if (RGFW_usingWayland()) { - wl_display_roundtrip(_RGFW->wl_display); - /* NOTE: this is a hack so that way wayland spawns a window, even if nothing is drawn */ - if (!(flags & RGFW_windowOpenGL) && !(flags & RGFW_windowEGL)) { - u8* data = (u8*)RGFW_ALLOC((u32)(win->w * win->h * 3)); - RGFW_MEMSET(data, 0, (u32)(win->w * win->h * 3) * sizeof(u8)); - RGFW_surface* surface = RGFW_createSurface(data, win->w, win->h, RGFW_formatBGR8); - RGFW_window_blitSurface(win, surface); - RGFW_FREE(data); - RGFW_surface_free(surface); - } - } -#endif - - RGFW_window_setMouseDefault(win); - RGFW_window_setName(win, name); - if (!(flags & RGFW_windowHide)) { - RGFW_window_show(win); - } - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a new window was created"); - - - return ret; -} - -void RGFW_window_closePtr(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - #ifdef RGFW_EGL - if ((win->src.gfxType & RGFW_gfxEGL) && win->src.ctx.egl) { - RGFW_window_deleteContext_EGL(win, win->src.ctx.egl); - win->src.ctx.egl = NULL; - } - #endif - - #ifdef RGFW_OPENGL - if ((win->src.gfxType & RGFW_gfxNativeOpenGL) && win->src.ctx.native) { - RGFW_window_deleteContext_OpenGL(win, win->src.ctx.native); - win->src.ctx.native = NULL; - } - #endif - - RGFW_window_closePlatform(win); - - RGFW_clipboard_switch(NULL); - _RGFW->windowCount--; - if (_RGFW->windowCount == 0) RGFW_deinit(); - - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed"); -} - -void RGFW_setQueueEvents(RGFW_bool queue) { _RGFW->queueEvents = RGFW_BOOL(queue); } - -void RGFW_eventQueueFlush(void) { _RGFW->eventLen = 0; } - -void RGFW_eventQueuePush(const RGFW_event* event) { - if (_RGFW->queueEvents == RGFW_FALSE) return; - RGFW_ASSERT(_RGFW->eventLen >= 0); - - if (_RGFW->eventLen >= RGFW_MAX_EVENTS) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEventQueue, "Event queue limit 'RGFW_MAX_EVENTS' has been reached automatically flushing queue."); - RGFW_eventQueueFlush(); - return; - } - - i32 eventTop = (_RGFW->eventBottom + _RGFW->eventLen) % RGFW_MAX_EVENTS; - _RGFW->eventLen += 1; - _RGFW->events[eventTop] = *event; +void RGFW_eventQueuePush(RGFW_event event) { + if (_RGFW.eventLen >= RGFW_MAX_EVENTS) return; + _RGFW.events[_RGFW.eventLen] = event; + _RGFW.eventLen++; } RGFW_event* RGFW_eventQueuePop(RGFW_window* win) { - RGFW_ASSERT(_RGFW->eventLen >= 0 && _RGFW->eventLen <= RGFW_MAX_EVENTS); - RGFW_event* ev; + RGFW_event* ev; + if (_RGFW.eventLen == 0) return NULL; - if (_RGFW->eventLen == 0) { - return NULL; - } - - ev = &_RGFW->events[_RGFW->eventBottom]; - _RGFW->eventLen -= 1; - _RGFW->eventBottom = (_RGFW->eventBottom + 1) % RGFW_MAX_EVENTS; - - if (ev->common.win != win && ev->common.win != NULL) { - RGFW_eventQueuePush(ev); - return NULL; + ev = (RGFW_event*)&_RGFW.events[_RGFW.eventIndex]; + + _RGFW.eventLen--; + if (_RGFW.eventLen >= 0 && _RGFW.eventIndex < _RGFW.eventLen) { + _RGFW.eventIndex++; + } else if (_RGFW.eventLen == 0) { + _RGFW.eventIndex = 0; + } + + if (ev->_win != win && ev->_win != NULL) { + RGFW_eventQueuePush(*ev); + return NULL; } + ev->droppedFilesCount = win->event.droppedFilesCount; + ev->droppedFiles = win->event.droppedFiles; return ev; } -void RGFW_resetPrevState(void) { - size_t i; /*!< reset each previous state */ - for (i = 0; i < RGFW_keyLast; i++) _RGFW->keyboard[i].prev = _RGFW->keyboard[i].current; - for (i = 0; i < RGFW_mouseFinal; i++) _RGFW->mouseButtons[i].prev = _RGFW->mouseButtons[i].current; - _RGFW->scrollX = 0.0f; - _RGFW->scrollY = 0.0f; - _RGFW->vectorX = (float)0.0f; - _RGFW->vectorY = (float)0.0f; - RGFW_MEMSET(&_RGFW->windowState, 0, sizeof(_RGFW->windowState)); -} - -RGFW_bool RGFW_isKeyPressed(RGFW_key key) { - return _RGFW != NULL && _RGFW->keyboard[key].current && !_RGFW->keyboard[key].prev; -} - -RGFW_bool RGFW_isKeyDown(RGFW_key key) { - return _RGFW != NULL && _RGFW->keyboard[key].current; -} - -RGFW_bool RGFW_isKeyReleased(RGFW_key key) { - return _RGFW != NULL && !_RGFW->keyboard[key].current && _RGFW->keyboard[key].prev; -} - - -RGFW_bool RGFW_isMousePressed(RGFW_mouseButton button) { - return _RGFW != NULL && _RGFW->mouseButtons[button].current && !_RGFW->mouseButtons[button].prev; -} -RGFW_bool RGFW_isMouseDown(RGFW_mouseButton button) { - return _RGFW != NULL && _RGFW->mouseButtons[button].current; -} -RGFW_bool RGFW_isMouseReleased(RGFW_mouseButton button) { - return _RGFW != NULL && !_RGFW->mouseButtons[button].current && _RGFW->mouseButtons[button].prev; -} - -void RGFW_getMouseScroll(float* x, float* y) { - RGFW_ASSERT(_RGFW != NULL); - if (x) *x = _RGFW->scrollX; - if (y) *y = _RGFW->scrollY; -} - -void RGFW_getMouseVector(float* x, float* y) { - RGFW_ASSERT(_RGFW != NULL); - if (x) *x = _RGFW->vectorX; - if (y) *y = _RGFW->vectorY; -} - -RGFW_bool RGFW_window_didMouseLeave(RGFW_window* win) { return _RGFW->windowState.winLeave == win && _RGFW->windowState.mouseLeave; } -RGFW_bool RGFW_window_didMouseEnter(RGFW_window* win) { return _RGFW->windowState.win == win && _RGFW->windowState.mouseEnter; } -RGFW_bool RGFW_window_isMouseInside(RGFW_window* win) { return win->internal.mouseInside; } - -RGFW_bool RGFW_window_isDataDragging(RGFW_window* win) { return RGFW_window_getDataDrag(win, (i32*)NULL, (i32*)NULL); } -RGFW_bool RGFW_window_didDataDrop(RGFW_window* win) { return RGFW_window_getDataDrop(win, (const char***)NULL, (size_t*)NULL);} - - -RGFW_bool RGFW_window_getDataDrag(RGFW_window* win, i32* x, i32* y) { - if (_RGFW->windowState.win != win || _RGFW->windowState.dataDragging == RGFW_FALSE) return RGFW_FALSE; - if (x) *x = _RGFW->windowState.dropX; - if (y) *y = _RGFW->windowState.dropY; - return RGFW_TRUE; -} -RGFW_bool RGFW_window_getDataDrop(RGFW_window* win, const char*** files, size_t* count) { - if (_RGFW->windowState.win != win || _RGFW->windowState.dataDrop == RGFW_FALSE) return RGFW_FALSE; - if (files) *files = (const char**)_RGFW->files; - if (count) *count = _RGFW->windowState.filesCount; - return RGFW_TRUE; -} - -RGFW_bool RGFW_window_checkEvent(RGFW_window* win, RGFW_event* event) { - if (_RGFW->eventLen == 0 && _RGFW->polledEvents == RGFW_FALSE) { - _RGFW->queueEvents = RGFW_TRUE; - RGFW_pollEvents(); - _RGFW->polledEvents = RGFW_TRUE; - } - - if (RGFW_window_checkQueuedEvent(win, event) == RGFW_FALSE) { - _RGFW->polledEvents = RGFW_FALSE; - return RGFW_FALSE; - } - - return RGFW_TRUE; -} - -RGFW_bool RGFW_window_checkQueuedEvent(RGFW_window* win, RGFW_event* event) { +RGFW_event* RGFW_window_checkEventCore(RGFW_window* win); +RGFW_event* RGFW_window_checkEventCore(RGFW_window* win) { RGFW_event* ev; - RGFW_ASSERT(win != NULL); - _RGFW->queueEvents = RGFW_TRUE; + RGFW_ASSERT(win != NULL); + if (win->event.type == 0 && _RGFW.eventLen == 0) + RGFW_resetKeyPrev(); + + if (win->event.type == RGFW_quit && win->_flags & RGFW_windowFreeOnClose) { + static RGFW_event event; + event = win->event; + RGFW_window_close(win); + return &event; + } + + if (win->event.type != RGFW_DNDInit) win->event.type = 0; + /* check queued events */ ev = RGFW_eventQueuePop(win); if (ev != NULL) { if (ev->type == RGFW_quit) RGFW_window_setShouldClose(win, RGFW_TRUE); - *event = *ev; - return RGFW_TRUE; + win->event = *ev; } + else return NULL; - return RGFW_FALSE; + return &win->event; } -void RGFW_setRootWindow(RGFW_window* win) { _RGFW->root = win; } -RGFW_window* RGFW_getRootWindow(void) { return _RGFW->root; } -#ifndef RGFW_EGL -RGFW_bool RGFW_loadEGL(void) { return RGFW_FALSE; } -#endif +RGFWDEF void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags); +void RGFW_setRootWindow(RGFW_window* win) { _RGFW.root = win; } +RGFW_window* RGFW_getRootWindow(void) { return _RGFW.root; } + +/* do a basic initialization for RGFW_window, this is to standard it for each OS */ +void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags) { + RGFW_UNUSED(flags); + if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init(); + _RGFW.windowCount++; + + /* rect based the requested flags */ + if (_RGFW.root == NULL) { + RGFW_setRootWindow(win); + RGFW_setTime(0); + } + + if (!(win->_flags & RGFW_WINDOW_ALLOC)) win->_flags = 0; + + /* set and init the new window's data */ + win->r = rect; + win->exitKey = RGFW_escape; + win->event.droppedFilesCount = 0; + + win->_flags = 0 | (win->_flags & RGFW_WINDOW_ALLOC); + win->_flags |= flags; + win->event.keyMod = 0; + win->_lastMousePoint.x = 0; + win->_lastMousePoint.y = 0; + + win->event.droppedFiles = (char**)RGFW_ALLOC(RGFW_MAX_PATH * RGFW_MAX_DROPS); + RGFW_ASSERT(win->event.droppedFiles != NULL); + + { + u32 i; + for (i = 0; i < RGFW_MAX_DROPS; i++) + win->event.droppedFiles[i] = (char*)(win->event.droppedFiles + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH)); + } +} + +void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { + RGFW_windowFlags cmpFlags = win->_flags; + if (win->_flags & RGFW_WINDOW_INIT) cmpFlags = 0; -void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW_windowFlags cmpFlags) { #ifndef RGFW_NO_MONITOR if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); #endif if (flags & RGFW_windowCenter) RGFW_window_center(win); - if (flags & RGFW_windowCenterCursor) RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); + if (flags & RGFW_windowCenterCursor) + RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0); - else if (cmpFlags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 1); + else RGFW_window_setBorder(win, 1); if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE); else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0); if (flags & RGFW_windowMaximize) RGFW_window_maximize(win); @@ -3559,97 +2111,153 @@ void RGFW_window_setFlagsInternal(RGFW_window* win, RGFW_windowFlags flags, RGFW else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1); if (flags & RGFW_windowHide) RGFW_window_hide(win); else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win); + if (flags & RGFW_windowCocoaCHDirToRes) RGFW_moveToMacOSResourceDir(); if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1); else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0); if (flags & RGFW_windowFocus) RGFW_window_focus(win); if (flags & RGFW_windowNoResize) { - RGFW_window_setMaxSize(win, win->w, win->h); - RGFW_window_setMinSize(win, win->w, win->h); + RGFW_window_setMaxSize(win, RGFW_AREA(win->r.w, win->r.h)); + RGFW_window_setMinSize(win, RGFW_AREA(win->r.w, win->r.h)); } else if (cmpFlags & RGFW_windowNoResize) { - RGFW_window_setMaxSize(win, 0, 0); - RGFW_window_setMinSize(win, 0, 0); + RGFW_window_setMaxSize(win, RGFW_AREA(0, 0)); + RGFW_window_setMinSize(win, RGFW_AREA(0, 0)); } - win->internal.flags = flags; + win->_flags = flags | (win->_flags & RGFW_INTERNAL_FLAGS); } - -void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) { RGFW_window_setFlagsInternal(win, flags, win->internal.flags); } +RGFW_bool RGFW_window_opengl_isSoftware(RGFW_window* win) { + return RGFW_BOOL(win->_flags |= RGFW_windowOpenglSoftware); +} RGFW_bool RGFW_window_isInFocus(RGFW_window* win) { #ifdef RGFW_WASM return RGFW_TRUE; #else - return RGFW_BOOL(win->internal.inFocus); + return RGFW_BOOL(win->_flags & RGFW_windowFocus); #endif } -void RGFW_setClassName(const char* name) { RGFW_init(); _RGFW->className = name; } +void RGFW_window_initBuffer(RGFW_window* win) { + RGFW_area area = RGFW_getScreenSize(); + if ((win->_flags & RGFW_windowNoResize)) + area = RGFW_AREA(win->r.w, win->r.h); + + RGFW_window_initBufferSize(win, area); +} + +void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area) { +#if defined(RGFW_BUFFER) || defined(RGFW_OSMESA) + win->_flags |= RGFW_BUFFER_ALLOC; + #ifndef RGFW_WINDOWS + u8* buffer = (u8*)RGFW_ALLOC(area.w * area.h * 4); + RGFW_ASSERT(buffer != NULL); + + RGFW_window_initBufferPtr(win, buffer, area); + #else /* windows's bitmap allocs memory for us */ + RGFW_window_initBufferPtr(win, (u8*)NULL, area); + #endif +#else + RGFW_UNUSED(win); RGFW_UNUSED(area); +#endif +} + +#ifdef RGFW_MACOS +RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer); +RGFWDEF void* RGFW_cocoaGetLayer(void); +#endif + +const char* RGFW_className = NULL; +void RGFW_setClassName(const char* name) { RGFW_className = name; } #ifndef RGFW_X11 void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); } #endif -RGFW_bool RGFW_window_getMouse(RGFW_window* win, i32* x, i32* y) { - RGFW_ASSERT(win != NULL); - if (x) *x = win->internal.lastMouseX; - if (y) *y = win->internal.lastMouseY; - return RGFW_TRUE; +RGFW_keyState RGFW_mouseButtons[RGFW_mouseFinal] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }; + +RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { + return RGFW_mouseButtons[button].current && (win == NULL || RGFW_window_isInFocus(win)); +} +RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) { + return RGFW_mouseButtons[button].prev && (win != NULL || RGFW_window_isInFocus(win)); +} +RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) { + return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); +} +RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { + return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); } -RGFW_bool RGFW_window_isKeyPressed(RGFW_window* win, RGFW_key key) { return RGFW_isKeyPressed(key) && RGFW_window_isInFocus(win); } -RGFW_bool RGFW_window_isKeyDown(RGFW_window* win, RGFW_key key) { return RGFW_isKeyDown(key) && RGFW_window_isInFocus(win); } -RGFW_bool RGFW_window_isKeyReleased(RGFW_window* win, RGFW_key key) { return RGFW_isKeyReleased(key) && RGFW_window_isInFocus(win); } +RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + return win->_lastMousePoint; +} -RGFW_bool RGFW_window_isMousePressed(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMousePressed(button) && RGFW_window_isInFocus(win); } -RGFW_bool RGFW_window_isMouseDown(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseDown(button) && RGFW_window_isInFocus(win); } -RGFW_bool RGFW_window_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) { return RGFW_isMouseReleased(button) && RGFW_window_isInFocus(win); } +RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key) { + return RGFW_keyboard[key].current && (win == NULL || RGFW_window_isInFocus(win)); +} +RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key) { + return RGFW_keyboard[key].prev && (win == NULL || RGFW_window_isInFocus(win)); +} +RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key) { + return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); +} -#ifndef RGFW_X11 -void* RGFW_getDisplay_X11(void) { return NULL; } -u64 RGFW_window_getWindow_X11(RGFW_window* win) { RGFW_UNUSED(win); return 0; } +RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key) { + return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key)); +} + +RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key) { + return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); +} + +void RGFW_window_makeCurrent(RGFW_window* win) { + _RGFW.current = win; +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) + RGFW_window_makeCurrent_OpenGL(win); #endif +} -#ifndef RGFW_WAYLAND -struct wl_display* RGFW_getDisplay_Wayland(void) { return NULL; } -struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } +RGFW_window* RGFW_getCurrent(void) { + return _RGFW.current; +} + +void RGFW_window_swapBuffers(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + RGFW_window_swapBuffers_software(win); +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) + RGFW_window_swapBuffers_OpenGL(win); #endif +} -#ifndef RGFW_WINDOWS -void* RGFW_window_getHWND(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } -void* RGFW_window_getHDC(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } -#endif - -#ifndef RGFW_MACOS -void* RGFW_window_getView_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } -void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) { RGFW_UNUSED(win); RGFW_UNUSED(layer); } -void* RGFW_getLayer_OSX(void) { return NULL; } -void* RGFW_window_getWindow_OSX(RGFW_window* win) { RGFW_UNUSED(win); return NULL; } -#endif - -void RGFW_setBit(u32* var, u32 mask, RGFW_bool set) { - if (set) *var |= mask; - else *var &= ~mask; +RGFWDEF void RGFW_setBit(u32* data, u32 bit, RGFW_bool value); +void RGFW_setBit(u32* data, u32 bit, RGFW_bool value) { + if (value) + *data |= bit; + else if (!value && (*(data) & bit)) + *data ^= bit; } void RGFW_window_center(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_monitor mon = RGFW_window_getMonitor(win); - RGFW_window_move(win, (i32)(mon.mode.w - win->w) / 2, (mon.mode.h - win->h) / 2); + RGFW_area screenR = RGFW_getScreenSize(); + RGFW_window_move(win, RGFW_POINT((i32)(screenR.w - (u32)win->r.w) / 2, (screenR.h - (u32)win->r.h) / 2)); } RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win) { RGFW_monitorMode mode; RGFW_ASSERT(win != NULL); - mode.w = win->w; - mode.h = win->h; + mode.area.w = (u32)win->r.w; + mode.area.h = (u32)win->r.h; return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale); } +void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode); void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) { if (bpp == 32) bpp = 24; mode->red = mode->green = mode->blue = (u8)(bpp / 3); @@ -3660,21 +2268,21 @@ void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) { } RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) { - return (((mon.w == mon2.w && mon.h == mon2.h) || !(request & RGFW_monitorScale)) && + return (((mon.area.w == mon2.area.w && mon.area.h == mon2.area.h) || !(request & RGFW_monitorScale)) && ((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) && ((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB))); } RGFW_bool RGFW_window_shouldClose(RGFW_window* win) { - return (win == NULL || win->internal.shouldClose || (win->internal.exitKey && RGFW_window_isKeyPressed(win, win->internal.exitKey))); + return (win == NULL || (win->_flags & RGFW_EVENT_QUIT)|| (win->exitKey && RGFW_isPressed(win, win->exitKey))); } void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) { if (shouldClose) { - win->internal.shouldClose = RGFW_TRUE; + win->_flags |= RGFW_EVENT_QUIT; RGFW_windowQuitCallback(win); } else { - win->internal.shouldClose = RGFW_FALSE; + win->_flags &= ~(u32)RGFW_EVENT_QUIT; } } @@ -3684,169 +2292,123 @@ void RGFW_window_scaleToMonitor(RGFW_window* win) { if (monitor.scaleX == 0 && monitor.scaleY == 0) return; - RGFW_window_resize(win, (i32)(monitor.scaleX * (float)win->w), (i32)(monitor.scaleY * (float)win->h)); + RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleY * (float)win->r.h))); } void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) { - RGFW_window_move(win, m.x + win->x, m.y + win->y); + RGFW_window_move(win, RGFW_POINT(m.x + win->r.x, m.y + win->r.y)); } #endif -RGFW_surface* RGFW_createSurface(u8* data, i32 w, i32 h, RGFW_format format) { - RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface)); - RGFW_MEMSET(surface, 0, sizeof(RGFW_surface)); - RGFW_createSurfacePtr(data, w, h, format, surface); - return surface; +RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { + return RGFW_window_setIconEx(win, icon, a, channels, RGFW_iconBoth); } -void RGFW_surface_free(RGFW_surface* surface) { - RGFW_surface_freePtr(surface); - RGFW_FREE(surface); +RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect); +RGFWDEF void RGFW_releaseCursor(RGFW_window* win); + + +RGFW_bool RGFW_window_mouseHeld(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_HOLD_MOUSE); } + +void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) { + if (!area.w && !area.h) + area = RGFW_AREA(win->r.w / 2, win->r.h / 2); + + win->_flags |= RGFW_HOLD_MOUSE; + RGFW_captureCursor(win, win->r); + RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); } -RGFW_nativeImage* RGFW_surface_getNativeImage(RGFW_surface* surface) { - return &surface->native; -} - -RGFW_surface* RGFW_window_createSurface(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) { - RGFW_surface* surface = (RGFW_surface*)RGFW_ALLOC(sizeof(RGFW_surface)); - RGFW_MEMSET(surface, 0, sizeof(RGFW_surface)); - RGFW_window_createSurfacePtr(win, data, w, h, format, surface); - return surface; -} -#ifndef RGFW_X11 -RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { - RGFW_UNUSED(win); - return RGFW_createSurfacePtr(data, w, h, format, surface); -} -#endif - -const RGFW_colorLayout RGFW_layouts[RGFW_formatCount] = { - { 0, 1, 2, 3 }, /* RGFW_formatRGB8 */ - { 2, 1, 0, 3 }, /* RGFW_formatBGR8 */ - { 0, 1, 2, 3 }, /* RGFW_formatRGBA8 */ - { 1, 2, 3, 0 }, /* RGFW_formatARGB8 */ - { 2, 1, 0, 3 }, /* RGFW_formatBGRA8 */ - { 3, 2, 1, 0 }, /* RGFW_formatABGR8 */ -}; - - -void RGFW_copyImageData(u8* dest_data, i32 w, i32 h, RGFW_format dest_format, u8* src_data, RGFW_format src_format) { - RGFW_copyImageData64(dest_data, w, h, dest_format, src_data, src_format, RGFW_FALSE); -} - -void RGFW_copyImageData64(u8* dest_data, i32 dest_w, i32 dest_h, RGFW_format dest_format, u8* src_data, RGFW_format src_format, RGFW_bool is64bit) { - RGFW_ASSERT(dest_data && src_data); - - u32 src_channels = (src_format >= RGFW_formatRGBA8) ? 4 : 3; - u32 dest_channels = (dest_format >= RGFW_formatRGBA8) ? 4 : 3; - - u32 pixel_count = (u32)(dest_w * dest_h); - - if (src_format == dest_format) { - RGFW_MEMCPY(dest_data, src_data, pixel_count * dest_channels); - return; - } - - const RGFW_colorLayout* src_layout = &RGFW_layouts[src_format]; - const RGFW_colorLayout* dest_layout = &RGFW_layouts[dest_format]; - - u32 i, i2 = 0; - for (i = 0; i < pixel_count; i++) { - const u8* src_px = &src_data[i * src_channels]; - u8* dst_px = &dest_data[i2 * dest_channels]; - u8 rgba[4] = {0}; - rgba[0] = src_px[src_layout->r]; - rgba[1] = src_px[src_layout->g]; - rgba[2] = src_px[src_layout->b]; - rgba[3] = 255; - if (src_channels == 4) - rgba[3] = src_px[src_layout->a]; - - dst_px[dest_layout->r] = rgba[0]; - dst_px[dest_layout->g] = rgba[1]; - dst_px[dest_layout->b] = rgba[2]; - if (dest_channels == 4) - dst_px[dest_layout->a] = rgba[3]; - - i2 += 1 + is64bit; - } -} - -RGFW_monitorNode* RGFW_monitors_add(RGFW_monitor mon) { - RGFW_monitorNode* node = NULL; - if (_RGFW->monitors.freeList.head == NULL) return node; - - node = _RGFW->monitors.freeList.head; - mon = node->mon; - - _RGFW->monitors.freeList.head = node->next; - if (_RGFW->monitors.freeList.head == NULL) { - _RGFW->monitors.freeList.cur = NULL; - } - - node->next = NULL; - - if (_RGFW->monitors.list.head == NULL) { - _RGFW->monitors.list.head = node; - } else { - _RGFW->monitors.list.cur->next = node; - } - - _RGFW->monitors.list.cur = node; - - node->mon = mon; - _RGFW->monitors.count += 1; - return node; -} - -void RGFW_monitors_remove(RGFW_monitorNode* node, RGFW_monitorNode* prev) { - _RGFW->monitors.count -= 1; - - /* remove node from the list */ - if (prev != node) { - prev->next = node->next; - } else { /* node is the head */ - _RGFW->monitors.list.head = NULL; - } - - node->next = NULL; - - /* move node to the free list */ - if (_RGFW->monitors.freeList.head == NULL) { - _RGFW->monitors.freeList.head = node; - } else { - _RGFW->monitors.freeList.cur->next = node; - } - - _RGFW->monitors.freeList.cur = node; -} - -RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format) { - return RGFW_window_setIconEx(win, data, w, h, format, RGFW_iconBoth); -} - -void RGFW_window_holdMouse(RGFW_window* win) { - win->internal.holdMouse = RGFW_TRUE; - _RGFW->mouseOwner = win; - RGFW_captureCursor(win); - RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); -} - -RGFW_bool RGFW_window_isHoldingMouse(RGFW_window* win) { return RGFW_BOOL(win->internal.holdMouse); } - -void RGFW_window_unholdMouse(RGFW_window* win) { - win->internal.holdMouse = RGFW_FALSE; - _RGFW->mouseOwner = NULL; +void RGFW_window_mouseUnhold(RGFW_window* win) { + win->_flags &= ~(u32)RGFW_HOLD_MOUSE; RGFW_releaseCursor(win); } -void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) { - if (value) win->internal.mod |= mod; - else win->internal.mod &= ~mod; +u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap) { + double deltaTime = RGFW_getTime() - startTime; + if (deltaTime == 0) return 0; + + double fps = (frameCount / deltaTime); /* the numer of frames over the time it took for them to render */ + if (fpsCap && fps > fpsCap) { + double frameTime = (double)frameCount / (double)fpsCap; /* how long it should take to finish the frames */ + double sleepTime = frameTime - deltaTime; /* subtract how long it should have taken with how long it did take */ + + if (sleepTime > 0) RGFW_sleep((u32)(sleepTime * 1000)); + } + + return (u32) fps; } -void RGFW_updateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) +void RGFW_RGB_to_BGR(RGFW_window* win, u8* data) { + #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA) + u32 x, y; + for (y = 0; y < (u32)win->r.h; y++) { + for (x = 0; x < (u32)win->r.w; x++) { + u32 index = (y * 4 * win->bufferSize.w) + x * 4; + + u8 red = data[index]; + data[index] = win->buffer[index + 2]; + data[index + 2] = red; + } + } + #elif defined(RGFW_OSMESA) + u32 y; + for(y = 0; y < (u32)win->r.h; y++){ + u32 index_from = (y + (win->bufferSize.h - win->r.h)) * 4 * win->bufferSize.w; + u32 index_to = y * 4 * win->bufferSize.w; + memcpy(&data[index_to], &data[index_from], 4 * win->bufferSize.w); + } + #else + RGFW_UNUSED(win); RGFW_UNUSED(data); + #endif +} +#endif + +u32 RGFW_isPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) { + RGFW_UNUSED(win); + return RGFW_gamepadPressed[c][button].current; +} +u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) { + RGFW_UNUSED(win); + return RGFW_gamepadPressed[c][button].prev; +} +u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) { + RGFW_UNUSED(win); + return !RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button); +} +u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) { + RGFW_UNUSED(win); + return RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button); +} + +RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis) { + RGFW_UNUSED(win); + return RGFW_gamepadAxes[controller][whichAxis]; +} +const char* RGFW_getGamepadName(RGFW_window* win, u16 controller) { + RGFW_UNUSED(win); + return (const char*)RGFW_gamepads_name[controller]; +} + +size_t RGFW_getGamepadCount(RGFW_window* win) { + RGFW_UNUSED(win); + return RGFW_gamepadCount; +} + +RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller) { + RGFW_UNUSED(win); + return RGFW_gamepads_type[controller]; +} + +RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value); +void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) { + if (value) win->event.keyMod |= mod; + else win->event.keyMod &= ~mod; +} + +RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll); +void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { RGFW_updateKeyMod(win, RGFW_modCapsLock, capital); RGFW_updateKeyMod(win, RGFW_modNumLock, numlock); RGFW_updateKeyMod(win, RGFW_modControl, control); @@ -3856,63 +2418,60 @@ void RGFW_updateKeyModsEx(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll); } +RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll); void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) { - RGFW_updateKeyModsEx(win, capital, numlock, - RGFW_window_isKeyDown(win, RGFW_controlL) || RGFW_window_isKeyDown(win, RGFW_controlR), - RGFW_window_isKeyDown(win, RGFW_altL) || RGFW_window_isKeyDown(win, RGFW_altR), - RGFW_window_isKeyDown(win, RGFW_shiftL) || RGFW_window_isKeyDown(win, RGFW_shiftR), - RGFW_window_isKeyDown(win, RGFW_superL) || RGFW_window_isKeyDown(win, RGFW_superR), + RGFW_updateKeyModsPro(win, capital, numlock, + RGFW_isPressed(win, RGFW_controlL) || RGFW_isPressed(win, RGFW_controlR), + RGFW_isPressed(win, RGFW_altL) || RGFW_isPressed(win, RGFW_altR), + RGFW_isPressed(win, RGFW_shiftL) || RGFW_isPressed(win, RGFW_shiftR), + RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR), scroll); } +RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show); void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) { - if (show && (win->internal.flags & RGFW_windowHideMouse)) - win->internal.flags ^= RGFW_windowHideMouse; - else if (!show && !(win->internal.flags & RGFW_windowHideMouse)) - win->internal.flags |= RGFW_windowHideMouse; + if (show && (win->_flags & RGFW_windowHideMouse)) + win->_flags ^= RGFW_windowHideMouse; + else if (!show && !(win->_flags & RGFW_windowHideMouse)) + win->_flags |= RGFW_windowHideMouse; } -RGFW_bool RGFW_window_isMouseHidden(RGFW_window* win) { - return (RGFW_bool)RGFW_BOOL(((RGFW_window*)win)->internal.flags & RGFW_windowHideMouse); +RGFW_bool RGFW_window_mouseHidden(RGFW_window* win) { + return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowHideMouse); } RGFW_bool RGFW_window_borderless(RGFW_window* win) { - return (RGFW_bool)RGFW_BOOL(win->internal.flags & RGFW_windowNoBorder); + return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowNoBorder); } -RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->internal.flags & RGFW_windowFullscreen); } -RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->internal.flags & RGFW_windowAllowDND); } +RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->_flags & RGFW_windowFullscreen); } +RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_windowAllowDND); } void RGFW_window_focusLost(RGFW_window* win) { /* standard routines for when a window looses focus */ - win->internal.inFocus = RGFW_FALSE; - if ((win->internal.flags & RGFW_windowFullscreen)) + _RGFW.root->_flags &= ~(u32)RGFW_windowFocus; + if ((win->_flags & RGFW_windowFullscreen)) RGFW_window_minimize(win); - size_t key; - for (key = 0; key < RGFW_keyLast; key++) { - if (RGFW_isKeyDown((u8)key) == RGFW_FALSE) continue; - - _RGFW->keyboard[key].current = RGFW_FALSE; - u8 sym = RGFW_rgfwToKeyChar((u32)key); - - if ((win->internal.enabledEvents & RGFW_BIT(RGFW_keyReleased))) { - RGFW_keyCallback(win, (u8)key, sym, win->internal.mod, RGFW_FALSE, RGFW_FALSE); - RGFW_eventQueuePushEx(e.type = RGFW_keyReleased; - e.key.value = (u8)key; - e.key.sym = sym; - e.key.repeat = RGFW_FALSE; - e.key.mod = win->internal.mod; - e.common.win = win); - } + for (size_t key = 0; key < RGFW_keyLast; key++) { + if (RGFW_isPressed(NULL, (u8)key) == RGFW_FALSE) continue; + RGFW_keyboard[key].current = RGFW_FALSE; + u8 keyChar = RGFW_rgfwToKeyChar((u32)key); + RGFW_keyCallback(win, (u8)key, keyChar, win->event.keyMod, RGFW_FALSE); + RGFW_eventQueuePushEx(e.type = RGFW_keyReleased; + e.key = (u8)key; + e.keyChar = keyChar; + e.repeat = RGFW_FALSE; + e.keyMod = win->event.keyMod; + e._win = win); } - + RGFW_resetKey(); } #ifndef RGFW_WINDOWS void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { - RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow); + RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow); } #endif @@ -3927,8 +2486,8 @@ struct timespec; #if defined(RGFW_WAYLAND) || defined(RGFW_X11) || defined(RGFW_WINDOWS) void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { RGFW_window_showMouseFlags(win, show); - if (show == RGFW_FALSE) - RGFW_window_setMouse(win, _RGFW->hiddenMouse); + if (show == 0) + RGFW_window_setMouse(win, _RGFW.hiddenMouse); else RGFW_window_setMouseDefault(win); } @@ -3948,109 +2507,50 @@ void RGFW_moveToMacOSResourceDir(void) { } OpenGL defines start here (Normal, EGL, OSMesa) */ -#if defined(RGFW_OPENGL) -/* EGL, OpenGL */ -#define RGFW_DEFAULT_GL_HINTS { \ - /* Stencil */ 0, \ - /* Samples */ 0, \ - /* Stereo */ RGFW_FALSE, \ - /* AuxBuffers */ 0, \ - /* DoubleBuffer */ RGFW_TRUE, \ - /* Red */ 8, \ - /* Green */ 8, \ - /* Blue */ 8, \ - /* Alpha */ 8, \ - /* Depth */ 24, \ - /* AccumRed */ 0, \ - /* AccumGreen */ 0, \ - /* AccumBlue */ 0, \ - /* AccumAlpha */ 0, \ - /* SRGB */ RGFW_FALSE, \ - /* Robustness */ RGFW_FALSE, \ - /* Debug */ RGFW_FALSE, \ - /* NoError */ RGFW_FALSE, \ - /* ReleaseBehavior */ RGFW_glReleaseNone, \ - /* Profile */ RGFW_glCore, \ - /* Major */ 1, \ - /* Minor */ 0, \ - /* Share */ NULL, \ - /* Share_EGL */ NULL, \ - /* renderer */ RGFW_glAccelerated \ -} +#if defined(RGFW_OPENGL) || defined(RGFW_EGL) -RGFW_glHints RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS; -RGFW_glHints* RGFW_globalHints_OpenGL = &RGFW_globalHints_OpenGL_SRC; - -void RGFW_resetGlobalHints_OpenGL(void) { -#if !defined(__cplusplus) || defined(RGFW_MACOS) - RGFW_globalHints_OpenGL_SRC = (RGFW_glHints)RGFW_DEFAULT_GL_HINTS; -#else - RGFW_globalHints_OpenGL_SRC = RGFW_DEFAULT_GL_HINTS; -#endif -} -void RGFW_setGlobalHints_OpenGL(RGFW_glHints* hints) { RGFW_globalHints_OpenGL = hints; } -RGFW_glHints* RGFW_getGlobalHints_OpenGL(void) { RGFW_init(); return RGFW_globalHints_OpenGL; } - - -void* RGFW_glContext_getSourceContext(RGFW_glContext* ctx) { - RGFW_UNUSED(ctx); - -#ifdef RGFW_WAYLAND - if (RGFW_usingWayland()) return (void*)ctx->egl.ctx; +#ifdef RGFW_WINDOWS + #define WIN32_LEAN_AND_MEAN + #define OEMRESOURCE + #include #endif -#if defined(RGFW_X11) - return (void*)ctx->ctx; -#else - return NULL; -#endif -} - -RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints) { - #ifdef RGFW_WAYLAND - if (RGFW_usingWayland()) { - return (RGFW_glContext*)RGFW_window_createContext_EGL(win, hints); - } +#if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER) + #include +#elif defined(__APPLE__) + #ifndef GL_SILENCE_DEPRECATION + #define GL_SILENCE_DEPRECATION #endif - RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext)); - if (RGFW_window_createContextPtr_OpenGL(win, ctx, hints) == RGFW_FALSE) { - RGFW_FREE(ctx); - win->src.ctx.native = NULL; - return NULL; - } - win->src.gfxType |= RGFW_gfxOwnedByRGFW; - return ctx; -} + #include + #include +#endif -RGFW_glContext* RGFW_window_getContext_OpenGL(RGFW_window* win) { - if (win->src.gfxType & RGFW_windowEGL) return NULL; - return win->src.ctx.native; -} +/* EGL, normal OpenGL only */ +#ifndef RGFW_EGL +i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {8, +#else +i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {0, +#endif + 0, 0, 0, 1, 8, 8, 8, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, RGFW_glReleaseNone, RGFW_glCore, 0, 0}; -void RGFW_window_deleteContext_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { - RGFW_window_deleteContextPtr_OpenGL(win, ctx); - if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx); +void RGFW_setGLHint(RGFW_glHints hint, i32 value) { + if (hint < RGFW_glFinalHint && hint) RGFW_GL_HINTS[hint] = value; } RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, size_t len) { const char *start = extensions; - const char *where; + const char *where; const char* terminator; - if (extensions == NULL || ext == NULL) { + if (extensions == NULL || ext == NULL) return RGFW_FALSE; - } - while (ext[len - 1] == '\0' && len > 3) { - len--; - } - - where = RGFW_STRSTR(extensions, ext); + where = strstr(extensions, ext); while (where) { - terminator = where + len; + terminator = where + len; if ((where == start || *(where - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) { - return RGFW_TRUE; + return RGFW_TRUE; } where = RGFW_STRSTR(terminator, ext); } @@ -4058,523 +2558,457 @@ RGFW_bool RGFW_extensionSupportedStr(const char* extensions, const char* ext, si return RGFW_FALSE; } -RGFWDEF RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len); -RGFW_bool RGFW_extensionSupported_base(const char* extension, size_t len) { +RGFW_bool RGFW_extensionSupported(const char* extension, size_t len) { #ifdef GL_NUM_EXTENSIONS - if (RGFW_globalHints_OpenGL->major >= 3) { + if (RGFW_GL_HINTS[RGFW_glMajor] >= 3) { i32 i; - GLint count = 0; - RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress_OpenGL("glGetStringi"); - RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress_OpenGL("glGetIntegerv"); - if (RGFW_glGetIntegerv) + RGFW_proc RGFW_glGetStringi = RGFW_getProcAddress("glGetStringi"); + RGFW_proc RGFW_glGetIntegerv = RGFW_getProcAddress("RGFW_glGetIntegerv"); + if (RGFW_glGetIntegerv) ((void(*)(GLenum, GLint*))RGFW_glGetIntegerv)(GL_NUM_EXTENSIONS, &count); for (i = 0; RGFW_glGetStringi && i < count; i++) { const char* en = ((const char* (*)(u32, u32))RGFW_glGetStringi)(GL_EXTENSIONS, (u32)i); - if (en && RGFW_STRNCMP(en, extension, len) == 0) { - return RGFW_TRUE; - } + if (en && RGFW_STRNCMP(en, extension, len) == 0) + return RGFW_TRUE; } - } else + } else #endif { - RGFW_proc RGFW_glGetString = RGFW_getProcAddress_OpenGL("glGetString"); - #define RGFW_GL_EXTENSIONS 0x1F03 + RGFW_proc RGFW_glGetString = RGFW_getProcAddress("glGetString"); + if (RGFW_glGetString) { - const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(RGFW_GL_EXTENSIONS); - - if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) { - return RGFW_TRUE; - } + const char* extensions = ((const char*(*)(u32))RGFW_glGetString)(GL_EXTENSIONS); + if ((extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len)) + return RGFW_TRUE; } } - return RGFW_FALSE; + + return RGFW_extensionSupportedPlatform(extension, len); } -RGFW_bool RGFW_extensionSupported_OpenGL(const char* extension, size_t len) { - if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE; - return RGFW_extensionSupportedPlatform_OpenGL(extension, len); +/* OPENGL normal only (no EGL / OSMesa) */ +#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) && !defined(RGFW_CUSTOM_BACKEND) && !defined(RGFW_WASM) + +#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0) + #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0) + #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0) + #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0) + #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0) + #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0) + #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0) + #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0) + +#if defined(RGFW_X11) || defined(RGFW_WINDOWS) + #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0) + #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0) + #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0) + #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0) + #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0) + #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0) + #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0) + #define RGFW_GL_ACCUM_RED_SIZE RGFW_OS_BASED_VALUE(14, 0x201E, 0, 0) + #define RGFW_GL_ACCUM_GREEN_SIZE RGFW_OS_BASED_VALUE(15, 0x201F, 0, 0) + #define RGFW_GL_ACCUM_BLUE_SIZE RGFW_OS_BASED_VALUE(16, 0x2020, 0, 0) + #define RGFW_GL_ACCUM_ALPHA_SIZE RGFW_OS_BASED_VALUE(17, 0x2021, 0, 0) + #define RGFW_GL_SRGB RGFW_OS_BASED_VALUE(0x20b2, 0x3089, 0, 0) + #define RGFW_GL_NOERROR RGFW_OS_BASED_VALUE(0x31b3, 0x31b3, 0, 0) + #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) + #define RGFW_GL_RELEASE_BEHAVIOR RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 0x2097 , 0, 0) + #define RGFW_GL_CONTEXT_RELEASE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB, 0x2098, 0, 0) + #define RGFW_GL_CONTEXT_NONE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB, 0x0000, 0, 0) + #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) + #define RGFW_GL_DEBUG_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0) + #define RGFW_GL_ROBUST_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB, 0x00000004, 0, 0) +#endif + +#ifdef RGFW_WINDOWS + #define WGL_SUPPORT_OPENGL_ARB 0x2010 + #define WGL_COLOR_BITS_ARB 0x2014 + #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 + #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 + #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 + #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 + #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + #define WGL_SAMPLE_BUFFERS_ARB 0x2041 + #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 + #define WGL_PIXEL_TYPE_ARB 0x2013 + #define WGL_TYPE_RGBA_ARB 0x202B + + #define WGL_TRANSPARENT_ARB 0x200A +#endif + +/* The window'ing api needs to know how to render the data we (or opengl) give it + 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 */ +i32* RGFW_initFormatAttribs(void); +i32* RGFW_initFormatAttribs(void) { + static i32 attribs[] = { + #if defined(RGFW_X11) || defined(RGFW_WINDOWS) + RGFW_GL_RENDER_TYPE, + RGFW_GL_FULL_FORMAT, + RGFW_GL_DRAW, 1, + RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA, + #endif + + #ifdef RGFW_X11 + GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, + #endif + + #ifdef RGFW_MACOS + 72, + 8, 24, + #endif + + #ifdef RGFW_WINDOWS + WGL_SUPPORT_OPENGL_ARB, 1, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_COLOR_BITS_ARB, 32, + #endif + 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, 0, 0 + }; + + size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 27; + + #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ + if (attVal) { \ + attribs[index] = attrib;\ + attribs[index + 1] = attVal;\ + index += 2;\ + } + + #if defined(RGFW_MACOS) && defined(RGFW_COCOA_GRAPHICS_SWITCHING) + RGFW_GL_ADD_ATTRIB(96, kCGLPFASupportsAutomaticGraphicsSwitching); + #endif + + RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1); + + RGFW_GL_ADD_ATTRIB(RGFW_GL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_GL_HINTS[RGFW_glStereo]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_GL_HINTS[RGFW_glAuxBuffers]); + + #if defined(RGFW_X11) || defined(RGFW_WINDOWS) + RGFW_GL_ADD_ATTRIB(RGFW_GL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]); + #endif + + #if defined(RGFW_X11) || defined(RGFW_WINDOWS) + RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_RED_SIZE, RGFW_GL_HINTS[RGFW_glAccumRed]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glAccumBlue]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glAccumGreen]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAccumAlpha]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_SRGB, RGFW_GL_HINTS[RGFW_glSRGB]); + RGFW_GL_ADD_ATTRIB(RGFW_GL_NOERROR, RGFW_GL_HINTS[RGFW_glNoError]); + + if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) { + RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_RELEASE); + } else if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_glReleaseNone) { + RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_NONE); + } + + i32 flags = 0; + if (RGFW_GL_HINTS[RGFW_glDebug]) flags |= RGFW_GL_DEBUG_BIT; + if (RGFW_GL_HINTS[RGFW_glRobustness]) flags |= RGFW_GL_ROBUST_BIT; + RGFW_GL_ADD_ATTRIB(RGFW_GL_FLAGS, flags); + #else + i32 accumSize = (i32)(RGFW_GL_HINTS[RGFW_glAccumRed] + RGFW_GL_HINTS[RGFW_glAccumGreen] + RGFW_GL_HINTS[RGFW_glAccumBlue] + RGFW_GL_HINTS[RGFW_glAccumAlpha]) / 4; + RGFW_GL_ADD_ATTRIB(14, accumSize); + #endif + + #ifndef RGFW_X11 + RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]); + #endif + + #ifdef RGFW_MACOS + if (_RGFW.root->_flags & RGFW_windowOpenglSoftware) { + RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID); + } else { + attribs[index] = RGFW_GL_RENDER_TYPE; + index += 1; + } + #endif + + #ifdef RGFW_MACOS + /* macOS has the surface attribs and the opengl attribs connected for some reason + maybe this is to give macOS more control to limit openGL/the opengl version? */ + + attribs[index] = 99; + attribs[index + 1] = 0x1000; + + + if (RGFW_GL_HINTS[RGFW_glMajor] >= 4 || RGFW_GL_HINTS[RGFW_glMajor] >= 3) { + attribs[index + 1] = (i32) ((RGFW_GL_HINTS[RGFW_glMajor] >= 4) ? 0x4100 : 0x3200); + } + #endif + + RGFW_GL_ADD_ATTRIB(0, 0); + + return attribs; } -void RGFW_window_makeCurrentWindow_OpenGL(RGFW_window* win) { - if (win) { - _RGFW->current = win; - } +/* EGL only (no OSMesa nor normal OPENGL) */ +#elif defined(RGFW_EGL) - RGFW_window_makeCurrentContext_OpenGL(win); -} - -RGFW_window* RGFW_getCurrentWindow_OpenGL(void) { return _RGFW->current; } -void RGFW_attribStack_init(RGFW_attribStack* stack, i32* attribs, size_t max) { stack->attribs = attribs; stack->count = 0; stack->max = max; } -void RGFW_attribStack_pushAttrib(RGFW_attribStack* stack, i32 attrib) { - RGFW_ASSERT(stack->count < stack->max); - stack->attribs[stack->count] = attrib; - stack->count += 1; -} -void RGFW_attribStack_pushAttribs(RGFW_attribStack* stack, i32 attrib1, i32 attrib2) { - RGFW_attribStack_pushAttrib(stack, attrib1); - RGFW_attribStack_pushAttrib(stack, attrib2); -} - -/* EGL */ -#ifdef RGFW_EGL #include -PFNEGLINITIALIZEPROC RGFW_eglInitialize; -PFNEGLGETCONFIGSPROC RGFW_eglGetConfigs; -PFNEGLCHOOSECONFIGPROC RGFW_eglChooseConfig; -PFNEGLCREATEWINDOWSURFACEPROC RGFW_eglCreateWindowSurface; -PFNEGLCREATECONTEXTPROC RGFW_eglCreateContext; -PFNEGLMAKECURRENTPROC RGFW_eglMakeCurrent; -PFNEGLGETDISPLAYPROC RGFW_eglGetDisplay; -PFNEGLSWAPBUFFERSPROC RGFW_eglSwapBuffers; -PFNEGLSWAPINTERVALPROC RGFW_eglSwapInterval; -PFNEGLBINDAPIPROC RGFW_eglBindAPI; -PFNEGLDESTROYCONTEXTPROC RGFW_eglDestroyContext; -PFNEGLTERMINATEPROC RGFW_eglTerminate; -PFNEGLDESTROYSURFACEPROC RGFW_eglDestroySurface; -PFNEGLGETCURRENTCONTEXTPROC RGFW_eglGetCurrentContext; -PFNEGLGETPROCADDRESSPROC RGFW_eglGetProcAddress = NULL; -PFNEGLQUERYSTRINGPROC RGFW_eglQueryString; -PFNEGLGETCONFIGATTRIBPROC RGFW_eglGetConfigAttrib; +#if defined(RGFW_LINK_EGL) + typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*); + + PFNEGLINITIALIZEPROC eglInitializeSource; + PFNEGLGETCONFIGSPROC eglGetConfigsSource; + PFNEGLCHOOSECONFIgamepadROC eglChooseConfigSource; + PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource; + PFNEGLCREATECONTEXTPROC eglCreateContextSource; + PFNEGLMAKECURRENTPROC eglMakeCurrentSource; + PFNEGLGETDISPLAYPROC eglGetDisplaySource; + PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource; + PFNEGLSWAPINTERVALPROC eglSwapIntervalSource; + PFNEGLBINDAPIPROC eglBindAPISource; + PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource; + PFNEGLTERMINATEPROC eglTerminateSource; + PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource; + + #define eglInitialize eglInitializeSource + #define eglGetConfigs eglGetConfigsSource + #define eglChooseConfig eglChooseConfigSource + #define eglCreateWindowSurface eglCreateWindowSurfaceSource + #define eglCreateContext eglCreateContextSource + #define eglMakeCurrent eglMakeCurrentSource + #define eglGetDisplay eglGetDisplaySource + #define eglSwapBuffers eglSwapBuffersSource + #define eglSwapInterval eglSwapIntervalSource + #define eglBindAPI eglBindAPISource + #define eglDestroyContext eglDestroyContextSource + #define eglTerminate eglTerminateSource + #define eglDestroySurface eglDestroySurfaceSource; +#endif + #define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098 #define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb -#ifdef RGFW_WINDOWS - #include -#elif defined(RGFW_MACOS) || defined(RGFW_UNIX) - #include +#ifndef RGFW_GL_ADD_ATTRIB +#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ + if (attVal) { \ + attribs[index] = attrib;\ + attribs[index + 1] = attVal;\ + index += 2;\ + } #endif + +void RGFW_window_initOpenGL(RGFW_window* win) { +#if defined(RGFW_LINK_EGL) + eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize"); + eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs"); + eglChooseConfigSource = (PFNEGLCHOOSECONFIgamepadROC) eglGetProcAddress("eglChooseConfig"); + eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface"); + eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext"); + eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent"); + eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay"); + eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers"); + eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval"); + eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI"); + eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext"); + eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate"); + eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface"); + + RGFW_ASSERT(eglInitializeSource != NULL && + eglGetConfigsSource != NULL && + eglChooseConfigSource != NULL && + eglCreateWindowSurfaceSource != NULL && + eglCreateContextSource != NULL && + eglMakeCurrentSource != NULL && + eglGetDisplaySource != NULL && + eglSwapBuffersSource != NULL && + eglSwapIntervalsSource != NULL && + eglBindAPISource != NULL && + eglDestroyContextSource != NULL && + eglTerminateSource != NULL && + eglDestroySurfaceSource != NULL); +#endif /* RGFW_LINK_EGL */ + #ifdef RGFW_WAYLAND -#include + if (RGFW_useWaylandBool) + win->src.eglWindow = wl_egl_window_create(win->src.surface, win->r.w, win->r.h); #endif -void* RGFW_eglLibHandle = NULL; - -void* RGFW_getDisplay_EGL(void) { return _RGFW->EGL_display; } -void* RGFW_eglContext_getSourceContext(RGFW_eglContext* ctx) { return ctx->ctx; } -void* RGFW_eglContext_getSurface(RGFW_eglContext* ctx) { return ctx->surface; } -struct wl_egl_window* RGFW_eglContext_wlEGLWindow(RGFW_eglContext* ctx) { return ctx->eglWindow; } - -RGFW_bool RGFW_loadEGL(void) { - RGFW_init(); - if (RGFW_eglGetProcAddress != NULL) { - return RGFW_TRUE; - } - -#ifndef RGFW_WASM #ifdef RGFW_WINDOWS - const char* libNames[] = { "libEGL.dll", "EGL.dll" }; - #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) - /* Linux and macOS */ - const char* libNames[] = { - "libEGL.so.1", /* most common */ - "libEGL.so", /* fallback */ - "/System/Library/Frameworks/OpenGL.framework/OpenGL" /* fallback for older macOS EGL-like systems */ - }; + win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc); + #elif defined(RGFW_MACOS) + win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0); + #elif defined(RGFW_WAYLAND) + if (RGFW_useWaylandBool) + win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.wl_display); + else + #endif + #ifdef RGFW_X11 + win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display); + #else + {} + #endif + #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11) + win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display); #endif - for (size_t i = 0; i < sizeof(libNames) / sizeof(libNames[0]); ++i) { - #ifdef RGFW_WINDOWS - RGFW_eglLibHandle = (void*)LoadLibraryA(libNames[i]); - if (RGFW_eglLibHandle) { - RGFW_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC)(RGFW_proc)GetProcAddress((HMODULE)RGFW_eglLibHandle, "eglGetProcAddress"); - break; - } - #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) - RGFW_eglLibHandle = dlopen(libNames[i], RTLD_LAZY | RTLD_GLOBAL); - if (RGFW_eglLibHandle) { - void* lib = dlsym(RGFW_eglLibHandle, "eglGetProcAddress"); - if (lib != NULL) RGFW_MEMCPY(&RGFW_eglGetProcAddress, &lib, sizeof(PFNEGLGETPROCADDRESSPROC)); - break; - } - #endif - } + EGLint major, minor; - if (!RGFW_eglLibHandle || !RGFW_eglGetProcAddress) { - return RGFW_FALSE; - } - - RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) RGFW_eglGetProcAddress("eglInitialize"); - RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) RGFW_eglGetProcAddress("eglGetConfigs"); - RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) RGFW_eglGetProcAddress("eglChooseConfig"); - RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) RGFW_eglGetProcAddress("eglCreateWindowSurface"); - RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) RGFW_eglGetProcAddress("eglCreateContext"); - RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) RGFW_eglGetProcAddress("eglMakeCurrent"); - RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) RGFW_eglGetProcAddress("eglGetDisplay"); - RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) RGFW_eglGetProcAddress("eglSwapBuffers"); - RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) RGFW_eglGetProcAddress("eglSwapInterval"); - RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) RGFW_eglGetProcAddress("eglBindAPI"); - RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) RGFW_eglGetProcAddress("eglDestroyContext"); - RGFW_eglTerminate = (PFNEGLTERMINATEPROC) RGFW_eglGetProcAddress("eglTerminate"); - RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) RGFW_eglGetProcAddress("eglDestroySurface"); - RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) RGFW_eglGetProcAddress("eglQueryString"); - RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) RGFW_eglGetProcAddress("eglGetCurrentContext"); - RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) RGFW_eglGetProcAddress("eglGetConfigAttrib"); - -#else - RGFW_eglGetProcAddress = eglGetProcAddress; - RGFW_eglInitialize = (PFNEGLINITIALIZEPROC) eglInitialize; - RGFW_eglGetConfigs = (PFNEGLGETCONFIGSPROC) eglGetConfigs; - RGFW_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) eglChooseConfig; - RGFW_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) eglCreateWindowSurface; - RGFW_eglCreateContext = (PFNEGLCREATECONTEXTPROC) eglCreateContext; - RGFW_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) eglMakeCurrent; - RGFW_eglGetDisplay = (PFNEGLGETDISPLAYPROC) eglGetDisplay; - RGFW_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) eglSwapBuffers; - RGFW_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) eglSwapInterval; - RGFW_eglBindAPI = (PFNEGLBINDAPIPROC) eglBindAPI; - RGFW_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) eglDestroyContext; - RGFW_eglTerminate = (PFNEGLTERMINATEPROC) eglTerminate; - RGFW_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) eglDestroySurface; - RGFW_eglQueryString = (PFNEGLQUERYSTRINGPROC) eglQueryString; - RGFW_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) eglGetCurrentContext; - RGFW_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)eglGetConfigAttrib; -#endif - - RGFW_bool out = RGFW_BOOL(RGFW_eglInitialize!= NULL && - RGFW_eglGetConfigs!= NULL && - RGFW_eglChooseConfig!= NULL && - RGFW_eglCreateWindowSurface!= NULL && - RGFW_eglCreateContext!= NULL && - RGFW_eglMakeCurrent!= NULL && - RGFW_eglGetDisplay!= NULL && - RGFW_eglSwapBuffers!= NULL && - RGFW_eglSwapInterval != NULL && - RGFW_eglBindAPI!= NULL && - RGFW_eglDestroyContext!= NULL && - RGFW_eglTerminate!= NULL && - RGFW_eglDestroySurface!= NULL && - RGFW_eglQueryString != NULL && - RGFW_eglGetCurrentContext != NULL && - RGFW_eglGetConfigAttrib != NULL); - - if (out) { - #ifdef RGFW_WINDOWS - HDC dc = GetDC(NULL); - _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) dc); - ReleaseDC(NULL, dc); - #elif defined(RGFW_WAYLAND) - if (_RGFW->useWaylandBool) - _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->wl_display); - else - #endif - #ifdef RGFW_X11 - _RGFW->EGL_display = RGFW_eglGetDisplay((EGLNativeDisplayType) _RGFW->display); - #else - {} - #endif - #if !defined(RGFW_WAYLAND) && !defined(RGFW_WINDOWS) && !defined(RGFW_X11) - _RGFW->EGL_display = RGFW_eglGetDisplay(EGL_DEFAULT_DISPLAY); - #endif - } - - RGFW_eglInitialize(_RGFW->EGL_display, NULL, NULL); - return out; -} - - -void RGFW_unloadEGL(void) { - if (!RGFW_eglLibHandle) return; - RGFW_eglTerminate(_RGFW->EGL_display); - #ifdef RGFW_WINDOWS - FreeLibrary((HMODULE)RGFW_eglLibHandle); - #elif defined(RGFW_MACOS) || defined(RGFW_UNIX) - dlclose(RGFW_eglLibHandle); - #endif - - RGFW_eglLibHandle = NULL; - RGFW_eglGetProcAddress = NULL; -} - -RGFW_bool RGFW_window_createContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx, RGFW_glHints* hints) { - if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE; - win->src.ctx.egl = ctx; - win->src.gfxType = RGFW_gfxEGL; - -#ifdef RGFW_WAYLAND - if (_RGFW->useWaylandBool) - win->src.ctx.egl->eglWindow = wl_egl_window_create(win->src.surface, win->w, win->h); -#endif + eglInitialize(win->src.EGL_display, &major, &minor); #ifndef EGL_OPENGL_ES1_BIT #define EGL_OPENGL_ES1_BIT 0x1 #endif - EGLint egl_config[24]; + EGLint egl_config[24] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, + #ifdef RGFW_OPENGL_ES1 + EGL_OPENGL_ES1_BIT, + #elif defined(RGFW_OPENGL_ES3) + EGL_OPENGL_ES3_BIT, + #elif defined(RGFW_OPENGL_ES2) + EGL_OPENGL_ES2_BIT, + #else + EGL_OPENGL_BIT, + #endif + EGL_NONE, EGL_NONE + }; { - RGFW_attribStack stack; - RGFW_attribStack_init(&stack, egl_config, 24); + size_t index = 7; + EGLint* attribs = egl_config; - RGFW_attribStack_pushAttribs(&stack, EGL_SURFACE_TYPE, EGL_WINDOW_BIT); - RGFW_attribStack_pushAttrib(&stack, EGL_RENDERABLE_TYPE); + RGFW_GL_ADD_ATTRIB(EGL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]); + RGFW_GL_ADD_ATTRIB(EGL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]); + RGFW_GL_ADD_ATTRIB(EGL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]); + RGFW_GL_ADD_ATTRIB(EGL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]); + RGFW_GL_ADD_ATTRIB(EGL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]); - if (hints->profile == RGFW_glES) { - switch (hints->major) { - case 1: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES1_BIT); break; - case 2: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES2_BIT); break; - case 3: RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_ES3_BIT); break; - default: break; - } - } else { - RGFW_attribStack_pushAttrib(&stack, EGL_OPENGL_BIT); - } + if (RGFW_GL_HINTS[RGFW_glSRGB]) + RGFW_GL_ADD_ATTRIB(0x3089, RGFW_GL_HINTS[RGFW_glSRGB]); - RGFW_attribStack_pushAttribs(&stack, EGL_RED_SIZE, hints->red); - RGFW_attribStack_pushAttribs(&stack, EGL_GREEN_SIZE, hints->green); - RGFW_attribStack_pushAttribs(&stack, EGL_BLUE_SIZE, hints->blue); - RGFW_attribStack_pushAttribs(&stack, EGL_ALPHA_SIZE, hints->alpha); - RGFW_attribStack_pushAttribs(&stack, EGL_DEPTH_SIZE, hints->depth); - - RGFW_attribStack_pushAttribs(&stack, EGL_STENCIL_SIZE, hints->stencil); - if (hints->samples) { - RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLE_BUFFERS, 1); - RGFW_attribStack_pushAttribs(&stack, EGL_SAMPLES, hints->samples); - } - - RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); + RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE); } - EGLint numConfigs, best_config = -1, best_samples = 0; + EGLConfig config; + EGLint numConfigs; + eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs); - RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, NULL, 0, &numConfigs); - EGLConfig* configs = (EGLConfig*)RGFW_ALLOC(sizeof(EGLConfig) * (u32)numConfigs); - - RGFW_eglChooseConfig(_RGFW->EGL_display, egl_config, configs, numConfigs, &numConfigs); - -#ifdef RGFW_X11 - RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent); - EGLint best_depth = 0; -#endif - - for (EGLint i = 0; i < numConfigs; i++) { - EGLint visual_id = 0; - EGLint samples = 0; - - RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_NATIVE_VISUAL_ID, &visual_id); - RGFW_eglGetConfigAttrib(_RGFW->EGL_display, configs[i], EGL_SAMPLES, &samples); - - if (best_config == -1) best_config = i; - -#ifdef RGFW_X11 - if (_RGFW->useWaylandBool == RGFW_FALSE) { - XVisualInfo vinfo_template; - vinfo_template.visualid = (VisualID)visual_id; - - int num_visuals = 0; - XVisualInfo* vi = XGetVisualInfo(_RGFW->display, VisualIDMask, &vinfo_template, &num_visuals); - if (!vi) continue; - if ((!transparent || vi->depth == 32) && best_depth == 0) { - best_config = i; - best_depth = vi->depth; - } - - if ((!(transparent) || vi->depth == 32) && (samples <= hints->samples && samples > best_samples)) { - best_depth = vi->depth; - best_config = i; - best_samples = samples; - XFree(vi); - continue; - } - } -#endif - - if (samples <= hints->samples && samples > best_samples) { - best_config = i; - best_samples = samples; - } - } - - EGLConfig config = configs[best_config]; - RGFW_FREE(configs); -#ifdef RGFW_X11 - if (_RGFW->useWaylandBool == RGFW_FALSE) { - /* This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */ - XVisualInfo* result; - XVisualInfo desired; - EGLint visualID = 0, count = 0; - - RGFW_eglGetConfigAttrib(_RGFW->EGL_display, config, EGL_NATIVE_VISUAL_ID, &visualID); - if (visualID) { - desired.visualid = (VisualID)visualID; - result = XGetVisualInfo(_RGFW->display, VisualIDMask, &desired, &count); - } else RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to fetch a valid EGL VisualID"); - - if (result == NULL || count == 0) { - if (win->src.window == 0) { - /* try to create a EGL context anyway (this will work if you're not using a NVidia driver) */ - win->internal.flags &= ~(u32)RGFW_windowEGL; - RGFW_createWindowPlatform("", win->internal.flags, win); - } - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to find a valid visual for the EGL config"); - } else { - if (win->src.window) RGFW_window_closePlatform(win); - RGFW_XCreateWindow(*result, "", win->internal.flags, win); - XFree(result); - } - } -#endif - - EGLint surf_attribs[9]; - - { - RGFW_attribStack stack; - RGFW_attribStack_init(&stack, surf_attribs, 9); - - const char present_opaque_str[] = "EGL_EXT_present_opaque"; - RGFW_bool opaque_extension_Found = RGFW_extensionSupportedPlatform_EGL(present_opaque_str, sizeof(present_opaque_str)); - - #ifndef EGL_PRESENT_OPAQUE_EXT - #define EGL_PRESENT_OPAQUE_EXT 0x31df - #endif - - #ifndef EGL_GL_COLORSPACE_KHR - #define EGL_GL_COLORSPACE_KHR 0x309D - #ifndef EGL_GL_COLORSPACE_SRGB_KHR - #define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 - #endif - #endif - - const char gl_colorspace_str[] = "EGL_KHR_gl_colorspace"; - RGFW_bool gl_colorspace_Found = RGFW_extensionSupportedPlatform_EGL(gl_colorspace_str, sizeof(gl_colorspace_str)); - - if (hints->sRGB && gl_colorspace_Found) { - RGFW_attribStack_pushAttribs(&stack, EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR); - } - - if (!(win->internal.flags & RGFW_windowTransparent) && opaque_extension_Found) - RGFW_attribStack_pushAttribs(&stack, EGL_PRESENT_OPAQUE_EXT, EGL_TRUE); - - if (hints->doubleBuffer == 0) { - RGFW_attribStack_pushAttribs(&stack, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); - } - - RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); - } #if defined(RGFW_MACOS) - void* layer = RGFW_getLayer_OSX(); + void* layer = RGFW_cocoaGetLayer(); - RGFW_window_setLayer_OSX(win, layer); + RGFW_window_cocoaSetLayer(win, layer); - win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) layer, surf_attribs); + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL); #elif defined(RGFW_WINDOWS) - win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs); + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); #elif defined(RGFW_WAYLAND) - if (_RGFW->useWaylandBool) - win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.ctx.egl->eglWindow, surf_attribs); + if (RGFW_useWaylandBool) + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.eglWindow, NULL); else #endif #ifdef RGFW_X11 - win->src.ctx.egl->surface = RGFW_eglCreateWindowSurface(_RGFW->EGL_display, config, (EGLNativeWindowType) win->src.window, surf_attribs); + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); #else {} #endif - #ifdef RGFW_WASM - win->src.ctx.egl->surface = eglCreateWindowSurface(_RGFW->EGL_display, config, 0, 0); + #if !defined(RGFW_X11) && !defined(RGFW_WAYLAND) && !defined(RGFW_MACOS) + win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); #endif - if (win->src.ctx.egl->surface == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL surface."); - return RGFW_FALSE; + EGLint attribs[12]; + size_t index = 0; + +#ifdef RGFW_OPENGL_ES1 + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 1); +#elif defined(RGFW_OPENGL_ES2) + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 2); +#elif defined(RGFW_OPENGL_ES3) + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 3); +#endif + + RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]); + RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]); + + if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0) + RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); + + if (RGFW_GL_HINTS[RGFW_glMajor]) { + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_GL_HINTS[RGFW_glMajor]); + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_GL_HINTS[RGFW_glMinor]); + + if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) { + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); + } + else { + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); + } } - EGLint attribs[20]; - { - RGFW_attribStack stack; - RGFW_attribStack_init(&stack, attribs, 20); - - if (hints->major || hints->minor) { - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MAJOR_VERSION, hints->major); - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_MINOR_VERSION, hints->minor); - } - - if (hints->profile == RGFW_glCore) { - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); - } else if (hints->profile == RGFW_glCompatibility) { - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); - } - - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_ROBUST_ACCESS, hints->robustness); - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_OPENGL_DEBUG, hints->debug); - - #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_KHR - #define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 - #endif - - #ifndef EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR - #define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 - #endif - - if (hints->releaseBehavior == RGFW_glReleaseFlush) { - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR); - } else { - RGFW_attribStack_pushAttribs(&stack, EGL_CONTEXT_RELEASE_BEHAVIOR_KHR, 0x0000); - } - - RGFW_attribStack_pushAttribs(&stack, EGL_NONE, EGL_NONE); + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, RGFW_GL_HINTS[RGFW_glRobustness]); + RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_DEBUG, RGFW_GL_HINTS[RGFW_glDebug]); + if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) { + RGFW_GL_ADD_ATTRIB(0x2097, 0x2098); + } else { + RGFW_GL_ADD_ATTRIB(0x2096, 0x0000); } - if (hints->profile == RGFW_glES) - RGFW_eglBindAPI(EGL_OPENGL_ES_API); - else - RGFW_eglBindAPI(EGL_OPENGL_API); + RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE); - win->src.ctx.egl->ctx = RGFW_eglCreateContext(_RGFW->EGL_display, config, hints->shareEGL, attribs); - - if (win->src.ctx.egl->ctx == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, "Failed to create an EGL context."); - return RGFW_FALSE; - } - - RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx); - RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context initalized."); - return RGFW_TRUE; -} - -RGFW_eglContext* RGFW_window_getContext_EGL(RGFW_window* win) { - if (win->src.gfxType == RGFW_windowOpenGL) return NULL; - return win->src.ctx.egl; -} - -void RGFW_window_deleteContextPtr_EGL(RGFW_window* win, RGFW_eglContext* ctx) { - if (_RGFW->EGL_display == NULL) return; - - RGFW_eglDestroySurface(_RGFW->EGL_display, ctx->surface); - RGFW_eglDestroyContext(_RGFW->EGL_display, ctx->ctx); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL context freed"); - #ifdef RGFW_WAYLAND - if (_RGFW->useWaylandBool == RGFW_FALSE) return; - wl_egl_window_destroy(win->src.ctx.egl->eglWindow); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "EGL window context freed"); + #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3) + eglBindAPI(EGL_OPENGL_ES_API); + #else + eglBindAPI(EGL_OPENGL_API); #endif - win->src.ctx.egl = NULL; + + win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs); + + if (win->src.EGL_context == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, RGFW_DEBUG_CTX(win, 0), "failed to create an EGL opengl context"); + return; + } + + eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); + eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context initalized"); } -void RGFW_window_makeCurrentContext_EGL(RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.egl); - if (win == NULL) - RGFW_eglMakeCurrent(_RGFW->EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +void RGFW_window_freeOpenGL(RGFW_window* win) { + if (win->src.EGL_display == NULL) return; + + eglDestroySurface(win->src.EGL_display, win->src.EGL_surface); + eglDestroyContext(win->src.EGL_display, win->src.EGL_context); + eglTerminate(win->src.EGL_display); + win->src.EGL_display = NULL; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context freed"); +} + +void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { + if (win == NULL) + eglMakeCurrent(_RGFW.root->src.EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); else { - RGFW_eglMakeCurrent(_RGFW->EGL_display, win->src.ctx.egl->surface, win->src.ctx.egl->surface, win->src.ctx.egl->ctx); + eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); } } -void RGFW_window_swapBuffers_EGL(RGFW_window* win) { - if (RGFW_eglSwapBuffers) - RGFW_eglSwapBuffers(_RGFW->EGL_display, win->src.ctx.egl->surface); - else RGFW_window_swapBuffers_OpenGL(win); -} +void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); } -void* RGFW_getCurrentContext_EGL(void) { - return RGFW_eglGetCurrentContext(); -} +void* RGFW_getCurrent_OpenGL(void) { return eglGetCurrentContext(); } -RGFW_proc RGFW_getProcAddress_EGL(const char* procname) { +#ifdef RGFW_APPLE +void* RGFWnsglFramework = NULL; +#elif defined(RGFW_WINDOWS) +HMODULE RGFW_wgl_dll = NULL; +#endif + +RGFW_proc RGFW_getProcAddress(const char* procname) { #if defined(RGFW_WINDOWS) RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); @@ -4582,46 +3016,19 @@ RGFW_proc RGFW_getProcAddress_EGL(const char* procname) { return proc; #endif - return (RGFW_proc) RGFW_eglGetProcAddress(procname); + return (RGFW_proc) eglGetProcAddress(procname); } -RGFW_bool RGFW_extensionSupportedPlatform_EGL(const char* extension, size_t len) { - if (RGFW_loadEGL() == RGFW_FALSE) return RGFW_FALSE; - const char* extensions = RGFW_eglQueryString(_RGFW->EGL_display, EGL_EXTENSIONS); - return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); +RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) { + const char* extensions = eglQueryString(_RGFW.root->src.EGL_display, EGL_EXTENSIONS); + return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); } -void RGFW_window_swapInterval_EGL(RGFW_window* win, i32 swapInterval) { +void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_ASSERT(win != NULL); - RGFW_eglSwapInterval(_RGFW->EGL_display, swapInterval); -} -RGFW_bool RGFW_extensionSupported_EGL(const char* extension, size_t len) { - if (RGFW_extensionSupported_base(extension, len)) return RGFW_TRUE; - return RGFW_extensionSupportedPlatform_EGL(extension, len); -} + eglSwapInterval(win->src.EGL_display, swapInterval); -void RGFW_window_makeCurrentWindow_EGL(RGFW_window* win) { - _RGFW->current = win; - RGFW_window_makeCurrentContext_EGL(win); -} - -RGFW_window* RGFW_getCurrentWindow_EGL(void) { return _RGFW->current; } - -RGFW_eglContext* RGFW_window_createContext_EGL(RGFW_window* win, RGFW_glHints* hints) { - RGFW_eglContext* ctx = (RGFW_eglContext*)RGFW_ALLOC(sizeof(RGFW_eglContext)); - if (RGFW_window_createContextPtr_EGL(win, ctx, hints) == RGFW_FALSE) { - RGFW_FREE(ctx); - win->src.ctx.egl = NULL; - return NULL; - } - win->src.gfxType |= RGFW_gfxOwnedByRGFW; - return ctx; -} - -void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) { - RGFW_window_deleteContextPtr_EGL(win, ctx); - if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(ctx); } #endif /* RGFW_EGL */ @@ -4639,7 +3046,7 @@ void RGFW_window_deleteContext_EGL(RGFW_window* win, RGFW_eglContext* ctx) { #include #endif -const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count) { +const char** RGFW_getVKRequiredInstanceExtensions(size_t* count) { static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME}; arr[1] = RGFW_VK_SURFACE; if (count != NULL) *count = 2; @@ -4647,20 +3054,20 @@ const char** RGFW_getRequiredInstanceExtensions_Vulkan(size_t* count) { return (const char**)arr; } -VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) { +VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) { RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance); RGFW_ASSERT(surface != NULL); *surface = VK_NULL_HANDLE; #ifdef RGFW_X11 - - VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) _RGFW->display, (Window) win->src.window }; + RGFW_GOTO_WAYLAND(0); + VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window }; return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface); #endif #if defined(RGFW_WAYLAND) - - VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) _RGFW->wl_display, (struct wl_surface*) win->src.surface }; +RGFW_WAYLAND_LABEL + VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) win->src.wl_display, (struct wl_surface*) win->src.surface }; return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface); #elif defined(RGFW_WINDOWS) VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window }; @@ -4668,24 +3075,28 @@ VkResult RGFW_window_createSurface_Vulkan(RGFW_window* win, VkInstance instance, return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface); #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) void* contentView = ((void* (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView")); - VkMacOSSurfaceCreateSurfaceMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, 0, (void*)contentView }; + VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, win->src.display, (void*)contentView }; + return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface); #endif } -RGFW_bool RGFW_getPresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { +RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) { RGFW_ASSERT(instance); - if (_RGFW == NULL) RGFW_init(); + if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) RGFW_init(); #ifdef RGFW_X11 + RGFW_GOTO_WAYLAND(0); + Visual* visual = DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)); + if (_RGFW.root) + visual = _RGFW.root->src.visual.visual; - Visual* visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)); - RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->display, XVisualIDFromVisual(visual)); + RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.display, XVisualIDFromVisual(visual)); return out; #endif #if defined(RGFW_WAYLAND) - - RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW->wl_display); +RGFW_WAYLAND_LABEL + RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.wl_display); return wlout; #elif defined(RGFW_WINDOWS) #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11) @@ -4698,138 +3109,1341 @@ RGFW_bool RGFW_getPresentationSupport_Vulkan(VkInstance instance, VkPhysicalDevi This is where OS specific stuff starts */ -/* start of unix (wayland or X11 (unix) ) defines */ + +#if (defined(RGFW_WAYLAND) || defined(RGFW_X11)) && !defined(RGFW_NO_LINUX) + int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */ + + #if defined(__linux__) + #include + #include + #include + #include + + u32 RGFW_linux_updateGamepad(RGFW_window* win); + u32 RGFW_linux_updateGamepad(RGFW_window* win) { + /* check for new gamepads */ + static const char* str[] = {"/dev/input/js0", "/dev/input/js1", "/dev/input/js2", "/dev/input/js3", "/dev/input/js4", "/dev/input/js5"}; + static u8 RGFW_rawGamepads[6]; + { + u16 i; + for (i = 0; i < 6; i++) { + u16 index = RGFW_gamepadCount; + if (RGFW_rawGamepads[i]) { + struct input_id device_info; + if (ioctl(RGFW_rawGamepads[i], EVIOCGID, &device_info) == -2) { + if (errno == ENODEV) { + RGFW_rawGamepads[i] = 0; + } + } + continue; + } + + i32 js = open(str[i], O_RDONLY); + + if (js <= 0) + break; + + if (RGFW_gamepadCount >= 4) { + close(js); + break; + } + + RGFW_rawGamepads[i] = 1; + + int axes, buttons; + if (ioctl(js, JSIOCGAXES, &axes) < 0 || ioctl(js, JSIOCGBUTTONS, &buttons) < 0) { + close(js); + continue; + } + + if (buttons <= 5 || buttons >= 30) { + close(js); + continue; + } + + RGFW_gamepadCount++; + + RGFW_gamepads[index] = js; + + ioctl(js, JSIOCGNAME(sizeof(RGFW_gamepads_name[index])), RGFW_gamepads_name[index]); + RGFW_gamepads_name[index][sizeof(RGFW_gamepads_name[index]) - 1] = 0; + + u8 j; + for (j = 0; j < 16; j++) { + RGFW_gamepadPressed[index][j].prev = 0; + RGFW_gamepadPressed[index][j].current = 0; + } + + win->event.type = RGFW_gamepadConnected; + + RGFW_gamepads_type[index] = RGFW_gamepadUnknown; + if (RGFW_STRSTR(RGFW_gamepads_name[index], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[index], "X-Box")) + RGFW_gamepads_type[index] = RGFW_gamepadMicrosoft; + else if (RGFW_STRSTR(RGFW_gamepads_name[index], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS5")) + RGFW_gamepads_type[index] = RGFW_gamepadSony; + else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Nintendo")) + RGFW_gamepads_type[index] = RGFW_gamepadNintendo; + else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Logitech")) + RGFW_gamepads_type[index] = RGFW_gamepadLogitech; + + win->event.gamepad = index; + RGFW_gamepadCallback(win, index, 1); + return 1; + } + } + /* check gamepad events */ + u8 i; + + for (i = 0; i < RGFW_gamepadCount; i++) { + struct js_event e; + if (RGFW_gamepads[i] == 0) + continue; + + i32 flags = fcntl(RGFW_gamepads[i], F_GETFL, 0); + fcntl(RGFW_gamepads[i], F_SETFL, flags | O_NONBLOCK); + + ssize_t bytes; + while ((bytes = read(RGFW_gamepads[i], &e, sizeof(e))) > 0) { + switch (e.type) { + case JS_EVENT_BUTTON: { + size_t typeIndex = 0; + if (RGFW_gamepads_type[i] == RGFW_gamepadMicrosoft) typeIndex = 1; + else if (RGFW_gamepads_type[i] == RGFW_gamepadLogitech) typeIndex = 2; + + win->event.type = e.value ? RGFW_gamepadButtonPressed : RGFW_gamepadButtonReleased; + u8 RGFW_linux2RGFW[3][RGFW_gamepadR3 + 8] = {{ /* ps */ + RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadY, RGFW_gamepadX, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, + RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, + },{ /* xbox */ + RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadSelect, RGFW_gamepadStart, + RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, 255, 255, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight + },{ /* Logitech */ + RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, + RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight + } + }; + + win->event.button = RGFW_linux2RGFW[typeIndex][e.number]; + win->event.gamepad = i; + if (win->event.button == 255) break; + + RGFW_gamepadPressed[i][win->event.button].prev = RGFW_gamepadPressed[i][win->event.button].current; + RGFW_gamepadPressed[i][win->event.button].current = RGFW_BOOL(e.value); + RGFW_gamepadButtonCallback(win, i, win->event.button, RGFW_BOOL(e.value)); + + return 1; + } + case JS_EVENT_AXIS: { + size_t axis = e.number / 2; + if (axis == 2) axis = 1; + + ioctl(RGFW_gamepads[i], JSIOCGAXES, &win->event.axisesCount); + win->event.axisesCount = 2; + + if (axis < 3) { + if (e.number == 0 || e.number == 3) + RGFW_gamepadAxes[i][axis].x = (i32)((e.value / 32767.0f) * 100); + else if (e.number == 1 || e.number == 4) { + RGFW_gamepadAxes[i][axis].y = (i32)((e.value / 32767.0f) * 100); + } + } + + win->event.axis[axis] = RGFW_gamepadAxes[i][axis]; + win->event.type = RGFW_gamepadAxisMove; + win->event.gamepad = i; + win->event.whichAxis = (u8)axis; + RGFW_gamepadAxisCallback(win, i, win->event.axis, win->event.axisesCount, win->event.whichAxis); + return 1; + } + default: break; + } + } + if (bytes == -1 && errno == ENODEV) { + RGFW_gamepadCount--; + close(RGFW_gamepads[i]); + RGFW_gamepads[i] = 0; + + win->event.type = RGFW_gamepadDisconnected; + win->event.gamepad = i; + RGFW_gamepadCallback(win, i, 0); + return 1; + } + } + return 0; + } + + #endif +#endif + + + +/* + + Start of Wayland defines + + +*/ + +#ifdef RGFW_WAYLAND +/* +Wayland TODO: (out of date) +- fix RGFW_keyPressed lock state + + RGFW_windowMoved, the window was moved (by the user) + RGFW_windowResized the window was resized (by the user), [on WASM this means the browser was resized] + RGFW_windowRefresh The window content needs to be refreshed + + RGFW_DND a file has been dropped into the window + RGFW_DNDInit + +- window args: + #define RGFW_windowNoResize the window cannot be resized by the user + #define RGFW_windowAllowDND the window supports drag and drop + #define RGFW_scaleToMonitor scale the window to the screen + +- other missing functions functions ("TODO wayland") (~30 functions) +- fix buffer rendering weird behavior +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +RGFW_window* RGFW_key_win = NULL; + +/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */ +#include "xdg-shell.h" +#include "xdg-decoration-unstable-v1.h" + +struct xkb_context *xkb_context; +struct xkb_keymap *keymap = NULL; +struct xkb_state *xkb_state = NULL; +enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode; +struct zxdg_decoration_manager_v1 *decoration_manager = NULL; + +struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL; +struct wl_surface* RGFW_cursor_surface = NULL; +struct wl_cursor_image* RGFW_cursor_image = NULL; + +void xdg_wm_base_ping_handler(void *data, + struct xdg_wm_base *wm_base, uint32_t serial) +{ + RGFW_UNUSED(data); + xdg_wm_base_pong(wm_base, serial); +} + +const struct xdg_wm_base_listener xdg_wm_base_listener = { + .ping = xdg_wm_base_ping_handler, +}; + +RGFW_bool RGFW_wl_configured = 0; + +void xdg_surface_configure_handler(void *data, + struct xdg_surface *xdg_surface, uint32_t serial) +{ + RGFW_UNUSED(data); + xdg_surface_ack_configure(xdg_surface, serial); + RGFW_wl_configured = 1; +} + +const struct xdg_surface_listener xdg_surface_listener = { + .configure = xdg_surface_configure_handler, +}; + +void xdg_toplevel_configure_handler(void *data, + struct xdg_toplevel *toplevel, int32_t width, int32_t height, + struct wl_array *states) +{ + RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states); + RGFW_UNUSED(width); RGFW_UNUSED(height); +} + +void xdg_toplevel_close_handler(void *data, + struct xdg_toplevel *toplevel) +{ + RGFW_UNUSED(data); + RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel); + if (win == NULL) + win = RGFW_key_win; + + RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); + RGFW_windowQuitCallback(win); +} + +void shm_format_handler(void *data, + struct wl_shm *shm, uint32_t format) +{ + RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format); +} + +const struct wl_shm_listener shm_listener = { + .format = shm_format_handler, +}; + +const struct xdg_toplevel_listener xdg_toplevel_listener = { + .configure = xdg_toplevel_configure_handler, + .close = xdg_toplevel_close_handler, +}; + +RGFW_window* RGFW_mouse_win = NULL; + +void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y); + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + RGFW_mouse_win = win; + + RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter; + e.point = RGFW_POINT(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)); + e._win = win); + + RGFW_mouseNotifyCallback(win, win->event.point, RGFW_TRUE); +} +void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface); + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + if (RGFW_mouse_win == win) + RGFW_mouse_win = NULL; + + RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave; + e.point = win->event.point; + e._win = win); + + RGFW_mouseNotifyCallback(win, win->event.point, RGFW_FALSE); +} +void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y); + + RGFW_ASSERT(RGFW_mouse_win != NULL); + RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; + e.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)); + e._win = RGFW_mouse_win); + + RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)), RGFW_mouse_win->event.vector); +} +void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); + RGFW_ASSERT(RGFW_mouse_win != NULL); + + u32 b = (button - 0x110); + + /* flip right and middle button codes */ + if (b == 1) b = 2; + else if (b == 2) b = 1; + + RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current; + RGFW_mouseButtons[b].current = RGFW_BOOL(state); + + RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased - RGFW_BOOL(state); + e.point = RGFW_mouse_win->event.point; + e.button = (u8)b; + e._win = RGFW_mouse_win); + RGFW_mouseButtonCallback(RGFW_mouse_win, (u8)b, 0, RGFW_BOOL(state)); +} +void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { + RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis); + RGFW_ASSERT(RGFW_mouse_win != NULL); + + double scroll = - wl_fixed_to_double(value); + + RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; + e.point = RGFW_mouse_win->event.point; + e.button = RGFW_mouseScrollUp + (scroll < 0); + e.scroll = scroll; + e._win = RGFW_mouse_win); + + RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1); +} + +void RGFW_doNothing(void) { } + +void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format); + + char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); + xkb_keymap_unref (keymap); + keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + + munmap (keymap_string, size); + close (fd); + xkb_state_unref (xkb_state); + xkb_state = xkb_state_new (keymap); +} +void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys); + + RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface); + + RGFW_key_win->_flags |= RGFW_windowFocus; + RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = RGFW_key_win); + RGFW_focusCallback(RGFW_key_win, RGFW_TRUE); + + if ((RGFW_key_win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(RGFW_key_win, RGFW_AREA(RGFW_key_win->r.w, RGFW_key_win->r.h)); +} +void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); + + RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); + if (RGFW_key_win == win) + RGFW_key_win = NULL; + + RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win); + RGFW_focusCallback(win, RGFW_FALSE); + RGFW_window_focusLost(win); +} +void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); + + if (RGFW_key_win == NULL) return; + + xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8); + + u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8); + RGFW_keyboard[RGFWkey].prev = RGFW_keyboard[RGFWkey].current; + RGFW_keyboard[RGFWkey].current = RGFW_BOOL(state); + + RGFW_eventQueuePushEx(e.type = (u8)(RGFW_keyPressed + state); + e.key = (u8)RGFWkey; + e.keyChar = (u8)keysym; + e.repeat = RGFW_isHeld(RGFW_key_win, (u8)RGFWkey); + e._win = RGFW_key_win); + + RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "ScrollLock"))); + RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->event.keyMod, RGFW_BOOL(state)); +} +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); + xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); +} +struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void (*)(void *, struct wl_keyboard *, +int, int))&RGFW_doNothing}; + +void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) { + RGFW_UNUSED(data); + static struct wl_pointer_listener pointer_listener = {&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void (*)(void *, struct wl_pointer *))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void*, struct wl_pointer*, uint32_t, uint32_t))&RGFW_doNothing}; + + if (capabilities & WL_SEAT_CAPABILITY_POINTER) { + struct wl_pointer *pointer = wl_seat_get_pointer (seat); + wl_pointer_add_listener (pointer, &pointer_listener, NULL); + } + if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat); + wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL); + } +} +struct wl_seat_listener seat_listener = {&seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing}; + +void wl_global_registry_handler(void *data, + struct wl_registry *registry, uint32_t id, const char *interface, + uint32_t version) +{ + RGFW_window* win = (RGFW_window*)data; + RGFW_UNUSED(version); + if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) { + win->src.compositor = wl_registry_bind(registry, + id, &wl_compositor_interface, 4); + } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) { + win->src.xdg_wm_base = wl_registry_bind(registry, + id, &xdg_wm_base_interface, 1); + } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) { + decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); + } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) { + win->src.shm = wl_registry_bind(registry, + id, &wl_shm_interface, 1); + wl_shm_add_listener(win->src.shm, &shm_listener, NULL); + } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) { + win->src.seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); + wl_seat_add_listener(win->src.seat, &seat_listener, NULL); + } +} + +void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); } +const struct wl_registry_listener registry_listener = { + .global = wl_global_registry_handler, + .global_remove = wl_global_registry_remove, +}; + +void decoration_handle_configure(void *data, + struct zxdg_toplevel_decoration_v1 *decoration, + enum zxdg_toplevel_decoration_v1_mode mode) { + RGFW_UNUSED(data); RGFW_UNUSED(decoration); + RGFW_current_mode = mode; +} + +const struct zxdg_toplevel_decoration_v1_listener decoration_listener = { + .configure = decoration_handle_configure, +}; + +void randname(char *buf) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + + int i; + for (i = 0; i < 6; ++i) { + buf[i] = (char)('A'+(r&15)+(r&16)*2); + r >>= 5; + } +} + +size_t wl_stringlen(char* name) { + size_t i = 0; + while (name[i]) { i++; } + return i; +} + +int anonymous_shm_open(void) { + char name[] = "/RGFW-wayland-XXXXXX"; + int retries = 100; + + do { + randname(name + wl_stringlen(name) - 6); + + --retries; + /* shm_open guarantees that O_CLOEXEC is set */ + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + + return -1; +} + +int create_shm_file(off_t size) { + int fd = anonymous_shm_open(); + if (fd < 0) { + return fd; + } + + if (ftruncate(fd, size) < 0) { + close(fd); + return -1; + } + + return fd; +} + +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; + wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); + wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h); + wl_surface_commit(win->src.surface); + #endif +} + +const struct wl_callback_listener wl_surface_frame_listener = { + .done = wl_surface_frame_done, +}; +#endif /* RGFW_WAYLAND */ +/* + End of Wayland defines +*/ + +/* + + +Start of Linux / Unix defines + + +*/ #ifdef RGFW_UNIX -#include -#include +#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11) +#include +#endif + +#include + +#ifndef RGFW_NO_DPI +#include +#include +#endif + +#include +#include +#include #include -void RGFW_stopCheckEvents(void) { +#include /* for converting keycode to string */ +#include /* for hiding */ +#include +#include +#include - _RGFW->eventWait_forceStop[2] = 1; - while (1) { - const char byte = 0; - const ssize_t result = write(_RGFW->eventWait_forceStop[1], &byte, 1); - if (result == 1 || result == -1) - break; - } +#include /* for data limits (mainly used in drag and drop functions) */ +#include + +/* atoms needed for drag and drop */ +Atom XdndAware, XtextPlain, XtextUriList; +Atom RGFW_XUTF8_STRING = 0; + +Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0; + +#if defined(RGFW_X11) && !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) + typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int); + typedef void (*PFN_XcursorImageDestroy)(XcursorImage*); + typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*); +#endif +#if defined(RGFW_OPENGL) && defined(RGFW_X11) + typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); +#endif + +#if !defined(RGFW_NO_X11_XI_PRELOAD) && defined(RGFW_X11) + typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); + PFN_XISelectEvents XISelectEventsSRC = NULL; + #define XISelectEvents XISelectEventsSRC + + void* X11Xihandle = NULL; +#endif + +#if !defined(RGFW_NO_X11_EXT_PRELOAD) && defined(RGFW_X11) + typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int); + PFN_XSyncIntToValue XSyncIntToValueSRC = NULL; + #define XSyncIntToValue XSyncIntToValueSRC + + typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue); + PFN_XSyncSetCounter XSyncSetCounterSRC = NULL; + #define XSyncSetCounter XSyncSetCounterSRC + + typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue); + PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL; + #define XSyncCreateCounter XSyncCreateCounterSRC + + typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); + PFN_XShapeCombineMask XShapeCombineMaskSRC; + #define XShapeCombineMask XShapeCombineMaskSRC + + typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); + PFN_XShapeCombineRegion XShapeCombineRegionSRC; + #define XShapeCombineRegion XShapeCombineRegionSRC + void* X11XEXThandle = NULL; +#endif + +#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) && defined(RGFW_X11) + PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL; + PFN_XcursorImageCreate XcursorImageCreateSRC = NULL; + PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL; + + #define XcursorImageLoadCursor XcursorImageLoadCursorSRC + #define XcursorImageCreate XcursorImageCreateSRC + #define XcursorImageDestroy XcursorImageDestroySRC + + void* X11Cursorhandle = NULL; +#endif + +#ifdef RGFW_X11 +const char* RGFW_instName = NULL; +void RGFW_setXInstName(const char* name) { RGFW_instName = name; } +#endif + +#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) +RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { + const char* extensions = glXQueryExtensionsString(_RGFW.display, XDefaultScreen(_RGFW.display)); + return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len); } +RGFW_proc RGFW_getProcAddress(const char* procname) { return (RGFW_proc) glXGetProcAddress((GLubyte*) procname); } +#endif -RGFWDEF u64 RGFW_linux_getTimeNS(i32 clock); -u64 RGFW_linux_getTimeNS(i32 clock) { - struct timespec ts; - const u64 scale_factor = 1000000000; - clock_gettime(clock, &ts); - return (u64)ts.tv_sec * scale_factor + (u64)ts.tv_nsec; -} +void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) { + RGFW_GOTO_WAYLAND(0); -void RGFW_waitForEvent(i32 waitMS) { - if (waitMS == 0) return; +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + win->buffer = (u8*)buffer; + win->bufferSize = area; - if (_RGFW->eventWait_forceStop[0] == 0 || _RGFW->eventWait_forceStop[1] == 0) { - if (pipe(_RGFW->eventWait_forceStop) != -1) { - fcntl(_RGFW->eventWait_forceStop[0], F_GETFL, 0); - fcntl(_RGFW->eventWait_forceStop[0], F_GETFD, 0); - fcntl(_RGFW->eventWait_forceStop[1], F_GETFL, 0); - fcntl(_RGFW->eventWait_forceStop[1], F_GETFD, 0); - } - } - - struct pollfd fds[2]; - fds[0].fd = 0; - fds[0].events = POLLIN; - fds[0].revents = 0; - fds[1].fd = _RGFW->eventWait_forceStop[0]; - fds[1].events = POLLIN; - fds[1].revents = 0; - - - if (RGFW_usingWayland()) { - #ifdef RGFW_WAYLAND - fds[0].fd = wl_display_get_fd(_RGFW->wl_display); - - /* empty the queue */ - while (wl_display_prepare_read(_RGFW->wl_display) != 0) { - /* error occured when dispatching the queue */ - if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { - return; - } - } - - /* send any pending requests to the compositor */ - while (wl_display_flush(_RGFW->wl_display) == -1) { - - /* queue is full dispatch them */ - if (errno == EAGAIN) { - if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { - return; - } - } else { - return; - } - } + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, RGFW_DEBUG_CTX(win, 0), "createing a 4 channel buffer"); + #ifdef RGFW_X11 + #ifdef RGFW_OSMESA + win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); + OSMesaPixelStore(OSMESA_Y_UP, 0); #endif - } else { - #ifdef RGFW_X11 - fds[0].fd = ConnectionNumber(_RGFW->display); + + win->src.bitmap = XCreateImage( + win->src.display, win->src.visual.visual, (u32)win->src.visual.depth, + ZPixmap, 0, NULL, area.w, area.h, 32, 0 + ); + #endif + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL {} + u32 size = (u32)(win->r.w * win->r.h * 4); + int fd = create_shm_file(size); + if (fd < 0) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, (u32)fd),"Failed to create a buffer."); + exit(1); + } + + win->src.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (win->src.buffer == MAP_FAILED) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, 0), "mmap failed!"); + close(fd); + exit(1); + } + + win->_flags |= RGFW_BUFFER_ALLOC; + + struct wl_shm_pool* pool = wl_shm_create_pool(win->src.shm, fd, (i32)size); + win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4, + WL_SHM_FORMAT_ARGB8888); + wl_shm_pool_destroy(pool); + + close(fd); + + wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); + wl_surface_commit(win->src.surface); + + u8 color[] = {0x00, 0x00, 0x00, 0xFF}; + + size_t i; + for (i = 0; i < area.w * area.h * 4; i += 4) { + RGFW_MEMCPY(&win->buffer[i], color, 4); + } + + RGFW_MEMCPY(win->src.buffer, win->buffer, (size_t)(win->r.w * win->r.h * 4)); + + #if defined(RGFW_OSMESA) + win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); + OSMesaPixelStore(OSMESA_Y_UP, 0); #endif - } - - i32 clock = 0; - #if defined(_POSIX_MONOTONIC_CLOCK) - struct timespec ts; - RGFW_MEMSET(&ts, 0, sizeof(struct timespec)); - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - clock = CLOCK_MONOTONIC; - #else - clock = CLOCK_REALTIME; + #endif +#else + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL{} #endif - u64 start = RGFW_linux_getTimeNS(clock); - if (RGFW_usingWayland()) { - #ifdef RGFW_WAYLAND - while (wl_display_dispatch_pending(_RGFW->wl_display) == 0) { - if (poll(fds, 1, waitMS) <= 0) { - wl_display_cancel_read(_RGFW->wl_display); - break; - } else { - if (wl_display_read_events(_RGFW->wl_display) == -1) - return; - } + RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); +#endif +} - if (waitMS != RGFW_eventWaitNext) { - waitMS -= (i32)(RGFW_linux_getTimeNS(clock) - start) / (i32)1e+6; - } - } +#define RGFW_LOAD_ATOM(name) \ + static Atom name = 0; \ + if (name == 0) name = XInternAtom(_RGFW.display, #name, False); - /* queue contains events from read, dispatch them */ - if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { +void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { + RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); + + RGFW_GOTO_WAYLAND(0); + #ifdef RGFW_X11 + RGFW_LOAD_ATOM(_MOTIF_WM_HINTS); + + struct __x11WindowHints { + unsigned long flags, functions, decorations, status; + long input_mode; + } hints; + hints.flags = 2; + hints.decorations = border; + + XChangeProperty(win->src.display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, + PropModeReplace, (u8*)&hints, 5 + ); + + if (RGFW_window_isHidden(win) == 0) { + RGFW_window_hide(win); + RGFW_window_show(win); + } + + #endif + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_UNUSED(win); RGFW_UNUSED(border); + #endif +} + +void RGFW_releaseCursor(RGFW_window* win) { +RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + XUngrabPointer(win->src.display, CurrentTime); + + /* disable raw input */ + unsigned char mask[] = { 0 }; + XIEventMask em; + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_UNUSED(win); +#endif +} + +void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { +RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + /* enable raw input */ + unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; + XISetMask(mask, XI_RawMotion); + + XIEventMask em; + em.deviceid = XIAllMasterDevices; + em.mask_len = sizeof(mask); + em.mask = mask; + + 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))); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_UNUSED(win); RGFW_UNUSED(r); +#endif +} + +#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL) +#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \ + void* ptr = dlsym(proc, #name); \ + if (ptr != NULL) memcpy(&name##SRC, &ptr, sizeof(PFN_##name)); \ +} + +#ifdef RGFW_X11 +void RGFW_window_getVisual(RGFW_window* win) { +#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) + i32* visual_attribs = RGFW_initFormatAttribs(); + i32 fbcount; + GLXFBConfig* fbc = glXChooseFBConfig(win->src.display, DefaultScreen(win->src.display), visual_attribs, &fbcount); + + i32 best_fbc = -1; + i32 best_depth = 0; + i32 best_samples = 0; + + if (fbcount == 0) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to find any valid GLX visual configs"); return; } - #endif - } else { - #ifdef RGFW_X11 - while (XPending(_RGFW->display) == 0) { - if (poll(fds, 1, waitMS) <= 0) - break; - if (waitMS != RGFW_eventWaitNext) { - waitMS -= (i32)(RGFW_linux_getTimeNS(clock) - start) / (i32)1e+6; + i32 i; + for (i = 0; i < fbcount; i++) { + XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, fbc[i]); + if (vi == NULL) + continue; + + i32 samp_buf, samples; + glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); + glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLES, &samples); + + if (best_fbc == -1) best_fbc = i; + if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && best_depth == 0) { + best_fbc = i; + best_depth = vi->depth; } + if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && samples <= RGFW_GL_HINTS[RGFW_glSamples] && samples > best_samples) { + best_fbc = i; + best_depth = vi->depth; + best_samples = samples; + } + XFree(vi); } + + if (best_fbc == -1) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to get a valid GLX visual"); + return; + } + + win->src.bestFbc = fbc[best_fbc]; + XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, win->src.bestFbc); + if (vi->depth != 32 && (win->_flags & RGFW_windowTransparent)) + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to to find a matching visual with a 32-bit depth"); + + if (best_samples < RGFW_GL_HINTS[RGFW_glSamples]) + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load matching sampiling"); + + int configCaveat; + if (glXGetFBConfigAttrib(win->src.display, win->src.bestFbc, GLX_CONFIG_CAVEAT, &configCaveat) == Success && + configCaveat == GLX_SLOW_CONFIG) { + win->_flags |= RGFW_windowOpenglSoftware; + } + + XFree(fbc); + win->src.visual = *vi; + XFree(vi); +#else + win->src.visual.visual = DefaultVisual(win->src.display, DefaultScreen(win->src.display)); + win->src.visual.depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display)); + if (win->_flags & RGFW_windowTransparent) { + XMatchVisualInfo(win->src.display, DefaultScreen(win->src.display), 32, TrueColor, &win->src.visual); /*!< for RGBA backgrounds */ + if (win->src.visual.depth != 32) + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load a 32-bit depth"); + } +#endif +} +#endif +#ifndef RGFW_EGL +void RGFW_window_initOpenGL(RGFW_window* win) { +#ifdef RGFW_OPENGL + i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 }; + context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB; + if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) + context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + else + context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + + if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) { + context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB; + context_attribs[3] = RGFW_GL_HINTS[RGFW_glMajor]; + context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB; + context_attribs[5] = RGFW_GL_HINTS[RGFW_glMinor]; + } + + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) + glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB"); + + GLXContext ctx = NULL; + if (_RGFW.root != NULL && _RGFW.root != win) { + ctx = _RGFW.root->src.ctx; + RGFW_window_makeCurrent_OpenGL(_RGFW.root); + } + + if (glXCreateContextAttribsARB == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to load proc address 'glXCreateContextAttribsARB', loading a generic opengl context"); + win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True); + } + else { + win->src.ctx = glXCreateContextAttribsARB(win->src.display, win->src.bestFbc, ctx, True, context_attribs); + XSync(win->src.display, False); + if (win->src.ctx == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to create an opengl context with AttribsARB, loading a generic opengl context"); + win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True); + } + } + + glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); +#else + RGFW_UNUSED(win); +#endif +} + +void RGFW_window_freeOpenGL(RGFW_window* win) { +#ifdef RGFW_OPENGL + if (win->src.ctx == NULL) return; + glXDestroyContext(win->src.display, win->src.ctx); + win->src.ctx = NULL; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); +#else +RGFW_UNUSED(win); +#endif +} +#endif + + +i32 RGFW_init(void) { + RGFW_GOTO_WAYLAND(1); +#if defined(RGFW_C89) || defined(__cplusplus) + if (_RGFW_init) return 0; + _RGFW_init = RGFW_TRUE; + _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; +#endif + +#ifdef RGFW_X11 + if (_RGFW.windowCount != -1) return 0; + #ifdef RGFW_USE_XDL + XDL_init(); + #endif + + #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) + #if defined(__CYGWIN__) + RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so"); + #elif defined(__OpenBSD__) || defined(__NetBSD__) + RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so"); + #else + RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1"); + #endif + RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate); + RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy); + RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor); + #endif + + #if !defined(RGFW_NO_X11_XI_PRELOAD) + #if defined(__CYGWIN__) + RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so"); + #elif defined(__OpenBSD__) || defined(__NetBSD__) + RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so"); + #else + RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6"); + #endif + RGFW_PROC_DEF(X11Xihandle, XISelectEvents); + #endif + + #if !defined(RGFW_NO_X11_EXT_PRELOAD) + #if defined(__CYGWIN__) + RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so"); + #elif defined(__OpenBSD__) || defined(__NetBSD__) + RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so"); + #else + RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6"); + #endif + RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter); + RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue); + RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter); + RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion); + RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask); + #endif + + XInitThreads(); /*!< init X11 threading */ + _RGFW.display = XOpenDisplay(0); + XSetWindowAttributes wa; + RGFW_MEMSET(&wa, 0, sizeof(wa)); + wa.event_mask = PropertyChangeMask; + _RGFW.helperWindow = XCreateWindow(_RGFW.display, XDefaultRootWindow(_RGFW.display), 0, 0, 1, 1, 0, 0, + InputOnly, DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)), CWEventMask, &wa); + + _RGFW.windowCount = 0; + u8 RGFW_blk[] = { 0, 0, 0, 0 }; + _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4); + _RGFW.clipboard = NULL; + + XkbComponentNamesRec rec; + XkbDescPtr desc = XkbGetMap(_RGFW.display, 0, XkbUseCoreKbd); + XkbDescPtr evdesc; + u8 old[sizeof(RGFW_keycodes) / sizeof(RGFW_keycodes[0])]; + + XkbGetNames(_RGFW.display, XkbKeyNamesMask, desc); + + RGFW_MEMSET(&rec, 0, sizeof(rec)); + rec.keycodes = (char*)"evdev"; + evdesc = XkbGetKeyboardByName(_RGFW.display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False); + /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */ + if(evdesc != NULL && desc != NULL){ + for(int i = 0; i < (int)sizeof(RGFW_keycodes) / (int)sizeof(RGFW_keycodes[0]); i++){ + old[i] = RGFW_keycodes[i]; + RGFW_keycodes[i] = 0; + } + for(int i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){ + for(int j = desc->min_key_code; j <= desc->max_key_code; j++){ + if(strncmp(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){ + RGFW_keycodes[j] = old[i]; + break; + } + } + } + XkbFreeKeyboard(desc, 0, True); + XkbFreeKeyboard(evdesc, 0, True); + } +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL + _RGFW.wl_display = wl_display_connect(NULL); +#endif + _RGFW.windowCount = 0; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); + return 0; +} + + +RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { + RGFW_window_basic_init(win, rect, flags); + +#ifdef RGFW_WAYLAND + win->src.compositor = NULL; +#endif + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted */ + + win->src.display = XOpenDisplay(NULL); + RGFW_window_getVisual(win); + + /* make X window attrubutes */ + XSetWindowAttributes swa; + RGFW_MEMSET(&swa, 0, sizeof(swa)); + + Colormap cmap; + swa.colormap = cmap = XCreateColormap(win->src.display, + DefaultRootWindow(win->src.display), + win->src.visual.visual, AllocNone); + swa.event_mask = event_mask; + + /* create the window */ + win->src.window = XCreateWindow(win->src.display, DefaultRootWindow(win->src.display), win->r.x, win->r.y, (u32)win->r.w, (u32)win->r.h, + 0, win->src.visual.depth, InputOutput, win->src.visual.visual, + CWColormap | CWBorderPixel | CWEventMask, &swa); + + XFreeColors(win->src.display, cmap, NULL, 0, 0); + + win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL); + + /* In your .desktop app, if you set the property + StartupWMClass=RGFW that will assoicate the launcher icon + with your application - robrohan */ + if (RGFW_className == NULL) + RGFW_className = (char*)name; + + XClassHint hint; + hint.res_class = (char*)RGFW_className; + if (RGFW_instName == NULL) hint.res_name = (char*)name; + else hint.res_name = (char*)RGFW_instName; + XSetClassHint(win->src.display, win->src.window, &hint); + + #ifndef RGFW_NO_MONITOR + if (flags & RGFW_windowScaleToMonitor) + RGFW_window_scaleToMonitor(win); + #endif + XSelectInput(win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */ + + /* make it so the user can't close the window until the program does */ + if (wm_delete_window == 0) { + wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False); + RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False); + RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False); + } + + XSetWMProtocols(win->src.display, (Drawable) win->src.window, &wm_delete_window, 1); + /* set the background */ + RGFW_window_setName(win, name); + + XMoveWindow(win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords */ + + if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */ + win->_flags |= RGFW_windowAllowDND; + + /* actions */ + XtextUriList = XInternAtom(win->src.display, "text/uri-list", False); + XtextPlain = XInternAtom(win->src.display, "text/plain", False); + XdndAware = XInternAtom(win->src.display, "XdndAware", False); + const u8 version = 5; + + XChangeProperty(win->src.display, win->src.window, + XdndAware, 4, 32, + PropModeReplace, &version, 1); /*!< turns on drag and drop */ + } + +#ifdef RGFW_ADVANCED_SMOOTH_RESIZE + RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER) + RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST) + Atom protcols[2] = {_NET_WM_SYNC_REQUEST, wm_delete_window}; + XSetWMProtocols(win->src.display, win->src.window, protcols, 2); + + XSyncValue initial_value; + XSyncIntToValue(&initial_value, 0); + win->src.counter = XSyncCreateCounter(win->src.display, initial_value); + + XChangeProperty(win->src.display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1); +#endif + + if ((flags & RGFW_windowNoInitAPI) == 0) { + RGFW_window_initOpenGL(win); + RGFW_window_initBuffer(win); + } + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); + RGFW_window_setMouseDefault(win); + RGFW_window_setFlags(win, flags); + + win->src.r = win->r; + + RGFW_window_show(win); + return win; /*return newly created window */ +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "RGFW Wayland support is experimental"); + + win->src.wl_display = _RGFW.wl_display; + if (win->src.wl_display == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Failed to load Wayland display"); + #ifdef RGFW_X11 + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "Falling back to X11"); + RGFW_useWayland(0); + return RGFW_createWindowPtr(name, rect, flags, win); #endif + return NULL; } - /* drain any data in the stop request */ - if (_RGFW->eventWait_forceStop[2]) { - char data[64]; - RGFW_MEMSET(data, 0, sizeof(data)); - (void)!read(_RGFW->eventWait_forceStop[0], data, sizeof(data)); - _RGFW->eventWait_forceStop[2] = 0; + #ifdef RGFW_X11 + win->src.display = _RGFW.display; + win->src.window = _RGFW.helperWindow; + XMapWindow(_RGFW.display, win->src.window); + XFlush(win->src.display); + if (wm_delete_window == 0) { + wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False); + RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False); + RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False); + } + #endif + + struct wl_registry *registry = wl_display_get_registry(win->src.wl_display); + wl_registry_add_listener(registry, ®istry_listener, win); + + wl_display_roundtrip(win->src.wl_display); + wl_display_dispatch(win->src.wl_display); + + if (win->src.compositor == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Can't find compositor."); + return NULL; } + + if (RGFW_wl_cursor_theme == NULL) { + RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, win->src.shm); + RGFW_cursor_surface = wl_compositor_create_surface(win->src.compositor); + + struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr"); + RGFW_cursor_image = cursor->images[0]; + struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); + + wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); + wl_surface_commit(RGFW_cursor_surface); + } + + xdg_wm_base_add_listener(win->src.xdg_wm_base, &xdg_wm_base_listener, NULL); + + xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + win->src.surface = wl_compositor_create_surface(win->src.compositor); + wl_surface_set_user_data(win->src.surface, win); + + win->src.xdg_surface = xdg_wm_base_get_xdg_surface(win->src.xdg_wm_base, win->src.surface); + xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL); + + xdg_wm_base_set_user_data(win->src.xdg_wm_base, win); + + win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); + xdg_toplevel_set_user_data(win->src.xdg_toplevel, win); + xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL); + + xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h); + + if (!(flags & RGFW_windowNoBorder)) { + win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + decoration_manager, win->src.xdg_toplevel); + } + + wl_display_roundtrip(win->src.wl_display); + + wl_surface_commit(win->src.surface); + RGFW_window_show(win); + + /* wait for the surface to be configured */ + while (wl_display_dispatch(win->src.wl_display) != -1 && !RGFW_wl_configured) { } + + if ((flags & RGFW_windowNoInitAPI) == 0) { + RGFW_window_initOpenGL(win); + RGFW_window_initBuffer(win); + } + struct wl_callback* callback = wl_surface_frame(win->src.surface); + wl_callback_add_listener(callback, &wl_surface_frame_listener, win); + wl_surface_commit(win->src.surface); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); + + #ifndef RGFW_NO_MONITOR + if (flags & RGFW_windowScaleToMonitor) + RGFW_window_scaleToMonitor(win); + #endif + + RGFW_window_setName(win, name); + RGFW_window_setMouseDefault(win); + RGFW_window_setFlags(win, flags); + return win; /* return newly created window */ +#endif +} + +RGFW_area RGFW_getScreenSize(void) { + RGFW_GOTO_WAYLAND(1); + RGFW_init(); + + #ifdef RGFW_X11 + Screen* scrn = DefaultScreenOfDisplay(_RGFW.display); + return RGFW_AREA(scrn->width, scrn->height); + #endif + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL return RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h); /* TODO */ + #endif +} + +RGFW_point RGFW_getGlobalMousePoint(void) { + RGFW_init(); + RGFW_point RGFWMouse = RGFW_POINT(0, 0); + RGFW_GOTO_WAYLAND(1); +#ifdef RGFW_X11 + i32 x, y; + u32 z; + Window window1, window2; + XQueryPointer(_RGFW.display, XDefaultRootWindow(_RGFW.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z); + return RGFWMouse; +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + return RGFWMouse; +#endif +} + +RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event); +void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event); +#ifdef RGFW_X11 + RGFW_LOAD_ATOM(ATOM_PAIR); + RGFW_LOAD_ATOM(MULTIPLE); + RGFW_LOAD_ATOM(TARGETS); + RGFW_LOAD_ATOM(SAVE_TARGETS); + + const XSelectionRequestEvent* request = &event->xselectionrequest; + const Atom formats[] = { RGFW_XUTF8_STRING, XA_STRING }; + const int formatCount = sizeof(formats) / sizeof(formats[0]); + + if (request->target == TARGETS) { + const Atom targets[] = { TARGETS, MULTIPLE, RGFW_XUTF8_STRING, XA_STRING }; + + XChangeProperty(_RGFW.display, request->requestor, request->property, + XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom)); + } else if (request->target == MULTIPLE) { + Atom* targets = NULL; + + Atom actualType = 0; + int actualFormat = 0; + unsigned long count = 0, bytesAfter = 0; + + XGetWindowProperty(_RGFW.display, request->requestor, request->property, 0, LONG_MAX, + False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); + + unsigned long i; + for (i = 0; i < (u32)count; i += 2) { + if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING) + XChangeProperty(_RGFW.display, request->requestor, targets[i + 1], targets[i], + 8, PropModeReplace, (const unsigned char *)_RGFW.clipboard, (i32)_RGFW.clipboard_len); + else + targets[i + 1] = None; + } + + XChangeProperty(_RGFW.display, + request->requestor, request->property, ATOM_PAIR, 32, + PropModeReplace, (u8*) targets, (i32)count); + + XFlush(_RGFW.display); + XFree(targets); + } else if (request->target == SAVE_TARGETS) + XChangeProperty(_RGFW.display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0); + else { + int i; + for (i = 0; i < formatCount; i++) { + if (request->target != formats[i]) + continue; + XChangeProperty(_RGFW.display, request->requestor, request->property, request->target, + 8, PropModeReplace, (u8*) _RGFW.clipboard, (i32)_RGFW.clipboard_len); + } + } + + XEvent reply = { SelectionNotify }; + reply.xselection.property = request->property; + reply.xselection.display = request->display; + reply.xselection.requestor = request->requestor; + reply.xselection.selection = request->selection; + reply.xselection.target = request->target; + reply.xselection.time = request->time; + + XSendEvent(_RGFW.display, request->requestor, False, 0, &reply); +#endif } char* RGFW_strtok(char* str, const char* delimStr); @@ -4882,678 +4496,19 @@ char* RGFW_strtok(char* str, const char* delimStr) { return token_start; } -#ifdef RGFW_X11 -RGFWDEF i32 RGFW_initPlatform_X11(void); -RGFWDEF void RGFW_deinitPlatform_X11(void); -#endif -#ifdef RGFW_WAYLAND -RGFWDEF i32 RGFW_initPlatform_Wayland(void); -RGFWDEF void RGFW_deinitPlatform_Wayland(void); -#endif - -RGFWDEF void RGFW_load_X11(void); -RGFWDEF void RGFW_load_Wayland(void); - -#if !defined(RGFW_X11) || !defined(RGFW_WAYLAND) -void RGFW_load_X11(void) { } -void RGFW_load_Wayland(void) { } -#endif - -/* - * Sadly we have to use magic linux keycodes - * We can't use X11 functions, because that breaks Wayland, but they use the same keycodes so there's no use redeffing them - * We can't use linux enums, because the headers don't exist on BSD - */ -void RGFW_initKeycodesPlatform(void) { - _RGFW->keycodes[49] = RGFW_backtick; - _RGFW->keycodes[19] = RGFW_0; - _RGFW->keycodes[10] = RGFW_1; - _RGFW->keycodes[11] = RGFW_2; - _RGFW->keycodes[12] = RGFW_3; - _RGFW->keycodes[13] = RGFW_4; - _RGFW->keycodes[14] = RGFW_5; - _RGFW->keycodes[15] = RGFW_6; - _RGFW->keycodes[16] = RGFW_7; - _RGFW->keycodes[17] = RGFW_8; - _RGFW->keycodes[18] = RGFW_9; - _RGFW->keycodes[65] = RGFW_space; - _RGFW->keycodes[38] = RGFW_a; - _RGFW->keycodes[56] = RGFW_b; - _RGFW->keycodes[54] = RGFW_c; - _RGFW->keycodes[40] = RGFW_d; - _RGFW->keycodes[26] = RGFW_e; - _RGFW->keycodes[41] = RGFW_f; - _RGFW->keycodes[42] = RGFW_g; - _RGFW->keycodes[43] = RGFW_h; - _RGFW->keycodes[31] = RGFW_i; - _RGFW->keycodes[44] = RGFW_j; - _RGFW->keycodes[45] = RGFW_k; - _RGFW->keycodes[46] = RGFW_l; - _RGFW->keycodes[58] = RGFW_m; - _RGFW->keycodes[57] = RGFW_n; - _RGFW->keycodes[32] = RGFW_o; - _RGFW->keycodes[33] = RGFW_p; - _RGFW->keycodes[24] = RGFW_q; - _RGFW->keycodes[27] = RGFW_r; - _RGFW->keycodes[39] = RGFW_s; - _RGFW->keycodes[28] = RGFW_t; - _RGFW->keycodes[30] = RGFW_u; - _RGFW->keycodes[55] = RGFW_v; - _RGFW->keycodes[25] = RGFW_w; - _RGFW->keycodes[53] = RGFW_x; - _RGFW->keycodes[29] = RGFW_y; - _RGFW->keycodes[52] = RGFW_z; - _RGFW->keycodes[60] = RGFW_period; - _RGFW->keycodes[59] = RGFW_comma; - _RGFW->keycodes[61] = RGFW_slash; - _RGFW->keycodes[34] = RGFW_bracket; - _RGFW->keycodes[35] = RGFW_closeBracket; - _RGFW->keycodes[47] = RGFW_semicolon; - _RGFW->keycodes[48] = RGFW_apostrophe; - _RGFW->keycodes[51] = RGFW_backSlash; - _RGFW->keycodes[36] = RGFW_return; - _RGFW->keycodes[119] = RGFW_delete; - _RGFW->keycodes[77] = RGFW_numLock; - _RGFW->keycodes[106] = RGFW_kpSlash; - _RGFW->keycodes[63] = RGFW_kpMultiply; - _RGFW->keycodes[86] = RGFW_kpPlus; - _RGFW->keycodes[82] = RGFW_kpMinus; - _RGFW->keycodes[87] = RGFW_kp1; - _RGFW->keycodes[88] = RGFW_kp2; - _RGFW->keycodes[89] = RGFW_kp3; - _RGFW->keycodes[83] = RGFW_kp4; - _RGFW->keycodes[84] = RGFW_kp5; - _RGFW->keycodes[85] = RGFW_kp6; - _RGFW->keycodes[81] = RGFW_kp9; - _RGFW->keycodes[90] = RGFW_kp0; - _RGFW->keycodes[91] = RGFW_kpPeriod; - _RGFW->keycodes[104] = RGFW_kpReturn; - _RGFW->keycodes[20] = RGFW_minus; - _RGFW->keycodes[21] = RGFW_equals; - _RGFW->keycodes[22] = RGFW_backSpace; - _RGFW->keycodes[23] = RGFW_tab; - _RGFW->keycodes[66] = RGFW_capsLock; - _RGFW->keycodes[50] = RGFW_shiftL; - _RGFW->keycodes[37] = RGFW_controlL; - _RGFW->keycodes[64] = RGFW_altL; - _RGFW->keycodes[133] = RGFW_superL; - _RGFW->keycodes[105] = RGFW_controlR; - _RGFW->keycodes[134] = RGFW_superR; - _RGFW->keycodes[62] = RGFW_shiftR; - _RGFW->keycodes[108] = RGFW_altR; - _RGFW->keycodes[67] = RGFW_F1; - _RGFW->keycodes[68] = RGFW_F2; - _RGFW->keycodes[69] = RGFW_F3; - _RGFW->keycodes[70] = RGFW_F4; - _RGFW->keycodes[71] = RGFW_F5; - _RGFW->keycodes[72] = RGFW_F6; - _RGFW->keycodes[73] = RGFW_F7; - _RGFW->keycodes[74] = RGFW_F8; - _RGFW->keycodes[75] = RGFW_F9; - _RGFW->keycodes[76] = RGFW_F10; - _RGFW->keycodes[95] = RGFW_F11; - _RGFW->keycodes[96] = RGFW_F12; - _RGFW->keycodes[111] = RGFW_up; - _RGFW->keycodes[116] = RGFW_down; - _RGFW->keycodes[113] = RGFW_left; - _RGFW->keycodes[114] = RGFW_right; - _RGFW->keycodes[118] = RGFW_insert; - _RGFW->keycodes[115] = RGFW_end; - _RGFW->keycodes[112] = RGFW_pageUp; - _RGFW->keycodes[117] = RGFW_pageDown; - _RGFW->keycodes[9] = RGFW_escape; - _RGFW->keycodes[110] = RGFW_home; - _RGFW->keycodes[78] = RGFW_scrollLock; - _RGFW->keycodes[107] = RGFW_printScreen; - _RGFW->keycodes[128] = RGFW_pause; - _RGFW->keycodes[191] = RGFW_F13; - _RGFW->keycodes[192] = RGFW_F14; - _RGFW->keycodes[193] = RGFW_F15; - _RGFW->keycodes[194] = RGFW_F16; - _RGFW->keycodes[195] = RGFW_F17; - _RGFW->keycodes[196] = RGFW_F18; - _RGFW->keycodes[197] = RGFW_F19; - _RGFW->keycodes[198] = RGFW_F20; - _RGFW->keycodes[199] = RGFW_F21; - _RGFW->keycodes[200] = RGFW_F22; - _RGFW->keycodes[201] = RGFW_F23; - _RGFW->keycodes[202] = RGFW_F24; - _RGFW->keycodes[203] = RGFW_F25; - _RGFW->keycodes[142] = RGFW_kpEqual; - _RGFW->keycodes[161] = RGFW_world1; /* non-US key #1 */ - _RGFW->keycodes[162] = RGFW_world2; /* non-US key #2 */ -} - -i32 RGFW_initPlatform(void) { -#ifdef RGFW_WAYLAND - RGFW_load_Wayland(); - i32 ret = RGFW_initPlatform_Wayland(); - if (ret == 0) { - return 0; - } else { - #ifdef RGFW_X11 - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, "Falling back to X11"); - RGFW_useWayland(0); - #else - return ret; - #endif - } -#endif -#ifdef RGFW_X11 - RGFW_load_X11(); - return RGFW_initPlatform_X11(); -#else - return 0; -#endif -} - - -void RGFW_deinitPlatform(void) { - if (_RGFW->eventWait_forceStop[0] || _RGFW->eventWait_forceStop[1]){ - close(_RGFW->eventWait_forceStop[0]); - close(_RGFW->eventWait_forceStop[1]); - } -#ifdef RGFW_WAYLAND - if (_RGFW->useWaylandBool) { - RGFW_deinitPlatform_Wayland(); - return; - } -#endif -#ifdef RGFW_X11 - RGFW_deinitPlatform_X11(); -#endif -} - -#endif /* end of wayland or X11 defines */ - - -/* - - -Start of Linux / Unix defines - - -*/ - -#ifdef RGFW_X11 -#ifdef RGFW_WAYLAND -#define RGFW_FUNC(func) func##_X11 -#else -#define RGFW_FUNC(func) func -#endif - -#include -#include - -#include /* for data limits (mainly used in drag and drop functions) */ -#include - -void RGFW_setXInstName(const char* name) { _RGFW->instName = name; } -#if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11) - #include -#endif - -#ifndef RGFW_NO_DPI - #include - #include -#endif - -#include -#include -#include - -#include /* for converting keycode to string */ -#include /* for hiding */ -#include -#include -#include - -#ifdef RGFW_OPENGL - #ifndef __gl_h_ - #define __gl_h_ - #define RGFW_gl_ndef - #define GLubyte unsigned char - #define GLenum unsigned int - #define GLint int - #define GLuint unsigned int - #define GLsizei int - #define GLfloat float - #define GLvoid void - #define GLbitfield unsigned int - #define GLintptr ptrdiff_t - #define GLsizeiptr ptrdiff_t - #define GLboolean unsigned char - #endif - - #include /* GLX defs, xlib.h, gl.h */ - #ifndef GLX_MESA_swap_control - #define GLX_MESA_swap_control - #endif - - #ifdef RGFW_gl_ndef - #undef __gl_h_ - #undef GLubyte - #undef GLenum - #undef GLint - #undef GLuint - #undef GLsizei - #undef GLfloat - #undef GLvoid - #undef GLbitfield - #undef GLintptr - #undef GLsizeiptr - #undef GLboolean - #endif - typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); -#endif - -/* atoms needed for drag and drop */ -#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) - typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int); - typedef void (*PFN_XcursorImageDestroy)(XcursorImage*); - typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*); -#endif - -#if !defined(RGFW_NO_X11_XI_PRELOAD) - typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); - PFN_XISelectEvents XISelectEventsSRC = NULL; - #define XISelectEvents XISelectEventsSRC - - void* X11Xihandle = NULL; -#endif - -#if !defined(RGFW_NO_X11_EXT_PRELOAD) - typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int); - PFN_XSyncIntToValue XSyncIntToValueSRC = NULL; - #define XSyncIntToValue XSyncIntToValueSRC - - typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue); - PFN_XSyncSetCounter XSyncSetCounterSRC = NULL; - #define XSyncSetCounter XSyncSetCounterSRC - - typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue); - PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL; - #define XSyncCreateCounter XSyncCreateCounterSRC - - typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); - PFN_XShapeCombineMask XShapeCombineMaskSRC; - #define XShapeCombineMask XShapeCombineMaskSRC - - typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); - PFN_XShapeCombineRegion XShapeCombineRegionSRC; - #define XShapeCombineRegion XShapeCombineRegionSRC - void* X11XEXThandle = NULL; -#endif - -#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) - PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL; - PFN_XcursorImageCreate XcursorImageCreateSRC = NULL; - PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL; - - #define XcursorImageLoadCursor XcursorImageLoadCursorSRC - #define XcursorImageCreate XcursorImageCreateSRC - #define XcursorImageDestroy XcursorImageDestroySRC - - void* X11Cursorhandle = NULL; -#endif - -void* RGFW_getDisplay_X11(void) { return _RGFW->display; } -u64 RGFW_window_getWindow_X11(RGFW_window* win) { return (u64)win->src.window; } - -RGFWDEF RGFW_format RGFW_XImage_getFormat(XImage* image); -RGFW_format RGFW_XImage_getFormat(XImage* image) { - switch (image->bits_per_pixel) { - case 24: - if (image->red_mask == 0xFF0000 && image->green_mask == 0x00FF00 && image->blue_mask == 0x0000FF) - return RGFW_formatRGB8; - if (image->red_mask == 0x0000FF && image->green_mask == 0x00FF00 && image->blue_mask == 0xFF0000) - return RGFW_formatBGR8; - break; - case 32: - if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF) - return RGFW_formatBGRA8; - if (image->red_mask == 0x000000FF && image->green_mask == 0x0000FF00 && image->blue_mask == 0x00FF0000) - return RGFW_formatRGBA8; - if (image->red_mask == 0x0000FF00 && image->green_mask == 0x00FF0000 && image->blue_mask == 0xFF000000) - return RGFW_formatABGR8; - if (image->red_mask == 0x00FF0000 && image->green_mask == 0x0000FF00 && image->blue_mask == 0x000000FF) - return RGFW_formatARGB8; /* ambiguous without alpha */ - break; - } - return RGFW_formatARGB8; -} - -RGFW_bool RGFW_window_createSurfacePtr(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { - RGFW_ASSERT(surface != NULL); - surface->data = data; - surface->w = w; - surface->h = h; - surface->format = format; - - XWindowAttributes attrs; - if (XGetWindowAttributes(_RGFW->display, win->src.window, &attrs) == 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to get window attributes."); - return RGFW_FALSE; - } - - surface->native.bitmap = XCreateImage(_RGFW->display, attrs.visual, (u32)attrs.depth, - ZPixmap, 0, NULL, (u32)surface->w, (u32)surface->h, 32, 0); - - surface->native.buffer = (u8*)RGFW_ALLOC((size_t)(w * h * 4)); - surface->native.format = RGFW_XImage_getFormat(surface->native.bitmap); - - if (surface->native.bitmap == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create XImage."); - return RGFW_FALSE; - } - - surface->native.format = RGFW_formatBGRA8; - return RGFW_TRUE; -} - -RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { - return RGFW_window_createSurfacePtr(_RGFW->root, data, w, h, format, surface); -} - -void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) { - RGFW_ASSERT(surface != NULL); - surface->native.bitmap->data = (char*)surface->native.buffer; - RGFW_copyImageData((u8*)surface->native.buffer, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); - - XPutImage(_RGFW->display, win->src.window, win->src.gc, surface->native.bitmap, 0, 0, 0, 0, (u32)RGFW_MIN(win->w, surface->w), (u32)RGFW_MIN(win->h, surface->h)); - surface->native.bitmap->data = NULL; - return; -} - -void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) { - RGFW_ASSERT(surface != NULL); - RGFW_FREE(surface->native.buffer); - XDestroyImage(surface->native.bitmap); - return; -} - -#define RGFW_LOAD_ATOM(name) \ - static Atom name = 0; \ - if (name == 0) name = XInternAtom(_RGFW->display, #name, False); - -void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) { - RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); - RGFW_LOAD_ATOM(_MOTIF_WM_HINTS); - - struct __x11WindowHints { - unsigned long flags, functions, decorations, status; - long input_mode; - } hints; - hints.flags = 2; - hints.decorations = border; - - XChangeProperty(_RGFW->display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32, PropModeReplace, (u8*)&hints, 5); - - if (RGFW_window_isHidden(win) == 0) { - RGFW_window_hide(win); - RGFW_window_show(win); - } -} - -void RGFW_FUNC(RGFW_releaseCursor) (RGFW_window* win) { - RGFW_UNUSED(win); - XUngrabPointer(_RGFW->display, CurrentTime); - - /* disable raw input */ - unsigned char mask[] = { 0 }; - XIEventMask em; - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - - XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1); -} - -void RGFW_FUNC(RGFW_captureCursor) (RGFW_window* win) { - /* enable raw input */ - unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; - XISetMask(mask, XI_RawMotion); - - XIEventMask em; - em.deviceid = XIAllMasterDevices; - em.mask_len = sizeof(mask); - em.mask = mask; - - XISelectEvents(_RGFW->display, XDefaultRootWindow(_RGFW->display), &em, 1); - - unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask; - XGrabPointer(_RGFW->display, win->src.window, False, event_mask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - RGFW_window_moveMouse(win, win->x + (i32)(win->w / 2), win->y + (i32)(win->h / 2)); -} - -#define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL) -#define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \ - void* ptr = dlsym(proc, #name); \ - if (ptr != NULL) RGFW_MEMCPY(&name##SRC, &ptr, sizeof(PFN_##name)); \ -} - -RGFWDEF void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent); -void RGFW_window_getVisual(XVisualInfo* visual, RGFW_bool transparent) { - visual->visual = DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)); - visual->depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)); - if (transparent) { - XMatchVisualInfo(_RGFW->display, DefaultScreen(_RGFW->display), 32, TrueColor, visual); /*!< for RGBA backgrounds */ - if (visual->depth != 32) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a 32-bit depth."); - } -} - -RGFWDEF int RGFW_XErrorHandler(Display* display, XErrorEvent* ev); -int RGFW_XErrorHandler(Display* display, XErrorEvent* ev) { - char errorText[512]; - XGetErrorText(display, ev->error_code, errorText, sizeof(errorText)); - - char buf[1024]; - RGFW_SNPRINTF(buf, sizeof(buf), "[X Error] %s\n Error code: %d\n Request code: %d\n Minor code: %d\n Serial: %lu\n", - errorText, - ev->error_code, ev->request_code, ev->minor_code, ev->serial); - - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errX11, buf); - _RGFW->x11Error = ev; - return 0; -} - -void RGFW_XCreateWindow (XVisualInfo visual, const char* name, RGFW_windowFlags flags, RGFW_window* win) { - i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | - LeaveWindowMask | EnterWindowMask | ExposureMask | VisibilityChangeMask | PropertyChangeMask; - - /* make X window attrubutes */ - XSetWindowAttributes swa; - RGFW_MEMSET(&swa, 0, sizeof(swa)); - - win->src.parent = DefaultRootWindow(_RGFW->display); - - Colormap cmap; - swa.colormap = cmap = XCreateColormap(_RGFW->display, - win->src.parent, - visual.visual, AllocNone); - swa.event_mask = event_mask; - swa.background_pixmap = None; - - /* create the window */ - win->src.window = XCreateWindow(_RGFW->display, win->src.parent, win->x, win->y, (u32)win->w, (u32)win->h, - 0, visual.depth, InputOutput, visual.visual, - CWBorderPixel | CWColormap | CWEventMask, &swa); - - XFreeColors(_RGFW->display, cmap, NULL, 0, 0); - - XSaveContext(_RGFW->display, win->src.window, _RGFW->context, (XPointer)win); - - win->src.gc = XCreateGC(_RGFW->display, win->src.window, 0, NULL); - - /* In your .desktop app, if you set the property - StartupWMClass=RGFW that will assoicate the launcher icon - with your application - robrohan */ - if (_RGFW->className == NULL) - _RGFW->className = (char*)name; - - XClassHint hint; - hint.res_class = (char*)_RGFW->className; - if (_RGFW->instName == NULL) hint.res_name = (char*)name; - else hint.res_name = (char*)_RGFW->instName; - XSetClassHint(_RGFW->display, win->src.window, &hint); - - #ifndef RGFW_NO_MONITOR - if (flags & RGFW_windowScaleToMonitor) - RGFW_window_scaleToMonitor(win); - #endif - XSelectInput(_RGFW->display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */ - - /* make it so the user can't close the window until the program does */ - RGFW_LOAD_ATOM(WM_DELETE_WINDOW); - XSetWMProtocols(_RGFW->display, (Drawable) win->src.window, &WM_DELETE_WINDOW, 1); - /* set the background */ - RGFW_window_setName(win, name); - - XMoveWindow(_RGFW->display, (Drawable) win->src.window, win->x, win->y); /*!< move the window to it's proper cords */ - - if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */ - win->internal.flags |= RGFW_windowAllowDND; - - /* actions */ - Atom XdndAware = XInternAtom(_RGFW->display, "XdndAware", False); - const u8 version = 5; - - XChangeProperty(_RGFW->display, win->src.window, - XdndAware, 4, 32, - PropModeReplace, &version, 1); /*!< turns on drag and drop */ - } - -#ifdef RGFW_ADVANCED_SMOOTH_RESIZE - RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER) - RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST) - - Atom protcols[2] = {_NET_WM_SYNC_REQUEST, WM_DELETE_WINDOW}; - XSetWMProtocols(_RGFW->display, win->src.window, protcols, 2); - - XSyncValue initial_value; - XSyncIntToValue(&initial_value, 0); - win->src.counter = XSyncCreateCounter(_RGFW->display, initial_value); - - XChangeProperty(_RGFW->display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1); -#endif - - win->src.x = win->x; - win->src.y = win->y; - win->src.w = win->w; - win->src.h = win->h; - - XSetWindowBackground(_RGFW->display, win->src.window, None); - XClearWindow(_RGFW->display, win->src.window); - - /* stupid hack to make resizing the window less bad */ - XSetWindowBackgroundPixmap(_RGFW->display, win->src.window, None); -} - -RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) { - if ((flags & RGFW_windowOpenGL) || (flags & RGFW_windowEGL)) { - win->src.window = 0; - return win; - } - - XVisualInfo visual; - RGFW_window_getVisual(&visual, RGFW_BOOL(win->internal.flags & RGFW_windowTransparent)); - RGFW_XCreateWindow(visual, name, flags, win); - return win; /*return newly created window */ -} - -RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* fX, i32* fY) { - RGFW_init(); - i32 x, y; - u32 z; - Window window1, window2; - XQueryPointer(_RGFW->display, XDefaultRootWindow(_RGFW->display), &window1, &window2, fX, fY, &x, &y, &z); - return RGFW_TRUE; -} - -RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event); -void RGFW_XHandleClipboardSelection(XEvent* event) { RGFW_UNUSED(event); - RGFW_LOAD_ATOM(ATOM_PAIR); - RGFW_LOAD_ATOM(MULTIPLE); - RGFW_LOAD_ATOM(TARGETS); - RGFW_LOAD_ATOM(SAVE_TARGETS); - RGFW_LOAD_ATOM(UTF8_STRING); - - const XSelectionRequestEvent* request = &event->xselectionrequest; - Atom formats[2] = {0}; - formats[0] = UTF8_STRING; - formats[1] = XA_STRING; - const int formatCount = sizeof(formats) / sizeof(formats[0]); - - if (request->target == TARGETS) { - Atom targets[4] = {0}; - targets[0] = TARGETS; - targets[1] = MULTIPLE; - targets[2] = UTF8_STRING; - targets[3] = XA_STRING; - - XChangeProperty(_RGFW->display, request->requestor, request->property, - XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom)); - } else if (request->target == MULTIPLE) { - Atom* targets = NULL; - - Atom actualType = 0; - int actualFormat = 0; - unsigned long count = 0, bytesAfter = 0; - - XGetWindowProperty(_RGFW->display, request->requestor, request->property, 0, LONG_MAX, - False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); - - unsigned long i; - for (i = 0; i < (u32)count; i += 2) { - if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) - XChangeProperty(_RGFW->display, request->requestor, targets[i + 1], targets[i], - 8, PropModeReplace, (const unsigned char *)_RGFW->clipboard, (i32)_RGFW->clipboard_len); - else - targets[i + 1] = None; - } - - XChangeProperty(_RGFW->display, - request->requestor, request->property, ATOM_PAIR, 32, - PropModeReplace, (u8*) targets, (i32)count); - - XFlush(_RGFW->display); - XFree(targets); - } else if (request->target == SAVE_TARGETS) - XChangeProperty(_RGFW->display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0); - else { - int i; - for (i = 0; i < formatCount; i++) { - if (request->target != formats[i]) - continue; - XChangeProperty(_RGFW->display, request->requestor, request->property, request->target, - 8, PropModeReplace, (u8*) _RGFW->clipboard, (i32)_RGFW->clipboard_len); - } - } - - XEvent reply = { SelectionNotify }; - reply.xselection.property = request->property; - reply.xselection.display = request->display; - reply.xselection.requestor = request->requestor; - reply.xselection.selection = request->selection; - reply.xselection.target = request->target; - reply.xselection.time = request->time; - - XSendEvent(_RGFW->display, request->requestor, False, 0, &reply); - XFlush(_RGFW->display); -} - i32 RGFW_XHandleClipboardSelectionHelper(void); -u8 RGFW_FUNC(RGFW_rgfwToKeyChar) (u32 key) { - u32 keycode = RGFW_rgfwToApiKey(key); - Window root = DefaultRootWindow(_RGFW->display); +u8 RGFW_rgfwToKeyChar(u32 key) { + u32 keycode = RGFW_rgfwToApiKey(key); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + Window root = DefaultRootWindow(_RGFW.display); Window ret_root, ret_child; int root_x, root_y, win_x, win_y; unsigned int mask; - XQueryPointer(_RGFW->display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask); - KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW->display, (KeyCode)keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0); + XQueryPointer(_RGFW.display, root, &ret_root, &ret_child, &root_x, &root_y, &win_x, &win_y, &mask); + KeySym sym = (KeySym)XkbKeycodeToKeysym(_RGFW.display, (KeyCode)keycode, 0, (KeyCode)mask & ShiftMask ? 1 : 0); if ((mask & LockMask) && sym >= XK_a && sym <= XK_z) sym = (mask & ShiftMask) ? sym + 32 : sym - 32; @@ -5561,10 +4516,25 @@ u8 RGFW_FUNC(RGFW_rgfwToKeyChar) (u32 key) { sym = 0; return (u8)sym; +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL RGFW_UNUSED(keycode); + return (u8)key; +#endif } -RGFWDEF void RGFW_XHandleEvent(void); -void RGFW_XHandleEvent(void) { +RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { + RGFW_XHandleClipboardSelectionHelper(); + + if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; + RGFW_event* ev = RGFW_window_checkEventCore(win); + if (ev) return ev; + + #if defined(__linux__) && !defined(RGFW_NO_LINUX) + if (RGFW_linux_updateGamepad(win)) return &win->event; + #endif + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 RGFW_LOAD_ATOM(XdndTypeList); RGFW_LOAD_ATOM(XdndSelection); RGFW_LOAD_ATOM(XdndEnter); @@ -5576,8 +4546,20 @@ void RGFW_XHandleEvent(void) { RGFW_LOAD_ATOM(XdndActionCopy); RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST); RGFW_LOAD_ATOM(WM_PROTOCOLS); - RGFW_LOAD_ATOM(WM_STATE); - RGFW_LOAD_ATOM(_NET_WM_STATE); + XPending(win->src.display); + + XEvent E; /*!< raw X11 event */ + + /* if there is no unread qued events, get a new one */ + if ((QLength(win->src.display) || XEventsQueued(win->src.display, QueuedAlready) + XEventsQueued(win->src.display, QueuedAfterReading)) + && win->event.type != RGFW_quit + ) + XNextEvent(win->src.display, &E); + else { + return NULL; + } + + win->event.type = 0; /* xdnd data */ static Window source = 0; @@ -5585,641 +4567,550 @@ void RGFW_XHandleEvent(void) { static i32 format = 0; XEvent reply = { ClientMessage }; - XEvent E; - RGFW_event event; - RGFW_MEMSET(&event, 0, sizeof(event)); - - XNextEvent(_RGFW->display, &E); - switch (E.type) { - case SelectionRequest: - RGFW_XHandleClipboardSelection(&E); - return; - case GenericEvent: { - RGFW_window* win = _RGFW->mouseOwner; - if (win == NULL) return; - if (!(win->internal.enabledEvents & RGFW_BIT(RGFW_mousePosChanged))) return; - - /* MotionNotify is used for mouse events if the mouse isn't held */ - if (!(win->internal.holdMouse)) { - XFreeEventData(_RGFW->display, &E.xcookie); - return; - } - - XGetEventData(_RGFW->display, &E.xcookie); - if (E.xcookie.evtype == XI_RawMotion) { - XIRawEvent *raw = (XIRawEvent *)E.xcookie.data; - if (raw->valuators.mask_len == 0) { - XFreeEventData(_RGFW->display, &E.xcookie); - return; - } - - double deltaX = 0.0f; - double deltaY = 0.0f; - - /* check if relative motion data exists where we think it does */ - if (XIMaskIsSet(raw->valuators.mask, 0) != 0) - deltaX += raw->raw_values[0]; - if (XIMaskIsSet(raw->valuators.mask, 1) != 0) - deltaY += raw->raw_values[1]; - - event.mouse.vecX = (float)deltaX; - event.mouse.vecY = (float)deltaY; - _RGFW->vectorX = (float)event.mouse.vecX; - _RGFW->vectorY = (float)event.mouse.vecY; - event.mouse.x = win->internal.lastMouseX + (i32)event.mouse.vecX; - event.mouse.y = win->internal.lastMouseY + (i32)event.mouse.vecY; - win->internal.lastMouseX = event.mouse.x; - win->internal.lastMouseY = event.mouse.y; - RGFW_window_moveMouse(win, win->x + (win->w / 2), win->y + (win->h / 2)); - - event.type = RGFW_mousePosChanged; - RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, (float)event.mouse.vecX, (float)event.mouse.vecY); - } - - XFreeEventData(_RGFW->display, &E.xcookie); - if (event.type) - RGFW_eventQueuePush(&event); - return; - } - } - - RGFW_window* win = NULL; - if (XFindContext(_RGFW->display, E.xany.window, _RGFW->context, (XPointer*) &win) != 0) { - return; - } - - event.common.win = win; - - /* - Repeated key presses are sent as a release followed by another press at the same time. - We want to convert that into a single key press event with the repeat flag set - */ - if (E.type == KeyRelease && XEventsQueued(_RGFW->display, QueuedAfterReading)) { - XEvent NE; - XPeekEvent(_RGFW->display, &NE); - if (NE.type == KeyPress && E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) { - /* Use the next KeyPress event */ - XNextEvent(_RGFW->display, &E); - event.key.repeat = RGFW_TRUE; - } - } switch (E.type) { - case KeyPress: { - if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return; - event.type = RGFW_keyPressed; - event.key.value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode); - event.key.sym = (u8)RGFW_rgfwToKeyChar(event.key.value); + case KeyPress: + case KeyRelease: { + win->event.repeat = RGFW_FALSE; + /* check if it's a real key release */ + if (E.type == KeyRelease && XEventsQueued(win->src.display, QueuedAfterReading)) { /* get next event if there is one */ + XEvent NE; + XPeekEvent(win->src.display, &NE); - _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; - _RGFW->keyboard[event.key.value].current = RGFW_TRUE; + if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same */ + win->event.repeat = RGFW_TRUE; + } - XkbStateRec state; - XkbGetState(_RGFW->display, XkbUseCoreKbd, &state); - RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); + /* set event key data */ + win->event.key = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode); + win->event.keyChar = (u8)RGFW_rgfwToKeyChar(win->event.key); - RGFW_keyCallback(win, event.key.value, event.key.sym, win->internal.mod, event.key.repeat, RGFW_TRUE); + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; + + /* get keystate data */ + win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased; + + XKeyboardState keystate; + XGetKeyboardControl(win->src.display, &keystate); + + RGFW_keyboard[win->event.key].current = (E.type == KeyPress); + + XkbStateRec state; + XkbGetState(win->src.display, XkbUseCoreKbd, &state); + RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); + + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, (E.type == KeyPress)); + break; + } + case ButtonPress: + case ButtonRelease: + if (E.xbutton.button > RGFW_mouseFinal) { /* skip this event */ + XFlush(win->src.display); + return RGFW_window_checkEvent(win); + } + + win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); /* the events match */ + win->event.button = (u8)(E.xbutton.button - 1); + switch(win->event.button) { + case RGFW_mouseScrollUp: + win->event.scroll = 1; + break; + case RGFW_mouseScrollDown: + win->event.scroll = -1; + break; + default: break; + } + + 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.key); + + RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress); + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress)); + break; + + case MotionNotify: + win->event.point.x = E.xmotion.x; + win->event.point.y = E.xmotion.y; + + win->event.vector.x = win->event.point.x - win->_lastMousePoint.x; + win->event.vector.y = win->event.point.y - win->_lastMousePoint.y; + win->_lastMousePoint = win->event.point; + + win->event.type = RGFW_mousePosChanged; + RGFW_mousePosCallback(win, win->event.point, win->event.vector); + break; + + case GenericEvent: { + /* MotionNotify is used for mouse events if the mouse isn't held */ + if (!(win->_flags & RGFW_HOLD_MOUSE)) { + XFreeEventData(win->src.display, &E.xcookie); break; } - case KeyRelease: { - if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return; - event.type = RGFW_keyReleased; - event.key.value = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode); - event.key.sym = (u8)RGFW_rgfwToKeyChar(event.key.value); - - /* get keystate data */ - _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; - _RGFW->keyboard[event.key.value].current = RGFW_FALSE; - - XkbStateRec state; - XkbGetState(_RGFW->display, XkbUseCoreKbd, &state); - RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask)); - - RGFW_keyCallback(win, event.key.value, event.key.sym, win->internal.mod, event.key.repeat, RGFW_FALSE); - break; - } - case ButtonPress: - if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) { - if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return; - event.type = RGFW_mouseScroll; - } else { - if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag) || E.xbutton.button > RGFW_mouseFinal) return; - event.type = RGFW_mouseButtonPressed; - } - - switch(E.xbutton.button) { - case Button1: event.button.value = RGFW_mouseLeft; break; - case Button2: event.button.value = RGFW_mouseMiddle; break; - case Button3: event.button.value = RGFW_mouseRight; break; - case Button4: event.scroll.y = 1.0; break; - case Button5: event.scroll.y = -1.0; break; - case 6: event.scroll.x = 1.0f; break; - case 7: event.scroll.x = -1.0f; break; - default: - event.button.value = (u8)E.xbutton.button - Button1 - 4; - break; - } - - if (event.type == RGFW_mouseScroll) { - _RGFW->scrollX = event.scroll.x; - _RGFW->scrollY = event.scroll.y; - RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); + XGetEventData(win->src.display, &E.xcookie); + if (E.xcookie.evtype == XI_RawMotion) { + XIRawEvent *raw = (XIRawEvent *)E.xcookie.data; + if (raw->valuators.mask_len == 0) { + XFreeEventData(win->src.display, &E.xcookie); break; } - _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; - _RGFW->mouseButtons[event.button.value].current = RGFW_TRUE; - RGFW_mouseButtonCallback(win, event.button.value, RGFW_TRUE); - break; - case ButtonRelease: - if (E.xbutton.button >= Button4 && E.xbutton.button <= 7) break; - if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag) || E.xbutton.button > RGFW_mouseFinal) return; - event.type = RGFW_mouseButtonReleased; - switch(E.xbutton.button) { - case Button1: event.button.value = RGFW_mouseLeft; break; - case Button2: event.button.value = RGFW_mouseMiddle; break; - case Button3: event.button.value = RGFW_mouseRight; break; - default: - event.button.value = (u8)E.xbutton.button - Button1 - 4; - break; - } + double deltaX = 0.0f; + double deltaY = 0.0f; - _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; - _RGFW->mouseButtons[event.button.value].current = RGFW_FALSE; - RGFW_mouseButtonCallback(win, event.button.value, RGFW_FALSE); - break; - case MotionNotify: - if (win->internal.holdMouse) return; - if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return; - event.mouse.x = E.xmotion.x; - event.mouse.y = E.xmotion.y; + /* check if relative motion data exists where we think it does */ + if (XIMaskIsSet(raw->valuators.mask, 0) != 0) + deltaX += raw->raw_values[0]; + if (XIMaskIsSet(raw->valuators.mask, 1) != 0) + deltaY += raw->raw_values[1]; - event.mouse.vecX = (float)(event.mouse.x - win->internal.lastMouseX); - event.mouse.vecY = (float)(event.mouse.y - win->internal.lastMouseY); - _RGFW->vectorX = event.mouse.vecX; - _RGFW->vectorY = event.mouse.vecY; - win->internal.lastMouseX = event.mouse.x; - win->internal.lastMouseY = event.mouse.y; - event.type = RGFW_mousePosChanged; - RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, (float)event.mouse.vecX, (float)event.mouse.vecY); - break; + win->event.vector = RGFW_POINT((i32)deltaX, (i32)deltaY); + win->event.point.x = win->_lastMousePoint.x + win->event.vector.x; + win->event.point.y = win->_lastMousePoint.y + win->event.vector.y; + win->_lastMousePoint = win->event.point; - case Expose: { - if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return; - event.type = RGFW_windowRefresh; - RGFW_windowRefreshCallback(win); + RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); + + win->event.type = RGFW_mousePosChanged; + RGFW_mousePosCallback(win, win->event.point, win->event.vector); + } + + XFreeEventData(win->src.display, &E.xcookie); + break; + } + + case Expose: { + win->event.type = RGFW_windowRefresh; + RGFW_windowRefreshCallback(win); #ifdef RGFW_ADVANCED_SMOOTH_RESIZE - XSyncValue value; - XSyncIntToValue(&value, (i32)win->src.counter_value); - XSyncSetCounter(_RGFW->display, win->src.counter, value); + XSyncValue value; + XSyncIntToValue(&value, (i32)win->src.counter_value); + XSyncSetCounter(win->src.display, win->src.counter, value); #endif + break; + } + case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break; + case ClientMessage: { + /* if the client closed the window */ + if (E.xclient.data.l[0] == (long)wm_delete_window) { + win->event.type = RGFW_quit; + RGFW_window_setShouldClose(win, RGFW_TRUE); + RGFW_windowQuitCallback(win); break; } - - case PropertyNotify: - if (E.xproperty.state != PropertyNewValue) break; - - if (E.xproperty.atom == WM_STATE) { - if (RGFW_window_isMinimized(win) && !(win->internal.flags & RGFW_windowMinimized)) { - win->internal.flags |= RGFW_windowMinimize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); - RGFW_windowMinimizedCallback(win); - break; - } - } else if (E.xproperty.atom == _NET_WM_STATE) { - if (!(win->internal.flags & RGFW_windowMaximize)) { - win->internal.flags |= RGFW_windowMaximize; - RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); - RGFW_windowMaximizedCallback(win, win->x, win->y, win->w, win->h); - break; - } - } - - RGFW_window_checkMode(win); - break; - case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break; - case ClientMessage: { - RGFW_LOAD_ATOM(WM_DELETE_WINDOW); - /* if the client closed the window */ - if (E.xclient.data.l[0] == (long)WM_DELETE_WINDOW) { - event.type = RGFW_quit; - RGFW_window_setShouldClose(win, RGFW_TRUE); - RGFW_windowQuitCallback(win); - break; - } #ifdef RGFW_ADVANCED_SMOOTH_RESIZE - if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) { - RGFW_windowRefreshCallback(win); - win->src.counter_value = 0; - win->src.counter_value |= E.xclient.data.l[2]; - win->src.counter_value |= (E.xclient.data.l[3] << 32); + if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) { + RGFW_windowRefreshCallback(win); + win->src.counter_value = 0; + win->src.counter_value |= E.xclient.data.l[2]; + win->src.counter_value |= (E.xclient.data.l[3] << 32); - XSyncValue value; - XSyncIntToValue(&value, (i32)win->src.counter_value); - XSyncSetCounter(_RGFW->display, win->src.counter, value); - break; - } + XSyncValue value; + XSyncIntToValue(&value, (i32)win->src.counter_value); + XSyncSetCounter(win->src.display, win->src.counter, value); + break; + } #endif - if ((win->internal.flags & RGFW_windowAllowDND) == 0) - return; + if ((win->_flags & RGFW_windowAllowDND) == 0) + break; - reply.xclient.window = source; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)win->src.window; - reply.xclient.data.l[1] = 0; - reply.xclient.data.l[2] = None; - - if (E.xclient.message_type == XdndEnter) { - if (version > 5) - break; - - unsigned long count; - Atom* formats; - Atom real_formats[6]; - Bool list = E.xclient.data.l[1] & 1; - - source = (unsigned long int)E.xclient.data.l[0]; - version = E.xclient.data.l[1] >> 24; - format = None; - if (list) { - Atom actualType; - i32 actualFormat; - unsigned long bytesAfter; - - XGetWindowProperty( - _RGFW->display, source, XdndTypeList, - 0, LONG_MAX, False, 4, - &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats - ); - } else { - count = 0; - - size_t i; - for (i = 2; i < 5; i++) { - if (E.xclient.data.l[i] != None) { - real_formats[count] = (unsigned long int)E.xclient.data.l[i]; - count += 1; - } - } - - formats = real_formats; - } - - Atom XtextPlain = XInternAtom(_RGFW->display, "text/plain", False); - Atom XtextUriList = XInternAtom(_RGFW->display, "text/uri-list", False); - - size_t i; - for (i = 0; i < count; i++) { - if (formats[i] == XtextUriList || formats[i] == XtextPlain) { - format = (int)formats[i]; - break; - } - } - - if (list) { - XFree(formats); - } + reply.xclient.window = source; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long)win->src.window; + reply.xclient.data.l[1] = 0; + reply.xclient.data.l[2] = None; + if (E.xclient.message_type == XdndEnter) { + if (version > 5) break; - } - if (E.xclient.message_type == XdndPosition) { - const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff; - const i32 yabs = (E.xclient.data.l[2]) & 0xffff; - Window dummy; - i32 xpos, ypos; + unsigned long count; + Atom* formats; + Atom real_formats[6]; + Bool list = E.xclient.data.l[1] & 1; - if (version > 5) - break; + source = (unsigned long int)E.xclient.data.l[0]; + version = E.xclient.data.l[1] >> 24; + format = None; + if (list) { + Atom actualType; + i32 actualFormat; + unsigned long bytesAfter; - XTranslateCoordinates( - _RGFW->display, XDefaultRootWindow(_RGFW->display), win->src.window, - xabs, yabs, &xpos, &ypos, &dummy + XGetWindowProperty( + win->src.display, source, XdndTypeList, + 0, LONG_MAX, False, 4, + &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats ); + } else { + count = 0; - event.drag.x = xpos; - event.drag.y = ypos; - - reply.xclient.window = source; - reply.xclient.message_type = XdndStatus; - - if (format) { - reply.xclient.data.l[1] = 1; - if (version >= 2) - reply.xclient.data.l[4] = (long)XdndActionCopy; + size_t i; + for (i = 2; i < 5; i++) { + if (E.xclient.data.l[i] != None) { + real_formats[count] = (unsigned long int)E.xclient.data.l[i]; + count += 1; + } } - XSendEvent(_RGFW->display, source, False, NoEventMask, &reply); - XFlush(_RGFW->display); - break; + formats = real_formats; } - if (E.xclient.message_type != XdndDrop) - break; + + size_t i; + for (i = 0; i < count; i++) { + if (formats[i] == XtextUriList || formats[i] == XtextPlain) { + format = (int)formats[i]; + break; + } + } + + if (list) { + XFree(formats); + } + + break; + } + + if (E.xclient.message_type == XdndPosition) { + const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff; + const i32 yabs = (E.xclient.data.l[2]) & 0xffff; + Window dummy; + i32 xpos, ypos; if (version > 5) break; - event.type = RGFW_dataDrag; + XTranslateCoordinates( + win->src.display, XDefaultRootWindow(win->src.display), win->src.window, + xabs, yabs, &xpos, &ypos, &dummy + ); + + win->event.point.x = xpos; + win->event.point.y = ypos; + + reply.xclient.window = source; + reply.xclient.message_type = XdndStatus; if (format) { - Time time = (version >= 1) - ? (Time)E.xclient.data.l[2] - : CurrentTime; - - XConvertSelection( - _RGFW->display, XdndSelection, (Atom)format, - XdndSelection, win->src.window, time - ); - } else if (version >= 2) { - XEvent new_reply = { ClientMessage }; - - XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply); - XFlush(_RGFW->display); + reply.xclient.data.l[1] = 1; + if (version >= 2) + reply.xclient.data.l[4] = (long)XdndActionCopy; } - _RGFW->windowState.win = win; - _RGFW->windowState.dataDragging = RGFW_TRUE; - _RGFW->windowState.dropX = event.drag.x; - _RGFW->windowState.dropY = event.drag.y; + XSendEvent(win->src.display, source, False, NoEventMask, &reply); + XFlush(win->src.display); + break; + } + if (E.xclient.message_type != XdndDrop) + break; - if (win->internal.enabledEvents & RGFW_dataDragFlag) return; - RGFW_dataDragCallback(win, event.drag.x, event.drag.y); - } break; - case SelectionNotify: { - /* this is only for checking for xdnd drops */ - if (!(win->internal.enabledEvents & RGFW_dataDropFlag) || E.xselection.property != XdndSelection || !(win->internal.flags & RGFW_windowAllowDND)) - return; - char* data; - unsigned long result; + if (version > 5) + break; - Atom actualType; - i32 actualFormat; - unsigned long bytesAfter; + size_t i; + for (i = 0; i < win->event.droppedFilesCount; i++) + win->event.droppedFiles[i][0] = '\0'; - XGetWindowProperty(_RGFW->display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data); + win->event.droppedFilesCount = 0; - if (result == 0) - break; - const char* prefix = (const char*)"file://"; + win->event.type = RGFW_DNDInit; - char* line; + if (format) { + Time time = (version >= 1) + ? (Time)E.xclient.data.l[2] + : CurrentTime; - event.drop.files = _RGFW->files; - event.drop.count = 0; - event.type = RGFW_dataDrop; + XConvertSelection( + win->src.display, XdndSelection, (Atom)format, + XdndSelection, win->src.window, time + ); + } else if (version >= 2) { + XEvent new_reply = { ClientMessage }; - while ((line = (char*)RGFW_strtok(data, "\r\n"))) { - char path[RGFW_MAX_PATH]; + XSendEvent(win->src.display, source, False, NoEventMask, &new_reply); + XFlush(win->src.display); + } - data = NULL; + RGFW_dndInitCallback(win, win->event.point); + } break; + case SelectionRequest: + RGFW_XHandleClipboardSelection(&E); + XFlush(win->src.display); + return RGFW_window_checkEvent(win); + case SelectionNotify: { + /* this is only for checking for xdnd drops */ + if (E.xselection.property != XdndSelection || !(win->_flags & RGFW_windowAllowDND)) + break; + char* data; + unsigned long result; - if (line[0] == '#') - continue; + Atom actualType; + i32 actualFormat; + unsigned long bytesAfter; - char* l; - for (l = line; 1; l++) { - if ((l - line) > 7) - break; - else if (*l != prefix[(l - line)]) - break; - else if (*l == '\0' && prefix[(l - line)] == '\0') { - line += 7; - while (*line != '/') - line++; - break; - } else if (*l == '\0') - break; - } + XGetWindowProperty(win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data); - event.drop.count++; + if (result == 0) + break; - size_t index = 0; - while (*line) { - if (line[0] == '%' && line[1] && line[2]) { - char digits[3] = {0}; - digits[0] = line[1]; - digits[1] = line[2]; - digits[2] = '\0'; - path[index] = (char) RGFW_STRTOL(digits, NULL, 16); - line += 2; - } else + const char* prefix = (const char*)"file://"; + + char* line; + + win->event.droppedFilesCount = 0; + win->event.type = RGFW_DND; + + while ((line = (char*)RGFW_strtok(data, "\r\n"))) { + char path[RGFW_MAX_PATH]; + + data = NULL; + + if (line[0] == '#') + continue; + + char* l; + for (l = line; 1; l++) { + if ((l - line) > 7) + break; + else if (*l != prefix[(l - line)]) + break; + else if (*l == '\0' && prefix[(l - line)] == '\0') { + line += 7; + while (*line != '/') + line++; + break; + } else if (*l == '\0') + break; + } + + win->event.droppedFilesCount++; + + size_t index = 0; + while (*line) { + if (line[0] == '%' && line[1] && line[2]) { + const char digits[3] = { line[1], line[2], '\0' }; + path[index] = (char) RGFW_STRTOL(digits, NULL, 16); + line += 2; + } else path[index] = *line; - index++; - line++; - } - path[index] = '\0'; - RGFW_MEMCPY(event.drop.files[event.drop.count - 1], path, index + 1); + index++; + line++; } - - _RGFW->windowState.win = win; - _RGFW->windowState.dataDrop = RGFW_TRUE; - _RGFW->windowState.filesCount = event.drop.count; - - RGFW_dataDropCallback(win, event.drop.files, event.drop.count); - if (data) - XFree(data); - - if (version >= 2) { - XEvent new_reply = { ClientMessage }; - new_reply.xclient.window = source; - new_reply.xclient.message_type = XdndFinished; - new_reply.xclient.format = 32; - new_reply.xclient.data.l[1] = (long int)result; - new_reply.xclient.data.l[2] = (long int)XdndActionCopy; - XSendEvent(_RGFW->display, source, False, NoEventMask, &new_reply); - XFlush(_RGFW->display); - } - break; - } - case FocusIn: - if ((win->internal.flags & RGFW_windowFullscreen)) - XMapRaised(_RGFW->display, win->src.window); - if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); - - if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; - win->internal.inFocus = RGFW_TRUE; - event.type = RGFW_focusIn; - RGFW_focusCallback(win, 1); - - break; - case FocusOut: - if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; - event.type = RGFW_focusOut; - RGFW_focusCallback(win, 0); - RGFW_window_focusLost(win); - break; - case EnterNotify: { - win->internal.mouseInside = RGFW_TRUE; - _RGFW->windowState.win = win; - _RGFW->windowState.mouseEnter = RGFW_TRUE; - - if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; - event.type = RGFW_mouseEnter; - event.mouse.x = E.xcrossing.x; - event.mouse.y = E.xcrossing.y; - RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 1); - break; + path[index] = '\0'; + RGFW_MEMCPY(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1); } - case LeaveNotify: { - win->internal.mouseInside = RGFW_FALSE; - _RGFW->windowState.winLeave = win; - _RGFW->windowState.mouseLeave = RGFW_TRUE; - if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; - event.type = RGFW_mouseLeave; - RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 0); - break; + RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); + if (data) + XFree(data); + + if (version >= 2) { + XEvent new_reply = { ClientMessage }; + new_reply.xclient.window = source; + new_reply.xclient.message_type = XdndFinished; + new_reply.xclient.format = 32; + new_reply.xclient.data.l[1] = (long int)result; + new_reply.xclient.data.l[2] = (long int)XdndActionCopy; + XSendEvent(win->src.display, source, False, NoEventMask, &new_reply); + XFlush(win->src.display); } - case ReparentNotify: - win->src.parent = E.xreparent.parent; - break; - case ConfigureNotify: { - /* detect resize */ - RGFW_window_checkMode(win); - if (E.xconfigure.width != win->src.w || E.xconfigure.height != win->src.h) { - win->src.w = win->w = E.xconfigure.width; - win->src.h = win->h = E.xconfigure.height; + break; + } + case FocusIn: + if ((win->_flags & RGFW_windowFullscreen)) + XMapRaised(win->src.display, win->src.window); - if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return; - event.type = RGFW_windowResized; - RGFW_windowResizedCallback(win, win->w, win->h); - RGFW_eventQueuePush(&event); - } + win->_flags |= RGFW_windowFocus; + win->event.type = RGFW_focusIn; + RGFW_focusCallback(win, 1); - i32 x = E.xconfigure.x; - i32 y = E.xconfigure.y; - /* - if the event came from the server and we're not a direct child of the root window then - we're using local coords which need to be translated into screen coords - */ - Window root = DefaultRootWindow(_RGFW->display); - if (E.xany.send_event == 0 && win->src.parent != root) { - Window dummy = 0; - XTranslateCoordinates(_RGFW->display, win->src.parent, root, x, y, &x, &y, &dummy); - } - - /* detect move */ - if (E.xconfigure.x != win->src.x || E.xconfigure.y != win->src.y) { - win->src.x = win->x = E.xconfigure.x; - win->src.y = win->y = E.xconfigure.y; - - if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; - event.type = RGFW_windowMoved; - RGFW_windowMovedCallback(win, win->x, win->y); - RGFW_eventQueuePush(&event); - } - return; - } - default: - break; + if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h)); + break; + case FocusOut: + win->event.type = RGFW_focusOut; + RGFW_focusCallback(win, 0); + RGFW_window_focusLost(win); + break; + case PropertyNotify: RGFW_window_checkMode(win); break; + case EnterNotify: { + win->event.type = RGFW_mouseEnter; + win->event.point.x = E.xcrossing.x; + win->event.point.y = E.xcrossing.y; + RGFW_mouseNotifyCallback(win, win->event.point, 1); + break; } - if (event.type) { - RGFW_eventQueuePush(&event); + case LeaveNotify: { + win->event.type = RGFW_mouseLeave; + RGFW_mouseNotifyCallback(win, win->event.point, 0); + break; } - XFlush(_RGFW->display); + case ConfigureNotify: { + /* detect resize */ + RGFW_window_checkMode(win); + if (E.xconfigure.width != win->src.r.w || E.xconfigure.height != win->src.r.h) { + win->event.type = RGFW_windowResized; + win->src.r = win->r = RGFW_RECT(win->src.r.x, win->src.r.y, E.xconfigure.width, E.xconfigure.height); + RGFW_windowResizedCallback(win, win->r); + break; + } + + /* detect move */ + if (E.xconfigure.x != win->src.r.x || E.xconfigure.y != win->src.r.y) { + win->event.type = RGFW_windowMoved; + win->src.r = win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->src.r.w, win->src.r.h); + RGFW_windowMovedCallback(win, win->r); + break; + } + + break; + } + default: + XFlush(win->src.display); + return RGFW_window_checkEvent(win); + } + XFlush(win->src.display); + if (win->event.type) return &win->event; + else return NULL; +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + if ((win->_flags & RGFW_windowHide) == 0) + wl_display_roundtrip(win->src.wl_display); + return NULL; +#endif } -void RGFW_FUNC(RGFW_pollEvents) (void) { - RGFW_resetPrevState(); - - XPending(_RGFW->display); - /* if there is no unread queued events, get a new one */ - while ((QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading))) { - RGFW_XHandleEvent(); - } -} - -void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) { +void RGFW_window_move(RGFW_window* win, RGFW_point v) { + RGFW_ASSERT(win != NULL); + win->r.x = v.x; + win->r.y = v.y; + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + XMoveWindow(win->src.display, win->src.window, v.x, v.y); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL RGFW_ASSERT(win != NULL); - win->x = x; - win->y = y; - XMoveWindow(_RGFW->display, win->src.window, x, y); - return; + if (win->src.compositor) { + struct wl_pointer *pointer = wl_seat_get_pointer(win->src.seat); + if (!pointer) { + return; + } + + wl_display_flush(win->src.wl_display); + } +#endif } -void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) { +void RGFW_window_resize(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); - win->w = (i32)w; - win->h = (i32)h; + win->r.w = (i32)a.w; + win->r.h = (i32)a.h; + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + XResizeWindow(win->src.display, win->src.window, a.w, a.h); - XResizeWindow(_RGFW->display, win->src.window, (u32)w, (u32)h); - - if ((win->internal.flags & RGFW_windowNoResize)) { + if ((win->_flags & RGFW_windowNoResize)) { XSizeHints sh; sh.flags = (1L << 4) | (1L << 5); - sh.min_width = sh.max_width = (i32)w; - sh.min_height = sh.max_height = (i32)h; + sh.min_width = sh.max_width = (i32)a.w; + sh.min_height = sh.max_height = (i32)a.h; - XSetWMSizeHints(_RGFW->display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS); + XSetWMSizeHints(win->src.display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS); } - return; +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + if (win->src.compositor) { + xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h); + #ifdef RGFW_OPENGL + wl_egl_window_resize(win->src.eglWindow, (i32)a.w, (i32)a.h, 0, 0); + #endif + } +#endif } -void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) { +void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); + RGFW_GOTO_WAYLAND(0); - - if (w == 0 && h == 0) + if (a.w == 0 && a.h == 0) return; +#ifdef RGFW_X11 XSizeHints hints; long flags; - XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); + XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); hints.flags |= PAspect; - hints.min_aspect.x = hints.max_aspect.x = (i32)w; - hints.min_aspect.y = hints.max_aspect.y = (i32)h; + hints.min_aspect.x = hints.max_aspect.x = (i32)a.w; + hints.min_aspect.y = hints.max_aspect.y = (i32)a.h; - XSetWMNormalHints(_RGFW->display, win->src.window, &hints); + XSetWMNormalHints(win->src.display, win->src.window, &hints); return; +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL +#endif } -void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) { +void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); - + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 long flags; XSizeHints hints; RGFW_MEMSET(&hints, 0, sizeof(XSizeHints)); - XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); + XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); hints.flags |= PMinSize; - hints.min_width = (i32)w; - hints.min_height = (i32)h; + hints.min_width = (i32)a.w; + hints.min_height = (i32)a.h; - XSetWMNormalHints(_RGFW->display, win->src.window, &hints); + XSetWMNormalHints(win->src.display, win->src.window, &hints); return; +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL RGFW_UNUSED(a); +#endif } -void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) { +void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); - + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 long flags; XSizeHints hints; RGFW_MEMSET(&hints, 0, sizeof(XSizeHints)); - XGetWMNormalHints(_RGFW->display, win->src.window, &hints, &flags); + XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags); hints.flags |= PMaxSize; - hints.max_width = (i32)w; - hints.max_height = (i32)h; + hints.max_width = (i32)a.w; + hints.max_height = (i32)a.h; - XSetWMNormalHints(_RGFW->display, win->src.window, &hints); - return; + XSetWMNormalHints(win->src.display, win->src.window, &hints); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL RGFW_UNUSED(a); +#endif } +#ifdef RGFW_X11 void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized); void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) { RGFW_ASSERT(win != NULL); @@ -6238,36 +5129,52 @@ void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) { xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } +#endif -void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) { - win->internal.oldX = win->x; - win->internal.oldY = win->y; - win->internal.oldW = win->w; - win->internal.oldH = win->h; - +void RGFW_window_maximize(RGFW_window* win) { + win->_oldRect = win->r; + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 RGFW_toggleXMaximized(win, 1); return; +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + return; +#endif } -void RGFW_FUNC(RGFW_window_focus) (RGFW_window* win) { +void RGFW_window_focus(RGFW_window* win) { RGFW_ASSERT(win); - + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 XWindowAttributes attr; - XGetWindowAttributes(_RGFW->display, win->src.window, &attr); + XGetWindowAttributes(win->src.display, win->src.window, &attr); if (attr.map_state != IsViewable) return; - XSetInputFocus(_RGFW->display, win->src.window, RevertToPointerRoot, CurrentTime); - XFlush(_RGFW->display); + XSetInputFocus(win->src.display, win->src.window, RevertToPointerRoot, CurrentTime); + XFlush(win->src.display); +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL; +#endif } -void RGFW_FUNC(RGFW_window_raise) (RGFW_window* win) { +void RGFW_window_raise(RGFW_window* win) { RGFW_ASSERT(win); - XRaiseWindow(_RGFW->display, win->src.window); - XMapRaised(_RGFW->display, win->src.window); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + XRaiseWindow(win->src.display, win->src.window); + XMapRaised(win->src.display, win->src.window); +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL; +#endif } +#ifdef RGFW_X11 void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen); void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); @@ -6284,66 +5191,94 @@ void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) xev.xclient.data.l[1] = (long int)netAtom; xev.xclient.data.l[2] = 0; - XSendEvent(_RGFW->display, DefaultRootWindow(_RGFW->display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); + XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); } +#endif -void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) { +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); - + RGFW_GOTO_WAYLAND(0); if (fullscreen) { - win->internal.flags |= RGFW_windowFullscreen; - win->internal.oldX = win->x; - win->internal.oldY = win->y; - win->internal.oldW = win->w; - win->internal.oldH = win->h; + win->_flags |= RGFW_windowFullscreen; + win->_oldRect = win->r; } - else win->internal.flags &= ~(u32)RGFW_windowFullscreen; + else win->_flags &= ~(u32)RGFW_windowFullscreen; +#ifdef RGFW_X11 RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN); RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen); - XRaiseWindow(_RGFW->display, win->src.window); - XMapRaised(_RGFW->display, win->src.window); + XRaiseWindow(win->src.display, win->src.window); + XMapRaised(win->src.display, win->src.window); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL; +#endif } -void RGFW_FUNC(RGFW_window_setFloating)(RGFW_window* win, RGFW_bool floating) { +void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_ASSERT(win != NULL); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating); +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL RGFW_UNUSED(floating); +#endif } -void RGFW_FUNC(RGFW_window_setOpacity)(RGFW_window* win, u8 opacity) { +void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { RGFW_ASSERT(win != NULL); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 const u32 value = (u32) (0xffffffffu * (double) opacity); RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY); - XChangeProperty(_RGFW->display, win->src.window, + XChangeProperty(win->src.display, win->src.window, NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1); +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL RGFW_UNUSED(opacity); +#endif } -void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) { +void RGFW_window_minimize(RGFW_window* win) { RGFW_ASSERT(win != NULL); - + RGFW_GOTO_WAYLAND(0); if (RGFW_window_isMaximized(win)) return; - win->internal.oldX = win->x; - win->internal.oldY = win->y; - win->internal.oldW = win->w; - win->internal.oldH = win->h; - XIconifyWindow(_RGFW->display, win->src.window, DefaultScreen(_RGFW->display)); - XFlush(_RGFW->display); + win->_oldRect = win->r; +#ifdef RGFW_X11 + XIconifyWindow(win->src.display, win->src.window, DefaultScreen(win->src.display)); + XFlush(win->src.display); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL; +#endif } -void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) { +void RGFW_window_restore(RGFW_window* win) { RGFW_ASSERT(win != NULL); - RGFW_toggleXMaximized(win, RGFW_FALSE); - RGFW_window_move(win, win->internal.oldX, win->internal.oldY); - RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); - + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + RGFW_toggleXMaximized(win, 0); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL +#endif + win->r = win->_oldRect; + RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y)); + RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); + RGFW_window_show(win); - XFlush(_RGFW->display); +#ifdef RGFW_X11 + XFlush(win->src.display); +#endif } -RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) { +RGFW_bool RGFW_window_isFloating(RGFW_window* win) { + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 RGFW_LOAD_ATOM(_NET_WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE); @@ -6352,7 +5287,7 @@ RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) { unsigned long nitems, bytes_after; Atom* prop_return = NULL; - int status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM, + int status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, (unsigned char **)&prop_return); @@ -6365,148 +5300,226 @@ RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) { if (prop_return) XFree(prop_return); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL RGFW_UNUSED(win); +#endif return RGFW_FALSE; } -void RGFW_FUNC(RGFW_window_setName)(RGFW_window* win, const char* name) { +void RGFW_window_setName(RGFW_window* win, const char* name) { RGFW_ASSERT(win != NULL); + RGFW_GOTO_WAYLAND(0); + #ifdef RGFW_X11 + XStoreName(win->src.display, win->src.window, name); - XStoreName(_RGFW->display, win->src.window, name); - - RGFW_LOAD_ATOM(_NET_WM_NAME); RGFW_LOAD_ATOM(UTF8_STRING); + RGFW_LOAD_ATOM(_NET_WM_NAME); char buf[256]; RGFW_MEMSET(buf, 0, sizeof(buf)); RGFW_STRNCPY(buf, name, sizeof(buf) - 1); XChangeProperty( - _RGFW->display, win->src.window, _NET_WM_NAME, UTF8_STRING, + win->src.display, win->src.window, _NET_WM_NAME, RGFW_XUTF8_STRING, 8, PropModeReplace, (u8*)buf, sizeof(buf) ); + #endif + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + if (win->src.compositor) + xdg_toplevel_set_title(win->src.xdg_toplevel, name); + #endif } #ifndef RGFW_NO_PASSTHROUGH -void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) { +void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_ASSERT(win != NULL); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 if (passthrough) { Region region = XCreateRegion(); - XShapeCombineRegion(_RGFW->display, win->src.window, ShapeInput, 0, 0, region, ShapeSet); + XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet); XDestroyRegion(region); return; } - XShapeCombineMask(_RGFW->display, win->src.window, ShapeInput, 0, 0, None, ShapeSet); + XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL RGFW_UNUSED(passthrough); +#endif } #endif /* RGFW_NO_PASSTHROUGH */ -RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data_src, i32 w, i32 h, RGFW_format format, RGFW_icon type) { - Atom _NET_WM_ICON = XInternAtom(_RGFW->display, "_NET_WM_ICON", False); +RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { RGFW_ASSERT(win != NULL); - if (data_src == NULL) { + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + RGFW_LOAD_ATOM(_NET_WM_ICON); + if (icon == NULL || (channels != 3 && channels != 4)) { RGFW_bool res = (RGFW_bool)XChangeProperty( - _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, + win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8*)NULL, 0 ); return res; } - i32 count = (i32)(2 + (w * h)); + i32 count = (i32)(2 + (a.w * a.h)); unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long)); RGFW_ASSERT(data != NULL); - RGFW_MEMSET(data, 0, (u32)count * sizeof(unsigned long)); - data[0] = (unsigned long)w; - data[1] = (unsigned long)h; + data[0] = (unsigned long)a.w; + data[1] = (unsigned long)a.h; + + unsigned long* target = &data[2]; + u32 x, y; + + for (x = 0; x < a.w; x++) { + for (y = 0; y < a.h; y++) { + size_t i = y * a.w + x; + u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF; + + target[i] = (unsigned long)((icon[i * 4 + 0]) << 16) | + (unsigned long)((icon[i * 4 + 1]) << 8) | + (unsigned long)((icon[i * 4 + 2]) << 0) | + (unsigned long)(alpha << 24); + } + } - RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_TRUE); RGFW_bool res = RGFW_TRUE; if (type & RGFW_iconTaskbar) { res = (RGFW_bool)XChangeProperty( - _RGFW->display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, + win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, (u8*)data, count ); } - RGFW_copyImageData64((u8*)&data[2], w, h, RGFW_formatBGRA8, data_src, format, RGFW_FALSE); - if (type & RGFW_iconWindow) { XWMHints wm_hints; wm_hints.flags = IconPixmapHint; - i32 depth = DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)); - XImage *image = XCreateImage(_RGFW->display, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), - (u32)depth, ZPixmap, 0, (char *)&data[2], (u32)w, (u32)h, 32, 0); + i32 depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display)); + XImage *image = XCreateImage(win->src.display, DefaultVisual(win->src.display, DefaultScreen(win->src.display)), + (u32)depth, ZPixmap, 0, (char *)target, a.w, a.h, 32, 0); - wm_hints.icon_pixmap = XCreatePixmap(_RGFW->display, win->src.window, (u32)w, (u32)h, (u32)depth); - XPutImage(_RGFW->display, wm_hints.icon_pixmap, DefaultGC(_RGFW->display, DefaultScreen(_RGFW->display)), image, 0, 0, 0, 0, (u32)w, (u32)h); + wm_hints.icon_pixmap = XCreatePixmap(win->src.display, win->src.window, a.w, a.h, (u32)depth); + XPutImage(win->src.display, wm_hints.icon_pixmap, DefaultGC(win->src.display, DefaultScreen(win->src.display)), image, 0, 0, 0, 0, a.w, a.h); image->data = NULL; XDestroyImage(image); - XSetWMHints(_RGFW->display, win->src.window, &wm_hints); + XSetWMHints(win->src.display, win->src.window, &wm_hints); } RGFW_FREE(data); - XFlush(_RGFW->display); + XFlush(win->src.display); return RGFW_BOOL(res); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); + return RGFW_FALSE; +#endif } -RGFW_mouse* RGFW_FUNC(RGFW_loadMouse) (u8* data, i32 w, i32 h, RGFW_format format) { - RGFW_ASSERT(data); +RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { + RGFW_ASSERT(icon); + RGFW_ASSERT(channels == 3 || channels == 4); + RGFW_GOTO_WAYLAND(0); + +#ifdef RGFW_X11 #ifndef RGFW_NO_X11_CURSOR RGFW_init(); - XcursorImage* native = XcursorImageCreate((i32)w, (i32)h); + XcursorImage* native = XcursorImageCreate((i32)a.w, (i32)a.h); native->xhot = 0; native->yhot = 0; - RGFW_MEMSET(native->pixels, 0, (u32)(w * h * 4)); - RGFW_copyImageData((u8*)native->pixels, w, h, RGFW_formatBGRA8, data, format); - Cursor cursor = XcursorImageLoadCursor(_RGFW->display, native); + XcursorPixel* target = native->pixels; + size_t x, y; + for (x = 0; x < a.w; x++) { + for (y = 0; y < a.h; y++) { + size_t i = y * a.w + x; + u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF; + + target[i] = (u32)((icon[i * 4 + 0]) << 16) + | (u32)((icon[i * 4 + 1]) << 8) + | (u32)((icon[i * 4 + 2]) << 0) + | (u32)(alpha << 24); + } + } + + Cursor cursor = XcursorImageLoadCursor(_RGFW.display, native); XcursorImageDestroy(native); return (void*)cursor; #else - RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); + RGFW_UNUSED(image); RGFW_UNUSED(a.w); RGFW_UNUSED(channels); return NULL; #endif +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); + return NULL; /* TODO */ +#endif } -void RGFW_FUNC(RGFW_window_setMouse)(RGFW_window* win, RGFW_mouse* mouse) { +void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { +RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 RGFW_ASSERT(win && mouse); - XDefineCursor(_RGFW->display, win->src.window, (Cursor)mouse); + XDefineCursor(win->src.display, win->src.window, (Cursor)mouse); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_UNUSED(win); RGFW_UNUSED(mouse); +#endif } -void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) { +void RGFW_freeMouse(RGFW_mouse* mouse) { +RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 RGFW_ASSERT(mouse); - XFreeCursor(_RGFW->display, (Cursor)mouse); + XFreeCursor(_RGFW.display, (Cursor)mouse); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_UNUSED(mouse); +#endif } -void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) { +void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { +RGFW_GOTO_WAYLAND(1); +#ifdef RGFW_X11 RGFW_ASSERT(win != NULL); XEvent event; - XQueryPointer(_RGFW->display, DefaultRootWindow(_RGFW->display), + XQueryPointer(win->src.display, DefaultRootWindow(win->src.display), &event.xbutton.root, &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); - win->internal.lastMouseX = x - win->x; - win->internal.lastMouseY = y - win->y; - if (event.xbutton.x == x && event.xbutton.y == 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(_RGFW->display, None, win->src.window, 0, 0, 0, 0, (int) x - win->x, (int) y - win->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); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_UNUSED(win); RGFW_UNUSED(p); +#endif } -RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault) (RGFW_window* win) { +RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); } -RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard) (RGFW_window* win, u8 mouse) { +RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { RGFW_ASSERT(win != NULL); - + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 static const u8 mouseIconSrc[16] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; if (mouse > (sizeof(mouseIconSrc) / sizeof(u8))) @@ -6514,33 +5527,63 @@ RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard) (RGFW_window* win, u8 mouse) { mouse = mouseIconSrc[mouse]; - Cursor cursor = XCreateFontCursor(_RGFW->display, mouse); - XDefineCursor(_RGFW->display, win->src.window, (Cursor) cursor); - XFreeCursor(_RGFW->display, (Cursor) cursor); + Cursor cursor = XCreateFontCursor(win->src.display, mouse); + XDefineCursor(win->src.display, win->src.window, (Cursor) cursor); + + XFreeCursor(win->src.display, (Cursor) cursor); return RGFW_TRUE; +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL { } + static const char* iconStrings[16] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" }; + + struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]); + RGFW_cursor_image = wlcursor->images[0]; + struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); + + wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); + wl_surface_commit(RGFW_cursor_surface); + return RGFW_TRUE; + +#endif } -void RGFW_FUNC(RGFW_window_hide)(RGFW_window* win) { - XUnmapWindow(_RGFW->display, win->src.window); +void RGFW_window_hide(RGFW_window* win) { + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + XUnmapWindow(win->src.display, win->src.window); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + wl_surface_attach(win->src.surface, NULL, 0, 0); + wl_surface_commit(win->src.surface); + win->_flags |= RGFW_windowHide; +#endif } -void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) { - win->internal.flags &= ~(u32)RGFW_windowHide; - if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); - - XMapWindow(_RGFW->display, win->src.window); - RGFW_window_move(win, win->x, win->y); - return; +void RGFW_window_show(RGFW_window* win) { + win->_flags &= ~(u32)RGFW_windowHide; + if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + XMapWindow(win->src.display, win->src.window); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + /* wl_surface_attach(win->src.surface, win->rc., 0, 0); */ + wl_surface_commit(win->src.surface); +#endif } -RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr)(char* str, size_t strCapacity) { +RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { + RGFW_GOTO_WAYLAND(1); +#ifdef RGFW_X11 RGFW_init(); - RGFW_LOAD_ATOM(XSEL_DATA); RGFW_LOAD_ATOM(UTF8_STRING); RGFW_LOAD_ATOM(CLIPBOARD); - if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) { + if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) { if (str != NULL) - RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1); - _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0'; - return (RGFW_ssize_t)_RGFW->clipboard_len - 1; + RGFW_STRNCPY(str, _RGFW.clipboard, _RGFW.clipboard_len - 1); + _RGFW.clipboard[_RGFW.clipboard_len - 1] = '\0'; + return (RGFW_ssize_t)_RGFW.clipboard_len - 1; } XEvent event; @@ -6549,13 +5592,15 @@ RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr)(char* str, size_t strCapacity) { char* data; Atom target; - XConvertSelection(_RGFW->display, CLIPBOARD, UTF8_STRING, XSEL_DATA, _RGFW->helperWindow, CurrentTime); - XSync(_RGFW->display, 0); + RGFW_LOAD_ATOM(XSEL_DATA); + + XConvertSelection(_RGFW.display, RGFW_XCLIPBOARD, RGFW_XUTF8_STRING, XSEL_DATA, _RGFW.helperWindow, CurrentTime); + XSync(_RGFW.display, 0); while (1) { - XNextEvent(_RGFW->display, &event); + XNextEvent(_RGFW.display, &event); if (event.type != SelectionNotify) continue; - if (event.xselection.selection != CLIPBOARD || event.xselection.property == 0) + if (event.xselection.selection != RGFW_XCLIPBOARD || event.xselection.property == 0) return -1; break; } @@ -6568,7 +5613,7 @@ RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr)(char* str, size_t strCapacity) { if (sizeN > strCapacity && str != NULL) size = -1; - if ((target == UTF8_STRING || target == XA_STRING) && str != NULL) { + if ((target == RGFW_XUTF8_STRING || target == XA_STRING) && str != NULL) { RGFW_MEMCPY(str, data, sizeN); str[sizeN] = '\0'; XFree(data); @@ -6578,16 +5623,22 @@ RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr)(char* str, size_t strCapacity) { size = (RGFW_ssize_t)sizeN; return size; + #endif + #if defined(RGFW_WAYLAND) + RGFW_WAYLAND_LABEL RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); + return 0; + #endif } i32 RGFW_XHandleClipboardSelectionHelper(void) { +#ifdef RGFW_X11 RGFW_LOAD_ATOM(SAVE_TARGETS); XEvent event; - XPending(_RGFW->display); + XPending(_RGFW.display); - if (QLength(_RGFW->display) || XEventsQueued(_RGFW->display, QueuedAlready) + XEventsQueued(_RGFW->display, QueuedAfterReading)) - XNextEvent(_RGFW->display, &event); + if (QLength(_RGFW.display) || XEventsQueued(_RGFW.display, QueuedAlready) + XEventsQueued(_RGFW.display, QueuedAfterReading)) + XNextEvent(_RGFW.display, &event); else return 0; @@ -6603,41 +5654,60 @@ i32 RGFW_XHandleClipboardSelectionHelper(void) { } return 0; +#else + return 1; +#endif } -void RGFW_FUNC(RGFW_writeClipboard)(const char* text, u32 textLen) { - RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_LOAD_ATOM(CLIPBOARD); +void RGFW_writeClipboard(const char* text, u32 textLen) { + RGFW_GOTO_WAYLAND(1); + #ifdef RGFW_X11 + RGFW_LOAD_ATOM(SAVE_TARGETS); RGFW_init(); /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */ - XSetSelectionOwner(_RGFW->display, CLIPBOARD, _RGFW->helperWindow, CurrentTime); - if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) != _RGFW->helperWindow) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "X11 failed to become owner of clipboard selection"); + XSetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD, _RGFW.helperWindow, CurrentTime); + if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) != _RGFW.helperWindow) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(_RGFW.root, 0), "X11 failed to become owner of clipboard selection"); return; } - if (_RGFW->clipboard) - RGFW_FREE(_RGFW->clipboard); + if (_RGFW.clipboard) + RGFW_FREE(_RGFW.clipboard); - _RGFW->clipboard = (char*)RGFW_ALLOC(textLen); - RGFW_ASSERT(_RGFW->clipboard != NULL); + _RGFW.clipboard = (char*)RGFW_ALLOC(textLen); + RGFW_ASSERT(_RGFW.clipboard != NULL); - RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1); - _RGFW->clipboard[textLen - 1] = '\0'; - _RGFW->clipboard_len = textLen; - return; + RGFW_STRNCPY(_RGFW.clipboard, text, textLen - 1); + _RGFW.clipboard[textLen - 1] = '\0'; + _RGFW.clipboard_len = textLen; + #endif + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + RGFW_UNUSED(text); RGFW_UNUSED(textLen); + #endif } -RGFW_bool RGFW_FUNC(RGFW_window_isHidden)(RGFW_window* win) { +RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_ASSERT(win != NULL); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 + XWindowAttributes windowAttributes; - XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes); + XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes); return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win)); +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + return RGFW_FALSE; +#endif } -RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) { +RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_ASSERT(win != NULL); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 RGFW_LOAD_ATOM(WM_STATE); Atom actual_type; @@ -6645,7 +5715,7 @@ RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) { unsigned long nitems, bytes_after; unsigned char* prop_data; - i32 status = XGetWindowProperty(_RGFW->display, win->src.window, WM_STATE, 0, 2, False, + i32 status = XGetWindowProperty(win->src.display, win->src.window, WM_STATE, 0, 2, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data); @@ -6658,12 +5728,19 @@ RGFW_bool RGFW_FUNC(RGFW_window_isMinimized)(RGFW_window* win) { XFree(prop_data); XWindowAttributes windowAttributes; - XGetWindowAttributes(_RGFW->display, win->src.window, &windowAttributes); + XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes); return windowAttributes.map_state != IsViewable; +#endif +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + return RGFW_FALSE; +#endif } -RGFW_bool RGFW_FUNC(RGFW_window_isMaximized)(RGFW_window* win) { +RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_ASSERT(win != NULL); + RGFW_GOTO_WAYLAND(0); +#ifdef RGFW_X11 RGFW_LOAD_ATOM(_NET_WM_STATE); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); @@ -6673,7 +5750,7 @@ RGFW_bool RGFW_FUNC(RGFW_window_isMaximized)(RGFW_window* win) { unsigned long nitems, bytes_after; unsigned char* prop_data; - i32 status = XGetWindowProperty(_RGFW->display, win->src.window, _NET_WM_STATE, 0, 1024, False, + i32 status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, 1024, False, XA_ATOM, &actual_type, &actual_format, &nitems, &bytes_after, &prop_data); @@ -6695,10 +5772,23 @@ RGFW_bool RGFW_FUNC(RGFW_window_isMaximized)(RGFW_window* win) { if (prop_data != NULL) XFree(prop_data); - +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL; +#endif return RGFW_FALSE; } +#ifndef RGFW_NO_DPI +u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi); +u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi) { + if (mi.hTotal == 0 || mi.vTotal == 0) return 0; + return (u32) RGFW_ROUND((double) mi.dotClock / ((double) mi.hTotal * (double) mi.vTotal)); +} +#endif + + +#ifdef RGFW_X11 static float XGetSystemContentDPI(Display* display, i32 screen) { float dpi = 96.0f; @@ -6722,53 +5812,49 @@ static float XGetSystemContentDPI(Display* display, i32 screen) { return dpi; } +#endif RGFW_monitor RGFW_XCreateMonitor(i32 screen); RGFW_monitor RGFW_XCreateMonitor(i32 screen) { RGFW_monitor monitor; RGFW_init(); - Display* display = _RGFW->display; + RGFW_GOTO_WAYLAND(1); +#ifdef RGFW_X11 + Display* display = _RGFW.display; if (screen == -1) screen = DefaultScreen(display); Screen* scrn = DefaultScreenOfDisplay(display); + RGFW_area size = RGFW_AREA(scrn->width, scrn->height); monitor.x = 0; monitor.y = 0; - monitor.mode.w = scrn->width; - monitor.mode.h = scrn->height; + monitor.mode.area = RGFW_AREA(size.w, size.h); monitor.physW = (float)DisplayWidthMM(display, screen) / 25.4f; monitor.physH = (float)DisplayHeightMM(display, screen) / 25.4f; - RGFW_splitBPP((u32)DefaultDepth(display, screen), &monitor.mode); + RGFW_splitBPP((u32)DefaultDepth(display, DefaultScreen(display)), &monitor.mode); char* name = XDisplayName((const char*)display); RGFW_STRNCPY(monitor.name, name, sizeof(monitor.name) - 1); monitor.name[sizeof(monitor.name) - 1] = '\0'; float dpi = XGetSystemContentDPI(display, screen); - monitor.pixelRatio = dpi >= 192.0f ? 2 : 1.0f; + monitor.pixelRatio = dpi >= 192.0f ? 2 : 1; monitor.scaleX = (float) (dpi) / 96.0f; monitor.scaleY = (float) (dpi) / 96.0f; #ifndef RGFW_NO_DPI - XRRCrtcInfo* ci = NULL; - XRRScreenResources* sr = NULL; + XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); + monitor.mode.refreshRate = RGFW_XCalculateRefreshRate(sr->modes[screen]); - { - XRRScreenConfiguration* conf = XRRGetScreenInfo(display, RootWindow(display, screen)); - monitor.mode.refreshRate = (u32)XRRConfigCurrentRate(conf); - - sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); + XRRCrtcInfo* ci = NULL; int crtc = screen; if (sr->ncrtc > crtc) { ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]); } - - XRRFreeScreenConfigInfo(conf); - } #endif #ifndef RGFW_NO_DPI @@ -6776,7 +5862,7 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { if (info == NULL || ci == NULL) { XRRFreeScreenResources(sr); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); return monitor; } @@ -6787,21 +5873,18 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { RGFW_STRNCPY(monitor.name, info->name, sizeof(monitor.name) - 1); monitor.name[sizeof(monitor.name) - 1] = '\0'; - XRRFreeOutputInfo(info); - info = NULL; + if ((u8)physW && (u8)physH) { + monitor.physW = physW; + monitor.physH = physH; + } - if (physW > 0.0f && physH > 0.0f) { - monitor.physW = physW; - monitor.physH = physH; - } + monitor.x = ci->x; + monitor.y = ci->y; - monitor.x = ci->x; - monitor.y = ci->y; - - if (ci->width && ci->height) { - monitor.mode.w = (i32)ci->width; - monitor.mode.h = (i32)ci->height; - } + if (ci->width && ci->height) { + monitor.mode.area.w = (u32)ci->width; + monitor.mode.area.h = (u32)ci->height; + } #endif #ifndef RGFW_NO_DPI @@ -6809,15 +5892,24 @@ RGFW_monitor RGFW_XCreateMonitor(i32 screen) { XRRFreeScreenResources(sr); #endif - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); return monitor; +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL RGFW_UNUSED(screen); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); + return monitor; +#endif } -RGFW_monitor* RGFW_FUNC(RGFW_getMonitors)(size_t* len) { +RGFW_monitor* RGFW_getMonitors(size_t* len) { static RGFW_monitor monitors[7]; + + RGFW_GOTO_WAYLAND(1); + #ifdef RGFW_X11 RGFW_init(); - Display* display = _RGFW->display; + Display* display = _RGFW.display; i32 max = ScreenCount(display); i32 i; @@ -6827,41 +5919,52 @@ RGFW_monitor* RGFW_FUNC(RGFW_getMonitors)(size_t* len) { if (len != NULL) *len = (size_t)((max <= 6) ? (max) : (6)); return monitors; + #endif + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL RGFW_UNUSED(len); + return monitors; /* TODO WAYLAND */ + #endif } -RGFW_monitor RGFW_FUNC(RGFW_getPrimaryMonitor)(void) { +RGFW_monitor RGFW_getPrimaryMonitor(void) { + RGFW_GOTO_WAYLAND(1); + #ifdef RGFW_X11 return RGFW_XCreateMonitor(-1); + #endif + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL return (RGFW_monitor){ 0 }; /* TODO WAYLAND */ + #endif } -RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { +RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { + RGFW_GOTO_WAYLAND(1); +#ifdef RGFW_X11 #ifndef RGFW_NO_DPI RGFW_init(); - XRRScreenConfiguration *conf = XRRGetScreenInfo(_RGFW->display, DefaultRootWindow(_RGFW->display)); - XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW->display, DefaultRootWindow(_RGFW->display)); + XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW.display, DefaultRootWindow(_RGFW.display)); if (screenRes == NULL) return RGFW_FALSE; int i; for (i = 0; i < screenRes->ncrtc; i++) { - XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW->display, screenRes, screenRes->crtcs[i]); + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW.display, screenRes, screenRes->crtcs[i]); if (!crtcInfo) continue; - if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.w == crtcInfo->width && (u32)mon.mode.h == crtcInfo->height) { + if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.area.w == crtcInfo->width && (u32)mon.mode.area.h == crtcInfo->height) { RRMode rmode = None; int index; for (index = 0; index < screenRes->nmode; index++) { RGFW_monitorMode foundMode; - foundMode.w = (i32)screenRes->modes[index].width; - foundMode.h = (i32)screenRes->modes[index].height; - foundMode.refreshRate = (u32)XRRConfigCurrentRate(conf); - RGFW_splitBPP((u32)DefaultDepth(_RGFW->display, DefaultScreen(_RGFW->display)), &foundMode); + foundMode.area = RGFW_AREA(screenRes->modes[index].width, screenRes->modes[index].height); + foundMode.refreshRate = RGFW_XCalculateRefreshRate(screenRes->modes[index]); + RGFW_splitBPP((u32)DefaultDepth(_RGFW.display, DefaultScreen(_RGFW.display)), &foundMode); if (RGFW_monitorModeCompare(mode, foundMode, request)) { rmode = screenRes->modes[index].id; RROutput output = screenRes->outputs[i]; - XRROutputInfo* info = XRRGetOutputInfo(_RGFW->display, screenRes, output); + XRROutputInfo* info = XRRGetOutputInfo(_RGFW.display, screenRes, output); if (info) { - XRRSetCrtcConfig(_RGFW->display, screenRes, screenRes->crtcs[i], + XRRSetCrtcConfig(_RGFW.display, screenRes, screenRes->crtcs[i], CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1); XRRFreeOutputInfo(info); XRRFreeCrtcInfo(crtcInfo); @@ -6880,394 +5983,144 @@ RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode)(RGFW_monitor mon, RGFW_monitorMode } XRRFreeScreenResources(screenRes); - XRRFreeScreenConfigInfo(conf); + return RGFW_FALSE; + #endif +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); #endif return RGFW_FALSE; } -RGFW_monitor RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) { +RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_monitor mon; RGFW_MEMSET(&mon, 0, sizeof(mon)); RGFW_ASSERT(win != NULL); - + RGFW_GOTO_WAYLAND(1); +#ifdef RGFW_X11 XWindowAttributes attrs; - if (!XGetWindowAttributes(_RGFW->display, win->src.window, &attrs)) { + if (!XGetWindowAttributes(win->src.display, win->src.window, &attrs)) { return mon; } i32 i; - for (i = 0; i < ScreenCount(_RGFW->display) && i < 6; i++) { - Screen* screen = ScreenOfDisplay(_RGFW->display, i); + for (i = 0; i < ScreenCount(win->src.display) && i < 6; i++) { + Screen* screen = ScreenOfDisplay(win->src.display, i); if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) && attrs.y >= 0 && attrs.y < XHeightOfScreen(screen)) return RGFW_XCreateMonitor(i); } +#endif +#ifdef RGFW_WAYLAND +RGFW_WAYLAND_LABEL +#endif return mon; } -#ifdef RGFW_OPENGL -RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* context, RGFW_glHints* hints) { - /* for checking extensions later */ - const char sRGBARBstr[] = "GLX_ARB_framebuffer_sRGB"; - const char sRGBEXTstr[] = "GLX_EXT_framebuffer_sRGB"; - const char noErorrStr[] = "GLX_ARB_create_context_no_error"; - const char flushStr[] = "GLX_ARB_context_flush_control"; - const char robustStr[] = "GLX_ARB_create_context_robustness"; - - /* basic RGFW int */ - win->src.ctx.native = context; - win->src.gfxType = RGFW_gfxNativeOpenGL; - /* This is required so that way the user can create their own OpenGL context after RGFW_createWindow is used */ - if (win->src.window) RGFW_window_closePlatform(win); - - RGFW_bool transparent = (win->internal.flags & RGFW_windowTransparent); - - /* start by creating a GLX config / X11 Viusal */ - XVisualInfo visual; - GLXFBConfig bestFbc; - - i32 visual_attribs[40]; - RGFW_attribStack stack; - RGFW_attribStack_init(&stack, visual_attribs, 40); - RGFW_attribStack_pushAttribs(&stack, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR); - RGFW_attribStack_pushAttribs(&stack, GLX_X_RENDERABLE, 1); - RGFW_attribStack_pushAttribs(&stack, GLX_RENDER_TYPE, GLX_RGBA_BIT); - RGFW_attribStack_pushAttribs(&stack, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT); - RGFW_attribStack_pushAttribs(&stack, GLX_DOUBLEBUFFER, 1); - RGFW_attribStack_pushAttribs(&stack, GLX_ALPHA_SIZE, hints->alpha); - RGFW_attribStack_pushAttribs(&stack, GLX_DEPTH_SIZE, hints->depth); - RGFW_attribStack_pushAttribs(&stack, GLX_STENCIL_SIZE, hints->stencil); - RGFW_attribStack_pushAttribs(&stack, GLX_STEREO, hints->stereo); - RGFW_attribStack_pushAttribs(&stack, GLX_AUX_BUFFERS, hints->auxBuffers); - RGFW_attribStack_pushAttribs(&stack, GLX_RED_SIZE, hints->red); - RGFW_attribStack_pushAttribs(&stack, GLX_GREEN_SIZE, hints->green); - RGFW_attribStack_pushAttribs(&stack, GLX_BLUE_SIZE, hints->blue); - RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_RED_SIZE, hints->accumRed); - RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_GREEN_SIZE, hints->accumGreen); - RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_BLUE_SIZE, hints->accumBlue); - RGFW_attribStack_pushAttribs(&stack, GLX_ACCUM_ALPHA_SIZE, hints->accumAlpha); - - if (hints->sRGB) { - if (RGFW_extensionSupportedPlatform_OpenGL(sRGBARBstr, sizeof(sRGBARBstr))) - RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, hints->sRGB); - if (RGFW_extensionSupportedPlatform_OpenGL(sRGBEXTstr, sizeof(sRGBEXTstr))) - RGFW_attribStack_pushAttribs(&stack, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, hints->sRGB); - } - - RGFW_attribStack_pushAttribs(&stack, 0, 0); - - /* find the configs */ - i32 fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(_RGFW->display, DefaultScreen(_RGFW->display), visual_attribs, &fbcount); - - i32 best_fbc = -1; - i32 best_depth = 0; - i32 best_samples = 0; - - if (fbcount == 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to find any valid GLX visual configs."); - return 0; - } - - /* search through all found configs to find the best match */ - i32 i; - for (i = 0; i < fbcount; i++) { - XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, fbc[i]); - if (vi == NULL) - continue; - - i32 samp_buf, samples; - glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); - glXGetFBConfigAttrib(_RGFW->display, fbc[i], GLX_SAMPLES, &samples); - - if (best_fbc == -1) best_fbc = i; - if ((!(transparent) || vi->depth == 32) && best_depth == 0) { - best_fbc = i; - best_depth = vi->depth; - } - if ((!(transparent) || vi->depth == 32) && samples <= hints->samples && samples > best_samples) { - best_fbc = i; - best_depth = vi->depth; - best_samples = samples; - } - XFree(vi); - } - - if (best_fbc == -1) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to get a valid GLX visual."); - return 0; - } - - /* we found a config */ - bestFbc = fbc[best_fbc]; - XVisualInfo* vi = glXGetVisualFromFBConfig(_RGFW->display, bestFbc); - if (vi->depth != 32 && transparent) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to to find a matching visual with a 32-bit depth."); - - if (best_samples < hints->samples) - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Failed to load a matching sample count."); - - XFree(fbc); - visual = *vi; - XFree(vi); - - /* use the visual to create a new window */ - RGFW_XCreateWindow(visual, "", win->internal.flags, win); - - /* create the actual OpenGL context */ - i32 context_attribs[40]; - RGFW_attribStack_init(&stack, context_attribs, 40); - - i32 mask = 0; - switch (hints->profile) { - case RGFW_glES: mask |= GLX_CONTEXT_ES_PROFILE_BIT_EXT; break; - case RGFW_glCompatibility: mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break; - case RGFW_glCore: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break; - default: mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; break; - } - - RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_PROFILE_MASK_ARB, mask); - - if (hints->minor || hints->major) { - RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MAJOR_VERSION_ARB, hints->major); - RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_MINOR_VERSION_ARB, hints->minor); - } - - - if (RGFW_extensionSupportedPlatform_OpenGL(flushStr, sizeof(flushStr))) { - if (hints->releaseBehavior == RGFW_glReleaseFlush) { - RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); - } else if (hints->releaseBehavior == RGFW_glReleaseNone) { - RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); - } - } - - i32 flags = 0; - if (hints->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; - if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustStr, sizeof(robustStr))) flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; - if (flags) { - RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_FLAGS_ARB, flags); - } - - if (RGFW_extensionSupportedPlatform_OpenGL(noErorrStr, sizeof(noErorrStr))) { - RGFW_attribStack_pushAttribs(&stack, GLX_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError); - } - - RGFW_attribStack_pushAttribs(&stack, 0, 0); - - /* create the context */ - glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; - char str[] = "glXCreateContextAttribsARB"; - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((u8*) str); - - GLXContext ctx = NULL; - if (hints->share) { - ctx = hints->share->ctx; - } - - if (glXCreateContextAttribsARB == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load proc address 'glXCreateContextAttribsARB', loading a generic OpenGL context."); - win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True); - } else { - _RGFW->x11Error = NULL; - win->src.ctx.native->ctx = glXCreateContextAttribsARB(_RGFW->display, bestFbc, ctx, True, context_attribs); - if (_RGFW->x11Error || win->src.ctx.native->ctx == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an OpenGL context with AttribsARB, loading a generic OpenGL context."); - win->src.ctx.native->ctx = glXCreateContext(_RGFW->display, &visual, ctx, True); - } - } - - #ifndef RGFW_NO_GLXWINDOW - win->src.ctx.native->window = glXCreateWindow(_RGFW->display, bestFbc, win->src.window, NULL); - #else - win->src.ctx.native->window = win->src.window; - #endif - - glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext)win->src.ctx.native->ctx); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); - - return RGFW_TRUE; -} - -void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) { - #ifndef RGFW_NO_GLXWINDOW - if (win->src.ctx.native->window != win->src.window) { - glXDestroyWindow(_RGFW->display, win->src.ctx.native->window); - } - #endif - - glXDestroyContext(_RGFW->display, ctx->ctx); - win->src.ctx.native = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); -} - -RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL)(const char * extension, size_t len) { - RGFW_init(); - const char* extensions = glXQueryExtensionsString(_RGFW->display, XDefaultScreen(_RGFW->display)); - return (extensions != NULL) && RGFW_extensionSupportedStr(extensions, extension, len); -} - -RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL)(const char* procname) { return glXGetProcAddress((u8*) procname); } - -void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { if (win) RGFW_ASSERT(win->src.ctx.native); +#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) +void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { if (win == NULL) glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL); else - glXMakeCurrent(_RGFW->display, (Drawable)win->src.ctx.native->window, (GLXContext) win->src.ctx.native->ctx); - return; + glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); } -void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return glXGetCurrentContext(); } -void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_ASSERT(win->src.ctx.native); glXSwapBuffers(_RGFW->display, win->src.ctx.native->window); } +void* RGFW_getCurrent_OpenGL(void) { return glXGetCurrentContext(); } +void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { glXSwapBuffers(win->src.display, win->src.window); } +#endif -void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) { +void RGFW_window_swapBuffers_software(RGFW_window* win) { RGFW_ASSERT(win != NULL); - /* cached pfn to avoid calling glXGetProcAddress more than once */ - static PFNGLXSWAPINTERVALEXTPROC pfn = NULL; - static int (*pfn2)(int) = NULL; - - if (pfn == NULL) { - u8 str[] = "glXSwapIntervalEXT"; - pfn = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress(str); - if (pfn == NULL) { - pfn = (PFNGLXSWAPINTERVALEXTPROC)1; - const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"}; - - size_t i; - for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++) { - pfn2 = (int(*)(int))glXGetProcAddress((u8*)array[i]); - } - - if (pfn2 != NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function, fallingback to the native swapinterval function"); - } else { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function"); - } + RGFW_GOTO_WAYLAND(0); +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + #ifdef RGFW_X11 + win->src.bitmap->data = (char*) win->buffer; + RGFW_RGB_to_BGR(win, (u8*)win->src.bitmap->data); + XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, win->bufferSize.w, win->bufferSize.h); + win->src.bitmap->data = NULL; + return; + #endif + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA) + RGFW_RGB_to_BGR(win, win->src.buffer); + #else + size_t y; + for (y = 0; y < win->r.h; y++) { + u32 index = (y * 4 * win->r.w); + u32 index2 = (y * 4 * win->bufferSize.w); + RGFW_MEMCPY(&win->src.buffer[index], &win->buffer[index2], win->r.w * 4); } - } + #endif - if (pfn != (PFNGLXSWAPINTERVALEXTPROC)1) { - pfn(_RGFW->display, win->src.ctx.native->window, swapInterval); - } - else if (pfn2 != NULL) { - pfn2(swapInterval); - } + wl_surface_frame_done(win, NULL, 0); + wl_surface_commit(win->src.surface); + #endif +#else +#ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL +#endif + RGFW_UNUSED(win); +#endif } -#endif /* RGFW_OPENGL */ -i32 RGFW_initPlatform_X11(void) { - #ifdef RGFW_USE_XDL - XDL_init(); - #endif +#if !defined(RGFW_EGL) - #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so"); - #else - RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1"); - #endif - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate); - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy); - RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor); - #endif +void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { + RGFW_ASSERT(win != NULL); - #if !defined(RGFW_NO_X11_XI_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so"); - #else - RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6"); - #endif - RGFW_PROC_DEF(X11Xihandle, XISelectEvents); - #endif + #if defined(RGFW_OPENGL) + // cached pfn to avoid calling glXGetProcAddress more than once + static PFNGLXSWAPINTERVALEXTPROC pfn = (PFNGLXSWAPINTERVALEXTPROC)123; + static int (*pfn2)(int) = NULL; - #if !defined(RGFW_NO_X11_EXT_PRELOAD) - #if defined(__CYGWIN__) - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so"); - #elif defined(__OpenBSD__) || defined(__NetBSD__) - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so"); - #else - RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6"); - #endif - RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter); - RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue); - RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter); - RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion); - RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask); - #endif + if (pfn == (PFNGLXSWAPINTERVALEXTPROC)123) { + pfn = ((PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT")); + if (pfn == NULL) { + const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"}; + u32 i; + for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++) + pfn2 = ((int(*)(int))glXGetProcAddress((GLubyte*) array[i])); - XInitThreads(); /*!< init X11 threading */ - _RGFW->display = XOpenDisplay(0); - _RGFW->context = XUniqueContext(); - - XSetWindowAttributes wa; - RGFW_MEMSET(&wa, 0, sizeof(wa)); - wa.event_mask = PropertyChangeMask; - _RGFW->helperWindow = XCreateWindow(_RGFW->display, XDefaultRootWindow(_RGFW->display), 0, 0, 1, 1, 0, 0, - InputOnly, DefaultVisual(_RGFW->display, DefaultScreen(_RGFW->display)), CWEventMask, &wa); - - u8 RGFW_blk[] = { 0, 0, 0, 0 }; - _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); - _RGFW->clipboard = NULL; - - XkbComponentNamesRec rec; - XkbDescPtr desc = XkbGetMap(_RGFW->display, 0, XkbUseCoreKbd); - XkbDescPtr evdesc; - XSetErrorHandler(RGFW_XErrorHandler); - u8 old[256]; - - XkbGetNames(_RGFW->display, XkbKeyNamesMask, desc); - - RGFW_MEMSET(&rec, 0, sizeof(rec)); - char evdev[] = "evdev"; - rec.keycodes = evdev; - evdesc = XkbGetKeyboardByName(_RGFW->display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False); - /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */ - if(evdesc != NULL && desc != NULL) { - int i, j; - for(i = 0; i < (int)sizeof(old); i++){ - old[i] = _RGFW->keycodes[i]; - _RGFW->keycodes[i] = 0; + if (pfn2 != NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function, fallingback to the native swapinterval function"); + } else { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function"); + } } - for(i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){ - for(j = desc->min_key_code; j <= desc->max_key_code; j++){ - if(RGFW_STRNCMP(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){ - _RGFW->keycodes[j] = old[i]; - break; - } - } - } - XkbFreeKeyboard(desc, 0, True); - XkbFreeKeyboard(evdesc, 0, True); } - return 0; + if (pfn != NULL) + pfn(win->src.display, win->src.window, swapInterval); + else if (pfn2 != NULL) { + pfn2(swapInterval); + } + #else + RGFW_UNUSED(swapInterval); + #endif } +#endif -void RGFW_deinitPlatform_X11(void) { +void RGFW_deinit(void) { + if (_RGFW.windowCount == -1 || _RGFW_init == RGFW_FALSE) return; #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL; +#ifdef RGFW_X11 /* to save the clipboard on the x server after the window is closed */ - RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); RGFW_LOAD_ATOM(CLIPBOARD); + RGFW_LOAD_ATOM(CLIPBOARD_MANAGER); RGFW_LOAD_ATOM(SAVE_TARGETS); - if (XGetSelectionOwner(_RGFW->display, CLIPBOARD) == _RGFW->helperWindow) { - XConvertSelection(_RGFW->display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW->helperWindow, CurrentTime); + if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) { + XConvertSelection(_RGFW.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW.helperWindow, CurrentTime); while (RGFW_XHandleClipboardSelectionHelper()); } - if (_RGFW->clipboard) { - RGFW_FREE(_RGFW->clipboard); - _RGFW->clipboard = NULL; + if (_RGFW.clipboard) { + RGFW_FREE(_RGFW.clipboard); + _RGFW.clipboard = NULL; } - if (_RGFW->hiddenMouse) { - RGFW_freeMouse(_RGFW->hiddenMouse); - _RGFW->hiddenMouse = NULL; - } + RGFW_freeMouse(_RGFW.hiddenMouse); - XDestroyWindow(_RGFW->display, (Drawable) _RGFW->helperWindow); /*!< close the window */ - XCloseDisplay(_RGFW->display); /*!< kill connection to the x server */ + XDestroyWindow(_RGFW.display, (Drawable) _RGFW.helperWindow); /*!< close the window */ + XCloseDisplay(_RGFW.display); /*!< kill connection to the x server */ #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) RGFW_FREE_LIBRARY(X11Cursorhandle); @@ -7283,1592 +6136,210 @@ void RGFW_deinitPlatform_X11(void) { #if !defined(RGFW_NO_X11_EXT_PRELOAD) RGFW_FREE_LIBRARY(X11XEXThandle); #endif +#endif +#ifdef RGFW_WAYLAND + wl_display_disconnect(_RGFW.wl_display); +#endif + #ifndef RGFW_NO_LINUX + if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){ + close(RGFW_eventWait_forceStop[0]); + close(RGFW_eventWait_forceStop[1]); + } + + u8 i; + for (i = 0; i < RGFW_gamepadCount; i++) { + if(RGFW_gamepads[i]) + close(RGFW_gamepads[i]); + } + #endif + + _RGFW.root = NULL; + _RGFW.windowCount = -1; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); } -void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) { - if (win->internal.holdMouse) - XUngrabPointer(_RGFW->display, CurrentTime); +void RGFW_window_close(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); - XFreeGC(_RGFW->display, win->src.gc); - XDeleteContext(_RGFW->display, win->src.window, _RGFW->context); - XDestroyWindow(_RGFW->display, (Drawable) win->src.window); /*!< close the window */ + RGFW_GOTO_WAYLAND(0); + #ifdef RGFW_X11 + /* ungrab pointer if it was grabbed */ + if (win->_flags & RGFW_HOLD_MOUSE) + XUngrabPointer(win->src.display, CurrentTime); + + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if (win->buffer != NULL) { + if ((win->_flags & RGFW_BUFFER_ALLOC)) + RGFW_FREE(win->buffer); + XDestroyImage((XImage*) win->src.bitmap); + } + #endif + + XFreeGC(win->src.display, win->src.gc); + XDestroyWindow(win->src.display, (Drawable) win->src.window); /*!< close the window */ + win->src.window = 0; + XCloseDisplay(win->src.display); + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); + _RGFW.windowCount--; + if (_RGFW.windowCount == 0) RGFW_deinit(); + + RGFW_clipboard_switch(NULL); + RGFW_FREE(win->event.droppedFiles); + if ((win->_flags & RGFW_WINDOW_ALLOC)) { + RGFW_FREE(win); + win = NULL; + } return; + #endif + + #ifdef RGFW_WAYLAND + RGFW_WAYLAND_LABEL + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); + + xdg_toplevel_destroy(win->src.xdg_toplevel); + xdg_surface_destroy(win->src.xdg_surface); + wl_surface_destroy(win->src.surface); + + _RGFW.windowCount--; + if (_RGFW.windowCount == 0) RGFW_deinit(); + + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + wl_buffer_destroy(win->src.wl_buffer); + if ((win->_flags & RGFW_BUFFER_ALLOC)) + RGFW_FREE(win->buffer); + + munmap(win->src.buffer, (size_t)(win->r.w * win->r.h * 4)); + #endif + + RGFW_clipboard_switch(NULL); + RGFW_FREE(win->event.droppedFiles); + if ((win->_flags & RGFW_WINDOW_ALLOC)) { + RGFW_FREE(win); + win = NULL; + } + #endif } -#ifdef RGFW_WEBGPU -WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) { - WGPUSurfaceDescriptor surfaceDesc = {0}; - WGPUSurfaceSourceXlibWindow fromXlib = {0}; - fromXlib.chain.sType = WGPUSType_SurfaceSourceXlibWindow; - fromXlib.display = _RGFW->display; - fromXlib.window = window->src.window; - surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromXlib.chain; - return wgpuInstanceCreateSurface(instance, &surfaceDesc); -} -#endif - -#endif /* End of X11 linux / wayland / unix defines */ -/* +#include +#include +#include - Start of Wayland defayland -*/ +void RGFW_stopCheckEvents(void) { -#ifdef RGFW_WAYLAND + RGFW_eventWait_forceStop[2] = 1; + while (1) { + const char byte = 0; + const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1); + if (result == 1 || result == -1) + break; + } +} + +void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { + if (waitMS == 0) return; + + u8 i; + if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) { + if (pipe(RGFW_eventWait_forceStop) != -1) { + fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0); + fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0); + fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0); + fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0); + } + } + + struct pollfd fds[] = { + #ifdef RGFW_WAYLAND + { wl_display_get_fd(win->src.wl_display), POLLIN, 0 }, + #else + { ConnectionNumber(win->src.display), POLLIN, 0 }, + #endif + #ifdef RGFW_X11 + { ConnectionNumber(_RGFW.display), POLLIN, 0 }, + #endif + { RGFW_eventWait_forceStop[0], POLLIN, 0 }, + #if defined(__linux__) + { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0} + #endif + }; + + u8 index = 2; #ifdef RGFW_X11 -#undef RGFW_FUNC /* remove previous define */ -#define RGFW_FUNC(func) func##_Wayland -#else -#define RGFW_FUNC(func) func + index++; #endif -/* -Wayland TODO: (out of date) -- fix RGFW_keyPressed lock state + #if defined(__linux__) || defined(__NetBSD__) + for (i = 0; i < RGFW_gamepadCount; i++) { + if (RGFW_gamepads[i] == 0) + continue; - RGFW_windowMoved, the window was moved (by the user) - RGFW_windowRefresh The window content needs to be refreshed - - RGFW_dataDrop a file has been dropped into the window - RGFW_dataDrag - -- window args: - #define RGFW_windowNoResize the window cannot be resized by the user - #define RGFW_windowAllowDND the window supports drag and drop - #define RGFW_scaleToMonitor scale the window to the screen - -- other missing functions functions ("TODO wayland") (~30 functions) -- fix buffer rendering weird behavior -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct wl_display* RGFW_getDisplay_Wayland(void) { return _RGFW->wl_display; } -struct wl_surface* RGFW_window_getWindow_Wayland(RGFW_window* win) { return win->src.surface; } - - -/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */ -#include "xdg-shell.h" -#include "xdg-toplevel-icon-v1.h" -#include "xdg-decoration-unstable-v1.h" -#include "relative-pointer-unstable-v1.h" -#include "pointer-constraints-unstable-v1.h" -#include "xdg-output-unstable-v1.h" - - -void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized); - -static void RGFW_wl_setOpaque(RGFW_window* win) { - struct wl_region* wl_region = wl_compositor_create_region(_RGFW->compositor); - - if (!wl_region) return; /* return if no region was created */ - - wl_region_add(wl_region, 0, 0, win->w, win->h); - wl_surface_set_opaque_region(win->src.surface, wl_region); - wl_region_destroy(wl_region); - -} - -static void RGFW_wl_xdg_wm_base_ping_handler(void* data, struct xdg_wm_base* wm_base, - u32 serial) { - RGFW_UNUSED(data); - xdg_wm_base_pong(wm_base, serial); -} -static void RGFW_wl_xdg_surface_configure_handler(void* data, struct xdg_surface* xdg_surface, - u32 serial) { - - xdg_surface_ack_configure(xdg_surface, serial); - - RGFW_window* win = (RGFW_window*)data; - - if (win == NULL) { - win = _RGFW->kbOwner; - if (win == NULL) - return; - } - - /* useful for libdecor */ - if (win->src.activated != win->src.pending_activated) { - win->src.activated = win->src.pending_activated; - } - - if (win->src.maximized != win->src.pending_maximized) { - RGFW_toggleWaylandMaximized(win, win->src.pending_maximized); - - RGFW_window_checkMode(win); - } - - - if (win->src.resizing) { - - /* Do not create a resize event if the window is maximized */ - if (!win->src.maximized && win->internal.enabledEvents & RGFW_windowResizedFlag) { - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); - RGFW_windowResizedCallback(win, win->w, win->h); + fds[index].fd = RGFW_gamepads[i]; + index++; } - RGFW_window_resize(win, win->w, win->h); - if (!(win->internal.flags & RGFW_windowTransparent)) { - RGFW_wl_setOpaque(win); - } - } - -} - -static void RGFW_wl_xdg_toplevel_configure_handler(void* data, struct xdg_toplevel* toplevel, - i32 width, i32 height, struct wl_array* states) { - - RGFW_UNUSED(toplevel); - RGFW_window* win = (RGFW_window*)data; - - - win->src.pending_activated = RGFW_FALSE; - win->src.pending_maximized = RGFW_FALSE; - win->src.resizing = RGFW_FALSE; - - - enum xdg_toplevel_state* state; - wl_array_for_each(state, states) { - switch (*state) { - case XDG_TOPLEVEL_STATE_ACTIVATED: - win->src.pending_activated = RGFW_TRUE; - break; - case XDG_TOPLEVEL_STATE_MAXIMIZED: - win->src.pending_maximized = RGFW_TRUE; - break; - default: - break; - } - - } - /* if width and height are not zero and are not the same as the window */ - /* the window is resizing so update the values */ - if ((width && height) && (win->w != width || win->h != height)) { - win->src.resizing = RGFW_TRUE; - win->src.w = win->w = width; - win->src.h = win->h = height; - } -} - -static void RGFW_wl_xdg_toplevel_close_handler(void* data, struct xdg_toplevel *toplevel) { - RGFW_UNUSED(toplevel); - RGFW_window* win = (RGFW_window*)data; - - if (!win->internal.shouldClose) { - RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); - RGFW_window_setShouldClose(win, RGFW_TRUE); - RGFW_windowQuitCallback(win); - } -} - -static void RGFW_wl_xdg_decoration_configure_handler(void* data, - struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, u32 mode) { - RGFW_window* win = (RGFW_window*)data; RGFW_UNUSED(zxdg_toplevel_decoration_v1); - - /* this is expected to run once */ - /* set the decoration mode set by earlier request */ - if (mode != win->src.decoration_mode) { - win->src.decoration_mode = mode; - } -} - -static void RGFW_wl_shm_format_handler(void* data, struct wl_shm *shm, u32 format) { - RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format); -} - -static void RGFW_wl_relative_pointer_motion(void *data, struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, - u32 time_hi, u32 time_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel) { - - RGFW_UNUSED(zwp_relative_pointer_v1); RGFW_UNUSED(time_hi); RGFW_UNUSED(time_lo); - RGFW_UNUSED(dx_unaccel); RGFW_UNUSED(dy_unaccel); - - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_window* win = RGFW->mouseOwner; - - RGFW_ASSERT(win); - - float vecX = (float)wl_fixed_to_double(dx); - float vecY = (float)wl_fixed_to_double(dy); - - RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.mouse.x = win->internal.lastMouseX; - e.mouse.y = win->internal.lastMouseY; - e.mouse.vecX = vecX; - e.mouse.vecY = vecY; - e.common.win = win); - - RGFW->vectorX = vecX; - RGFW->vectorY = vecY; - RGFW_mousePosCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, vecX, vecY); -} - -static void RGFW_wl_pointer_locked(void *data, struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1) { - RGFW_UNUSED(zwp_locked_pointer_v1); - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_window* win = RGFW->mouseOwner; - - win->internal.lastMouseX = win->w / 2; - win->internal.lastMouseY = win->h / 2; - zwp_locked_pointer_v1_set_cursor_position_hint(win->src.locked_pointer, wl_fixed_from_int((win->w / 2)), wl_fixed_from_int((win->h / 2))); - wl_pointer_set_cursor(RGFW->wl_pointer, RGFW->mouse_enter_serial, NULL, 0, 0); /* draw no cursor */ -} - -static void RGFW_wl_pointer_enter(void* data, struct wl_pointer* pointer, u32 serial, - struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - - /* save when the pointer is locked or using default cursor */ - RGFW->mouse_enter_serial = serial; - win->internal.mouseInside = RGFW_TRUE; - RGFW->windowState.win = win; - RGFW->windowState.mouseEnter = RGFW_TRUE; - - RGFW->mouseOwner = win; - - /* set the cursor */ - if (win->src.using_custom_cursor) { - wl_pointer_set_cursor(pointer, serial, win->src.custom_cursor_surface, 0, 0); - } - else { - RGFW_window_setMouseDefault(win); - } - - if (!(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; - - i32 x = (i32)wl_fixed_to_double(surface_x); - i32 y = (i32)wl_fixed_to_double(surface_y); - - RGFW_eventQueuePushEx(e.type = RGFW_mouseEnter; - e.mouse.x = x; - e.mouse.y = y; - e.common.win = win); - - win->internal.lastMouseX = x; - win->internal.lastMouseY = y; - - RGFW_mouseNotifyCallback(win, x, y, RGFW_TRUE); -} - -static void RGFW_wl_pointer_leave(void* data, struct wl_pointer *pointer, u32 serial, struct wl_surface *surface) { - RGFW_UNUSED(pointer); RGFW_UNUSED(serial); - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - RGFW_info* RGFW = (RGFW_info*)data; - if (RGFW->mouseOwner == win) - RGFW->mouseOwner = NULL; - - win->internal.mouseInside = RGFW_FALSE; - RGFW->windowState.winLeave = win; - RGFW->windowState.mouseLeave = RGFW_TRUE; - - if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; - - RGFW_eventQueuePushEx(e.type = RGFW_mouseLeave; - e.mouse.x = win->internal.lastMouseX; - e.mouse.y = win->internal.lastMouseY; - e.common.win = win); - - RGFW_mouseNotifyCallback(win, win->internal.lastMouseX, win->internal.lastMouseY, RGFW_FALSE); -} - -static void RGFW_wl_pointer_motion(void* data, struct wl_pointer *pointer, u32 time, wl_fixed_t x, wl_fixed_t y) { - RGFW_UNUSED(pointer); RGFW_UNUSED(time); - - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_ASSERT(RGFW->mouseOwner != NULL); - - RGFW_window* win = RGFW->mouseOwner; - - if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return; - - i32 convertedX = (i32)wl_fixed_to_double(x); - i32 convertedY = (i32)wl_fixed_to_double(y); - float newVecX = (float)(convertedX - win->internal.lastMouseX); - float newVecY = (float)(convertedY - win->internal.lastMouseY); - - RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.mouse.x = convertedX; - e.mouse.y = convertedY; - e.mouse.vecX = newVecX; - e.mouse.vecY = newVecY; - e.common.win = win); - - RGFW->vectorX = newVecX; - RGFW->vectorY = newVecY; - win->internal.lastMouseX = convertedX; - win->internal.lastMouseY = convertedY; - RGFW_mousePosCallback(win, convertedX, convertedY, newVecX, newVecY); -} - -static void RGFW_wl_pointer_button(void* data, struct wl_pointer *pointer, u32 serial, u32 time, u32 button, u32 state) { - RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); - RGFW_info* RGFW = (RGFW_info*)data; - - RGFW_ASSERT(RGFW->mouseOwner != NULL); - RGFW_window* win = RGFW->mouseOwner; - - if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseButtonReleased - RGFW_BOOL(state))))) return; - u32 b = (button - 0x110); - - /* flip right and middle button codes */ - if (b == 1) b = 2; - else if (b == 2) b = 1; - - RGFW->mouseButtons[b].prev = RGFW->mouseButtons[b].current; - RGFW->mouseButtons[b].current = RGFW_BOOL(state); - - RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased - RGFW_BOOL(state); - e.button.value = (u8)b; - e.common.win = win); - RGFW_mouseButtonCallback(win, (u8)b, RGFW_BOOL(state)); -} - -static void RGFW_wl_pointer_axis(void* data, struct wl_pointer *pointer, u32 time, u32 axis, wl_fixed_t value) { - RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis); - - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_ASSERT(RGFW->mouseOwner != NULL); - RGFW_window* win = RGFW->mouseOwner; - - float scrollX = 0.0; - float scrollY = 0.0; - - if (!(win->internal.enabledEvents & (RGFW_BIT(RGFW_mouseScroll)))) return; - - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) - scrollX = (float)(-wl_fixed_to_double(value) / 10.0); - else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) - scrollY = (float)(-wl_fixed_to_double(value) / 10.0); - - - RGFW->scrollX = (float)scrollX; - RGFW->scrollY = (float)scrollY; - RGFW_mouseScrollCallback(win, scrollX, scrollY); - RGFW_eventQueuePushEx(e.type = RGFW_mouseScroll; - e.scroll.x = scrollX; - e.scroll.y = scrollY; - e.common.win = win); -} - - -static void RGFW_doNothing(void) { } - -static void RGFW_wl_keyboard_keymap(void* data, struct wl_keyboard *keyboard, u32 format, i32 fd, u32 size) { - RGFW_UNUSED(keyboard); RGFW_UNUSED(format); - RGFW_info* RGFW = (RGFW_info*)data; - - char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); - xkb_keymap_unref(RGFW->keymap); - RGFW->keymap = xkb_keymap_new_from_string(RGFW->xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - - munmap(keymap_string, size); - close(fd); - xkb_state_unref(RGFW->xkb_state); - RGFW->xkb_state = xkb_state_new(RGFW->keymap); -} - -static void RGFW_wl_keyboard_enter(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface, struct wl_array *keys) { - RGFW_UNUSED(keyboard); RGFW_UNUSED(keys); - - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - RGFW->kbOwner = win; - - // this is to prevent race conditions - if (RGFW->data_device != NULL && win->src.data_source != NULL) { - wl_data_device_set_selection(RGFW->data_device, win->src.data_source, serial); - } - if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; - - /* is set when RGFW_window_minimize is called; if the minimize button is */ - /* pressed this flag is not set since there is no event to listen for */ - if (win->src.minimized == RGFW_TRUE) win->src.minimized = RGFW_FALSE; - - win->internal.inFocus = RGFW_TRUE; - RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = win); - RGFW_focusCallback(win, RGFW_TRUE); - - if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); -} - -static void RGFW_wl_keyboard_leave(void* data, struct wl_keyboard *keyboard, u32 serial, struct wl_surface *surface) { - RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); - - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); - if (RGFW->kbOwner == win) - RGFW->kbOwner = NULL; - - if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; - - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = win); - RGFW_focusCallback(win, RGFW_FALSE); - RGFW_window_focusLost(win); -} - -static void RGFW_wl_keyboard_key(void* data, struct wl_keyboard *keyboard, u32 serial, u32 time, u32 key, u32 state) { - RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); - - RGFW_info* RGFW = (RGFW_info*)data; - if (RGFW->kbOwner == NULL) return; - - RGFW_window *RGFW_key_win = RGFW->kbOwner; - if (!(RGFW_key_win->internal.enabledEvents & (RGFW_BIT(RGFW_keyPressed + state)))) return; - - xkb_keysym_t keysym = xkb_state_key_get_one_sym(RGFW->xkb_state, key + 8); - - u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8); - RGFW->keyboard[RGFWkey].prev = RGFW->keyboard[RGFWkey].current; - RGFW->keyboard[RGFWkey].current = RGFW_BOOL(state); - - RGFW_eventQueuePushEx(e.type = (u8)(RGFW_keyPressed + state); - e.key.value = (u8)RGFWkey; - e.key.sym = (u8)keysym; - e.key.repeat = RGFW_window_isKeyDown(RGFW_key_win, (u8)RGFWkey); - e.common.win = RGFW_key_win); - - RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(RGFW->keymap, "ScrollLock"))); - RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->internal.mod, RGFW_window_isKeyDown(RGFW_key_win, (u8)RGFWkey), RGFW_BOOL(state)); -} - -static void RGFW_wl_keyboard_modifiers(void* data, struct wl_keyboard *keyboard, u32 serial, u32 mods_depressed, u32 mods_latched, u32 mods_locked, u32 group) { - RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); - RGFW_info* RGFW = (RGFW_info*)data; - xkb_state_update_mask(RGFW->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); -} - -static void RGFW_wl_seat_capabilities(void* data, struct wl_seat *seat, u32 capabilities) { - RGFW_info* RGFW = (RGFW_info*)data; - static struct wl_pointer_listener pointer_listener; - RGFW_MEMSET(&pointer_listener, 0, sizeof(pointer_listener)); - pointer_listener.enter = &RGFW_wl_pointer_enter; - pointer_listener.leave = &RGFW_wl_pointer_leave; - pointer_listener.motion = &RGFW_wl_pointer_motion; - pointer_listener.button = &RGFW_wl_pointer_button; - pointer_listener.axis = &RGFW_wl_pointer_axis; - - static struct wl_keyboard_listener keyboard_listener; - RGFW_MEMSET(&keyboard_listener, 0, sizeof(keyboard_listener)); - keyboard_listener.keymap = &RGFW_wl_keyboard_keymap; - keyboard_listener.enter = &RGFW_wl_keyboard_enter; - keyboard_listener.leave = &RGFW_wl_keyboard_leave; - keyboard_listener.key = &RGFW_wl_keyboard_key; - keyboard_listener.modifiers = &RGFW_wl_keyboard_modifiers; - - if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !RGFW->wl_pointer) { - RGFW->wl_pointer = wl_seat_get_pointer(seat); - wl_pointer_add_listener(RGFW->wl_pointer, &pointer_listener, RGFW); - } - if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !RGFW->wl_keyboard) { - RGFW->wl_keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(RGFW->wl_keyboard, &keyboard_listener, RGFW); - } - - if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && RGFW->wl_pointer) { - wl_pointer_destroy(RGFW->wl_pointer); - } - if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && RGFW->wl_keyboard) { - wl_keyboard_destroy(RGFW->wl_keyboard); - } -} - -static void RGFW_wl_output_set_geometry(void *data, struct wl_output *wl_output, - int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, - int32_t subpixel, const char *make, const char *model, int32_t transform) { - - RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; - monitor->x = x; - monitor->y = y; - - monitor->physW = (float)physical_width / 25.4f; - monitor->physH = (float)physical_height / 25.4f; - - RGFW_UNUSED(wl_output); - RGFW_UNUSED(subpixel); - RGFW_UNUSED(make); - RGFW_UNUSED(model); - RGFW_UNUSED(transform); -} - -static void RGFW_wl_output_set_mode(void *data, struct wl_output *wl_output, uint32_t flags, - int32_t width, int32_t height, int32_t refresh) { - - RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; - - monitor->mode.w = width; - monitor->mode.h = height; - monitor->mode.refreshRate = (u32)RGFW_ROUND( ((float)refresh / 1000) ); - RGFW_UNUSED(width); - RGFW_UNUSED(height); - RGFW_UNUSED(wl_output); - RGFW_UNUSED(flags); -} - -static void RGFW_wl_output_set_scale(void *data, struct wl_output *wl_output, int32_t factor) { - /* this is for pixelRatio */ - RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; - - monitor->pixelRatio = (float)factor; - RGFW_UNUSED(wl_output); -} - -static void RGFW_wl_output_set_name(void *data, struct wl_output *wl_output, const char *name) { - RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; - - RGFW_STRNCPY(monitor->name, name, sizeof(monitor->name) - 1); - monitor->name[sizeof(monitor->name) - 1] = '\0'; - - RGFW_UNUSED(wl_output); - -} - -static void RGFW_xdg_output_logical_pos(void *data, struct zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y) { - RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; - monitor->x = x; - monitor->y = y; - RGFW_UNUSED(zxdg_output_v1); -} - -static void RGFW_xdg_output_logical_size(void *data, struct zxdg_output_v1 *zxdg_output_v1, int32_t width, int32_t height) { - RGFW_monitor* monitor = &((RGFW_monitorNode*)data)->mon; - - float mon_float_width = (float) monitor->mode.w; - float mon_float_height = (float) monitor->mode.h; - - monitor->scaleX = (mon_float_width / (float) width); - monitor->scaleY = (mon_float_height / (float) height); - - /* under xwayland the monitor changes w & h when compositor scales it */ - monitor->mode.w = width; - monitor->mode.h = height; - RGFW_UNUSED(zxdg_output_v1); -} - -static void RGFW_wl_create_outputs(struct wl_registry *const registry, uint32_t id) { - struct wl_output *output = wl_registry_bind(registry, id, &wl_output_interface, wl_display_get_version(_RGFW->wl_display) < 4 ? 3 : 4); - RGFW_monitorNode* node; - RGFW_monitor mon; - - if (!output) return; - - char RGFW_mon_default_name[10]; - - RGFW_SNPRINTF(RGFW_mon_default_name, sizeof(RGFW_mon_default_name), "monitor-%li", _RGFW->monitors.count); - RGFW_STRNCPY(mon.name, RGFW_mon_default_name, sizeof(mon.name) - 1); - mon.name[sizeof(mon.name) - 1] = '\0'; - - /* set in case compositor does not send one */ - /* or no xdg_output support */ - mon.scaleY = mon.scaleX = mon.pixelRatio = 1.0f; - - node = RGFW_monitors_add(mon); - if (node == NULL) return; - - node->id = id; - node->output = output; - - static const struct wl_output_listener wl_output_listener = { - .geometry = RGFW_wl_output_set_geometry, - .mode = RGFW_wl_output_set_mode, - .done = (void (*)(void *,struct wl_output *))&RGFW_doNothing, - .scale = RGFW_wl_output_set_scale, - .name = RGFW_wl_output_set_name, - .description = (void (*)(void *, struct wl_output *, const char *))&RGFW_doNothing - }; - - /* the wl_output will have a reference to the node */ - wl_output_set_user_data(output, node); - - /* pass the monitor so we can access it in the callback functions */ - wl_output_add_listener(output, &wl_output_listener, node); - - if (!_RGFW->xdg_output_manager) return; /* compositor does not support it */ - - static const struct zxdg_output_v1_listener xdg_output_listener = { - .name = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing, - .done = (void (*)(void *,struct zxdg_output_v1 *))&RGFW_doNothing, - .description = (void (*)(void *,struct zxdg_output_v1 *, const char *))&RGFW_doNothing, - .logical_position = RGFW_xdg_output_logical_pos, - .logical_size = RGFW_xdg_output_logical_size - }; - - node->xdg_output = zxdg_output_manager_v1_get_xdg_output(_RGFW->xdg_output_manager, node->output); - zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node); -} - -static void RGFW_wl_surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) { - RGFW_UNUSED(wl_surface); - - RGFW_window* win = (RGFW_window*)data; - RGFW_monitorNode* node = wl_output_get_user_data(output); - win->src.active_monitor = node->mon; - - #ifndef RGFW_NO_MONITOR - if (win->internal.flags & RGFW_windowScaleToMonitor) - RGFW_window_scaleToMonitor(win); #endif -} -static void RGFW_wl_data_source_send(void *data, struct wl_data_source *wl_data_source, const char *mime_type, int32_t fd) { - RGFW_UNUSED(data); RGFW_UNUSED(wl_data_source); - // a client can accept our clipboard - if (RGFW_STRNCMP(mime_type, "text/plain;charset=utf-8", 25) == 0) { - // do not write \0 - write(fd, _RGFW->clipboard, _RGFW->clipboard_len - 1); + u64 start = RGFW_getTimeNS(); + + + #ifdef RGFW_WAYLAND + while (wl_display_dispatch(win->src.wl_display) <= 0 + #else + while (XPending(win->src.display) == 0 + #endif + #ifdef RGFW_X11 + && XPending(_RGFW.display) == 0 + #endif + ) { + if (poll(fds, index, waitMS) <= 0) + break; + + if (waitMS != RGFW_eventWaitNext) + waitMS -= (i32)(RGFW_getTimeNS() - start) / (i32)1e+6; } - close(fd); -} + /* drain any data in the stop request */ + if (RGFW_eventWait_forceStop[2]) { + char data[64]; + (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data)); -static void RGFW_wl_data_source_cancelled(void *data, struct wl_data_source *wl_data_source) { - - RGFW_info* RGFW = (RGFW_info*)data; - - if (RGFW->kbOwner->src.data_source == wl_data_source) { - RGFW->kbOwner->src.data_source = NULL; - } - - wl_data_source_destroy(wl_data_source); - -} - -static void RGFW_wl_data_device_data_offer(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) { - - RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device); - static const struct wl_data_offer_listener wl_data_offer_listener = { - .offer = (void (*)(void *data, struct wl_data_offer *wl_data_offer, const char *))RGFW_doNothing, - .source_actions = (void (*)(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action))RGFW_doNothing, - .action = (void (*)(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action))RGFW_doNothing - }; - wl_data_offer_add_listener(wl_data_offer, &wl_data_offer_listener, NULL); -} - -static void RGFW_wl_data_device_selection(void *data, struct wl_data_device *wl_data_device, struct wl_data_offer *wl_data_offer) { - RGFW_UNUSED(data); RGFW_UNUSED(wl_data_device); - /* Clipboard is empty */ - if (wl_data_offer == NULL) { - return; - } - - int pfds[2]; - pipe(pfds); - - wl_data_offer_receive(wl_data_offer, "text/plain;charset=utf-8", pfds[1]); - close(pfds[1]); - - wl_display_roundtrip(_RGFW->wl_display); - - char buf[1024]; - - ssize_t n = read(pfds[0], buf, sizeof(buf)); - - _RGFW->clipboard = (char*)RGFW_ALLOC((size_t)n); - RGFW_ASSERT(_RGFW->clipboard != NULL); - RGFW_STRNCPY(_RGFW->clipboard, buf, (size_t)n); - - _RGFW->clipboard_len = (size_t)n + 1; - - close(pfds[0]); - - wl_data_offer_destroy(wl_data_offer); - -} - -static void RGFW_wl_global_registry_handler(void* data, struct wl_registry *registry, u32 id, const char *interface, u32 version) { - - static struct wl_seat_listener seat_listener = {&RGFW_wl_seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing}; - static const struct wl_shm_listener shm_listener = { .format = RGFW_wl_shm_format_handler }; - - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_UNUSED(version); - - if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) { - RGFW->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 4); - } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) { - RGFW->xdg_wm_base = wl_registry_bind(registry, id, &xdg_wm_base_interface, 1); - } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) { - RGFW->decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); - } else if (RGFW_STRNCMP(interface, zwp_pointer_constraints_v1_interface.name, 255) == 0) { - RGFW->constraint_manager = wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, 1); - } else if (RGFW_STRNCMP(interface, zwp_relative_pointer_manager_v1_interface.name, 255) == 0) { - RGFW->relative_pointer_manager = wl_registry_bind(registry, id, &zwp_relative_pointer_manager_v1_interface, 1); - } else if (RGFW_STRNCMP(interface, xdg_toplevel_icon_manager_v1_interface.name, 255) == 0) { - RGFW->icon_manager = wl_registry_bind(registry, id, &xdg_toplevel_icon_manager_v1_interface, 1); - } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) { - RGFW->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); - wl_shm_add_listener(RGFW->shm, &shm_listener, RGFW); - } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) { - RGFW->seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); - wl_seat_add_listener(RGFW->seat, &seat_listener, RGFW); - } else if (RGFW_STRNCMP(interface, zxdg_output_manager_v1_interface.name, 255) == 0) { - RGFW->xdg_output_manager = wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 1); - } else if (RGFW_STRNCMP(interface,"wl_output", 10) == 0) { - RGFW_wl_create_outputs(registry, id); - } else if (RGFW_STRNCMP(interface,"wl_data_device_manager", 23) == 0) { - RGFW->data_device_manager = wl_registry_bind(registry, id, &wl_data_device_manager_interface, 1); + RGFW_eventWait_forceStop[2] = 0; } } -static void RGFW_wl_global_registry_remove(void* data, struct wl_registry *registry, u32 id) { - RGFW_UNUSED(data); RGFW_UNUSED(registry); - RGFW_info* RGFW = (RGFW_info*)data; - RGFW_monitorNode* prev = RGFW->monitors.list.head; - RGFW_monitorNode* node = NULL; - if (prev == NULL) return; +i32 RGFW_getClock(void); +i32 RGFW_getClock(void) { + static i32 clock = -1; + if (clock != -1) return clock; - if (prev->id != id) { - /* find the first node that has a matching id */ - while(prev->next != NULL && prev->next->id != id) { - prev = prev->next; - } + #if defined(_POSIX_MONOTONIC_CLOCK) + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + clock = CLOCK_MONOTONIC; + #else + clock = CLOCK_REALTIME; + #endif - if (prev->next == NULL) return; - node = prev->next; - } else { - node = prev; - } - - if (node->output) { - wl_output_destroy(node->output); - } - - if (node->xdg_output) { - zxdg_output_v1_destroy(node->xdg_output); - } - - RGFW_monitors_remove(node, prev); + return clock; } -static void RGFW_wl_randname(char *buf) { +u64 RGFW_getTimerFreq(void) { return 1000000000LLU; } +u64 RGFW_getTimerValue(void) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); - long r = ts.tv_nsec; - - int i; - for (i = 0; i < 6; ++i) { - buf[i] = (char)('A'+(r&15)+(r&16)*2); - r >>= 5; - } + return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec; } +#endif /* end of wayland or X11 defines */ -static size_t RGFW_wl_stringlen(char* name) { - size_t i = 0; - while (name[i]) { i++; } - return i; -} -static int RGFW_wl_anonymous_shm_open(void) { - char name[] = "/RGFW-wayland-XXXXXX"; - int retries = 100; - - do { - RGFW_wl_randname(name + RGFW_wl_stringlen(name) - 6); - - --retries; - /* shm_open guarantees that O_CLOEXEC is set */ - int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) { - shm_unlink(name); - return fd; - } - } while (retries > 0 && errno == EEXIST); - - return -1; -} - -static int RGFW_wl_create_shm_file(off_t size) { - int fd = RGFW_wl_anonymous_shm_open(); - if (fd < 0) { - return fd; - } - - if (ftruncate(fd, size) < 0) { - close(fd); - return -1; - } - - return fd; -} - -i32 RGFW_initPlatform_Wayland(void) { - _RGFW->wl_display = wl_display_connect(NULL); - if (_RGFW->wl_display == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Failed to load Wayland display"); - return -1; - } - - _RGFW->compositor = NULL; - static const struct wl_registry_listener registry_listener = { - .global = RGFW_wl_global_registry_handler, - .global_remove = RGFW_wl_global_registry_remove, - }; - - _RGFW->registry = wl_display_get_registry(_RGFW->wl_display); - wl_registry_add_listener(_RGFW->registry, ®istry_listener, _RGFW); - - wl_display_roundtrip(_RGFW->wl_display); /* bind to globals */ - - if (_RGFW->compositor == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, "Can't find compositor."); - return 1; - } - - if (_RGFW->wl_cursor_theme == NULL) { - _RGFW->wl_cursor_theme = wl_cursor_theme_load(NULL, 24, _RGFW->shm); - _RGFW->cursor_surface = wl_compositor_create_surface(_RGFW->compositor); - } - - u8 RGFW_blk[] = { 0, 0, 0, 0 }; - _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); - - static const struct xdg_wm_base_listener xdg_wm_base_listener = { - .ping = RGFW_wl_xdg_wm_base_ping_handler, - }; - - xdg_wm_base_add_listener(_RGFW->xdg_wm_base, &xdg_wm_base_listener, NULL); - - _RGFW->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - static const struct wl_data_device_listener wl_data_device_listener = { - .data_offer = RGFW_wl_data_device_data_offer, - .enter = (void (*)(void *, struct wl_data_device *, u32, struct wl_surface*, wl_fixed_t, wl_fixed_t, struct wl_data_offer *))&RGFW_doNothing, - .leave = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing, - .motion = (void (*)(void *, struct wl_data_device *, u32, wl_fixed_t, wl_fixed_t))&RGFW_doNothing, - .drop = (void (*)(void *, struct wl_data_device *))&RGFW_doNothing, - .selection = RGFW_wl_data_device_selection - }; - - if (_RGFW->seat && _RGFW->data_device_manager) { - _RGFW->data_device = wl_data_device_manager_get_data_device(_RGFW->data_device_manager, _RGFW->seat); - wl_data_device_add_listener(_RGFW->data_device, &wl_data_device_listener, NULL); - } - - return 0; -} - -void RGFW_deinitPlatform_Wayland(void) { - if (_RGFW->clipboard) { - RGFW_FREE(_RGFW->clipboard); - _RGFW->clipboard = NULL; - } - - if (_RGFW->wl_pointer) { - wl_pointer_destroy(_RGFW->wl_pointer); - } - if (_RGFW->wl_keyboard) { - wl_keyboard_destroy(_RGFW->wl_keyboard); - } - - wl_registry_destroy(_RGFW->registry); - if (_RGFW->decoration_manager != NULL) - zxdg_decoration_manager_v1_destroy(_RGFW->decoration_manager); - if (_RGFW->relative_pointer_manager != NULL) { - zwp_relative_pointer_manager_v1_destroy(_RGFW->relative_pointer_manager); - } - - if (_RGFW->relative_pointer) { - zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer); - } - - if (_RGFW->constraint_manager != NULL) { - zwp_pointer_constraints_v1_destroy(_RGFW->constraint_manager); - } - - if (_RGFW->xdg_output_manager != NULL) - if (_RGFW->icon_manager != NULL) { - xdg_toplevel_icon_manager_v1_destroy(_RGFW->icon_manager); - } - - if (_RGFW->xdg_output_manager) { - zxdg_output_manager_v1_destroy(_RGFW->xdg_output_manager); - } - - if (_RGFW->data_device_manager) { - wl_data_device_manager_destroy(_RGFW->data_device_manager); - } - - if (_RGFW->data_device) { - wl_data_device_destroy(_RGFW->data_device); - } - - if (_RGFW->wl_cursor_theme != NULL) { - wl_cursor_theme_destroy(_RGFW->wl_cursor_theme); - } - - RGFW_freeMouse(_RGFW->hiddenMouse); - - RGFW_monitorNode* node = _RGFW->monitors.list.head; - - while (node != NULL) { - if (node->output) { - wl_output_destroy(node->output); - } - - if (node->xdg_output) { - zxdg_output_v1_destroy(node->xdg_output); - } - - _RGFW->monitors.count -= 1; - node = node->next; - - } - - wl_surface_destroy(_RGFW->cursor_surface); - wl_shm_destroy(_RGFW->shm); - wl_seat_release(_RGFW->seat); - xdg_wm_base_destroy(_RGFW->xdg_wm_base); - wl_compositor_destroy(_RGFW->compositor); - wl_display_disconnect(_RGFW->wl_display); -} - -RGFW_bool RGFW_FUNC(RGFW_createSurfacePtr) (u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { - RGFW_ASSERT(surface != NULL); - surface->data = data; - surface->w = w; - surface->h = h; - surface->format = format; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, "Creating a 4 channel buffer"); - - u32 size = (u32)(surface->w * surface->h * 4); - int fd = RGFW_wl_create_shm_file(size); - if (fd < 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create a buffer."); - return RGFW_FALSE; - } - - surface->native.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (surface->native.buffer == MAP_FAILED) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "mmap failed."); - return RGFW_FALSE; - } - - struct wl_shm_pool* pool = wl_shm_create_pool(_RGFW->shm, fd, (i32)size); - surface->native.wl_buffer = wl_shm_pool_create_buffer(pool, 0, (i32)surface->w, (i32)surface->h, (i32)surface->w * 4, WL_SHM_FORMAT_ARGB8888); - wl_shm_pool_destroy(pool); - - close(fd); - - surface->native.format = RGFW_formatBGRA8; - return RGFW_TRUE; -} - -void RGFW_FUNC(RGFW_window_blitSurface) (RGFW_window* win, RGFW_surface* surface) { - RGFW_ASSERT(surface != NULL); - RGFW_copyImageData(surface->native.buffer, win->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); - - wl_surface_attach(win->src.surface, surface->native.wl_buffer, 0, 0); - wl_surface_damage(win->src.surface, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h)); - wl_surface_commit(win->src.surface); -} - -void RGFW_FUNC(RGFW_surface_freePtr) (RGFW_surface* surface) { - RGFW_ASSERT(surface != NULL); - wl_buffer_destroy(surface->native.wl_buffer); - munmap(surface->native.buffer, (size_t)(surface->w * surface->h * 4)); -} - -void RGFW_FUNC(RGFW_window_setBorder) (RGFW_window* win, RGFW_bool border) { - RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); - - /* for now just toggle between SSD & CSD depending on the bool */ - if (_RGFW->decoration_manager != NULL) { - zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, (border ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)); - } -} - -void RGFW_FUNC(RGFW_releaseCursor) (RGFW_window* win) { - RGFW_ASSERT(win); - /* compositor has no support or window is not locked do nothing */ - if (_RGFW->constraint_manager == NULL || _RGFW->relative_pointer_manager == NULL) return; - - if (win->src.locked_pointer != NULL) { - zwp_locked_pointer_v1_destroy(win->src.locked_pointer); - win->src.locked_pointer = NULL; - } - if (_RGFW->relative_pointer != NULL) { - zwp_relative_pointer_v1_destroy(_RGFW->relative_pointer); - _RGFW->relative_pointer = NULL; - } - - _RGFW->mouseOwner = win; /* unhold mouse sets this to null; set it back */ -} - -void RGFW_FUNC(RGFW_captureCursor) (RGFW_window* win) { - RGFW_ASSERT(win); - /* compositor has no support or window already is locked do nothing */ - if (_RGFW->constraint_manager == NULL || _RGFW->relative_pointer_manager == NULL) return; - - if (_RGFW->relative_pointer == NULL) { - _RGFW->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(_RGFW->relative_pointer_manager, _RGFW->wl_pointer); - - static const struct zwp_relative_pointer_v1_listener relative_motion_listener = { - .relative_motion = RGFW_wl_relative_pointer_motion - }; - - zwp_relative_pointer_v1_add_listener(_RGFW->relative_pointer, &relative_motion_listener, _RGFW); - } - - if (win->src.locked_pointer == NULL) { - win->src.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(_RGFW->constraint_manager, win->src.surface, _RGFW->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); - - static const struct zwp_locked_pointer_v1_listener locked_listener = { - .locked = RGFW_wl_pointer_locked, - .unlocked = (void (*)(void *, struct zwp_locked_pointer_v1 *))RGFW_doNothing - }; - - zwp_locked_pointer_v1_add_listener(win->src.locked_pointer, &locked_listener, _RGFW); - } -} - -RGFW_window* RGFW_FUNC(RGFW_createWindowPlatform) (const char* name, RGFW_windowFlags flags, RGFW_window* win) { - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, "RGFW Wayland support is experimental"); - - static const struct xdg_surface_listener xdg_surface_listener = { - .configure = RGFW_wl_xdg_surface_configure_handler, - }; - - static const struct wl_surface_listener wl_surface_listener = { - .enter = RGFW_wl_surface_enter, - .leave = (void (*)(void *, struct wl_surface *, struct wl_output *))&RGFW_doNothing, - .preferred_buffer_scale = (void (*)(void *, struct wl_surface *, i32))&RGFW_doNothing, - .preferred_buffer_transform = (void (*)(void *, struct wl_surface *, u32))&RGFW_doNothing - }; - - win->src.surface = wl_compositor_create_surface(_RGFW->compositor); - wl_surface_add_listener(win->src.surface, &wl_surface_listener, win); - - /* create a surface for a custom cursor */ - win->src.custom_cursor_surface = wl_compositor_create_surface(_RGFW->compositor); - - win->src.xdg_surface = xdg_wm_base_get_xdg_surface(_RGFW->xdg_wm_base, win->src.surface); - xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, win); - - xdg_wm_base_set_user_data(_RGFW->xdg_wm_base, win); - - win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); - - xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h); - - if (!(win->internal.flags & RGFW_windowTransparent)) { /* no transparency */ - RGFW_wl_setOpaque(win); - } - - static const struct xdg_toplevel_listener xdg_toplevel_listener = { - .configure = RGFW_wl_xdg_toplevel_configure_handler, - .close = RGFW_wl_xdg_toplevel_close_handler, - }; - - xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, win); - - /* compositor supports both SSD & CSD - So choose accordingly - */ - if (_RGFW->decoration_manager) { - u32 decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; - win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - _RGFW->decoration_manager, win->src.xdg_toplevel); - - static const struct zxdg_toplevel_decoration_v1_listener xdg_decoration_listener = { - .configure = RGFW_wl_xdg_decoration_configure_handler - }; - - zxdg_toplevel_decoration_v1_add_listener(win->src.decoration, &xdg_decoration_listener, win); - - /* we want no decorations */ - if ((flags & RGFW_windowNoBorder)) { - decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - } - - zxdg_toplevel_decoration_v1_set_mode(win->src.decoration, decoration_mode); - - /* no xdg_decoration support */ - } else if (!(flags & RGFW_windowNoBorder)) { - /* TODO, some fallback */ - #ifdef RGFW_LIBDECOR - static struct libdecor_interface interface = { - .error = NULL, - }; - - static struct libdecor_frame_interface frameInterface = {0}; /*= { - RGFW_wl_handle_configure, - RGFW_wl_handle_close, - RGFW_wl_handle_commit, - RGFW_wl_handle_dismiss_popup, - };*/ - - win->src.decorContext = libdecor_new(_RGFW->wl_display, &interface); - if (win->src.decorContext) { - struct libdecor_frame *frame = libdecor_decorate(win->src.decorContext, win->src.surface, &frameInterface, win); - if (!frame) { - libdecor_unref(win->src.decorContext); - win->src.decorContext = NULL; - } else { - libdecor_frame_set_app_id(frame, "my-libdecor-app"); - libdecor_frame_set_title(frame, "My Libdecor Window"); - } - } - #endif - } - - if (_RGFW->icon_manager != NULL) { - /* set the default wayland icon */ - xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, NULL); - } - - wl_surface_commit(win->src.surface); - wl_display_dispatch(_RGFW->wl_display); - RGFW_UNUSED(name); - - return win; -} - -RGFW_bool RGFW_FUNC(RGFW_getGlobalMouse) (i32* x, i32* y) { - RGFW_init(); - if (x) *x = 0; - if (y) *y = 0; - return RGFW_FALSE; -} - -u8 RGFW_FUNC(RGFW_rgfwToKeyChar)(u32 key) { - return (u8)key; -} - -void RGFW_FUNC(RGFW_pollEvents) (void) { - RGFW_resetPrevState(); - - /* send buffered requests to compositor */ - while (wl_display_flush(_RGFW->wl_display) == -1) { - /* compositor not responding to new requests */ - /* so let's dispatch some events so the compositor responds */ - if (errno == EAGAIN) { - if (wl_display_dispatch_pending(_RGFW->wl_display) == -1) { - return; - } - } else { - return; - } - } - - /* read the events; if empty this reads from the */ - /* wayland file descriptor */ - if (wl_display_dispatch(_RGFW->wl_display) == -1) { - return; - } - -} - -void RGFW_FUNC(RGFW_window_move) (RGFW_window* win, i32 x, i32 y) { - RGFW_ASSERT(win != NULL); - win->x = x; - win->y = y; -} - - -void RGFW_FUNC(RGFW_window_resize) (RGFW_window* win, i32 w, i32 h) { - RGFW_ASSERT(win != NULL); - win->w = w; - win->h = h; - if (_RGFW->compositor) { - xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->w, win->h); - #ifdef RGFW_OPENGL - if (win->src.ctx.egl) - wl_egl_window_resize(win->src.ctx.egl->eglWindow, (i32)w, (i32)h, 0, 0); - #endif - } -} - -void RGFW_FUNC(RGFW_window_setAspectRatio) (RGFW_window* win, i32 w, i32 h) { - RGFW_ASSERT(win != NULL); - - if (w == 0 && h == 0) - return; - xdg_toplevel_set_max_size(win->src.xdg_toplevel, (i32)w, (i32)h); -} - -void RGFW_FUNC(RGFW_window_setMinSize) (RGFW_window* win, i32 w, i32 h) { - RGFW_ASSERT(win != NULL); - xdg_toplevel_set_min_size(win->src.xdg_toplevel, w, h); -} - -void RGFW_FUNC(RGFW_window_setMaxSize) (RGFW_window* win, i32 w, i32 h) { - RGFW_ASSERT(win != NULL); - xdg_toplevel_set_max_size(win->src.xdg_toplevel, w, h); -} - -void RGFW_toggleWaylandMaximized(RGFW_window* win, RGFW_bool maximized) { - win->src.maximized = maximized; - if (maximized) { - xdg_toplevel_set_maximized(win->src.xdg_toplevel); - } else { - xdg_toplevel_unset_maximized(win->src.xdg_toplevel); - } -} - -void RGFW_FUNC(RGFW_window_maximize) (RGFW_window* win) { - win->internal.oldX = win->x; - win->internal.oldY = win->y; - win->internal.oldW = win->w; - win->internal.oldH = win->h; - RGFW_toggleWaylandMaximized(win, 1); - return; -} - -void RGFW_FUNC(RGFW_window_focus)(RGFW_window* win) { - RGFW_ASSERT(win); -} - -void RGFW_FUNC(RGFW_window_raise)(RGFW_window* win) { - RGFW_ASSERT(win); -} - -void RGFW_FUNC(RGFW_window_setFullscreen)(RGFW_window* win, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); - if (fullscreen) { - - win->internal.flags |= RGFW_windowFullscreen; - win->internal.oldX = win->x; - win->internal.oldY = win->y; - win->internal.oldW = win->w; - win->internal.oldH = win->h; - xdg_toplevel_set_fullscreen(win->src.xdg_toplevel, NULL); /* let the compositor decide */ - } else { - win->internal.flags &= ~(u32)RGFW_windowFullscreen; - xdg_toplevel_unset_fullscreen(win->src.xdg_toplevel); - } - -} - -void RGFW_FUNC(RGFW_window_setFloating) (RGFW_window* win, RGFW_bool floating) { - RGFW_ASSERT(win != NULL); - RGFW_UNUSED(floating); -} - -void RGFW_FUNC(RGFW_window_setOpacity) (RGFW_window* win, u8 opacity) { - RGFW_ASSERT(win != NULL); - RGFW_UNUSED(opacity); -} - -void RGFW_FUNC(RGFW_window_minimize)(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - if (RGFW_window_isMaximized(win)) return; - win->internal.oldX = win->x; - win->internal.oldY = win->y; - win->internal.oldW = win->w; - win->internal.oldH = win->h; - win->src.minimized = RGFW_TRUE; - xdg_toplevel_set_minimized(win->src.xdg_toplevel); -} - -void RGFW_FUNC(RGFW_window_restore)(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_toggleWaylandMaximized(win, RGFW_FALSE); - - RGFW_window_move(win, win->internal.oldX, win->internal.oldY); - RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); - - RGFW_window_show(win); - RGFW_window_move(win, win->internal.oldX, win->internal.oldY); - RGFW_window_resize(win, win->internal.oldW, win->internal.oldH); - - RGFW_window_show(win); -} - -RGFW_bool RGFW_FUNC(RGFW_window_isFloating)(RGFW_window* win) { - return (!RGFW_window_isFullscreen(win) && !RGFW_window_isMaximized(win)); -} - -void RGFW_FUNC(RGFW_window_setName) (RGFW_window* win, const char* name) { - RGFW_ASSERT(win != NULL); - if (_RGFW->compositor) - xdg_toplevel_set_title(win->src.xdg_toplevel, name); -} - -#ifndef RGFW_NO_PASSTHROUGH -void RGFW_FUNC(RGFW_window_setMousePassthrough) (RGFW_window* win, RGFW_bool passthrough) { - RGFW_ASSERT(win != NULL); - RGFW_UNUSED(passthrough); -} -#endif /* RGFW_NO_PASSTHROUGH */ - -RGFW_bool RGFW_FUNC(RGFW_window_setIconEx) (RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { - RGFW_ASSERT(win != NULL); - RGFW_UNUSED(type); - - if (_RGFW->icon_manager == NULL || w != h) return RGFW_FALSE; - - if (win->src.icon) { - xdg_toplevel_icon_v1_destroy(win->src.icon); - win->src.icon= NULL; - } - - RGFW_surface* surface = RGFW_createSurface(data, w, h, format); - - if (surface == NULL) return RGFW_FALSE; - - RGFW_copyImageData(surface->native.buffer, RGFW_MIN(w, surface->w), RGFW_MIN(h, surface->h), surface->native.format, surface->data, surface->format); - - win->src.icon = xdg_toplevel_icon_manager_v1_create_icon(_RGFW->icon_manager); - xdg_toplevel_icon_v1_add_buffer(win->src.icon, surface->native.wl_buffer, 1); - xdg_toplevel_icon_manager_v1_set_icon(_RGFW->icon_manager, win->src.xdg_toplevel, win->src.icon); - - RGFW_surface_free(surface); - return RGFW_TRUE; -} - -RGFW_mouse* RGFW_FUNC(RGFW_loadMouse)(u8* data, i32 w, i32 h, RGFW_format format) { - - RGFW_surface *mouse_surface = RGFW_createSurface(data, w, h, format); - - if (mouse_surface == NULL) return NULL; - - RGFW_copyImageData(mouse_surface->native.buffer, RGFW_MIN(w, mouse_surface->w), RGFW_MIN(h, mouse_surface->h), mouse_surface->native.format, mouse_surface->data, mouse_surface->format); - - return (void*) mouse_surface; -} - -void RGFW_FUNC(RGFW_window_setMouse)(RGFW_window* win, RGFW_mouse* mouse) { - RGFW_ASSERT(win); RGFW_ASSERT(mouse); - RGFW_surface *mouse_surface = (RGFW_surface*)mouse; - - win->src.using_custom_cursor = RGFW_TRUE; - - struct wl_buffer *mouse_buffer = mouse_surface->native.wl_buffer; - - wl_surface_attach(win->src.custom_cursor_surface, mouse_buffer, 0, 0); - wl_surface_damage(win->src.custom_cursor_surface, 0, 0, mouse_surface->w, mouse_surface->h); - wl_surface_commit(win->src.custom_cursor_surface); - -} - -void RGFW_FUNC(RGFW_freeMouse)(RGFW_mouse* mouse) { - if (mouse != NULL) { - RGFW_surface_free((RGFW_surface*)mouse); - } -} - -void RGFW_FUNC(RGFW_window_moveMouse)(RGFW_window* win, i32 x, i32 y) { - RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); -} - -RGFW_bool RGFW_FUNC(RGFW_window_setMouseDefault)(RGFW_window* win) { - return RGFW_window_setMouseStandard(win, RGFW_mouseArrow); -} - -RGFW_bool RGFW_FUNC(RGFW_window_setMouseStandard)(RGFW_window* win, u8 mouse) { - RGFW_ASSERT(win != NULL); - static const char* iconStrings[16] = { "arrow", "left_ptr", "xterm", "crosshair", "hand2", "sb_h_double_arrow", "sb_v_double_arrow", "bottom_left_corner", "bottom_right_corner", "fleur", "forbidden" }; - - win->src.using_custom_cursor = RGFW_FALSE; - - if (mouse > RGFW_mouseIconCount - 1) return RGFW_FALSE; - - struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(_RGFW->wl_cursor_theme, iconStrings[mouse]); - struct wl_cursor_image* cursor_image = wlcursor->images[0]; - struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(cursor_image); - wl_pointer_set_cursor(_RGFW->wl_pointer, _RGFW->mouse_enter_serial, _RGFW->cursor_surface, (i32)cursor_image->hotspot_x, (i32)cursor_image->hotspot_y); - wl_surface_attach(_RGFW->cursor_surface, cursor_buffer, 0, 0); - wl_surface_damage(_RGFW->cursor_surface, 0, 0, (i32)cursor_image->width, (i32)cursor_image->height); - wl_surface_commit(_RGFW->cursor_surface); - return RGFW_TRUE; -} - -void RGFW_FUNC(RGFW_window_hide) (RGFW_window* win) { - wl_surface_attach(win->src.surface, NULL, 0, 0); - wl_surface_commit(win->src.surface); - win->internal.flags |= RGFW_windowHide; -} - -void RGFW_FUNC(RGFW_window_show) (RGFW_window* win) { - win->internal.flags &= ~(u32)RGFW_windowHide; - if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); - /* wl_surface_attach(win->src.surface, win->x, win->y, win->w, win->h, 0, 0); */ - wl_surface_commit(win->src.surface); -} - -RGFW_ssize_t RGFW_FUNC(RGFW_readClipboardPtr) (char* str, size_t strCapacity) { - - RGFW_UNUSED(strCapacity); - - if (str != NULL) - RGFW_STRNCPY(str, _RGFW->clipboard, _RGFW->clipboard_len - 1); - _RGFW->clipboard[_RGFW->clipboard_len - 1] = '\0'; - return (RGFW_ssize_t)_RGFW->clipboard_len - 1; -} - -void RGFW_FUNC(RGFW_writeClipboard) (const char* text, u32 textLen) { - - // compositor does not support wl_data_device_manager - // clients cannot read rgfw's clipboard - if (_RGFW->data_device_manager == NULL) return; - // clear the clipboard - if (_RGFW->clipboard) - RGFW_FREE(_RGFW->clipboard); - - // set the contents - _RGFW->clipboard = (char*)RGFW_ALLOC(textLen); - RGFW_ASSERT(_RGFW->clipboard != NULL); - RGFW_STRNCPY(_RGFW->clipboard, text, textLen - 1); - _RGFW->clipboard[textLen - 1] = '\0'; - _RGFW->clipboard_len = textLen; - - // means we already wrote to the clipboard - // so destroy it to create a new one - RGFW_window* win = _RGFW->kbOwner; - - if (win->src.data_source != NULL) { - wl_data_source_destroy(win->src.data_source); - win->src.data_source = NULL; - } - - // advertise to other clients that we offer text - win->src.data_source = wl_data_device_manager_create_data_source(_RGFW->data_device_manager); - - // basic error checking - if (win->src.data_source == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "Could not create clipboard data source"); - return; - } - wl_data_source_offer(win->src.data_source , "text/plain;charset=utf-8"); - - // needed RGFW_doNothing because wayland will call the functions - // if not set they are random data that lead to a crash - static const struct wl_data_source_listener data_source_listener = { - .target = (void (*)(void *, struct wl_data_source *, const char *))&RGFW_doNothing, - .action = (void (*)(void *, struct wl_data_source *, u32))&RGFW_doNothing, - .dnd_drop_performed = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing, - .dnd_finished = (void (*)(void *, struct wl_data_source *))&RGFW_doNothing, - .send = RGFW_wl_data_source_send, - .cancelled = RGFW_wl_data_source_cancelled - }; - - wl_data_source_add_listener(win->src.data_source, &data_source_listener, _RGFW); - -} - -RGFW_bool RGFW_FUNC(RGFW_window_isHidden) (RGFW_window* win) { - RGFW_ASSERT(win != NULL); - return RGFW_FALSE; -} - -RGFW_bool RGFW_FUNC(RGFW_window_isMinimized) (RGFW_window* win) { - RGFW_ASSERT(win != NULL); - return win->src.minimized; -} - -RGFW_bool RGFW_FUNC(RGFW_window_isMaximized) (RGFW_window* win) { - RGFW_ASSERT(win != NULL); - return win->src.maximized; -} - -RGFW_monitor* RGFW_FUNC(RGFW_getMonitors) (size_t* len) { - static RGFW_monitor monitors[RGFW_MAX_MONITORS]; - RGFW_init(); - if (len != NULL) { - *len = _RGFW->monitors.count; - } - - u8 i = 0; - RGFW_monitorNode* cur_node = _RGFW->monitors.list.head; - while (cur_node != NULL) { - monitors[i] = cur_node->mon; - ++i; - cur_node = cur_node->next; - } - return monitors; -} - -RGFW_monitor RGFW_FUNC(RGFW_getPrimaryMonitor) (void) { - return _RGFW->monitors.list.head->mon; -} - -RGFW_bool RGFW_FUNC(RGFW_monitor_requestMode) (RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { - RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); - return RGFW_FALSE; -} - -RGFW_monitor RGFW_FUNC(RGFW_window_getMonitor) (RGFW_window* win) { - RGFW_ASSERT(win); - return win->src.active_monitor; -} - -#ifdef RGFW_OPENGL -RGFW_bool RGFW_FUNC(RGFW_extensionSupportedPlatform_OpenGL) (const char * extension, size_t len) { return RGFW_extensionSupportedPlatform_EGL(extension, len); } -RGFW_proc RGFW_FUNC(RGFW_getProcAddress_OpenGL) (const char* procname) { return RGFW_getProcAddress_EGL(procname); } - - -RGFW_bool RGFW_FUNC(RGFW_window_createContextPtr_OpenGL)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { - RGFW_bool out = RGFW_window_createContextPtr_EGL(win, &ctx->egl, hints); - win->src.gfxType = RGFW_gfxNativeOpenGL; - return out; -} -void RGFW_FUNC(RGFW_window_deleteContextPtr_OpenGL) (RGFW_window* win, RGFW_glContext* ctx) { RGFW_window_deleteContextPtr_EGL(win, &ctx->egl); win->src.ctx.native = NULL; } - -void RGFW_FUNC(RGFW_window_makeCurrentContext_OpenGL) (RGFW_window* win) { RGFW_window_makeCurrentContext_EGL(win); } -void* RGFW_FUNC(RGFW_getCurrentContext_OpenGL) (void) { return RGFW_getCurrentContext_EGL(); } -void RGFW_FUNC(RGFW_window_swapBuffers_OpenGL) (RGFW_window* win) { RGFW_window_swapBuffers_EGL(win); } -void RGFW_FUNC(RGFW_window_swapInterval_OpenGL) (RGFW_window* win, i32 swapInterval) { RGFW_window_swapInterval_EGL(win, swapInterval); } -#endif /* RGFW_OPENGL */ - -void RGFW_FUNC(RGFW_window_closePlatform)(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, "a window was freed"); - #ifdef RGFW_LIBDECOR - if (win->src.decorContext) - libdecor_unref(win->src.decorContext); - #endif - - if (win->src.decoration) { - zxdg_toplevel_decoration_v1_destroy(win->src.decoration); - } - - if (win->src.xdg_toplevel) { - xdg_toplevel_destroy(win->src.xdg_toplevel); - } - - wl_surface_destroy(win->src.custom_cursor_surface); - - if (win->src.locked_pointer) { - zwp_locked_pointer_v1_destroy(win->src.locked_pointer); - } - - if (win->src.icon) { - xdg_toplevel_icon_v1_destroy(win->src.icon); - } - - xdg_surface_destroy(win->src.xdg_surface); - wl_surface_destroy(win->src.surface); -} - -#ifdef RGFW_WEBGPU -WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WGPUInstance instance) { - WGPUSurfaceDescriptor surfaceDesc = {0}; - WGPUSurfaceSourceWaylandSurface fromWl = {0}; - fromWl.chain.sType = WGPUSType_SurfaceSourceWaylandSurface; - fromWl.display = _RGFW->wl_display; - fromWl.surface = window->src.surface; - - surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromWl.chain; - return wgpuInstanceCreateSurface(instance, &surfaceDesc); -} -#endif - - - -#endif /* RGFW_WAYLAND */ -/* - End of Wayland defines -*/ /* @@ -8882,22 +6353,7 @@ WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WG #define OEMRESOURCE #include -#ifndef OCR_NORMAL -#define OCR_NORMAL 32512 -#define OCR_IBEAM 32513 -#define OCR_WAIT 32514 -#define OCR_CROSS 32515 -#define OCR_UP 32516 -#define OCR_SIZENWSE 32642 -#define OCR_SIZENESW 32643 -#define OCR_SIZEWE 32644 -#define OCR_SIZENS 32645 -#define OCR_SIZEALL 32646 -#define OCR_NO 32648 -#define OCR_HAND 32649 -#define OCR_APPSTARTING 32650 -#endif - +#include #include #include #include @@ -8909,7 +6365,19 @@ WGPUSurface RGFW_FUNC(RGFW_window_createSurface_WebGPU) (RGFW_window* window, WG #define WM_DPICHANGED 0x02E0 #endif -RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* out, size_t max); +#ifndef RGFW_NO_XINPUT + typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); + PFN_XInputGetState XInputGetStateSRC = NULL; + #define XInputGetState XInputGetStateSRC + + typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE); + PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL; + #define XInputGetKeystroke XInputGetKeystrokeSRC + + HMODULE RGFW_XInput_dll = NULL; +#endif + +char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source); #define GL_FRONT 0x0404 #define GL_BACK 0x0405 @@ -8920,11 +6388,16 @@ typedef int (*PFN_wglGetSwapIntervalEXT)(void); PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL; #define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc + +void* RGFWgamepadApi = NULL; + /* these two wgl functions need to be preloaded */ typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList); PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; -HMODULE RGFW_wgl_dll = NULL; +#ifndef RGFW_EGL + HMODULE RGFW_wgl_dll = NULL; +#endif #ifndef RGFW_NO_LOAD_WGL typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC); @@ -8952,11 +6425,28 @@ HMODULE RGFW_wgl_dll = NULL; #define wglShareLists wglShareListsSRC #endif -void* RGFW_window_getHWND(RGFW_window* win) { return win->src.window; } -void* RGFW_window_getHDC(RGFW_window* win) { return win->src.hdc; } +#if defined(RGFW_OPENGL) && !defined(RGFW_EGL) +RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { + const char* extensions = NULL; -#ifdef RGFW_OPENGL -RGFWDEF void RGFW_win32_loadOpenGLFuncs(HWND dummyWin); + RGFW_proc proc = RGFW_getProcAddress("wglGetExtensionsStringARB"); + RGFW_proc proc2 = RGFW_getProcAddress("wglGetExtensionsStringEXT"); + + if (proc) + extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC()); + else if (proc2) + extensions = ((const char*(*)(void))proc2)(); + + return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); +} + +RGFW_proc RGFW_getProcAddress(const char* procname) { + RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname); + if (proc) + return proc; + + return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); +} typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; @@ -8967,15 +6457,13 @@ PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #ifndef RGFW_NO_DWM HMODULE RGFW_dwm_dll = NULL; -#ifndef _DWMAPI_H_ typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND; -#endif typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*); PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL; #endif void RGFW_win32_makeWindowTransparent(RGFW_window* win); void RGFW_win32_makeWindowTransparent(RGFW_window* win) { - if (!(win->internal.flags & RGFW_windowTransparent)) return; + if (!(win->_flags & RGFW_windowTransparent)) return; #ifndef RGFW_NO_DWM if (DwmEnableBlurBehindWindowSRC != NULL) { @@ -8998,55 +6486,49 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW"); if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam); - static BYTE keyboardState[256]; - GetKeyboardState(keyboardState); - - RGFW_event event; - RGFW_MEMSET(&event, 0, sizeof(event)); - event.common.win = win; - RECT windowRect; GetWindowRect(hWnd, &windowRect); switch (message) { case WM_CLOSE: case WM_QUIT: - RGFW_window_setShouldClose(win, RGFW_TRUE); + RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); RGFW_windowQuitCallback(win); - RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); return 0; case WM_ACTIVATE: { RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE); + if (inFocus) win->_flags |= RGFW_windowFocus; + else win->_flags &= ~ (u32)RGFW_windowFocus; + RGFW_eventQueuePushEx(e.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus); e._win = win); - win->internal.inFocus = RGFW_BOOL(inFocus); - if ((win->internal.enabledEvents & (RGFW_BIT(RGFW_focusIn - inFocus)))) { - RGFW_eventQueuePushEx(e.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus); e.common.win = win); - RGFW_focusCallback(win, inFocus); - } - if (inFocus == RGFW_FALSE) RGFW_window_focusLost(win); - if ((win->internal.flags & RGFW_windowFullscreen) && inFocus == RGFW_TRUE) - RGFW_window_setFullscreen(win, 1); + RGFW_focusCallback(win, inFocus); + RGFW_window_focusLost(win); + + if ((win->_flags & RGFW_windowFullscreen) == 0) + return DefWindowProcW(hWnd, message, wParam, lParam); + + win->_flags &= ~(u32)RGFW_EVENT_PASSED; + if (inFocus == RGFW_FALSE) RGFW_window_minimize(win); + else RGFW_window_setFullscreen(win, 1); return DefWindowProcW(hWnd, message, wParam, lParam); } case WM_MOVE: - win->x = windowRect.left; - win->y = windowRect.top; - - if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; - RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e.common.win = win); - RGFW_windowMovedCallback(win, win->x, win->y); + win->r.x = windowRect.left; + win->r.y = windowRect.top; + RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win); + RGFW_windowMovedCallback(win, win->r); return DefWindowProcW(hWnd, message, wParam, lParam); case WM_SIZE: { - if (win->src.aspectRatioW != 0 && win->src.aspectRatioH != 0) { - double aspectRatio = (double)win->src.aspectRatioW / win->src.aspectRatioH; + if (win->src.aspectRatio.w != 0 && win->src.aspectRatio.h != 0) { + double aspectRatio = (double)win->src.aspectRatio.w / win->src.aspectRatio.h; int width = windowRect.right - windowRect.left; int height = windowRect.bottom - windowRect.top; int newHeight = (int)(width / aspectRatio); int newWidth = (int)(height * aspectRatio); - if (win->w > (i32)((windowRect.right - windowRect.left) - win->src.offsetW) || - win->h > (i32)((windowRect.bottom - windowRect.top) - win->src.offsetH)) + if (win->r.w > windowRect.right - windowRect.left || + win->r.h > (i32)((u32)(windowRect.bottom - windowRect.top) - win->src.hOffset)) { if (newHeight > height) windowRect.right = windowRect.left + newWidth; else windowRect.bottom = windowRect.top + newHeight; @@ -9055,47 +6537,43 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) else windowRect.bottom = windowRect.top + newHeight; } - RGFW_window_resize(win, (windowRect.right - windowRect.left) - win->src.offsetW, - (windowRect.bottom - windowRect.top) - win->src.offsetH); + RGFW_window_resize(win, RGFW_AREA((windowRect.right - windowRect.left), + (u32)(windowRect.bottom - windowRect.top) - (u32)win->src.hOffset)); } - win->w = (windowRect.right - windowRect.left) - (i32)win->src.offsetW; - win->h = (windowRect.bottom - windowRect.top) - (i32)win->src.offsetH; - if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); - RGFW_windowResizedCallback(win, win->w, win->h); + win->r.w = windowRect.right - windowRect.left; + win->r.h = (windowRect.bottom - windowRect.top) - (i32)win->src.hOffset; + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win); + RGFW_windowResizedCallback(win, win->r); RGFW_window_checkMode(win); return DefWindowProcW(hWnd, message, wParam, lParam); } #ifndef RGFW_NO_MONITOR case WM_DPICHANGED: { - if (win->internal.flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); + if (win->_flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win); const float scaleX = HIWORD(wParam) / (float) 96; const float scaleY = LOWORD(wParam) / (float) 96; - - if (!(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam);; RGFW_scaleUpdatedCallback(win, scaleX, scaleY); - RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scale.x = scaleX; e.scale.y = scaleY; e.common.win = win); + RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = scaleX; e.scaleY = scaleY; e._win = win); return DefWindowProcW(hWnd, message, wParam, lParam); } #endif case WM_GETMINMAXINFO: { MINMAXINFO* mmi = (MINMAXINFO*) lParam; - mmi->ptMinTrackSize.x = (LONG)(win->src.minSizeW + win->src.offsetW); - mmi->ptMinTrackSize.y = (LONG)(win->src.minSizeH + win->src.offsetH); - if (win->src.maxSizeW == 0 && win->src.maxSizeH == 0) + mmi->ptMinTrackSize.x = (LONG)win->src.minSize.w; + mmi->ptMinTrackSize.y = (LONG)(win->src.minSize.h + win->src.hOffset); + if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0) return DefWindowProcW(hWnd, message, wParam, lParam); - mmi->ptMaxTrackSize.x = (LONG)(win->src.maxSizeW + win->src.offsetW); - mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSizeH + win->src.offsetH); + mmi->ptMaxTrackSize.x = (LONG)win->src.maxSize.w; + mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSize.h + win->src.hOffset); return DefWindowProcW(hWnd, message, wParam, lParam); } case WM_PAINT: { - if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); PAINTSTRUCT ps; BeginPaint(hWnd, &ps); - RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e.common.win = win); + RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win); RGFW_windowRefreshCallback(win); EndPaint(hWnd, &ps); @@ -9111,9 +6589,7 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) #ifdef RGFW_ADVANCED_SMOOTH_RESIZE case WM_ENTERSIZEMOVE: SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break; case WM_EXITSIZEMOVE: KillTimer(win->src.window, 1); break; - case WM_TIMER: - if (!(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - RGFW_windowRefreshCallback(win); break; + case WM_TIMER: RGFW_windowRefreshCallback(win); break; #endif case WM_NCLBUTTONDOWN: { /* workaround for half-second pause when starting to move window @@ -9124,272 +6600,11 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; ScreenToClient(win->src.window, &point); - PostMessage(win->src.window, WM_MOUSEMOVE, 0, (u32)(point.x)|((u32)(point.y) << 16)); + PostMessage(win->src.window, WM_MOUSEMOVE, 0, ((uint32_t)point.x)|(((uint32_t)point.y) << 16)); break; } - case WM_MOUSELEAVE: - win->internal.mouseInside = RGFW_FALSE; - _RGFW->windowState.winLeave = win; - _RGFW->windowState.mouseLeave = RGFW_TRUE; - if (!(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - event.type = RGFW_mouseLeave; - RGFW_window_getMouse(win, &event.mouse.x, &event.mouse.y); - RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 0); - break; - case WM_SYSKEYUP: case WM_KEYUP: { - if (!(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); - if (scancode == 0) - scancode = (i32)MapVirtualKeyW((UINT)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; - } - - event.key.value = (u8)RGFW_apiKeyToRGFW((u32) scancode); - - if (wParam == VK_CONTROL) { - if (HIWORD(lParam) & KF_EXTENDED) - event.key.value = RGFW_controlR; - else event.key.value = RGFW_controlL; - } - - wchar_t charBuffer; - ToUnicodeEx((UINT)wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL); - - event.key.sym = (u8)charBuffer; - - _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; - event.type = RGFW_keyReleased; - event.key.repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, event.key.value); - _RGFW->keyboard[event.key.value].current = 0; - - RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); - event.key.mod = win->internal.mod; - - RGFW_keyCallback(win, event.key.value, event.key.sym, event.key.mod, event.key.repeat,0); - break; - } - case WM_SYSKEYDOWN: case WM_KEYDOWN: { - if (!(win->internal.enabledEvents & RGFW_keyPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - i32 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); - if (scancode == 0) - scancode = (i32)MapVirtualKeyW((u32)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; - } - - event.key.value = (u8)RGFW_apiKeyToRGFW((u32) scancode); - if (wParam == VK_CONTROL) { - if (HIWORD(lParam) & KF_EXTENDED) - event.key.value = RGFW_controlR; - else event.key.value = RGFW_controlL; - } - - wchar_t charBuffer; - ToUnicodeEx((UINT)wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL); - event.key.sym = (u8)charBuffer; - - _RGFW->keyboard[event.key.value].prev = _RGFW->keyboard[event.key.value].current; - event.type = RGFW_keyPressed; - event.key.repeat = ((lParam & 0x40000000) != 0) || RGFW_window_isKeyDown(win, event.key.value); - _RGFW->keyboard[event.key.value].current = 1; - - RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); - event.key.mod = win->internal.mod; - - RGFW_keyCallback(win, event.key.value, event.key.sym, event.key.mod, event.key.repeat, 1); - break; - } - case WM_MOUSEMOVE: { - if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - if ((win->internal.holdMouse)) - break; - - - event.mouse.x = GET_X_LPARAM(lParam); - event.mouse.y = GET_Y_LPARAM(lParam); - event.mouse.vecX = (float)(event.mouse.x - win->internal.lastMouseX); - event.mouse.vecY = (float)(event.mouse.y - win->internal.lastMouseY); - _RGFW->vectorX = event.mouse.vecX; - _RGFW->vectorY = event.mouse.vecY; - - RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, event.mouse.vecX, event.mouse.vecY); - - if (win->internal.mouseInside == RGFW_FALSE) { - win->internal.mouseInside = RGFW_TRUE; - _RGFW->windowState.win = win; - _RGFW->windowState.mouseEnter = RGFW_TRUE; - event.type = RGFW_mouseEnter; - RGFW_mouseNotifyCallback(win, event.mouse.x, event.mouse.y, 1); - RGFW_eventQueuePush(&event); - } - - event.type = RGFW_mousePosChanged; - win->internal.lastMouseX = event.mouse.x; - win->internal.lastMouseY = event.mouse.y; - break; - } - case WM_INPUT: { - if (!(win->internal.enabledEvents & RGFW_mousePosChangedFlag) || !(win->internal.holdMouse)) return DefWindowProcW(hWnd, message, wParam, lParam); - unsigned size = sizeof(RAWINPUT); - static RAWINPUT raw; - - GetRawInputData((HRAWINPUT)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, 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) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width); - pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height); - ScreenToClient(win->src.window, &pos); - - event.mouse.vecX = (float)(pos.x - win->internal.lastMouseX); - event.mouse.vecY = (float)(pos.y - win->internal.lastMouseY); - } else { - event.mouse.vecX = (float)(raw.data.mouse.lLastX); - event.mouse.vecY = (float)(raw.data.mouse.lLastY); - } - - event.type = RGFW_mousePosChanged; - win->internal.lastMouseX += (i32)event.mouse.vecX; - win->internal.lastMouseY += (i32)event.mouse.vecY; - _RGFW->vectorX = event.mouse.vecX; - _RGFW->vectorY = event.mouse.vecY; - event.mouse.x = win->internal.lastMouseX; - event.mouse.y = win->internal.lastMouseY; - RGFW_mousePosCallback(win, event.mouse.x, event.mouse.y, event.mouse.vecX, event.mouse.vecY); - break; - } - case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: - if (!(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - if (message == WM_XBUTTONDOWN) - event.button.value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2); - else event.button.value = (message == WM_LBUTTONDOWN) ? (u8)RGFW_mouseLeft : - (message == WM_RBUTTONDOWN) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle; - - event.type = RGFW_mouseButtonPressed; - _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; - _RGFW->mouseButtons[event.button.value].current = 1; - RGFW_mouseButtonCallback(win, event.button.value, 1); - break; - case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: - if (!(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - if (message == WM_XBUTTONUP) - event.button.value = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(wParam) == XBUTTON2); - else event.button.value = (message == WM_LBUTTONUP) ? (u8)RGFW_mouseLeft : - (message == WM_RBUTTONUP) ? (u8)RGFW_mouseRight : (u8)RGFW_mouseMiddle; - event.type = RGFW_mouseButtonReleased; - _RGFW->mouseButtons[event.button.value].prev = _RGFW->mouseButtons[event.button.value].current; - _RGFW->mouseButtons[event.button.value].current = 0; - RGFW_mouseButtonCallback(win, event.button.value, 0); - break; - case WM_MOUSEWHEEL: - if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - - event.type = RGFW_mouseScroll; - event.scroll.x = 0.0f; - event.scroll.y = (float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA); - _RGFW->scrollX = event.scroll.x; - _RGFW->scrollY = event.scroll.y; - - RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); - break; - case 0x020E: /* WM_MOUSEHWHEEL */ - if (!(win->internal.enabledEvents & RGFW_mouseScrollFlag)) return DefWindowProcW(hWnd, message, wParam, lParam); - - event.type = RGFW_mouseScroll; - event.scroll.x = -(float)((i16) HIWORD(wParam) / (double) WHEEL_DELTA); - event.scroll.y = (float)0.0f; - _RGFW->scrollX = event.scroll.x; - _RGFW->scrollY = event.scroll.y; - - RGFW_mouseScrollCallback(win, event.scroll.x, event.scroll.y); - break; - case WM_DROPFILES: { - event.type = RGFW_dataDrag; - - HDROP drop = (HDROP) wParam; - POINT pt; - - /* Move the mouse to the position of the drop */ - DragQueryPoint(drop, &pt); - - event.drag.x = pt.x; - event.drag.y = pt.y; - - _RGFW->windowState.win = win; - _RGFW->windowState.dataDragging = RGFW_TRUE; - _RGFW->windowState.dropX = event.drag.x; - _RGFW->windowState.dropY = event.drag.y; - - if ((win->internal.enabledEvents & RGFW_dataDrag)) { - RGFW_dataDragCallback(win, event.drag.x, event.drag.y); - RGFW_eventQueuePush(&event); - } - - if (!(win->internal.enabledEvents & RGFW_dataDrop)) return DefWindowProcW(hWnd, message, wParam, lParam); - event.type = 0; - event.type = RGFW_dataDrop; - event.drop.files = _RGFW->files; - event.drop.count = 0; - event.drop.count = DragQueryFileW(drop, 0xffffffff, NULL, 0); - - u32 i; - for (i = 0; i < event.drop.count; i++) { - UINT length = DragQueryFileW(drop, i, NULL, 0); - if (length == 0) - continue; - - WCHAR buffer[RGFW_MAX_PATH * 2]; - if (length > (RGFW_MAX_PATH * 2) - 1) - length = RGFW_MAX_PATH * 2; - - DragQueryFileW(drop, i, buffer, length + 1); - - RGFW_createUTF8FromWideStringWin32(buffer, event.drop.files[i], RGFW_MAX_PATH); - - event.drop.files[i][RGFW_MAX_PATH - 1] = '\0'; - event.common.win = win; - } - - DragFinish(drop); - - _RGFW->windowState.win = win; - _RGFW->windowState.dataDrop = RGFW_TRUE; - _RGFW->windowState.filesCount = event.drop.count; - RGFW_dataDropCallback(win, event.drop.files, event.drop.count); - break; - } default: break; } - - if (event.type) { - RGFW_eventQueuePush(&event); - } - return DefWindowProcW(hWnd, message, wParam, lParam); } @@ -9416,50 +6631,58 @@ LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) RGFW_ASSERT(name##SRC != NULL); \ } -RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { - RGFW_ASSERT(surface != NULL); - surface->data = data; - surface->w = w; - surface->h = h; - surface->format = format; +#ifndef RGFW_NO_XINPUT +void RGFW_loadXInput(void); +void RGFW_loadXInput(void) { + u32 i; + static const char* names[] = {"xinput1_4.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll"}; + + for (i = 0; i < sizeof(names) / sizeof(const char*) && (XInputGetStateSRC == NULL || XInputGetKeystrokeSRC != NULL); i++) { + RGFW_XInput_dll = LoadLibraryA(names[i]); + RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetState); + RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetKeystroke); + } + + if (XInputGetStateSRC == NULL) + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetState"); + if (XInputGetKeystrokeSRC == NULL) + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load XInputGetKeystroke"); +} +#endif + +void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){ +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + win->buffer = buffer; + win->bufferSize = area; BITMAPV5HEADER bi; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); - bi.bV5Width = (i32)w; - bi.bV5Height = -((LONG) h); + bi.bV5Width = (i32)area.w; + bi.bV5Height = -((LONG) area.h); bi.bV5Planes = 1; - bi.bV5BitCount = (format >= RGFW_formatRGBA8) ? 32 : 24; + bi.bV5BitCount = 32; bi.bV5Compression = BI_RGB; - surface->native.bitmap = CreateDIBSection(_RGFW->root->src.hdc, + win->src.bitmap = CreateDIBSection(win->src.hdc, (BITMAPINFO*) &bi, DIB_RGB_COLORS, - (void**) &surface->native.bitmapBits, + (void**) &win->src.bitmapBits, NULL, (DWORD) 0); - surface->native.format = (format >= RGFW_formatRGBA8) ? RGFW_formatBGRA8 : RGFW_formatBGR8; + if (win->buffer == NULL) + win->buffer = win->src.bitmapBits; - if (surface->native.bitmap == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, "Failed to create DIB section."); - return RGFW_FALSE; - } + win->src.hdcMem = CreateCompatibleDC(win->src.hdc); + SelectObject(win->src.hdcMem, win->src.bitmap); - surface->native.hdcMem = CreateCompatibleDC(_RGFW->root->src.hdc); - SelectObject(surface->native.hdcMem, surface->native.bitmap); - - return RGFW_TRUE; -} - -void RGFW_surface_freePtr(RGFW_surface* surface) { - RGFW_ASSERT(surface != NULL); - - DeleteDC(surface->native.hdcMem); - DeleteObject(surface->native.bitmap); -} - -void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { - RGFW_copyImageData(surface->native.bitmapBits, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); - BitBlt(win->src.hdc, 0, 0, RGFW_MIN(win->w, surface->w), RGFW_MIN(win->h, surface->h), surface->native.hdcMem, 0, 0, SRCCOPY); + #if defined(RGFW_OSMESA) + win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); + OSMesaPixelStore(OSMESA_Y_UP, 0); + #endif + #else + RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ + #endif } void RGFW_releaseCursor(RGFW_window* win) { @@ -9469,8 +6692,8 @@ void RGFW_releaseCursor(RGFW_window* win) { RegisterRawInputDevices(&id, 1, sizeof(id)); } -void RGFW_captureCursor(RGFW_window* win) { - RGFW_UNUSED(win); +void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) { + RGFW_UNUSED(win); RGFW_UNUSED(rect); RECT clipRect; GetClientRect(win->src.window, &clipRect); @@ -9485,13 +6708,13 @@ void RGFW_captureCursor(RGFW_window* win) { #define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) { x = LoadLibraryA(lib); RGFW_ASSERT(x != NULL); } #ifdef RGFW_DIRECTX -int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) { +int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) { RGFW_ASSERT(win && pFactory && pDevice && swapchain); static DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; swapChainDesc.BufferCount = 2; - swapChainDesc.BufferDesc.Width = win->w; - swapChainDesc.BufferDesc.Height = win->h; + swapChainDesc.BufferDesc.Width = win->r.w; + swapChainDesc.BufferDesc.Height = win->r.h; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.OutputWindow = (HWND)win->src.window; @@ -9502,7 +6725,7 @@ int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain); if (FAILED(hr)) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, "Failed to create DirectX swap chain!"); + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, RGFW_DEBUG_CTX(win, hr), "Failed to create DirectX swap chain!"); return -2; } @@ -9510,130 +6733,143 @@ int RGFW_window_createSwapChain_DirectX(RGFW_window* win, IDXGIFactory* pFactory } #endif -/* we're doing it with magic numbers because some keys are missing */ -void RGFW_initKeycodesPlatform(void) { - _RGFW->keycodes[0x00B] = RGFW_0; - _RGFW->keycodes[0x002] = RGFW_1; - _RGFW->keycodes[0x003] = RGFW_2; - _RGFW->keycodes[0x004] = RGFW_3; - _RGFW->keycodes[0x005] = RGFW_4; - _RGFW->keycodes[0x006] = RGFW_5; - _RGFW->keycodes[0x007] = RGFW_6; - _RGFW->keycodes[0x008] = RGFW_7; - _RGFW->keycodes[0x009] = RGFW_8; - _RGFW->keycodes[0x00A] = RGFW_9; - _RGFW->keycodes[0x01E] = RGFW_a; - _RGFW->keycodes[0x030] = RGFW_b; - _RGFW->keycodes[0x02E] = RGFW_c; - _RGFW->keycodes[0x020] = RGFW_d; - _RGFW->keycodes[0x012] = RGFW_e; - _RGFW->keycodes[0x021] = RGFW_f; - _RGFW->keycodes[0x022] = RGFW_g; - _RGFW->keycodes[0x023] = RGFW_h; - _RGFW->keycodes[0x017] = RGFW_i; - _RGFW->keycodes[0x024] = RGFW_j; - _RGFW->keycodes[0x025] = RGFW_k; - _RGFW->keycodes[0x026] = RGFW_l; - _RGFW->keycodes[0x032] = RGFW_m; - _RGFW->keycodes[0x031] = RGFW_n; - _RGFW->keycodes[0x018] = RGFW_o; - _RGFW->keycodes[0x019] = RGFW_p; - _RGFW->keycodes[0x010] = RGFW_q; - _RGFW->keycodes[0x013] = RGFW_r; - _RGFW->keycodes[0x01F] = RGFW_s; - _RGFW->keycodes[0x014] = RGFW_t; - _RGFW->keycodes[0x016] = RGFW_u; - _RGFW->keycodes[0x02F] = RGFW_v; - _RGFW->keycodes[0x011] = RGFW_w; - _RGFW->keycodes[0x02D] = RGFW_x; - _RGFW->keycodes[0x015] = RGFW_y; - _RGFW->keycodes[0x02C] = RGFW_z; - _RGFW->keycodes[0x028] = RGFW_apostrophe; - _RGFW->keycodes[0x02B] = RGFW_backSlash; - _RGFW->keycodes[0x033] = RGFW_comma; - _RGFW->keycodes[0x00D] = RGFW_equals; - _RGFW->keycodes[0x029] = RGFW_backtick; - _RGFW->keycodes[0x01A] = RGFW_bracket; - _RGFW->keycodes[0x00C] = RGFW_minus; - _RGFW->keycodes[0x034] = RGFW_period; - _RGFW->keycodes[0x01B] = RGFW_closeBracket; - _RGFW->keycodes[0x027] = RGFW_semicolon; - _RGFW->keycodes[0x035] = RGFW_slash; - _RGFW->keycodes[0x056] = RGFW_world2; - _RGFW->keycodes[0x00E] = RGFW_backSpace; - _RGFW->keycodes[0x153] = RGFW_delete; - _RGFW->keycodes[0x14F] = RGFW_end; - _RGFW->keycodes[0x01C] = RGFW_enter; - _RGFW->keycodes[0x001] = RGFW_escape; - _RGFW->keycodes[0x147] = RGFW_home; - _RGFW->keycodes[0x152] = RGFW_insert; - _RGFW->keycodes[0x15D] = RGFW_menu; - _RGFW->keycodes[0x151] = RGFW_pageDown; - _RGFW->keycodes[0x149] = RGFW_pageUp; - _RGFW->keycodes[0x045] = RGFW_pause; - _RGFW->keycodes[0x039] = RGFW_space; - _RGFW->keycodes[0x00F] = RGFW_tab; - _RGFW->keycodes[0x03A] = RGFW_capsLock; - _RGFW->keycodes[0x145] = RGFW_numLock; - _RGFW->keycodes[0x046] = RGFW_scrollLock; - _RGFW->keycodes[0x03B] = RGFW_F1; - _RGFW->keycodes[0x03C] = RGFW_F2; - _RGFW->keycodes[0x03D] = RGFW_F3; - _RGFW->keycodes[0x03E] = RGFW_F4; - _RGFW->keycodes[0x03F] = RGFW_F5; - _RGFW->keycodes[0x040] = RGFW_F6; - _RGFW->keycodes[0x041] = RGFW_F7; - _RGFW->keycodes[0x042] = RGFW_F8; - _RGFW->keycodes[0x043] = RGFW_F9; - _RGFW->keycodes[0x044] = RGFW_F10; - _RGFW->keycodes[0x057] = RGFW_F11; - _RGFW->keycodes[0x058] = RGFW_F12; - _RGFW->keycodes[0x064] = RGFW_F13; - _RGFW->keycodes[0x065] = RGFW_F14; - _RGFW->keycodes[0x066] = RGFW_F15; - _RGFW->keycodes[0x067] = RGFW_F16; - _RGFW->keycodes[0x068] = RGFW_F17; - _RGFW->keycodes[0x069] = RGFW_F18; - _RGFW->keycodes[0x06A] = RGFW_F19; - _RGFW->keycodes[0x06B] = RGFW_F20; - _RGFW->keycodes[0x06C] = RGFW_F21; - _RGFW->keycodes[0x06D] = RGFW_F22; - _RGFW->keycodes[0x06E] = RGFW_F23; - _RGFW->keycodes[0x076] = RGFW_F24; - _RGFW->keycodes[0x038] = RGFW_altL; - _RGFW->keycodes[0x01D] = RGFW_controlL; - _RGFW->keycodes[0x02A] = RGFW_shiftL; - _RGFW->keycodes[0x15B] = RGFW_superL; - _RGFW->keycodes[0x137] = RGFW_printScreen; - _RGFW->keycodes[0x138] = RGFW_altR; - _RGFW->keycodes[0x11D] = RGFW_controlR; - _RGFW->keycodes[0x036] = RGFW_shiftR; - _RGFW->keycodes[0x15C] = RGFW_superR; - _RGFW->keycodes[0x150] = RGFW_down; - _RGFW->keycodes[0x14B] = RGFW_left; - _RGFW->keycodes[0x14D] = RGFW_right; - _RGFW->keycodes[0x148] = RGFW_up; - _RGFW->keycodes[0x052] = RGFW_kp0; - _RGFW->keycodes[0x04F] = RGFW_kp1; - _RGFW->keycodes[0x050] = RGFW_kp2; - _RGFW->keycodes[0x051] = RGFW_kp3; - _RGFW->keycodes[0x04B] = RGFW_kp4; - _RGFW->keycodes[0x04C] = RGFW_kp5; - _RGFW->keycodes[0x04D] = RGFW_kp6; - _RGFW->keycodes[0x047] = RGFW_kp7; - _RGFW->keycodes[0x048] = RGFW_kp8; - _RGFW->keycodes[0x049] = RGFW_kp9; - _RGFW->keycodes[0x04E] = RGFW_kpPlus; - _RGFW->keycodes[0x053] = RGFW_kpPeriod; - _RGFW->keycodes[0x135] = RGFW_kpSlash; - _RGFW->keycodes[0x11C] = RGFW_kpReturn; - _RGFW->keycodes[0x059] = RGFW_kpEqual; - _RGFW->keycodes[0x037] = RGFW_kpMultiply; - _RGFW->keycodes[0x04A] = RGFW_kpMinus; +void RGFW_win32_loadOpenGLFuncs(HWND dummyWin); +void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) { +#ifdef RGFW_OPENGL + if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL) + return; + + HDC dummy_dc = GetDC(dummyWin); + u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + + PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0}; + + int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd); + SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd); + + HGLRC dummy_context = wglCreateContext(dummy_dc); + wglMakeCurrent(dummy_dc, dummy_context); + + wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB"); + wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB"); + + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT"); + if (wglSwapIntervalEXT == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function"); + } + + wglMakeCurrent(dummy_dc, 0); + wglDeleteContext(dummy_context); + ReleaseDC(dummyWin, dummy_dc); +#else + RGFW_UNUSED(dummyWin); +#endif } +#ifndef RGFW_EGL +void RGFW_window_initOpenGL(RGFW_window* win) { +#ifdef RGFW_OPENGL + PIXELFORMATDESCRIPTOR pfd; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.cColorBits = 32; + pfd.cAlphaBits = 8; + pfd.cDepthBits = 24; + pfd.cStencilBits = (BYTE)RGFW_GL_HINTS[RGFW_glStencil]; + pfd.cAuxBuffers = (BYTE)RGFW_GL_HINTS[RGFW_glAuxBuffers]; + if (RGFW_GL_HINTS[RGFW_glStereo]) pfd.dwFlags |= PFD_STEREO; + + /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */ + if (win->_flags & RGFW_windowOpenglSoftware) + pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED; + + /* get pixel format, default to a basic pixel format */ + int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd); + if (wglChoosePixelFormatARB != NULL) { + i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs(); + + int new_pixel_format; + UINT num_formats; + wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats); + if (!num_formats) + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create a pixel format for WGL"); + else pixel_format = new_pixel_format; + } + + PIXELFORMATDESCRIPTOR suggested; + if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) || + !SetPixelFormat(win->src.hdc, pixel_format, &pfd)) + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set the WGL pixel format"); + + if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED)) { + win->_flags |= RGFW_windowOpenglSoftware; + } + + if (wglCreateContextAttribsARB != NULL) { + /* create opengl/WGL context for the specified version */ + u32 index = 0; + i32 attribs[40]; + + if (RGFW_GL_HINTS[RGFW_glProfile]== RGFW_glCore) { + SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB); + } + else { + SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); + } + + if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) { + SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMajor]); + SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMinor]); + } + + SET_ATTRIB(0, 0); + + win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); + } else { /* fall back to a default context (probably opengl 2 or something) */ + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create an accelerated OpenGL Context"); + win->src.ctx = wglCreateContext(win->src.hdc); + } + + ReleaseDC(win->src.window, win->src.hdc); + win->src.hdc = GetDC(win->src.window); + wglMakeCurrent(win->src.hdc, win->src.ctx); + + if (_RGFW.root != win) + wglShareLists(_RGFW.root->src.ctx, win->src.ctx); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); +#else + RGFW_UNUSED(win); +#endif +} + +void RGFW_window_freeOpenGL(RGFW_window* win) { +#ifdef RGFW_OPENGL + if (win->src.ctx == NULL) return; + wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */ + win->src.ctx = NULL; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); +#else + RGFW_UNUSED(win); +#endif +} +#endif + + +i32 RGFW_init(void) { +#if defined(RGFW_C89) || defined(__cplusplus) + if (_RGFW_init) return 0; + _RGFW_init = RGFW_TRUE; + _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; +#endif + + #ifndef RGFW_NO_XINPUT + if (RGFW_XInput_dll == NULL) + RGFW_loadXInput(); + #endif -i32 RGFW_initPlatform(void) { #ifndef RGFW_NO_DPI #if (_WIN32_WINNT >= 0x0600) SetProcessDPIAware(); @@ -9666,33 +6902,36 @@ i32 RGFW_initPlatform(void) { #endif u8 RGFW_blk[] = { 0, 0, 0, 0 }; - _RGFW->hiddenMouse = RGFW_loadMouse(RGFW_blk, 1, 1, RGFW_formatRGBA8); + _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4); + + _RGFW.windowCount = 0; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); return 1; } -RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { +RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { if (name[0] == 0) name = (char*) " "; + + RGFW_window_basic_init(win, rect, flags); + win->src.hIconSmall = win->src.hIconBig = NULL; - win->src.maxSizeW = 0; - win->src.maxSizeH = 0; - win->src.minSizeW = 0; - win->src.minSizeH = 0; - win->src.aspectRatioW = 0; - win->src.aspectRatioH = 0; + win->src.maxSize = RGFW_AREA(0, 0); + win->src.minSize = RGFW_AREA(0, 0); + win->src.aspectRatio = RGFW_AREA(0, 0); HINSTANCE inh = GetModuleHandleA(NULL); #ifndef __cplusplus - WNDCLASSW Class = {0}; /*!< Setup the Window class. */ + WNDCLASSW Class = { 0 }; /*!< Setup the Window class. */ #else - WNDCLASSW Class = {}; + WNDCLASSW Class = { }; #endif - if (_RGFW->className == NULL) - _RGFW->className = (char*)name; + if (RGFW_className == NULL) + RGFW_className = (char*)name; wchar_t wide_class[256]; - MultiByteToWideChar(CP_UTF8, 0, _RGFW->className, -1, wide_class, 255); + MultiByteToWideChar(CP_UTF8, 0, RGFW_className, -1, wide_class, 255); Class.lpszClassName = wide_class; Class.hInstance = inh; @@ -9711,7 +6950,7 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RECT windowRect, clientRect; if (!(flags & RGFW_windowNoBorder)) { - window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX; + window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX | WS_THICKFRAME; if (!(flags & RGFW_windowNoResize)) window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX; @@ -9720,37 +6959,43 @@ RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, wchar_t wide_name[256]; MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255); - HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x, win->y, win->w, win->h, 0, 0, inh, 0); + HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0); GetWindowRect(dummyWin, &windowRect); GetClientRect(dummyWin, &clientRect); -#ifdef RGFW_OPENGL RGFW_win32_loadOpenGLFuncs(dummyWin); -#endif - DestroyWindow(dummyWin); - win->src.offsetW = (i32)(windowRect.right - windowRect.left) - (i32)(clientRect.right - clientRect.left); - win->src.offsetH = (i32)(windowRect.bottom - windowRect.top) - (i32)(clientRect.bottom - clientRect.top); - win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->x, win->y, win->w + (i32)win->src.offsetW, win->h + (i32)win->src.offsetH, 0, 0, inh, 0); + win->src.hOffset = (u32)(windowRect.bottom - windowRect.top) - (u32)(clientRect.bottom - clientRect.top); + win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + (i32)win->src.hOffset, 0, 0, inh, 0); SetPropW(win->src.window, L"RGFW", win); - RGFW_window_resize(win, win->w, win->h); /* so WM_GETMINMAXINFO gets called again */ + RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); /* so WM_GETMINMAXINFO gets called again */ if (flags & RGFW_windowAllowDND) { - win->internal.flags |= RGFW_windowAllowDND; + win->_flags |= RGFW_windowAllowDND; RGFW_window_setDND(win, 1); } win->src.hdc = GetDC(win->src.window); + if ((flags & RGFW_windowNoInitAPI) == 0) { + RGFW_window_initOpenGL(win); + RGFW_window_initBuffer(win); + } + + RGFW_window_setFlags(win, flags); RGFW_win32_makeWindowTransparent(win); - return win; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); + RGFW_window_show(win); + + return win; } void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { - RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); + RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); LONG style = GetWindowLong(win->src.window, GWL_STYLE); + if (border == 0) { SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); SetWindowPos( @@ -9759,8 +7004,8 @@ void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { ); } else { - if (win->internal.flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX; - SetWindowLong(win->src.window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW); + style |= WS_OVERLAPPEDWINDOW; + if (win->_flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX; SetWindowPos( win->src.window, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE @@ -9769,34 +7014,37 @@ void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { } void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) { - RGFW_setBit(&win->internal.flags, RGFW_windowAllowDND, allow); + RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow); DragAcceptFiles(win->src.window, allow); } -RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { +RGFW_area RGFW_getScreenSize(void) { + HDC dc = GetDC(NULL); + RGFW_area area = RGFW_AREA(GetDeviceCaps(dc, HORZRES), GetDeviceCaps(dc, VERTRES)); + ReleaseDC(NULL, dc); + return area; +} + +RGFW_point RGFW_getGlobalMousePoint(void) { POINT p; GetCursorPos(&p); - if (x) *x = p.x; - if (y) *y = p.y; - return RGFW_TRUE; + + return RGFW_POINT(p.x, p.y); } -void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { +void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); - win->src.aspectRatioW = w; - win->src.aspectRatioH = h; + win->src.aspectRatio = a; } -void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { +void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); - win->src.minSizeW = w; - win->src.minSizeH = h; + win->src.minSize = a; } -void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { +void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); - win->src.maxSizeW = w; - win->src.maxSizeH = h; + win->src.maxSize = a; } void RGFW_window_focus(RGFW_window* win) { @@ -9808,7 +7056,7 @@ void RGFW_window_focus(RGFW_window* win) { void RGFW_window_raise(RGFW_window* win) { RGFW_ASSERT(win); BringWindowToTop(win->src.window); - SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, win->w, win->h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); + SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, win->r.w, win->r.h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { @@ -9816,32 +7064,24 @@ void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { if (fullscreen == RGFW_FALSE) { RGFW_window_setBorder(win, 1); - SetWindowPos(win->src.window, HWND_NOTOPMOST, win->internal.oldX, win->internal.oldY, win->internal.oldW + (i32)win->src.offsetW, win->internal.oldH + (i32)win->src.offsetH, + SetWindowPos(win->src.window, HWND_NOTOPMOST, win->_oldRect.x, win->_oldRect.y, win->_oldRect.w, win->_oldRect.h + (i32)win->src.hOffset, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - win->internal.flags &= ~(u32)RGFW_windowFullscreen; - win->x = win->internal.oldX; - win->y = win->internal.oldY; - win->w = win->internal.oldW; - win->h = win->internal.oldH; + win->_flags &= ~(u32)RGFW_windowFullscreen; + win->r = win->_oldRect; return; } - win->internal.oldX = win->x; - win->internal.oldY = win->y; - win->internal.oldW = win->w; - win->internal.oldH = win->h; - win->internal.flags |= RGFW_windowFullscreen; + win->_oldRect = win->r; + win->_flags |= RGFW_windowFullscreen; RGFW_monitor mon = RGFW_window_getMonitor(win); RGFW_window_setBorder(win, 0); - SetWindowPos(win->src.window, HWND_TOPMOST, (i32)mon.x, (i32)mon.x, (i32)mon.mode.w, (i32)mon.mode.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW); + SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon.mode.area.w, (i32)mon.mode.area.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW); RGFW_monitor_scaleToWindow(mon, win); - win->x = mon.x; win->y = mon.x; - win->w = mon.mode.w; - win->h = mon.mode.h; + win->r = RGFW_RECT(0, 0, mon.mode.area.w, mon.mode.area.h); } void RGFW_window_maximize(RGFW_window* win) { @@ -9872,16 +7112,149 @@ RGFW_bool RGFW_window_isFloating(RGFW_window* win) { return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0; } -void RGFW_stopCheckEvents(void) { - PostMessageW(_RGFW->root->src.window, WM_NULL, 0, 0); +u8 RGFW_xinput2RGFW[] = { + RGFW_gamepadA, /* or PS X button */ + RGFW_gamepadB, /* or PS circle button */ + RGFW_gamepadX, /* or PS square button */ + RGFW_gamepadY, /* or PS triangle button */ + RGFW_gamepadR1, /* right bumper */ + RGFW_gamepadL1, /* left bump */ + RGFW_gamepadL2, /* left trigger */ + RGFW_gamepadR2, /* right trigger */ + 0, 0, 0, 0, 0, 0, 0, 0, + RGFW_gamepadUp, /* dpad up */ + RGFW_gamepadDown, /* dpad down */ + RGFW_gamepadLeft, /* dpad left */ + RGFW_gamepadRight, /* dpad right */ + RGFW_gamepadStart, /* start button */ + RGFW_gamepadSelect,/* select button */ + RGFW_gamepadL3, + RGFW_gamepadR3, +}; +i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e); +i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e) { + #ifndef RGFW_NO_XINPUT + + RGFW_UNUSED(win); + u16 i; + for (i = 0; i < 4; i++) { + XINPUT_KEYSTROKE keystroke; + + if (XInputGetKeystroke == NULL) + return 0; + + DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke); + + if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) { + if (result != ERROR_SUCCESS) + return 0; + + if (keystroke.VirtualKey > VK_PAD_RTHUMB_PRESS) + continue; + + /* gamepad + 1 = RGFW_gamepadButtonReleased */ + e->type = RGFW_gamepadButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); + e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800]; + RGFW_gamepadPressed[i][e->button].prev = RGFW_gamepadPressed[i][e->button].current; + RGFW_gamepadPressed[i][e->button].current = RGFW_BOOL(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); + + RGFW_gamepadButtonCallback(win, i, e->button, e->type == RGFW_gamepadButtonPressed); + return 1; + } + + XINPUT_STATE state; + if (XInputGetState == NULL || + XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED + ) { + if (RGFW_gamepads[i] == 0) + continue; + + RGFW_gamepads[i] = 0; + RGFW_gamepadCount--; + + win->event.type = RGFW_gamepadDisconnected; + win->event.gamepad = (u16)i; + RGFW_gamepadCallback(win, i, 0); + return 1; + } + + if (RGFW_gamepads[i] == 0) { + RGFW_gamepads[i] = 1; + RGFW_gamepadCount++; + + char str[] = "Microsoft X-Box (XInput device)"; + RGFW_MEMCPY(RGFW_gamepads_name[i], str, sizeof(str)); + RGFW_gamepads_name[i][sizeof(RGFW_gamepads_name[i]) - 1] = '\0'; + win->event.type = RGFW_gamepadConnected; + win->event.gamepad = i; + RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; + + RGFW_gamepadCallback(win, i, 1); + return 1; + } + +#define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) /* Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed. */ + + if ((state.Gamepad.sThumbLX < INPUT_DEADZONE && + state.Gamepad.sThumbLX > -INPUT_DEADZONE) && + (state.Gamepad.sThumbLY < INPUT_DEADZONE && + state.Gamepad.sThumbLY > -INPUT_DEADZONE)) + { + state.Gamepad.sThumbLX = 0; + state.Gamepad.sThumbLY = 0; + } + + if ((state.Gamepad.sThumbRX < INPUT_DEADZONE && + state.Gamepad.sThumbRX > -INPUT_DEADZONE) && + (state.Gamepad.sThumbRY < INPUT_DEADZONE && + state.Gamepad.sThumbRY > -INPUT_DEADZONE)) + { + state.Gamepad.sThumbRX = 0; + state.Gamepad.sThumbRY = 0; + } + + e->axisesCount = 2; + RGFW_point axis1 = RGFW_POINT(((float)state.Gamepad.sThumbLX / 32768.0f) * 100, ((float)state.Gamepad.sThumbLY / -32768.0f) * 100); + RGFW_point axis2 = RGFW_POINT(((float)state.Gamepad.sThumbRX / 32768.0f) * 100, ((float)state.Gamepad.sThumbRY / -32768.0f) * 100); + + if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y){ + win->event.whichAxis = 0; + + e->type = RGFW_gamepadAxisMove; + e->axis[0] = axis1; + RGFW_gamepadAxes[i][0] = e->axis[0]; + + RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis); + return 1; + } + + if (axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) { + win->event.whichAxis = 1; + e->type = RGFW_gamepadAxisMove; + e->axis[1] = axis2; + RGFW_gamepadAxes[i][1] = e->axis[1]; + + RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis); + return 1; + } + } + + #endif + + return 0; } -void RGFW_waitForEvent(i32 waitMS) { +void RGFW_stopCheckEvents(void) { + PostMessageW(_RGFW.root->src.window, WM_NULL, 0, 0); +} + +void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { + RGFW_UNUSED(win); MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT); } u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { - UINT vsc = RGFW_rgfwToApiKey(rgfw_keycode); /* Should return a Windows VK_* code */ + UINT vsc = RGFW_rgfwToApiKey(rgfw_keycode); // Should return a Windows VK_* code BYTE keyboardState[256] = {0}; if (!GetKeyboardState(keyboardState)) @@ -9899,17 +7272,273 @@ u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { return (u8)charBuffer[0]; } -void RGFW_pollEvents(void) { - RGFW_resetPrevState(); - MSG msg; - while (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessageA(&msg); +RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { + if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; + RGFW_event* ev = RGFW_window_checkEventCore(win); + if (ev) { + return ev; + } + + static HDROP drop; + if (win->event.type == RGFW_DNDInit) { + if (win->event.droppedFilesCount) { + u32 i; + for (i = 0; i < win->event.droppedFilesCount; i++) + win->event.droppedFiles[i][0] = '\0'; + } + + win->event.droppedFilesCount = 0; + win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0); + + u32 i; + for (i = 0; i < win->event.droppedFilesCount; i++) { + UINT length = DragQueryFileW(drop, i, NULL, 0); + if (length == 0) + continue; + + WCHAR buffer[RGFW_MAX_PATH * 2]; + if (length > (RGFW_MAX_PATH * 2) - 1) + length = RGFW_MAX_PATH * 2; + + DragQueryFileW(drop, i, buffer, length + 1); + + char* str = RGFW_createUTF8FromWideStringWin32(buffer); + if (str != NULL) + RGFW_MEMCPY(win->event.droppedFiles[i], str, length + 1); + + win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; + } + + DragFinish(drop); + RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); + + win->event.type = RGFW_DND; + return &win->event; } + + if (RGFW_checkXInput(win, &win->event)) + return &win->event; + + static BYTE keyboardState[256]; + GetKeyboardState(keyboardState); + + MSG msg; + if (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) { + if (msg.hwnd != win->src.window && msg.hwnd != NULL) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + return RGFW_window_checkEvent(win); + } + } else { + return NULL; + } + + switch (msg.message) { + case WM_MOUSELEAVE: + win->event.type = RGFW_mouseLeave; + win->_flags |= RGFW_MOUSE_LEFT; + RGFW_mouseNotifyCallback(win, win->event.point, 0); + break; + case WM_SYSKEYUP: case WM_KEYUP: { + i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); + if (scancode == 0) + scancode = (i32)MapVirtualKeyW((UINT)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 = (u8)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((UINT)msg.wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL); + + win->event.keyChar = (u8)charBuffer; + + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; + win->event.type = RGFW_keyReleased; + RGFW_keyboard[win->event.key].current = 0; + + RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); + + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); + break; + } + case WM_SYSKEYDOWN: case WM_KEYDOWN: { + i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff)); + if (scancode == 0) + scancode = (i32)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 = (u8)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((UINT)msg.wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL); + win->event.keyChar = (u8)charBuffer; + + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; + + win->event.type = RGFW_keyPressed; + win->event.repeat = RGFW_isPressed(win, win->event.key); + RGFW_keyboard[win->event.key].current = 1; + RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001)); + + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1); + break; + } + case WM_MOUSEMOVE: { + if ((win->_flags & RGFW_HOLD_MOUSE)) + break; + + win->event.type = RGFW_mousePosChanged; + + i32 x = GET_X_LPARAM(msg.lParam); + i32 y = GET_Y_LPARAM(msg.lParam); + + RGFW_mousePosCallback(win, win->event.point, win->event.vector); + + if (win->_flags & RGFW_MOUSE_LEFT) { + win->_flags &= ~(u32)RGFW_MOUSE_LEFT; + win->event.type = RGFW_mouseEnter; + RGFW_mouseNotifyCallback(win, win->event.point, 1); + } + + win->event.point.x = x; + win->event.point.y = y; + win->_lastMousePoint = RGFW_POINT(x, y); + + break; + } + case WM_INPUT: { + if (!(win->_flags & RGFW_HOLD_MOUSE)) + break; + + unsigned size = sizeof(RAWINPUT); + static RAWINPUT raw; + + 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, 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) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width); + pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height); + ScreenToClient(win->src.window, &pos); + + win->event.vector.x = pos.x - win->_lastMousePoint.x; + win->event.vector.y = pos.y - win->_lastMousePoint.y; + } else { + win->event.vector.x = raw.data.mouse.lLastX; + win->event.vector.y = raw.data.mouse.lLastY; + } + + win->event.type = RGFW_mousePosChanged; + win->_lastMousePoint.x += win->event.vector.x; + win->_lastMousePoint.y += win->event.vector.y; + win->event.point = win->_lastMousePoint; + RGFW_mousePosCallback(win, win->event.point, win->event.vector); + break; + } + case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: + if (msg.message == WM_XBUTTONDOWN) + win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2); + else win->event.button = (msg.message == WM_LBUTTONDOWN) ? RGFW_mouseLeft : + (msg.message == WM_RBUTTONDOWN) ? RGFW_mouseRight : RGFW_mouseMiddle; + + win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); + break; + case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: + if (msg.message == WM_XBUTTONUP) + win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2); + else win->event.button = (msg.message == WM_LBUTTONUP) ? RGFW_mouseLeft : + (msg.message == WM_RBUTTONUP) ? RGFW_mouseRight : RGFW_mouseMiddle; + win->event.type = RGFW_mouseButtonReleased; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); + break; + case WM_MOUSEWHEEL: + if (msg.wParam > 0) + win->event.button = RGFW_mouseScrollUp; + else + win->event.button = RGFW_mouseScrollDown; + + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + + win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA; + + win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); + break; + case WM_DROPFILES: { + win->event.type = RGFW_DNDInit; + + drop = (HDROP) msg.wParam; + POINT pt; + + /* Move the mouse to the position of the drop */ + DragQueryPoint(drop, &pt); + + win->event.point.x = pt.x; + win->event.point.y = pt.y; + + RGFW_dndInitCallback(win, win->event.point); + } + break; + default: + TranslateMessage(&msg); + DispatchMessageA(&msg); + return RGFW_window_checkEvent(win); + } + + TranslateMessage(&msg); + DispatchMessageA(&msg); + + return &win->event; } RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_ASSERT(win != NULL); + return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win); } @@ -9917,9 +7546,9 @@ RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_ASSERT(win != NULL); #ifndef __cplusplus - WINDOWPLACEMENT placement = {0}; + WINDOWPLACEMENT placement = { 0 }; #else - WINDOWPLACEMENT placement = {}; + WINDOWPLACEMENT placement = { }; #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMINIMIZED; @@ -9929,9 +7558,9 @@ RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_ASSERT(win != NULL); #ifndef __cplusplus - WINDOWPLACEMENT placement = {0}; + WINDOWPLACEMENT placement = { 0 }; #else - WINDOWPLACEMENT placement = {}; + WINDOWPLACEMENT placement = { }; #endif GetWindowPlacement(win->src.window, &placement); return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window); @@ -9939,49 +7568,51 @@ RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { typedef struct { int iIndex; HMONITOR hMonitor; RGFW_monitor* monitors; } RGFW_mInfo; #ifndef RGFW_NO_MONITOR -RGFW_monitor RGFW_win32_createMonitor(HMONITOR src); -RGFW_monitor RGFW_win32_createMonitor(HMONITOR src) { +RGFW_monitor win32CreateMonitor(HMONITOR src); +RGFW_monitor win32CreateMonitor(HMONITOR src) { RGFW_monitor monitor; - RGFW_MEMSET(&monitor, 0, sizeof(monitor)); + MONITORINFOEX monitorInfo; - MONITORINFOEXW monitorInfo; - monitorInfo.cbSize = sizeof(MONITORINFOEXW); - GetMonitorInfoW(src, (LPMONITORINFO)&monitorInfo); + monitorInfo.cbSize = sizeof(MONITORINFOEX); + GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo); /* get the monitor's index */ - DISPLAY_DEVICEW dd; + DISPLAY_DEVICEA dd; dd.cb = sizeof(dd); DWORD deviceNum; - for (deviceNum = 0; EnumDisplayDevicesW(NULL, deviceNum, &dd, 0); deviceNum++) { + for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) { if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; - DEVMODEW dm; + DEVMODEA dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); - if (EnumDisplaySettingsW(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { + if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { monitor.mode.refreshRate = dm.dmDisplayFrequency; RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode); } - DISPLAY_DEVICEW mdd; + DISPLAY_DEVICEA mdd; mdd.cb = sizeof(mdd); - if (EnumDisplayDevicesW(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) { - RGFW_createUTF8FromWideStringWin32(mdd.DeviceString, monitor.name, sizeof(monitor.name)); + if (EnumDisplayDevicesA(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) { + RGFW_STRNCPY(monitor.name, mdd.DeviceString, sizeof(monitor.name) - 1); monitor.name[sizeof(monitor.name) - 1] = '\0'; break; } } + + + monitor.x = monitorInfo.rcWork.left; monitor.y = monitorInfo.rcWork.top; - monitor.mode.w = (i32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left); - monitor.mode.h = (i32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); + monitor.mode.area.w = (u32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left); + monitor.mode.area.h = (u32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); - HDC hdc = CreateDCW(monitorInfo.szDevice, NULL, NULL, NULL); + HDC hdc = CreateDC(monitorInfo.szDevice, NULL, NULL, NULL); /* get pixels per inch */ float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX); float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX); @@ -10007,7 +7638,7 @@ RGFW_monitor RGFW_win32_createMonitor(HMONITOR src) { } #endif - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); return monitor; } #endif /* RGFW_NO_MONITOR */ @@ -10024,7 +7655,7 @@ BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMon if (info->iIndex >= 6) return FALSE; - info->monitors[info->iIndex] = RGFW_win32_createMonitor(hMonitor); + info->monitors[info->iIndex] = win32CreateMonitor(hMonitor); info->iIndex++; return TRUE; @@ -10032,9 +7663,9 @@ BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMon RGFW_monitor RGFW_getPrimaryMonitor(void) { #ifdef __cplusplus - return RGFW_win32_createMonitor(MonitorFromPoint({0, 0}, MONITOR_DEFAULTTOPRIMARY)); + return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); #else - return RGFW_win32_createMonitor(MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY)); + return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); #endif } @@ -10052,7 +7683,7 @@ RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY); - return RGFW_win32_createMonitor(src); + return win32CreateMonitor(src); } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { @@ -10074,7 +7705,7 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW if (strcmp(dd.DeviceName, (const char*)monitorInfo.szDevice) != 0) continue; - + DEVMODEA dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); @@ -10082,8 +7713,8 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) { if (request & RGFW_monitorScale) { dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT; - dm.dmPelsWidth = (u32)mode.w; - dm.dmPelsHeight = (u32)mode.h; + dm.dmPelsWidth = mode.area.w; + dm.dmPelsHeight = mode.area.h; } if (request & RGFW_monitorRefresh) { @@ -10096,8 +7727,8 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW dm.dmBitsPerPel = (DWORD)(mode.red + mode.green + mode.blue); } - if (ChangeDisplaySettingsExA(dd.DeviceName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { - if (ChangeDisplaySettingsExA(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) + if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) { + if (ChangeDisplaySettingsExA((LPCSTR)dd.DeviceName, (DEVMODE *)&dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL) return RGFW_TRUE; return RGFW_FALSE; } else return RGFW_FALSE; @@ -10108,15 +7739,17 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW } #endif -HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon); -HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon) { +HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon); +HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) { + size_t channels = (size_t)c; + BITMAPV5HEADER bi; ZeroMemory(&bi, sizeof(bi)); bi.bV5Size = sizeof(bi); - bi.bV5Width = (i32)w; - bi.bV5Height = -((LONG) h); + bi.bV5Width = (i32)a.w; + bi.bV5Height = -((LONG) a.h); bi.bV5Planes = 1; - bi.bV5BitCount = (WORD)32; + bi.bV5BitCount = (WORD)(channels * 8); bi.bV5Compression = BI_RGB; HDC dc = GetDC(NULL); u8* target = NULL; @@ -10125,16 +7758,26 @@ HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target, NULL, (DWORD) 0); - RGFW_copyImageData(target, w, h, RGFW_formatBGRA8, data, format); + size_t x, y; + for (y = 0; y < a.h; y++) { + for (x = 0; x < a.w; x++) { + size_t index = (y * 4 * (size_t)a.w) + x * channels; + target[index] = src[index + 2]; + target[index + 1] = src[index + 1]; + target[index + 2] = src[index]; + target[index + 3] = src[index + 3]; + } + } + ReleaseDC(NULL, dc); - HBITMAP mask = CreateBitmap((i32)w, (i32)h, 1, 1, NULL); + HBITMAP mask = CreateBitmap((i32)a.w, (i32)a.h, 1, 1, NULL); ICONINFO ii; ZeroMemory(&ii, sizeof(ii)); ii.fIcon = icon; - ii.xHotspot = (u32)w / 2; - ii.yHotspot = (u32)h / 2; + ii.xHotspot = a.w / 2; + ii.yHotspot = a.h / 2; ii.hbmMask = mask; ii.hbmColor = color; @@ -10145,8 +7788,9 @@ HICON RGFW_loadHandleImage(u8* data, i32 w, i32 h, RGFW_format format, BOOL icon return handle; } -RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { - HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(data, w, h, format, FALSE); + +void* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { + HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(icon, channels, a, FALSE); return cursor; } @@ -10184,12 +7828,16 @@ void RGFW_window_hide(RGFW_window* win) { } void RGFW_window_show(RGFW_window* win) { - if (win->internal.flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); + if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win); ShowWindow(win->src.window, SW_RESTORE); } #define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL; -void RGFW_deinitPlatform(void) { +void RGFW_deinit(void) { + #ifndef RGFW_NO_XINPUT + RGFW_FREE_LIBRARY(RGFW_XInput_dll); + #endif + #ifndef RGFW_NO_DPI RGFW_FREE_LIBRARY(RGFW_Shcore_dll); #endif @@ -10202,35 +7850,55 @@ void RGFW_deinitPlatform(void) { #endif RGFW_FREE_LIBRARY(RGFW_wgl_dll); + _RGFW.root = NULL; - RGFW_freeMouse(_RGFW->hiddenMouse); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, "global context deinitialized"); + RGFW_freeMouse(_RGFW.hiddenMouse); + _RGFW.windowCount = -1; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); } -void RGFW_window_closePlatform(RGFW_window* win) { +void RGFW_window_close(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + #ifdef RGFW_BUFFER + DeleteDC(win->src.hdcMem); + DeleteObject(win->src.bitmap); + #endif + + if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); RemovePropW(win->src.window, L"RGFW"); ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */ DestroyWindow(win->src.window); /*!< delete window */ if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall); if (win->src.hIconBig) DestroyIcon(win->src.hIconBig); + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); + _RGFW.windowCount--; + if (_RGFW.windowCount == 0) RGFW_deinit(); + + RGFW_clipboard_switch(NULL); + RGFW_FREE(win->event.droppedFiles); + if ((win->_flags & RGFW_WINDOW_ALLOC)) { + RGFW_FREE(win); + win = NULL; + } } -void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { +void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_ASSERT(win != NULL); - win->x = x; - win->y = y; - SetWindowPos(win->src.window, HWND_TOP, win->x, win->y, 0, 0, SWP_NOSIZE); + win->r.x = v.x; + win->r.y = v.y; + SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE); } -void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { +void RGFW_window_resize(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); - win->w = w; - win->h = h; - SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->w + (i32)win->src.offsetW, win->h + (i32)win->src.offsetH, SWP_NOMOVE); + win->r.w = (i32)a.w; + win->r.h = (i32)a.h; + SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + (i32)win->src.hOffset, SWP_NOMOVE); } @@ -10268,13 +7936,15 @@ void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { } #endif -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { +RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* src, RGFW_area a, i32 channels, u8 type) { RGFW_ASSERT(win != NULL); #ifndef RGFW_WIN95 + RGFW_UNUSED(channels); + if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall); if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig); - if (data == NULL) { + if (src == NULL) { HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION); if (type & RGFW_iconWindow) SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon); @@ -10284,17 +7954,18 @@ RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_f } if (type & RGFW_iconWindow) { - win->src.hIconSmall = RGFW_loadHandleImage(data, w, h, format, TRUE); + win->src.hIconSmall = RGFW_loadHandleImage(src, channels, a, TRUE); SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall); } if (type & RGFW_iconTaskbar) { - win->src.hIconBig = RGFW_loadHandleImage(data, w, h, format, TRUE); + win->src.hIconBig = RGFW_loadHandleImage(src, channels, a, TRUE); SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig); } return RGFW_TRUE; #else - RGFW_UNUSED(img); - RGFW_UNUSED(type); + RGFW_UNUSED(src); + RGFW_UNUSED(a); + RGFW_UNUSED(channels); return RGFW_FALSE; #endif } @@ -10326,7 +7997,7 @@ RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { if (textLen > 1) wcstombs(str, wstr, (size_t)(textLen)); - str[textLen - 1] = '\0'; + str[textLen] = '\0'; } } @@ -10354,7 +8025,7 @@ void RGFW_writeClipboard(const char* text, u32 textLen) { MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen); GlobalUnlock(object); - if (!OpenClipboard(_RGFW->root->src.window)) { + if (!OpenClipboard(_RGFW.root->src.window)) { GlobalFree(object); return; } @@ -10364,307 +8035,94 @@ void RGFW_writeClipboard(const char* text, u32 textLen) { CloseClipboard(); } -void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { +void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { RGFW_ASSERT(win != NULL); - win->internal.lastMouseX = x - win->x; - win->internal.lastMouseX = y - win->y; - SetCursorPos(x, y); + win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y); + SetCursorPos(p.x, p.y); } #ifdef RGFW_OPENGL -RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) { - const char* extensions = NULL; - - RGFW_proc proc = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringARB"); - RGFW_proc proc2 = RGFW_getProcAddress_OpenGL("wglGetExtensionsStringEXT"); - - if (proc) - extensions = ((const char* (*)(HDC))proc)(wglGetCurrentDC()); - else if (proc2) - extensions = ((const char*(*)(void))proc2)(); - return extensions != NULL && RGFW_extensionSupportedStr(extensions, extension, len); -} - -RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { - RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname); - if (proc) - return proc; - - return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname); -} - -void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) { - if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL) - return; - - HDC dummy_dc = GetDC(dummyWin); - u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - - PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0}; - - int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd); - SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd); - - HGLRC dummy_context = wglCreateContext(dummy_dc); - - HGLRC cur = wglGetCurrentContext(); - wglMakeCurrent(dummy_dc, dummy_context); - - wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB"); - wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB"); - - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT"); - if (wglSwapIntervalEXT == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load swap interval function"); - } - - wglMakeCurrent(dummy_dc, cur); - wglDeleteContext(dummy_context); - ReleaseDC(dummyWin, dummy_dc); -} - -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_FULL_ACCELERATION_ARB 0x2027 -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_TYPE_RGBA_ARB 0x202b -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_COLOR_BITS_ARB 0x2014 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_ALPHA_BITS_ARB 0x201b -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_STEREO_ARB 0x2012 -#define WGL_AUX_BUFFERS_ARB 0x2024 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_ACCUM_RED_BITS_ARB 0x201e -#define WGL_ACCUM_GREEN_BITS_ARB 0x201f -#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 -#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 -#define WGL_COLORSPACE_SRGB_EXT 0x3089 -#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_ACCESS_READ_WRITE_NV 0x00000001 -#define WGL_COVERAGE_SAMPLES_NV 0x2042 -#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 - -RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { - const char flushControl[] = "WGL_ARB_context_flush_control"; - const char noError[] = "WGL_ARB_create_context_no_error"; - const char robustness[] = "WGL_ARB_create_context_robustness"; - - win->src.ctx.native = ctx; - win->src.gfxType = RGFW_gfxNativeOpenGL; - - PIXELFORMATDESCRIPTOR pfd; - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.iLayerType = PFD_MAIN_PLANE; - pfd.cColorBits = 32; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = (BYTE)hints->stencil; - pfd.cAuxBuffers = (BYTE)hints->auxBuffers; - if (hints->stereo) pfd.dwFlags |= PFD_STEREO; - - /* try to create the pixel format we want for OpenGL and then try to create an OpenGL context for the specified version */ - if (hints->renderer == RGFW_glSoftware) - pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED; - - /* get pixel format, default to a basic pixel format */ - int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd); - if (wglChoosePixelFormatARB != NULL) { - i32 pixel_format_attribs[50]; - RGFW_attribStack stack; - RGFW_attribStack_init(&stack, pixel_format_attribs, 50); - - RGFW_attribStack_pushAttribs(&stack, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB); - RGFW_attribStack_pushAttribs(&stack, WGL_DRAW_TO_WINDOW_ARB, 1); - RGFW_attribStack_pushAttribs(&stack, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); - RGFW_attribStack_pushAttribs(&stack, WGL_SUPPORT_OPENGL_ARB, 1); - RGFW_attribStack_pushAttribs(&stack, WGL_COLOR_BITS_ARB, 32); - RGFW_attribStack_pushAttribs(&stack, WGL_DOUBLE_BUFFER_ARB, 1); - RGFW_attribStack_pushAttribs(&stack, WGL_ALPHA_BITS_ARB, hints->alpha); - RGFW_attribStack_pushAttribs(&stack, WGL_DEPTH_BITS_ARB, hints->depth); - RGFW_attribStack_pushAttribs(&stack, WGL_STENCIL_BITS_ARB, hints->stencil); - RGFW_attribStack_pushAttribs(&stack, WGL_STEREO_ARB, hints->stereo); - RGFW_attribStack_pushAttribs(&stack, WGL_AUX_BUFFERS_ARB, hints->auxBuffers); - RGFW_attribStack_pushAttribs(&stack, WGL_RED_BITS_ARB, hints->red); - RGFW_attribStack_pushAttribs(&stack, WGL_GREEN_BITS_ARB, hints->blue); - RGFW_attribStack_pushAttribs(&stack, WGL_BLUE_BITS_ARB, hints->green); - RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_RED_BITS_ARB, hints->accumRed); - RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_GREEN_BITS_ARB, hints->accumGreen); - RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_BLUE_BITS_ARB, hints->accumBlue); - RGFW_attribStack_pushAttribs(&stack, WGL_ACCUM_ALPHA_BITS_ARB, hints->accumAlpha); - - if(hints->sRGB) { - if (hints->profile != RGFW_glES) - RGFW_attribStack_pushAttribs(&stack, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, 1); - else - RGFW_attribStack_pushAttribs(&stack, WGL_COLORSPACE_SRGB_EXT, hints->sRGB); - } - - RGFW_attribStack_pushAttribs(&stack, WGL_COVERAGE_SAMPLES_NV, hints->samples); - - RGFW_attribStack_pushAttribs(&stack, 0, 0); - - int new_pixel_format; - UINT num_formats; - wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats); - if (!num_formats) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create a pixel format for WGL"); - else pixel_format = new_pixel_format; - } - - PIXELFORMATDESCRIPTOR suggested; - if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) || - !SetPixelFormat(win->src.hdc, pixel_format, &pfd)) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set the WGL pixel format"); - - if (wglCreateContextAttribsARB != NULL) { - /* create OpenGL/WGL context for the specified version */ - i32 attribs[40]; - RGFW_attribStack stack; - RGFW_attribStack_init(&stack, attribs, 50); - - - i32 mask = 0; - switch (hints->profile) { - case RGFW_glES: mask |= WGL_CONTEXT_ES_PROFILE_BIT_EXT; break; - case RGFW_glCompatibility: mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break; - case RGFW_glCore: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break; - default: mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; break; - } - - RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_PROFILE_MASK_ARB, mask); - - if (hints->minor || hints->major) { - RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MAJOR_VERSION_ARB, hints->major); - RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_MINOR_VERSION_ARB, hints->minor); - } - - if (RGFW_extensionSupportedPlatform_OpenGL(noError, sizeof(noError))) - RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_OPENGL_NO_ERROR_ARB, hints->noError); - - if (RGFW_extensionSupportedPlatform_OpenGL(flushControl, sizeof(flushControl))) { - if (hints->releaseBehavior == RGFW_glReleaseFlush) { - RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); /* WGL_CONTEXT_RELEASE_BEHAVIOR_ARB */ - } else if (hints->releaseBehavior == RGFW_glReleaseNone) { - RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); - } - } - - i32 flags = 0; - if (hints->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; - if (hints->robustness && RGFW_extensionSupportedPlatform_OpenGL(robustness, sizeof(robustness))) flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; - if (flags) { - RGFW_attribStack_pushAttribs(&stack, WGL_CONTEXT_FLAGS_ARB, flags); - } - - - RGFW_attribStack_pushAttribs(&stack, 0, 0); - - win->src.ctx.native->ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); - } - - if (wglCreateContextAttribsARB == NULL || win->src.ctx.native->ctx == NULL) { /* fall back to a default context (probably OpenGL 2 or something) */ - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to create an accelerated OpenGL Context."); - win->src.ctx.native->ctx = wglCreateContext(win->src.hdc); - } - - ReleaseDC(win->src.window, win->src.hdc); - win->src.hdc = GetDC(win->src.window); - - if (hints->share) { - wglShareLists((HGLRC)RGFW_getCurrentContext_OpenGL(), hints->share->ctx); - } - - wglMakeCurrent(win->src.hdc, win->src.ctx.native->ctx); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); - return RGFW_TRUE; -} - -void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { - wglDeleteContext((HGLRC) ctx->ctx); /*!< delete OpenGL context */ - win->src.ctx.native->ctx = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); -} - -void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { +void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { if (win == NULL) wglMakeCurrent(NULL, NULL); else - wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx.native->ctx); -} -void* RGFW_getCurrentContext_OpenGL(void) { - return wglGetCurrentContext(); -} -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { - RGFW_ASSERT(win->src.ctx.native); - SwapBuffers(win->src.hdc); + wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx); } +void* RGFW_getCurrent_OpenGL(void) { return wglGetCurrentContext(); } +void RGFW_window_swapBuffers_OpenGL(RGFW_window* win){ SwapBuffers(win->src.hdc); } +#endif -void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { +#ifndef RGFW_EGL +void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_ASSERT(win != NULL); +#if defined(RGFW_OPENGL) if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to set swap interval"); + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set swap interval"); +#else + RGFW_UNUSED(swapInterval); +#endif } #endif -RGFW_bool RGFW_createUTF8FromWideStringWin32(const WCHAR* source, char* output, size_t max) { - i32 size = 0; - if (source == NULL) { - return RGFW_FALSE; +void RGFW_window_swapBuffers_software(RGFW_window* win) { +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if (win->buffer != win->src.bitmapBits) + memcpy(win->src.bitmapBits, win->buffer, win->bufferSize.w * win->bufferSize.h * 4); + + RGFW_RGB_to_BGR(win, win->src.bitmapBits); + BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY); +#else + RGFW_UNUSED(win); +#endif +} + +char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source) { + if (source == NULL) { + return NULL; } - size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); + i32 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); if (!size) { - return RGFW_FALSE; + return NULL; } - if (size > (i32)max) - size = (i32)max; + static char target[RGFW_MAX_PATH * 2]; + if (size > RGFW_MAX_PATH * 2) + size = RGFW_MAX_PATH * 2; - if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, output, size, NULL, NULL)) { - return RGFW_FALSE; + target[size] = 0; + + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) { + return NULL; } - output[size] = 0; - return RGFW_TRUE; + return target; } -#ifdef RGFW_WEBGPU -WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { - WGPUSurfaceDescriptor surfaceDesc = {0}; - WGPUSurfaceSourceWindowsHWND fromHwnd = {0}; - fromHwnd.chain.sType = WGPUSType_SurfaceSourceWindowsHWND; - fromHwnd.hwnd = window->src.window; /* Get HWND from RGFW window source */ - if (!fromHwnd.hwnd) { - fprintf(stderr, "RGFW Error: HWND is NULL for Windows window.\n"); - return NULL; - } - fromHwnd.hinstance = GetModuleHandle(NULL); /* Get current process HINSTANCE */ +u64 RGFW_getTimerFreq(void) { + static u64 frequency = 0; + if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency); - surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromHwnd.chain; - return wgpuInstanceCreateSurface(instance, &surfaceDesc); + return frequency; } + +u64 RGFW_getTimerValue(void) { + u64 value; + QueryPerformanceCounter((LARGE_INTEGER*)&value); + return value; +} + +void RGFW_sleep(u64 ms) { + Sleep((u32)ms); +} + +#ifndef RGFW_NO_THREADS + +RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); } +void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); } +void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); } +void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); } + #endif - #endif /* RGFW_WINDOWS */ /* @@ -10693,7 +8151,6 @@ WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance i #include #include -#ifndef __OBJC__ typedef CGRect NSRect; typedef CGPoint NSPoint; typedef CGSize NSSize; @@ -10703,46 +8160,106 @@ typedef unsigned long NSUInteger; typedef long NSInteger; typedef NSInteger NSModalResponse; -typedef enum NSApplicationActivationPolicy { - NSApplicationActivationPolicyRegular, - NSApplicationActivationPolicyAccessory, - NSApplicationActivationPolicyProhibited -} NSApplicationActivationPolicy; +#ifdef __arm64__ + /* ARM just uses objc_msgSend */ +#define abi_objc_msgSend_stret objc_msgSend +#define abi_objc_msgSend_fpret objc_msgSend +#else /* __i386__ */ + /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ +#define abi_objc_msgSend_stret objc_msgSend_stret +#define abi_objc_msgSend_fpret objc_msgSend_fpret +#endif -typedef RGFW_ENUM(u32, NSBackingStoreType) { - NSBackingStoreRetained = 0, - NSBackingStoreNonretained = 1, - NSBackingStoreBuffered = 2 +#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) +#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z) +#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z) +#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z) +#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) +#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) +#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) +#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) +#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) +#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z) +#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y) +#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z) + +id NSApp = NULL; + +#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release")) +id NSString_stringWithUTF8String(const char* str); +id NSString_stringWithUTF8String(const char* str) { + return ((id(*)(id, SEL, const char*))objc_msgSend) + ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str); +} + +const char* NSString_to_char(id str); +const char* NSString_to_char(id str) { + return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String")); +} + +void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function); +void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) { + Class selected_class; + + if (RGFW_STRNCMP(class_name, "NSView", 6) == 0) { + selected_class = objc_getClass("ViewClass"); + } else if (RGFW_STRNCMP(class_name, "NSWindow", 8) == 0) { + selected_class = objc_getClass("WindowClass"); + } else { + selected_class = objc_getClass(class_name); + } + + class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0); +} + +/* Header for the array. */ +typedef struct siArrayHeader { + size_t count; + /* TODO(EimaMei): Add a `type_width` later on. */ +} siArrayHeader; + +/* Gets the header of the siArray. */ +#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1) +#define si_array_len(array) (SI_ARRAY_HEADER(array)->count) +#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", (void*)function) +/* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/ +#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", (void*)function) + +unsigned char* NSBitmapImageRep_bitmapData(id imageRep); +unsigned char* NSBitmapImageRep_bitmapData(id imageRep) { + return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData")); +} + +typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) { + NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */ + NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */ + NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */ + + NSBitmapFormatSixteenBitLittleEndian = (1 << 8), + NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9), + NSBitmapFormatSixteenBitBigEndian = (1 << 10), + NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11) }; -typedef RGFW_ENUM(u32, NSWindowStyleMask) { - NSWindowStyleMaskBorderless = 0, - NSWindowStyleMaskTitled = 1 << 0, - NSWindowStyleMaskClosable = 1 << 1, - NSWindowStyleMaskMiniaturizable = 1 << 2, - NSWindowStyleMaskResizable = 1 << 3, - NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ - NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, - NSWindowStyleMaskFullScreen = 1 << 14, - NSWindowStyleMaskFullSizeContentView = 1 << 15, - NSWindowStyleMaskUtilityWindow = 1 << 4, - NSWindowStyleMaskDocModalWindow = 1 << 6, - NSWindowStyleMaskNonactivatingpanel = 1 << 7, - NSWindowStyleMaskHUDWindow = 1 << 13 -}; +id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits); +id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) { + SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); -#define NSPasteboardTypeString "public.utf8-plain-text" + return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend) + (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); +} -typedef RGFW_ENUM(i32, NSDragOperation) { - NSDragOperationNone = 0, - NSDragOperationCopy = 1, - NSDragOperationLink = 2, - NSDragOperationGeneric = 4, - NSDragOperationPrivate = 8, - NSDragOperationMove = 16, - NSDragOperationDelete = 32, - NSDragOperationEvery = (int)ULONG_MAX -}; +id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); +id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { + void* nsclass = objc_getClass("NSColor"); + SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); + return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend) + ((id)nsclass, func, red, green, blue, alpha); +} typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) { NSOpenGLContextParameterSwapInterval = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */ @@ -10772,151 +8289,15 @@ typedef RGFW_ENUM(NSInteger, NSWindowButton) { NSWindowDocumentVersionsButton = 6, NSWindowFullScreenButton = 7, }; - -#define NSPasteboardTypeURL "public.url" -#define NSPasteboardTypeFileURL "public.file-url" -#define NSTrackingMouseEnteredAndExited 0x01 -#define NSTrackingMouseMoved 0x02 -#define NSTrackingCursorUpdate 0x04 -#define NSTrackingActiveWhenFirstResponder 0x10 -#define NSTrackingActiveInKeyWindow 0x20 -#define NSTrackingActiveInActiveApp 0x40 -#define NSTrackingActiveAlways 0x80 -#define NSTrackingAssumeInside 0x100 -#define NSTrackingInVisibleRect 0x200 -#define NSTrackingEnabledDuringMouseDrag 0x400 -enum { - NSOpenGLPFAAllRenderers = 1, /* choose from all available renderers */ - NSOpenGLPFATripleBuffer = 3, /* choose a triple buffered pixel format */ - NSOpenGLPFADoubleBuffer = 5, /* choose a double buffered pixel format */ - NSOpenGLPFAAuxBuffers = 7, /* number of aux buffers */ - NSOpenGLPFAColorSize = 8, /* number of color buffer bits */ - NSOpenGLPFAAlphaSize = 11, /* number of alpha component bits */ - NSOpenGLPFADepthSize = 12, /* number of depth buffer bits */ - NSOpenGLPFAStencilSize = 13, /* number of stencil buffer bits */ - NSOpenGLPFAAccumSize = 14, /* number of accum buffer bits */ - NSOpenGLPFAMinimumPolicy = 51, /* never choose smaller buffers than requested */ - NSOpenGLPFAMaximumPolicy = 52, /* choose largest buffers of type requested */ - NSOpenGLPFASampleBuffers = 55, /* number of multi sample buffers */ - NSOpenGLPFASamples = 56, /* number of samples per multi sample buffer */ - NSOpenGLPFAAuxDepthStencil = 57, /* each aux buffer has its own depth stencil */ - NSOpenGLPFAColorFloat = 58, /* color buffers store floating point pixels */ - NSOpenGLPFAMultisample = 59, /* choose multisampling */ - NSOpenGLPFASupersample = 60, /* choose supersampling */ - NSOpenGLPFASampleAlpha = 61, /* request alpha filtering */ - NSOpenGLPFARendererID = 70, /* request renderer by ID */ - NSOpenGLPFANoRecovery = 72, /* disable all failure recovery systems */ - NSOpenGLPFAAccelerated = 73, /* choose a hardware accelerated renderer */ - NSOpenGLPFAClosestPolicy = 74, /* choose the closest color buffer to request */ - NSOpenGLPFABackingStore = 76, /* back buffer contents are valid after swap */ - NSOpenGLPFAScreenMask = 84, /* bit mask of supported physical screens */ - NSOpenGLPFAAllowOfflineRenderers = 96, /* allow use of offline renderers */ - NSOpenGLPFAAcceleratedCompute = 97, /* choose a hardware accelerated compute device */ - NSOpenGLPFAOpenGLProfile = 99, /* specify an OpenGL Profile to use */ - NSOpenGLProfileVersionLegacy = 0x1000, /* The requested profile is a legacy (pre-OpenGL 3.0) profile. */ - NSOpenGLProfileVersion3_2Core = 0x3200, /* The 3.2 Profile of OpenGL */ - NSOpenGLProfileVersion4_1Core = 0x3200, /* The 4.1 profile of OpenGL */ - NSOpenGLPFAVirtualScreenCount = 128, /* number of virtual screens in this format */ - NSOpenGLPFAStereo = 6, - NSOpenGLPFAOffScreen = 53, - NSOpenGLPFAFullScreen = 54, - NSOpenGLPFASingleRenderer = 71, - NSOpenGLPFARobust = 75, - NSOpenGLPFAMPSafe = 78, - NSOpenGLPFAWindow = 80, - NSOpenGLPFAMultiScreen = 81, - NSOpenGLPFACompliant = 83, - NSOpenGLPFAPixelBuffer = 90, - NSOpenGLPFARemotePixelBuffer = 91, -}; - -typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */ - NSEventTypeApplicationDefined = 15, -}; -typedef unsigned long long NSEventMask; - -typedef enum NSEventModifierFlags { - NSEventModifierFlagCapsLock = 1 << 16, - NSEventModifierFlagShift = 1 << 17, - NSEventModifierFlagControl = 1 << 18, - NSEventModifierFlagOption = 1 << 19, - NSEventModifierFlagCommand = 1 << 20, - NSEventModifierFlagNumericPad = 1 << 21 -} NSEventModifierFlags; - -typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) { - NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */ - NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */ - NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */ - - NSBitmapFormatSixteenBitLittleEndian = (1 << 8), - NSBitmapFormatThirtyTwoBitLittleEndian = (1 << 9), - NSBitmapFormatSixteenBitBigEndian = (1 << 10), - NSBitmapFormatThirtyTwoBitBigEndian = (1 << 11) -}; - -#else -#import -#include -#endif /* notdef __OBJC__ */ - -#ifdef __arm64__ - /* ARM just uses objc_msgSend */ -#define abi_objc_msgSend_stret objc_msgSend -#define abi_objc_msgSend_fpret objc_msgSend -#else /* __i386__ */ - /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ -#define abi_objc_msgSend_stret objc_msgSend_stret -#define abi_objc_msgSend_fpret objc_msgSend_fpret -#endif - -#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) -#define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z) -#define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z) -#define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z) -#define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y) -#define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) -#define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z) -#define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) -#define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z) -#define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z) -#define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y) -#define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z) - -#define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release")) -RGFWDEF id NSString_stringWithUTF8String(const char* str); -id NSString_stringWithUTF8String(const char* str) { - return ((id(*)(id, SEL, const char*))objc_msgSend) ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str); +void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param); +void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) { + ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend) + (context, sel_registerName("setValues:forParameter:"), vals, param); } - -const char* NSString_to_char(id str); -const char* NSString_to_char(id str) { - return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String")); -} - -unsigned char* NSBitmapImageRep_bitmapData(id imageRep); -unsigned char* NSBitmapImageRep_bitmapData(id imageRep) { - return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData")); -} - -id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits); -id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) { - SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); - - return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend) - (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); -} - -id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); -id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { - Class nsclass = objc_getClass("NSColor"); - SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); - return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend) - ((id)nsclass, func, red, green, blue, alpha); +void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs); +void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) { + return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend) + (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), attribs); } id NSPasteboard_generalPasteboard(void); @@ -10937,7 +8318,7 @@ id* cstrToNSStringArray(char** strs, size_t len) { const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len); const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) { SEL func = sel_registerName("stringForType:"); - id nsstr = NSString_stringWithUTF8String((const char*)dataType); + id nsstr = NSString_stringWithUTF8String(dataType); id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr); const char* str = NSString_to_char(nsString); if (len != NULL) @@ -10947,7 +8328,10 @@ const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, id c_array_to_NSArray(void* array, size_t len); id c_array_to_NSArray(void* array, size_t len) { - return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) (NSAlloc(objc_getClass("NSArray")), sel_registerName("initWithObjects:count:"), array, len); + SEL func = sel_registerName("initWithObjects:count:"); + void* nsclass = objc_getClass("NSArray"); + return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) + (NSAlloc(nsclass), func, array, len); } @@ -10977,98 +8361,129 @@ NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, s #define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain")) +typedef enum NSApplicationActivationPolicy { + NSApplicationActivationPolicyRegular, + NSApplicationActivationPolicyAccessory, + NSApplicationActivationPolicyProhibited +} NSApplicationActivationPolicy; + +typedef RGFW_ENUM(u32, NSBackingStoreType) { + NSBackingStoreRetained = 0, + NSBackingStoreNonretained = 1, + NSBackingStoreBuffered = 2 +}; + +typedef RGFW_ENUM(u32, NSWindowStyleMask) { + NSWindowStyleMaskBorderless = 0, + NSWindowStyleMaskTitled = 1 << 0, + NSWindowStyleMaskClosable = 1 << 1, + NSWindowStyleMaskMiniaturizable = 1 << 2, + NSWindowStyleMaskResizable = 1 << 3, + NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ + NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, + NSWindowStyleMaskFullScreen = 1 << 14, + NSWindowStyleMaskFullSizeContentView = 1 << 15, + NSWindowStyleMaskUtilityWindow = 1 << 4, + NSWindowStyleMaskDocModalWindow = 1 << 6, + NSWindowStyleMaskNonactivatingpanel = 1 << 7, + NSWindowStyleMaskHUDWindow = 1 << 13 +}; + +NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; /* Replaces NSStringPasteboardType */ + + +typedef RGFW_ENUM(i32, NSDragOperation) { + NSDragOperationNone = 0, + NSDragOperationCopy = 1, + NSDragOperationLink = 2, + NSDragOperationGeneric = 4, + NSDragOperationPrivate = 8, + NSDragOperationMove = 16, + NSDragOperationDelete = 32, + NSDragOperationEvery = (int)ULONG_MAX +}; + +void* NSArray_objectAtIndex(id array, NSUInteger index) { + SEL func = sel_registerName("objectAtIndex:"); + return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index); +} + +id NSWindow_contentView(id window) { + SEL func = sel_registerName("contentView"); + return objc_msgSend_id(window, func); +} + /* End of cocoa wrapper */ -static id RGFW__osxCustomInitWithRGFWWindow(id self, SEL _cmd, RGFW_window* win) { - RGFW_UNUSED(_cmd); - struct objc_super s = { self, class_getSuperclass(object_getClass(self)) }; - self = ((id (*)(struct objc_super*, SEL))objc_msgSendSuper)(&s, sel_registerName("init")); +#ifdef RGFW_OPENGL +/* MacOS opengl API spares us yet again (there are no extensions) */ +RGFW_bool RGFW_extensionSupportedPlatform(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; } +CFBundleRef RGFWnsglFramework = NULL; - if (self != nil) { - object_setInstanceVariable(self, "RGFW_window", win); - object_setInstanceVariable(self, "trackingArea", nil); +RGFW_proc RGFW_getProcAddress(const char* procname) { + if (RGFWnsglFramework == NULL) + RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - object_setInstanceVariable( - self, "markedText", - ((id (*)(id, SEL))objc_msgSend)( - ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSMutableAttributedString"), sel_registerName("alloc")), - sel_registerName("init") - ) - ); + CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII); - ((void (*)(id, SEL))objc_msgSend)(self, sel_registerName("updateTrackingAreas")); + RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName); - ((void (*)(id, SEL, id))objc_msgSend)( - self, sel_registerName("registerForDraggedTypes:"), - ((id (*)(Class, SEL, id))objc_msgSend)( - objc_getClass("NSArray"), - sel_registerName("arrayWithObject:"), - ((id (*)(Class, SEL, const char*))objc_msgSend)( - objc_getClass("NSString"), - sel_registerName("stringWithUTF8String:"), - "public.url" - ) - ) - ); - } + CFRelease(symbolName); - return self; + return symbol; +} +#endif + +id NSWindow_delegate(RGFW_window* win) { + return (id) objc_msgSend_id((id)win->src.window, sel_registerName("delegate")); } -static u32 RGFW_OnClose(id self) { +u32 RGFW_OnClose(id self) { RGFW_window* win = NULL; object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win); if (win == NULL) return true; - RGFW_window_setShouldClose(win, RGFW_TRUE); - RGFW_eventQueuePushEx(e.type = RGFW_quit; e.common.win = win); + RGFW_eventQueuePushEx(e.type = RGFW_quit; e._win = win); RGFW_windowQuitCallback(win); return false; } /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */ -static bool RGFW__osxAcceptsFirstResponder(void) { return true; } -static bool RGFW__osxPerformKeyEquivalent(id event) { RGFW_UNUSED(event); return true; } +bool acceptsFirstResponder(void) { return true; } +bool performKeyEquivalent(id event) { RGFW_UNUSED(event); return true; } -static NSDragOperation RGFW__osxDraggingEntered(id self, SEL sel, id sender) { +NSDragOperation draggingEntered(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return NSDragOperationCopy; } -static NSDragOperation RGFW__osxDraggingUpdated(id self, SEL sel, id sender) { +NSDragOperation draggingUpdated(id self, SEL sel, id sender) { RGFW_UNUSED(sel); RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || (!(win->internal.flags & RGFW_windowAllowDND))) + if (win == NULL || (!(win->_flags & RGFW_windowAllowDND))) return 0; - if (!(win->internal.enabledEvents & RGFW_dataDragFlag)) return NSDragOperationCopy; NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); - RGFW_eventQueuePushEx(e.type = RGFW_dataDrag; - e.mouse.x = (i32)p.x; e.mouse.y = (i32)(win->h - p.y); - e.common.win = win); + RGFW_eventQueuePushEx(e.type = RGFW_DNDInit; + e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); + e._win = win); - _RGFW->windowState.win = win; - _RGFW->windowState.dataDragging = RGFW_TRUE; - _RGFW->windowState.dropX = (i32)p.x; - _RGFW->windowState.dropY = (i32)(win->h - p.y); - - RGFW_dataDragCallback(win, (i32) p.x, (i32) (win->h - p.y)); + RGFW_dndInitCallback(win, win->event.point); return NSDragOperationCopy; } -static bool RGFW__osxPrepareForDragOperation(id self) { +bool prepareForDragOperation(id self) { RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag))) + if (win == NULL) return true; - if (!(win->internal.flags & RGFW_windowAllowDND)) { + if (!(win->_flags & RGFW_windowAllowDND)) { return false; } @@ -11078,13 +8493,14 @@ static bool RGFW__osxPrepareForDragOperation(id self) { void RGFW__osxDraggingEnded(id self, SEL sel, id sender); void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; } -static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) { +/* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */ +bool performDragOperation(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || (!(win->internal.enabledEvents & RGFW_dataDropFlag))) + if (win == NULL) return false; /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */ @@ -11099,7 +8515,7 @@ static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) { /* Check if the pasteboard contains file URLs */ if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, "No files found on the pasteboard."); + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(win, 0), "No files found on the pasteboard."); return 0; } @@ -11109,54 +8525,49 @@ static bool RGFW__osxPerformDragOperation(id self, SEL sel, id sender) { if (count == 0) return 0; - RGFW_event event; - event.drop.files = (char**)(void*)_RGFW->files; - - u32 i; - for (i = 0; i < (u32)count; i++) { + int i; + for (i = 0; i < count; i++) { id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i); const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String")); - RGFW_STRNCPY(event.drop.files[i], filePath, RGFW_MAX_PATH - 1); - event.drop.files[i][RGFW_MAX_PATH - 1] = '\0'; + RGFW_STRNCPY(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH - 1); + win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; } - - event.drop.count = (size_t)count; - RGFW_eventQueuePushEx(e.type = RGFW_dataDrop; - e.drop.count = (size_t)count; - e.drop.files = event.drop.files; - e.common.win = win); - - _RGFW->windowState.win = win; - _RGFW->windowState.dataDrop = RGFW_TRUE; - _RGFW->windowState.filesCount = event.drop.count; - RGFW_dataDropCallback(win, event.drop.files, event.drop.count); + NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); + + win->event.droppedFilesCount = (size_t)count; + RGFW_eventQueuePushEx(e.type = RGFW_DND; + e.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); + e.droppedFilesCount = (size_t)count; + e._win = win); + + RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); return false; } #ifndef RGFW_NO_IOKIT #include +#include -u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID); u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) { u32 refreshRate = 0; io_iterator_t it; io_service_t service; CFNumberRef indexRef, clockRef, countRef; - u32 clock, count; + uint32_t clock, count; -#ifdef kIOMainPortDefault +#ifdef kIOMainPortDefault if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) -#elif defined(kIOMasterPortDefault) +#elif defined(kIOMasterPortDefault) if (IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching("IOFramebuffer"), &it) != 0) #endif return RGFW_FALSE; while ((service = IOIteratorNext(it)) != 0) { - u32 index; + uint32_t index; indexRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFramebufferOpenGLIndex"), kCFAllocatorDefault, kNilOptions); if (indexRef == 0) continue; - + if (CFNumberGetValue(indexRef, kCFNumberIntType, &index) && CGOpenGLDisplayMaskToDisplayID(1 << index) == displayID) { CFRelease(indexRef); break; @@ -11171,8 +8582,7 @@ u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) { if (CFNumberGetValue(clockRef, kCFNumberIntType, &clock) && clock) { countRef = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("IOFBCurrentPixelCount"), kCFAllocatorDefault, kNilOptions); if (countRef && CFNumberGetValue(countRef, kCFNumberIntType, &count) && count) { - float rate = (float)((double)clock / (double) count); - refreshRate = (u32)RGFW_ROUND(rate); + refreshRate = (u32)RGFW_ROUND(clock / (double) count); CFRelease(countRef); } } @@ -11183,6 +8593,201 @@ u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID) { IOObjectRelease(it); return refreshRate; } + +IOHIDDeviceRef RGFW_osxControllers[4] = {NULL}; + +size_t findControllerIndex(IOHIDDeviceRef device) { + size_t i; + for (i = 0; i < 4; i++) + if (RGFW_osxControllers[i] == device) + return i; + return (size_t)-1; +} + +void RGFW__osxInputValueChangedCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) { + RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); + IOHIDElementRef element = IOHIDValueGetElement(value); + + IOHIDDeviceRef device = IOHIDElementGetDevice(element); + size_t index = findControllerIndex(device); + if (index == (size_t)-1) return; + + uint32_t usagePage = IOHIDElementGetUsagePage(element); + uint32_t usage = IOHIDElementGetUsage(element); + + CFIndex intValue = IOHIDValueGetIntegerValue(value); + + u8 RGFW_osx2RGFWSrc[2][RGFW_gamepadFinal] = {{ + 0, RGFW_gamepadSelect, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadStart, + RGFW_gamepadUp, RGFW_gamepadRight, RGFW_gamepadDown, RGFW_gamepadLeft, + RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadL1, RGFW_gamepadR1, + RGFW_gamepadY, RGFW_gamepadB, RGFW_gamepadA, RGFW_gamepadX, RGFW_gamepadHome}, + {0, RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadR3, RGFW_gamepadX, + RGFW_gamepadY, RGFW_gamepadRight, RGFW_gamepadL1, RGFW_gamepadR1, + RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadDown, RGFW_gamepadStart, + RGFW_gamepadUp, RGFW_gamepadL3, RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome} + }; + + u8* RGFW_osx2RGFW = RGFW_osx2RGFWSrc[0]; + if (RGFW_gamepads_type[index] == RGFW_gamepadMicrosoft) + RGFW_osx2RGFW = RGFW_osx2RGFWSrc[1]; + + switch (usagePage) { + case kHIDPage_Button: { + u8 button = 0; + if (usage < sizeof(RGFW_osx2RGFW)) + button = RGFW_osx2RGFW[usage]; + + RGFW_gamepadButtonCallback(_RGFW.root, (u16)index, button, (u8)intValue); + RGFW_gamepadPressed[index][button].prev = RGFW_gamepadPressed[index][button].current; + RGFW_gamepadPressed[index][button].current = RGFW_BOOL(intValue); + RGFW_eventQueuePushEx(e.type = intValue ? RGFW_gamepadButtonPressed: RGFW_gamepadButtonReleased; + e.button = button; + e.gamepad = (u16)index; + e._win = _RGFW.root); + break; + } + case kHIDPage_GenericDesktop: { + CFIndex logicalMin = IOHIDElementGetLogicalMin(element); + CFIndex logicalMax = IOHIDElementGetLogicalMax(element); + + if (logicalMax <= logicalMin) return; + if (intValue < logicalMin) intValue = logicalMin; + if (intValue > logicalMax) intValue = logicalMax; + + i8 axisValue = (i8)(-100.0 + ((intValue - logicalMin) * 200.0) / (logicalMax - logicalMin)); + + u8 whichAxis = 0; + switch (usage) { + case kHIDUsage_GD_X: RGFW_gamepadAxes[index][0].x = axisValue; whichAxis = 0; break; + case kHIDUsage_GD_Y: RGFW_gamepadAxes[index][0].y = axisValue; whichAxis = 0; break; + case kHIDUsage_GD_Z: RGFW_gamepadAxes[index][1].x = axisValue; whichAxis = 1; break; + case kHIDUsage_GD_Rz: RGFW_gamepadAxes[index][1].y = axisValue; whichAxis = 1; break; + default: return; + } + + RGFW_event e; + e.type = RGFW_gamepadAxisMove; + e.gamepad = (u16)index; + e.whichAxis = whichAxis; + e._win = _RGFW.root; + for (size_t i = 0; i < 4; i++) + e.axis[i] = RGFW_gamepadAxes[index][i]; + + RGFW_eventQueuePush(e); + + RGFW_gamepadAxisCallback(_RGFW.root, (u16)index, RGFW_gamepadAxes[index], 2, whichAxis); + } + } +} + +void RGFW__osxDeviceAddedCallback(void* context, IOReturn result, void *sender, IOHIDDeviceRef device) { + RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); + CFTypeRef usageRef = (CFTypeRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey)); + int usage = 0; + if (usageRef) + CFNumberGetValue((CFNumberRef)usageRef, kCFNumberIntType, (void*)&usage); + + if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) { + return; + } + + size_t i; + for (i = 0; i < 4; i++) { + if (RGFW_osxControllers[i] != NULL) + continue; + + RGFW_osxControllers[i] = device; + + IOHIDDeviceRegisterInputValueCallback(device, RGFW__osxInputValueChangedCallback, NULL); + + CFStringRef deviceName = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); + if (deviceName) + CFStringGetCString(deviceName, RGFW_gamepads_name[i], sizeof(RGFW_gamepads_name[i]), kCFStringEncodingUTF8); + + RGFW_gamepads_type[i] = RGFW_gamepadUnknown; + if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box") || RGFW_STRSTR(RGFW_gamepads_name[i], "Xbox")) + RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; + else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5")) + RGFW_gamepads_type[i] = RGFW_gamepadSony; + else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo")) + RGFW_gamepads_type[i] = RGFW_gamepadNintendo; + else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech")) + RGFW_gamepads_type[i] = RGFW_gamepadLogitech; + + RGFW_gamepads[i] = (u16)i; + RGFW_gamepadCount++; + + RGFW_eventQueuePushEx(e.type = RGFW_gamepadConnected; + e.gamepad = (u16)i; + e._win = _RGFW.root); + + RGFW_gamepadCallback(_RGFW.root, (u16)i, 1); + break; + } +} + +void RGFW__osxDeviceRemovedCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) { + RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); RGFW_UNUSED(device); + CFNumberRef usageRef = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey)); + int usage = 0; + if (usageRef) + CFNumberGetValue(usageRef, kCFNumberIntType, &usage); + + if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) { + return; + } + + size_t index = findControllerIndex(device); + if (index != (size_t)-1) + RGFW_osxControllers[index] = NULL; + + RGFW_eventQueuePushEx(e.type = RGFW_gamepadDisconnected; + e.gamepad = (u16)index; + e._win = _RGFW.root); + RGFW_gamepadCallback(_RGFW.root, (u16)index, 0); + + RGFW_gamepadCount--; +} + +RGFWDEF void RGFW_osxInitIOKit(void); +void RGFW_osxInitIOKit(void) { + IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (!hidManager) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create IOHIDManager."); + return; + } + + CFMutableDictionaryRef matchingDictionary = CFDictionaryCreateMutable( + kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks + ); + if (!matchingDictionary) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create matching dictionary for IOKit."); + CFRelease(hidManager); + return; + } + + CFDictionarySetValue( + matchingDictionary, + CFSTR(kIOHIDDeviceUsagePageKey), + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (int[]){kHIDPage_GenericDesktop}) + ); + + IOHIDManagerSetDeviceMatching(hidManager, matchingDictionary); + + IOHIDManagerRegisterDeviceMatchingCallback(hidManager, RGFW__osxDeviceAddedCallback, NULL); + IOHIDManagerRegisterDeviceRemovalCallback(hidManager, RGFW__osxDeviceRemovedCallback, NULL); + + IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + + IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone); + + /* Execute the run loop once in order to register any initially-attached joysticks */ + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); +} #endif void RGFW_moveToMacOSResourceDir(void) { @@ -11211,94 +8816,83 @@ void RGFW_moveToMacOSResourceDir(void) { } -static void RGFW__osxWindowDeminiaturize(id self, SEL sel) { +void RGFW__osxWindowDeminiaturize(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; - win->internal.flags |= RGFW_windowMinimize; - if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); - RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); + win->_flags |= RGFW_windowMinimize; + RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); + RGFW_windowRestoredCallback(win, win->r); } -static void RGFW__osxWindowMiniaturize(id self, SEL sel) { +void RGFW__osxWindowMiniaturize(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; - win->internal.flags &= ~(u32)RGFW_windowMinimize; - if (!(win->internal.enabledEvents & RGFW_windowMinimizedFlag)) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e.common.win = win); - RGFW_windowMinimizedCallback(win); + win->_flags &= ~(u32)RGFW_windowMinimize; + RGFW_eventQueuePushEx(e.type = RGFW_windowMinimized; e._win = win); + RGFW_windowMinimizedCallback(win, win->r); } -static void RGFW__osxWindowBecameKey(id self, SEL sel) { +void RGFW__osxWindowBecameKey(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; + win->_flags |= RGFW_windowFocus; + RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = win); - win->internal.inFocus = RGFW_TRUE; - if ((win->internal.holdMouse)) RGFW_window_holdMouse(win); - if (!(win->internal.enabledEvents & RGFW_focusInFlag)) return; - - RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = win); RGFW_focusCallback(win, RGFW_TRUE); + + if ((win->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(win, RGFW_AREA(win->r.w, win->r.h)); } -static void RGFW__osxWindowResignKey(id self, SEL sel) { +void RGFW__osxWindowResignKey(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); if (win == NULL) return; RGFW_window_focusLost(win); - if (!(win->internal.enabledEvents & RGFW_focusOutFlag)) return; - - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = win); + RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = win); RGFW_focusCallback(win, RGFW_FALSE); } -static void RGFW__osxDidWindowResize(id self, SEL _cmd, id notification) { - RGFW_UNUSED(_cmd); RGFW_UNUSED(notification); +NSSize RGFW__osxWindowResize(id self, SEL sel, NSSize frameSize) { + RGFW_UNUSED(sel); + RGFW_window* win = NULL; object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; + if (win == NULL) return frameSize; - NSRect frame; - if (win->src.view) frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); - else return; - - if (frame.size.width == 0 || frame.size.height == 0) return; - win->w = (i32)frame.size.width; - win->h = (i32)frame.size.height; + win->r.w = (i32)frameSize.width; + win->r.h = (i32)frameSize.height; RGFW_monitor mon = RGFW_window_getMonitor(win); - if ((i32)mon.mode.w == win->w && (i32)mon.mode.h - 102 <= win->h) { - win->internal.flags |= RGFW_windowMaximize; - if (!(win->internal.enabledEvents & RGFW_windowMaximizedFlag)) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e.common.win = win); - RGFW_windowMaximizedCallback(win, 0, 0, win->w, win->h); - } else if (win->internal.flags & RGFW_windowMaximize) { - win->internal.flags &= ~(u32)RGFW_windowMaximize; - if (!(win->internal.enabledEvents & RGFW_windowRestoredFlag)) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e.common.win = win); - RGFW_windowRestoredCallback(win, win->x, win->y, win->w, win->h); + if ((i32)mon.mode.area.w == win->r.w && (i32)mon.mode.area.h - 102 <= win->r.h) { + win->_flags |= RGFW_windowMaximize; + RGFW_eventQueuePushEx(e.type = RGFW_windowMaximized; e._win = win); + RGFW_windowMaximizedCallback(win, win->r); + } else if (win->_flags & RGFW_windowMaximize) { + win->_flags &= ~(u32)RGFW_windowMaximize; + RGFW_eventQueuePushEx(e.type = RGFW_windowRestored; e._win = win); + RGFW_windowRestoredCallback(win, win->r); } - if (!(win->internal.enabledEvents & RGFW_windowResizedFlag)) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = win); - RGFW_windowResizedCallback(win, win->w, win->h); + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = win); + RGFW_windowResizedCallback(win, win->r); + return frameSize; } -static void RGFW__osxWindowMove(id self, SEL sel) { +void RGFW__osxWindowMove(id self, SEL sel) { RGFW_UNUSED(sel); RGFW_window* win = NULL; @@ -11306,601 +8900,289 @@ static void RGFW__osxWindowMove(id self, SEL sel) { if (win == NULL) return; NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); - win->x = (i32) frame.origin.x; - win->y = (i32) frame.origin.y; + win->r.x = (i32) frame.origin.x; + win->r.y = (i32) frame.origin.y; - if (!(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e.common.win = win); - RGFW_windowMovedCallback(win, win->x, win->y); + RGFW_eventQueuePushEx(e.type = RGFW_windowMoved; e._win = win); + RGFW_windowMovedCallback(win, win->r); } -static void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) { +void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) { RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return; + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL) return; RGFW_monitor mon = RGFW_window_getMonitor(win); RGFW_scaleUpdatedCallback(win, mon.scaleX, mon.scaleY); - RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scale.x = mon.scaleX; e.scale.y = mon.scaleY ; e.common.win = win); + RGFW_eventQueuePushEx(e.type = RGFW_scaleUpdated; e.scaleX = mon.scaleX; e.scaleY = mon.scaleY ; e._win = win); } -static BOOL RGFW__osxWantsUpdateLayer(id self, SEL _cmd) { RGFW_UNUSED(self); RGFW_UNUSED(_cmd); return YES; } - -static void RGFW__osxUpdateLayer(id self, SEL _cmd) { - RGFW_UNUSED(self); RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_windowRefreshFlag)) return; - RGFW_windowRefreshCallback(win); -} - -static void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) { +void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) { RGFW_UNUSED(rect); RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_scaleUpdatedFlag)) return; + RGFW_window* win = NULL; + object_getInstanceVariable(self, "RGFW_window", (void**)&win); + if (win == NULL) return; - RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e.common.win = win); - RGFW_windowRefreshCallback(win); + RGFW_eventQueuePushEx(e.type = RGFW_windowRefresh; e._win = win); + RGFW_windowRefreshCallback(win); } -static void RGFW__osxMouseEntered(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseEnterFlag)) return; - - win->internal.mouseInside = RGFW_TRUE; - _RGFW->windowState.win = win; - _RGFW->windowState.mouseEnter = RGFW_TRUE; - - RGFW_event e; - e.type = RGFW_mouseEnter; - NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow")); - e.mouse.x = (i32)p.x; - e.mouse.y = (i32)(win->h - p.y); - e.common.win = win; - - RGFW_eventQueuePush(&e); - RGFW_mouseNotifyCallback(win, e.mouse.x, e.mouse.y, 1); +void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) { + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + win->buffer = buffer; + win->bufferSize = area; + win->_flags |= RGFW_BUFFER_ALLOC; + #ifdef RGFW_OSMESA + win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); + OSMesaPixelStore(OSMESA_Y_UP, 0); + #endif + #else + RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ + #endif } -static void RGFW__osxMouseExited(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); RGFW_UNUSED(event); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseLeaveFlag)) return; - - - win->internal.mouseInside = RGFW_FALSE; - _RGFW->windowState.winLeave = win; - _RGFW->windowState.mouseLeave = RGFW_TRUE; - - RGFW_event e; - e.type = RGFW_mouseLeave; - e.mouse.x = 0; - e.mouse.y = 0; - e.common.win = win; - - RGFW_eventQueuePush(&e); - RGFW_mouseNotifyCallback(win, e.mouse.x, e.mouse.y, 0); -} - -static void RGFW__osxKeyDown(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_keyPressedFlag)) return; - - RGFW_event e; - u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); - u32 mappedKey = (u32)*(((char*)(const char*)NSString_to_char(((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("charactersIgnoringModifiers"))))); - if ((u8)mappedKey == 239) mappedKey = 0; - - e.key.sym = (u8)mappedKey; - e.key.value = (u8)RGFW_apiKeyToRGFW(key); - _RGFW->keyboard[e.key.value].prev = _RGFW->keyboard[e.key.value].current; - e.type = RGFW_keyPressed; - e.key.repeat = RGFW_window_isKeyPressed(win, e.key.value); - _RGFW->keyboard[e.key.value].current = 1; - e.common.win = win; - - RGFW_eventQueuePush(&e); - RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, 1); -} - -static void RGFW__osxKeyUp(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_keyReleasedFlag)) return; - - RGFW_event e; - u32 key = (u16)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("keyCode")); - u32 mappedKey = (u32)*(((char*)(const char*)NSString_to_char(((id(*)(id, SEL))objc_msgSend)(event, sel_registerName("charactersIgnoringModifiers"))))); - if ((u8)mappedKey == 239) mappedKey = 0; - - e.key.sym = (u8)mappedKey; - e.key.value = (u8)RGFW_apiKeyToRGFW(key); - _RGFW->keyboard[e.key.value].prev = _RGFW->keyboard[e.key.value].current; - e.type = RGFW_keyReleased; - e.key.repeat = RGFW_window_isKeyDown(win, (u8)e.key.value); - _RGFW->keyboard[e.key.value].current = 0; - e.common.win = win; - - RGFW_eventQueuePush(&e); - RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, 0); -} - -static void RGFW__osxFlagsChanged(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL) return; - - RGFW_event e; - u32 flags = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("modifierFlags")); - RGFW_updateKeyModsEx(win, - ((u32)(flags & NSEventModifierFlagCapsLock) % 255), - ((flags & NSEventModifierFlagNumericPad) % 255), - ((flags & NSEventModifierFlagControl) % 255), - ((flags & NSEventModifierFlagOption) % 255), - ((flags & NSEventModifierFlagShift) % 255), - ((flags & NSEventModifierFlagCommand) % 255), 0); - u8 i; - for (i = 0; i < 9; i++) - _RGFW->keyboard[i + RGFW_capsLock].prev = _RGFW->keyboard[i + RGFW_capsLock].current; - - for (i = 0; i < 5; i++) { - u32 shift = (1 << (i + 16)); - u32 key = i + RGFW_capsLock; - if ((flags & shift) && !RGFW_window_isKeyDown(win, (u8)key)) { - _RGFW->keyboard[key].current = 1; - if (key != RGFW_capsLock) - _RGFW->keyboard[key + 4].current = 1; - e.type = RGFW_keyPressed; - e.key.value = (u8)key; - break; - } - if (!(flags & shift) && RGFW_window_isKeyDown(win, (u8)key)) { - _RGFW->keyboard[key].current = 0; - if (key != RGFW_capsLock) - _RGFW->keyboard[key + 4].current = 0; - e.type = RGFW_keyReleased; - e.key.value = (u8)key; - break; - } - } - e.key.repeat = RGFW_window_isKeyDown(win, (u8)e.key.value); - e.common.win = win; - - if (!(win->internal.enabledEvents & (RGFW_BIT(e.type)))) return; - RGFW_eventQueuePush(&e); - RGFW_keyCallback(win, e.key.value, e.key.sym, win->internal.mod, e.key.repeat, e.type == RGFW_keyPressed); -} - -static void RGFW__osxMouseMoved(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_windowMovedFlag)) return; - - RGFW_event e; - e.type = RGFW_mousePosChanged; - NSPoint p = ((NSPoint(*)(id, SEL))objc_msgSend)(event, sel_registerName("locationInWindow")); - e.mouse.x = (i32)p.x; - e.mouse.y = (i32)(win->h - p.y); - p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX")); - p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY")); - e.mouse.vecX = (float)p.x; - e.mouse.vecY = (float)p.y; - _RGFW->vectorX = e.mouse.vecX; - _RGFW->vectorY = e.mouse.vecY; - win->internal.lastMouseX = e.mouse.x; - win->internal.lastMouseY = e.mouse.y; - e.common.win = win; - - RGFW_eventQueuePush(&e); - RGFW_mousePosCallback(win, e.mouse.x, e.mouse.y, e.mouse.vecX, e.mouse.vecY); -} - -static void RGFW__osxMouseDown(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL || !(win->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return; - - RGFW_event e; - u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber")); - switch (buttonNumber) { - case 0: e.button.value = RGFW_mouseLeft; break; - case 1: e.button.value = RGFW_mouseRight; break; - case 2: e.button.value = RGFW_mouseMiddle; break; - default: e.button.value = (u8)buttonNumber; - } - e.type = RGFW_mouseButtonPressed; - _RGFW->mouseButtons[e.button.value].prev = _RGFW->mouseButtons[e.button.value].current; - _RGFW->mouseButtons[e.button.value].current = 1; - e.common.win = win; - - RGFW_eventQueuePush(&e); - RGFW_mouseButtonCallback(win, e.button.value, 1); -} - -static void RGFW__osxMouseUp(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL|| !(win->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return; - - RGFW_event e; - u32 buttonNumber = (u32)((u32(*)(id, SEL))objc_msgSend)(event, sel_registerName("buttonNumber")); - switch (buttonNumber) { - case 0: e.button.value = RGFW_mouseLeft; break; - case 1: e.button.value = RGFW_mouseRight; break; - case 2: e.button.value = RGFW_mouseMiddle; break; - default: e.button.value = (u8)buttonNumber; - } - e.type = RGFW_mouseButtonReleased; - _RGFW->mouseButtons[e.button.value].prev = _RGFW->mouseButtons[e.button.value].current; - _RGFW->mouseButtons[e.button.value].current = 0; - e.common.win = win; - - RGFW_eventQueuePush(&e); - RGFW_mouseButtonCallback(win, e.button.value, 0); -} - -static void RGFW__osxScrollWheel(id self, SEL _cmd, id event) { - RGFW_UNUSED(_cmd); - RGFW_window* win = NULL; - object_getInstanceVariable(self, "RGFW_window", (void**)&win); - if (win == NULL|| !(win->internal.enabledEvents & RGFW_mouseScroll)) return; - - RGFW_event e; - float deltaX = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaX")); - float deltaY = (float)((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(event, sel_registerName("deltaY")); - - e.type = RGFW_mouseScroll; - e.scroll.x = deltaX; - e.scroll.y = deltaY; - e.common.win = win; - _RGFW->scrollX = e.scroll.x; - _RGFW->scrollY = e.scroll.y; - - RGFW_eventQueuePush(&e); - RGFW_mouseScrollCallback(win, deltaX, deltaY); -} - -RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { - surface->data = data; - surface->w = w; - surface->h = h; - surface->format = format; - surface->native.format = RGFW_formatRGBA8; - return RGFW_TRUE; -} - -void RGFW_surface_freePtr(RGFW_surface* surface) { RGFW_UNUSED(surface); } - -void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { - RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), surface->native.format, surface->data, surface->format); - - size_t depth = (surface->format >= RGFW_formatRGBA8) ? 4 : 3; - id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc")); - NSSize size = (NSSize){(double)surface->w, (double)surface->h}; - image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size); - - int minX = RGFW_MIN(win->w, surface->w); - int minY = RGFW_MIN(win->h, surface->h); - - id rep = NSBitmapImageRep_initWithBitmapData(&surface->data, minX, minY, 8, (i32)depth, (depth == 4), false, "NSDeviceRGBColorSpace", 1 << 1, (u32)surface->w * (u32)depth, 8 * (u32)depth); - RGFW_copyImageData(NSBitmapImageRep_bitmapData(rep), minX, minY , RGFW_formatRGBA8, surface->data, surface->format); - ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep); - - id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView")); - ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES); - id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer")); - - ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image); - ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES); - - NSRelease(rep); - NSRelease(image); -} - -void* RGFW_window_getView_OSX(RGFW_window* win) { return win->src.view; } - -void RGFW_window_setLayer_OSX(RGFW_window* win, void* layer) { +void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) { objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer"), (id)layer); } -void* RGFW_getLayer_OSX(void) { +void* RGFW_cocoaGetLayer(void) { return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer")); } -void* RGFW_window_getWindow_OSX(RGFW_window* win) { return win->src.window; } -void RGFW_initKeycodesPlatform(void) { - _RGFW->keycodes[0x1D] = RGFW_0; - _RGFW->keycodes[0x12] = RGFW_1; - _RGFW->keycodes[0x13] = RGFW_2; - _RGFW->keycodes[0x14] = RGFW_3; - _RGFW->keycodes[0x15] = RGFW_4; - _RGFW->keycodes[0x17] = RGFW_5; - _RGFW->keycodes[0x16] = RGFW_6; - _RGFW->keycodes[0x1A] = RGFW_7; - _RGFW->keycodes[0x1C] = RGFW_8; - _RGFW->keycodes[0x19] = RGFW_9; - _RGFW->keycodes[0x00] = RGFW_a; - _RGFW->keycodes[0x0B] = RGFW_b; - _RGFW->keycodes[0x08] = RGFW_c; - _RGFW->keycodes[0x02] = RGFW_d; - _RGFW->keycodes[0x0E] = RGFW_e; - _RGFW->keycodes[0x03] = RGFW_f; - _RGFW->keycodes[0x05] = RGFW_g; - _RGFW->keycodes[0x04] = RGFW_h; - _RGFW->keycodes[0x22] = RGFW_i; - _RGFW->keycodes[0x26] = RGFW_j; - _RGFW->keycodes[0x28] = RGFW_k; - _RGFW->keycodes[0x25] = RGFW_l; - _RGFW->keycodes[0x2E] = RGFW_m; - _RGFW->keycodes[0x2D] = RGFW_n; - _RGFW->keycodes[0x1F] = RGFW_o; - _RGFW->keycodes[0x23] = RGFW_p; - _RGFW->keycodes[0x0C] = RGFW_q; - _RGFW->keycodes[0x0F] = RGFW_r; - _RGFW->keycodes[0x01] = RGFW_s; - _RGFW->keycodes[0x11] = RGFW_t; - _RGFW->keycodes[0x20] = RGFW_u; - _RGFW->keycodes[0x09] = RGFW_v; - _RGFW->keycodes[0x0D] = RGFW_w; - _RGFW->keycodes[0x07] = RGFW_x; - _RGFW->keycodes[0x10] = RGFW_y; - _RGFW->keycodes[0x06] = RGFW_z; - _RGFW->keycodes[0x27] = RGFW_apostrophe; - _RGFW->keycodes[0x2A] = RGFW_backSlash; - _RGFW->keycodes[0x2B] = RGFW_comma; - _RGFW->keycodes[0x18] = RGFW_equals; - _RGFW->keycodes[0x32] = RGFW_backtick; - _RGFW->keycodes[0x21] = RGFW_bracket; - _RGFW->keycodes[0x1B] = RGFW_minus; - _RGFW->keycodes[0x2F] = RGFW_period; - _RGFW->keycodes[0x1E] = RGFW_closeBracket; - _RGFW->keycodes[0x29] = RGFW_semicolon; - _RGFW->keycodes[0x2C] = RGFW_slash; - _RGFW->keycodes[0x0A] = RGFW_world1; - _RGFW->keycodes[0x33] = RGFW_backSpace; - _RGFW->keycodes[0x39] = RGFW_capsLock; - _RGFW->keycodes[0x75] = RGFW_delete; - _RGFW->keycodes[0x7D] = RGFW_down; - _RGFW->keycodes[0x77] = RGFW_end; - _RGFW->keycodes[0x24] = RGFW_enter; - _RGFW->keycodes[0x35] = RGFW_escape; - _RGFW->keycodes[0x7A] = RGFW_F1; - _RGFW->keycodes[0x78] = RGFW_F2; - _RGFW->keycodes[0x63] = RGFW_F3; - _RGFW->keycodes[0x76] = RGFW_F4; - _RGFW->keycodes[0x60] = RGFW_F5; - _RGFW->keycodes[0x61] = RGFW_F6; - _RGFW->keycodes[0x62] = RGFW_F7; - _RGFW->keycodes[0x64] = RGFW_F8; - _RGFW->keycodes[0x65] = RGFW_F9; - _RGFW->keycodes[0x6D] = RGFW_F10; - _RGFW->keycodes[0x67] = RGFW_F11; - _RGFW->keycodes[0x6F] = RGFW_F12; - _RGFW->keycodes[0x69] = RGFW_printScreen; - _RGFW->keycodes[0x6B] = RGFW_F14; - _RGFW->keycodes[0x71] = RGFW_F15; - _RGFW->keycodes[0x6A] = RGFW_F16; - _RGFW->keycodes[0x40] = RGFW_F17; - _RGFW->keycodes[0x4F] = RGFW_F18; - _RGFW->keycodes[0x50] = RGFW_F19; - _RGFW->keycodes[0x5A] = RGFW_F20; - _RGFW->keycodes[0x73] = RGFW_home; - _RGFW->keycodes[0x72] = RGFW_insert; - _RGFW->keycodes[0x7B] = RGFW_left; - _RGFW->keycodes[0x3A] = RGFW_altL; - _RGFW->keycodes[0x3B] = RGFW_controlL; - _RGFW->keycodes[0x38] = RGFW_shiftL; - _RGFW->keycodes[0x37] = RGFW_superL; - _RGFW->keycodes[0x6E] = RGFW_menu; - _RGFW->keycodes[0x47] = RGFW_numLock; - _RGFW->keycodes[0x79] = RGFW_pageDown; - _RGFW->keycodes[0x74] = RGFW_pageUp; - _RGFW->keycodes[0x7C] = RGFW_right; - _RGFW->keycodes[0x3D] = RGFW_altR; - _RGFW->keycodes[0x3E] = RGFW_controlR; - _RGFW->keycodes[0x3C] = RGFW_shiftR; - _RGFW->keycodes[0x36] = RGFW_superR; - _RGFW->keycodes[0x31] = RGFW_space; - _RGFW->keycodes[0x30] = RGFW_tab; - _RGFW->keycodes[0x7E] = RGFW_up; - _RGFW->keycodes[0x52] = RGFW_kp0; - _RGFW->keycodes[0x53] = RGFW_kp1; - _RGFW->keycodes[0x54] = RGFW_kp2; - _RGFW->keycodes[0x55] = RGFW_kp3; - _RGFW->keycodes[0x56] = RGFW_kp4; - _RGFW->keycodes[0x57] = RGFW_kp5; - _RGFW->keycodes[0x58] = RGFW_kp6; - _RGFW->keycodes[0x59] = RGFW_kp7; - _RGFW->keycodes[0x5B] = RGFW_kp8; - _RGFW->keycodes[0x5C] = RGFW_kp9; - _RGFW->keycodes[0x45] = RGFW_kpSlash; - _RGFW->keycodes[0x41] = RGFW_kpPeriod; - _RGFW->keycodes[0x4B] = RGFW_kpSlash; - _RGFW->keycodes[0x4C] = RGFW_kpReturn; - _RGFW->keycodes[0x51] = RGFW_kpEqual; - _RGFW->keycodes[0x43] = RGFW_kpMultiply; - _RGFW->keycodes[0x4E] = RGFW_kpMinus; +NSPasteboardType const NSPasteboardTypeURL = "public.url"; +NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url"; + +id RGFW__osx_generateViewClass(const char* subclass, RGFW_window* win) { + Class customViewClass; + customViewClass = objc_allocateClassPair(objc_getClass(subclass), "RGFWCustomView", 0); + + class_addIvar( customViewClass, "RGFW_window", sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), "L"); + class_addMethod(customViewClass, sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}"); + class_addMethod(customViewClass, sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, ""); + + id customView = objc_msgSend_id(NSAlloc(customViewClass), sel_registerName("init")); + object_setInstanceVariable(customView, "RGFW_window", win); + + return customView; } -i32 RGFW_initPlatform(void) { - class_addMethod(objc_getClass("NSObject"), sel_registerName("windowShouldClose:"), (IMP)(void*)RGFW_OnClose, 0); +#ifndef RGFW_EGL +void RGFW_window_initOpenGL(RGFW_window* win) { +#ifdef RGFW_OPENGL + void* attrs = RGFW_initFormatAttribs(); + void* format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)attrs); + + if (format == NULL) { + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to load pixel format for OpenGL"); + win->_flags |= RGFW_windowOpenglSoftware; + void* subAttrs = RGFW_initFormatAttribs(); + format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)subAttrs); + + if (format == NULL) + RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "and loading software rendering OpenGL failed"); + else + RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Switching to software rendering"); + } + + /* the pixel format can be passed directly to opengl context creation to create a context + this is because the format also includes information about the opengl version (which may be a bad thing) */ + + win->src.view = (id) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) (RGFW__osx_generateViewClass("NSOpenGLView", win), + sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {win->r.w, win->r.h}}, (uint32_t*)format); + + objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL")); + win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext")); + + if (win->_flags & RGFW_windowTransparent) { + i32 opacity = 0; + #define NSOpenGLCPSurfaceOpacity 236 + NSOpenGLContext_setValues((id)win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity); + } + + objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); +#else + RGFW_UNUSED(win); +#endif +} + +void RGFW_window_freeOpenGL(RGFW_window* win) { +#ifdef RGFW_OPENGL + if (win->src.ctx == NULL) return; + objc_msgSend_void(win->src.ctx, sel_registerName("release")); + win->src.ctx = NULL; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); +#else + RGFW_UNUSED(win); +#endif +} +#endif + + +i32 RGFW_init(void) { +#if defined(RGFW_C89) || defined(__cplusplus) + if (_RGFW_init) return 0; + _RGFW_init = RGFW_TRUE; + _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -1; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; +#endif + + /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea??? + Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance). + */ + si_func_to_SEL_with_name("NSObject", "windowShouldClose", (void*)RGFW_OnClose); /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */ - class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("acceptsFirstResponder:"), (IMP)(void*)RGFW__osxAcceptsFirstResponder, 0); - class_addMethod(objc_getClass("NSWindowClass"), sel_registerName("performKeyEquivalent:"), (IMP)(void*)RGFW__osxPerformKeyEquivalent, 0); + si_func_to_SEL("NSWindow", acceptsFirstResponder); + si_func_to_SEL("NSWindow", performKeyEquivalent); - _RGFW->NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); + if (NSApp == NULL) { + NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); - ((void (*)(id, SEL, NSUInteger))objc_msgSend) - ((id)_RGFW->NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); + ((void (*)(id, SEL, NSUInteger))objc_msgSend) + (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); - _RGFW->customViewClasses[0] = objc_allocateClassPair(objc_getClass("NSView"), "RGFWCustomView", 0); - _RGFW->customViewClasses[1] = objc_allocateClassPair(objc_getClass("NSOpenGLView"), "RGFWOpenGLCustomView", 0); - for (size_t i = 0; i < 2; i++) { - class_addIvar((Class)_RGFW->customViewClasses[i], "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "v@:"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDown:"), (IMP)RGFW__osxMouseDown, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseUp:"), (IMP)RGFW__osxMouseUp, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("scrollWheel:"), (IMP)RGFW__osxScrollWheel, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("rightMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("otherMouseDragged:"), (IMP)RGFW__osxMouseMoved, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyDown:"), (IMP)RGFW__osxKeyDown, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("keyUp:"), (IMP)RGFW__osxKeyUp, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseMoved:"), (IMP)RGFW__osxMouseMoved, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseEntered:"), (IMP)RGFW__osxMouseEntered, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("mouseExited:"), (IMP)RGFW__osxMouseExited, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("flagsChanged:"), (IMP)RGFW__osxFlagsChanged, "v@:@"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_getUid("acceptsFirstResponder"), (IMP)RGFW__osxAcceptsFirstResponder, "B@:"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("initWithRGFWWindow:"), (IMP)RGFW__osxCustomInitWithRGFWWindow, "@@:{CGRect={CGPoint=dd}{CGSize=dd}}"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("wantsUpdateLayer"), (IMP)RGFW__osxWantsUpdateLayer, "B@:"); - class_addMethod((Class)_RGFW->customViewClasses[i], sel_registerName("updateLayer"), (IMP)RGFW__osxUpdateLayer, "v@:"); - objc_registerClassPair((Class)_RGFW->customViewClasses[i]); + #ifndef RGFW_NO_IOKIT + RGFW_osxInitIOKit(); + #endif } - _RGFW->customWindowDelegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "RGFWWindowDelegate", 0); - class_addIvar((Class)_RGFW->customWindowDelegateClass, "RGFW_window", sizeof(RGFW_window*), sizeof(RGFW_window*), "L"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResize:"), (IMP)RGFW__osxDidWindowResize, "v@:@"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, ""); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, ""); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, ""); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, ""); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, ""); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEntered:"), (IMP)RGFW__osxDraggingEntered, "l@:@"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingUpdated:"), (IMP)RGFW__osxDraggingUpdated, "l@:@"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("prepareForDragOperation:"), (IMP)RGFW__osxPrepareForDragOperation, "B@:@"); - class_addMethod((Class)_RGFW->customWindowDelegateClass, sel_registerName("performDragOperation:"), (IMP)RGFW__osxPerformDragOperation, "B@:@"); - objc_registerClassPair((Class)_RGFW->customWindowDelegateClass); - return 0; + + _RGFW.windowCount = 0; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); + return 0; } -void RGFW_osx_initView(RGFW_window* win) { - NSRect contentRect; - contentRect.origin.x = 0; - contentRect.origin.y = 0; - contentRect.size.width = (double)win->w; - contentRect.size.height = (double)win->h; - ((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), contentRect); +RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { + static u8 RGFW_loaded = 0; + RGFW_window_basic_init(win, rect, flags); - - if (RGFW_COCOA_FRAME_NAME) - objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME); - - object_setInstanceVariable((id)win->src.view, "RGFW_window", win); - objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view); - objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true); - objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); - - id trackingArea = objc_msgSend_id(objc_getClass("NSTrackingArea"), sel_registerName("alloc")); - trackingArea = ((id (*)(id, SEL, NSRect, NSUInteger, id, id))objc_msgSend)( - trackingArea, - sel_registerName("initWithRect:options:owner:userInfo:"), - contentRect, - NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect, - (id)win->src.view, - nil - ); - - ((void (*)(id, SEL, id))objc_msgSend)((id)win->src.view, sel_registerName("addTrackingArea:"), trackingArea); - ((void (*)(id, SEL))objc_msgSend)(trackingArea, sel_registerName("release")); -} - -RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { - /* RR Create an autorelease pool */ + /* RR Create an autorelease pool */ id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); pool = objc_msgSend_id(pool, sel_registerName("init")); RGFW_window_setMouseDefault(win); NSRect windowRect; - windowRect.origin.x = (double)win->x; - windowRect.origin.y = (double)win->y; - windowRect.size.width = (double)win->w; - windowRect.size.height = (double)win->h; - NSBackingStoreType macArgs = (NSBackingStoreType)(NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled); + windowRect.origin.x = win->r.x; + windowRect.origin.y = win->r.y; + windowRect.size.width = win->r.w; + windowRect.size.height = win->r.h; + + NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled; if (!(flags & RGFW_windowNoResize)) - macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskResizable); + macArgs |= NSWindowStyleMaskResizable; if (!(flags & RGFW_windowNoBorder)) - macArgs = (NSBackingStoreType)(macArgs | (NSBackingStoreType)NSWindowStyleMaskTitled); + macArgs |= NSWindowStyleMaskTitled; { void* nsclass = objc_getClass("NSWindow"); SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend) - (NSAlloc(nsclass), func, windowRect, (NSWindowStyleMask)macArgs, macArgs, false); + (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false); } id str = NSString_stringWithUTF8String(name); objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str); - id delegate = objc_msgSend_id(NSAlloc((Class)_RGFW->customWindowDelegateClass), sel_registerName("init")); - object_setInstanceVariable(delegate, "RGFW_window", win); + if ((flags & RGFW_windowNoInitAPI) == 0) { + RGFW_window_initOpenGL(win); + RGFW_window_initBuffer(win); + } - objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate); + #ifdef RGFW_OPENGL + else + #endif + { + NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}}; + win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) (NSAlloc(objc_getClass("NSView")), sel_registerName("initWithFrame:"), contentRect); + } - if (flags & RGFW_windowAllowDND) { - win->internal.flags |= RGFW_windowAllowDND; - - NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString}; - NSregisterForDraggedTypes((id)win->src.window, types, 3); - } - - objc_msgSend_void_bool((id)win->src.window, sel_registerName("setAcceptsMouseMovedEvents:"), true); + void* contentView = NSWindow_contentView((id)win->src.window); + objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true); + objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); + objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view); if (flags & RGFW_windowTransparent) { objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), - NSColor_colorWithSRGB(0, 0, 0, 0)); + NSColor_colorWithSRGB(0, 0, 0, 0)); } - /* Show the window */ - objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true); + Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0); - if (_RGFW->root == NULL) { + class_addIvar( + delegateClass, "RGFW_window", + sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), + "L" + ); + + class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}"); + class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, ""); + class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, ""); + class_addMethod(delegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, ""); + class_addMethod(delegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, ""); + class_addMethod(delegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, ""); + class_addMethod(delegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, ""); + class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@"); + class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@"); + class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); + class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); + class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@"); + class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@"); + + id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init")); + + if (RGFW_COCOA_FRAME_NAME) + objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME); + + object_setInstanceVariable(delegate, "RGFW_window", win); + + objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate); + + if (flags & RGFW_windowAllowDND) { + win->_flags |= RGFW_windowAllowDND; + + NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString}; + NSregisterForDraggedTypes((id)win->src.window, types, 3); + } + + RGFW_window_setFlags(win, flags); + + /* Show the window */ + objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); + ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); + RGFW_window_show(win); + + if (!RGFW_loaded) { objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow")); + + RGFW_loaded = 1; } objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow")); - objc_msgSend_void((id)_RGFW->NSApp, sel_registerName("finishLaunching")); + objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); NSRetain(win->src.window); - NSRetain(_RGFW->NSApp); + NSRetain(NSApp); - win->src.view = ((id(*)(id, SEL, RGFW_window*))objc_msgSend) (NSAlloc((Class)_RGFW->customViewClasses[0]), sel_registerName("initWithRGFWWindow:"), win); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); return win; } void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); - double offset = 0; + float offset = 0; - RGFW_setBit(&win->internal.flags, RGFW_windowNoBorder, !border); - NSBackingStoreType storeType = (NSBackingStoreType)(NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView); + RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border); + NSBackingStoreType storeType = NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView; if (border) - storeType = (NSBackingStoreType)(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable); - if (!(win->internal.flags & RGFW_windowNoResize)) { - storeType = (NSBackingStoreType)(storeType | (NSBackingStoreType)NSWindowStyleMaskResizable); + storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; + if (!(win->_flags & RGFW_windowNoResize)) { + storeType |= NSWindowStyleMaskResizable; } ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType); @@ -11910,25 +9192,84 @@ void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview")); objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true); - offset = (double)(frame.size.height - content.size.height); + offset = (float)(frame.size.height - content.size.height); } - RGFW_window_resize(win, win->w, win->h + (i32)offset); - win->h -= (i32)offset; + RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h + offset)); + win->r.h -= (i32)offset; } -RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { - RGFW_ASSERT(_RGFW->root != NULL); +RGFW_area RGFW_getScreenSize(void) { + static CGDirectDisplayID display = 0; + + if (display == 0) + display = CGMainDisplayID(); + + return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display)); +} + +RGFW_point RGFW_getGlobalMousePoint(void) { + RGFW_ASSERT(_RGFW.root != NULL); CGEventRef e = CGEventCreate(NULL); CGPoint point = CGEventGetLocation(e); CFRelease(e); - if (x) *x = (i32)point.x; - if (y) *y = (i32)point.y; - return RGFW_TRUE; + return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */ } +typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */ + NSEventTypeLeftMouseDown = 1, + NSEventTypeLeftMouseUp = 2, + NSEventTypeRightMouseDown = 3, + NSEventTypeRightMouseUp = 4, + NSEventTypeMouseMoved = 5, + NSEventTypeLeftMouseDragged = 6, + NSEventTypeRightMouseDragged = 7, + NSEventTypeMouseEntered = 8, + NSEventTypeMouseExited = 9, + NSEventTypeKeyDown = 10, + NSEventTypeKeyUp = 11, + NSEventTypeFlagsChanged = 12, + NSEventTypeAppKitDefined = 13, + NSEventTypeSystemDefined = 14, + NSEventTypeApplicationDefined = 15, + NSEventTypePeriodic = 16, + NSEventTypeCursorUpdate = 17, + NSEventTypeScrollWheel = 22, + NSEventTypeTabletPoint = 23, + NSEventTypeTabletProximity = 24, + NSEventTypeOtherMouseDown = 25, + NSEventTypeOtherMouseUp = 26, + NSEventTypeOtherMouseDragged = 27, + /* The following event types are available on some hardware on 10.5.2 and later */ + NSEventTypeGesture = 29, + NSEventTypeMagnify = 30, + NSEventTypeSwipe = 31, + NSEventTypeRotate = 18, + NSEventTypeBeginGesture = 19, + NSEventTypeEndGesture = 20, + + NSEventTypeSmartMagnify = 32, + NSEventTypeQuickLook = 33, + + NSEventTypePressure = 34, + NSEventTypeDirectTouch = 37, + + NSEventTypeChangeMode = 38, +}; + +typedef unsigned long long NSEventMask; + +typedef enum NSEventModifierFlags { + NSEventModifierFlagCapsLock = 1 << 16, + NSEventModifierFlagShift = 1 << 17, + NSEventModifierFlagControl = 1 << 18, + NSEventModifierFlagOption = 1 << 19, + NSEventModifierFlagCommand = 1 << 20, + NSEventModifierFlagNumericPad = 1 << 21 +} NSEventModifierFlags; + void RGFW_stopCheckEvents(void) { id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); @@ -11938,12 +9279,14 @@ void RGFW_stopCheckEvents(void) { NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0); ((void (*)(id, SEL, id, bool))objc_msgSend) - ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1); + (NSApp, sel_registerName("postEvent:atStart:"), e, 1); objc_msgSend_bool_void(eventPool, sel_registerName("drain")); } -void RGFW_waitForEvent(i32 waitMS) { +void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { + RGFW_UNUSED(win); + id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); @@ -11952,12 +9295,12 @@ void RGFW_waitForEvent(i32 waitMS) { SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) - ((id)_RGFW->NSApp, eventFunc, + (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); if (e) { ((void (*)(id, SEL, id, bool))objc_msgSend) - ((id)_RGFW->NSApp, sel_registerName("postEvent:atStart:"), e, 1); + (NSApp, sel_registerName("postEvent:atStart:"), e, 1); } objc_msgSend_bool_void(eventPool, sel_registerName("drain")); @@ -11967,66 +9310,251 @@ u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { return (u8)rgfw_keycode; /* TODO */ } -void RGFW_pollEvents(void) { - /* - * TODO look to see if all these events can be replaced with callbacks - * callbacks seem to give better info on mac's api - */ +RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { + if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; - RGFW_resetPrevState(); + objc_msgSend_void((id)win->src.mouse, sel_registerName("set")); + RGFW_event* ev = RGFW_window_checkEventCore(win); + if (ev) { + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return ev; + } id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); + SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); - while (1) { - void* date = NULL; - id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) - ((id)_RGFW->NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); + void* date = NULL; - if (e == NULL) { - objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)((id)_RGFW->NSApp, sel_registerName("updateWindows")); + id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend) + (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); + + if (e == NULL) { + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return NULL; + } + + if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) { + ((void (*)(id, SEL, id, bool))objc_msgSend) + (NSApp, sel_registerName("postEvent:atStart:"), e, 0); + + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return NULL; + } + + if (win->event.droppedFilesCount) { + u32 i; + for (i = 0; i < win->event.droppedFilesCount; i++) + win->event.droppedFiles[i][0] = '\0'; + } + + win->event.droppedFilesCount = 0; + win->event.type = 0; + + u32 type = (u32)objc_msgSend_uint(e, sel_registerName("type")); + switch (type) { + case NSEventTypeMouseEntered: { + win->event.type = RGFW_mouseEnter; + 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); break; } - RGFW_event event; - RGFW_MEMSET(&event, 0, sizeof(event)); - objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("sendEvent:"), e); - ((void(*)(id, SEL))objc_msgSend)((id)_RGFW->NSApp, sel_registerName("updateWindows")); + case NSEventTypeMouseExited: + win->event.type = RGFW_mouseLeave; + RGFW_mouseNotifyCallback(win, win->event.point, 0); + break; + + case NSEventTypeKeyDown: { + 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"))))); + if (((u8)mappedKey) == 239) + mappedKey = 0; + + win->event.keyChar = (u8)mappedKey; + + win->event.key = (u8)RGFW_apiKeyToRGFW(key); + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; + + win->event.type = RGFW_keyPressed; + 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.keyMod, 1); + break; + } + + case NSEventTypeKeyUp: { + 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"))))); + if (((u8)mappedKey) == 239) + mappedKey = 0; + + win->event.keyChar = (u8)mappedKey; + + win->event.key = (u8)RGFW_apiKeyToRGFW(key); + + RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current; + + win->event.type = RGFW_keyReleased; + + RGFW_keyboard[win->event.key].current = 0; + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0); + break; + } + + case NSEventTypeFlagsChanged: { + u32 flags = (u32)objc_msgSend_uint(e, sel_registerName("modifierFlags")); + RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255), + ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255), + ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0); + u8 i; + for (i = 0; i < 9; i++) + RGFW_keyboard[i + RGFW_capsLock].prev = 0; + + for (i = 0; i < 5; i++) { + u32 shift = (1 << (i + 16)); + u32 key = i + RGFW_capsLock; + + if ((flags & shift) && !RGFW_wasPressed(win, (u8)key)) { + RGFW_keyboard[key].current = 1; + + if (key != RGFW_capsLock) + RGFW_keyboard[key+ 4].current = 1; + + win->event.type = RGFW_keyPressed; + win->event.key = (u8)key; + break; + } + + if (!(flags & shift) && RGFW_wasPressed(win, (u8)key)) { + RGFW_keyboard[key].current = 0; + + if (key != RGFW_capsLock) + RGFW_keyboard[key + 4].current = 0; + + win->event.type = RGFW_keyReleased; + win->event.key = (u8)key; + break; + } + } + + RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed); + + break; + } + case NSEventTypeLeftMouseDragged: + case NSEventTypeOtherMouseDragged: + case NSEventTypeRightMouseDragged: + case NSEventTypeMouseMoved: { + win->event.type = RGFW_mousePosChanged; + NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); + win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); + + p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX")); + p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); + win->event.vector = RGFW_POINT((i32)p.x, (i32)p.y); + + win->_lastMousePoint = win->event.point; + RGFW_mousePosCallback(win, win->event.point, win->event.vector); + break; + } + case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: { + u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber")); + switch (buttonNumber) { + case 0: win->event.button = RGFW_mouseLeft; break; + case 1: win->event.button = RGFW_mouseRight; break; + case 2: win->event.button = RGFW_mouseMiddle; break; + default: win->event.button = (u8)buttonNumber; + } + + win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); + break; + } + case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: { + u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber")); + switch (buttonNumber) { + case 0: win->event.button = RGFW_mouseLeft; break; + case 1: win->event.button = RGFW_mouseRight; break; + case 2: win->event.button = RGFW_mouseMiddle; break; + default: win->event.button = (u8)buttonNumber; + } + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 0; + win->event.type = RGFW_mouseButtonReleased; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); + break; + } + case NSEventTypeScrollWheel: { + double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); + + if (deltaY > 0) { + win->event.button = RGFW_mouseScrollUp; + } + else if (deltaY < 0) { + win->event.button = RGFW_mouseScrollDown; + } + + RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; + RGFW_mouseButtons[win->event.button].current = 1; + + win->event.scroll = deltaY; + + win->event.type = RGFW_mouseButtonPressed; + RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); + break; + } + + default: + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); + return RGFW_window_checkEvent(win); } + objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); + ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); objc_msgSend_bool_void(eventPool, sel_registerName("drain")); + return &win->event; } -void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { +void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_ASSERT(win != NULL); - win->x = x; - win->y = y; - ((void(*)(id,SEL,NSPoint))objc_msgSend)((id)win->src.window, sel_registerName("setFrameOrigin:"), (NSPoint){(double)x, (double)y}); + win->r.x = v.x; + win->r.y = v.y; + ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) + ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); } -void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { +void RGFW_window_resize(RGFW_window* win, RGFW_area a) { RGFW_ASSERT(win != NULL); NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame")); NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame")); float offset = (float)(frame.size.height - content.size.height); - win->w = w; - win->h = h; + win->r.w = (i32)a.w; + win->r.h = (i32)a.h; - - ((void(*)(id, SEL, CGRect))objc_msgSend)((id)win->src.view, sel_registerName("setFrame:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}}); ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) - ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{(double)win->x, (double)win->y}, {(double)win->w, (double)win->h + (double)offset}}, true, true); + ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h + offset}}, true, true); } void RGFW_window_focus(RGFW_window* win) { RGFW_ASSERT(win); - objc_msgSend_void_bool((id)_RGFW->NSApp, sel_registerName("activateIgnoringOtherApps:"), true); + objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow")); } @@ -12038,38 +9566,25 @@ void RGFW_window_raise(RGFW_window* win) { void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_ASSERT(win != NULL); - if (fullscreen && (win->internal.flags & RGFW_windowFullscreen)) return; - if (!fullscreen && !(win->internal.flags & RGFW_windowFullscreen)) return; + if (fullscreen && (win->_flags & RGFW_windowFullscreen)) return; + if (!fullscreen && !(win->_flags & RGFW_windowFullscreen)) return; if (fullscreen) { - if (!(win->internal.flags & RGFW_windowFullscreen)) { - return; - } - - win->internal.oldX = win->x; - win->internal.oldY = win->y; - win->internal.oldW = win->w; - win->internal.oldH = win->h; + win->_oldRect = win->r; RGFW_monitor mon = RGFW_window_getMonitor(win); - win->x = mon.x; - win->y = mon.y; - win->w = mon.mode.w; - win->h = mon.mode.h; - win->internal.flags |= RGFW_windowFullscreen; - RGFW_window_resize(win, mon.mode.w, mon.mode.h); - RGFW_window_move(win, mon.x, mon.y); + win->r = RGFW_RECT(0, 0, mon.x, mon.y); + win->_flags |= RGFW_windowFullscreen; + RGFW_window_resize(win, RGFW_AREA(mon.mode.area.w, mon.mode.area.h)); + RGFW_window_move(win, RGFW_POINT(0, 0)); } objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL); if (!fullscreen) { - win->x = win->internal.oldX; - win->y = win->internal.oldY; - win->w = win->internal.oldW; - win->h = win->internal.oldH; - win->internal.flags &= ~(u32)RGFW_windowFullscreen; + win->r = win->_oldRect; + win->_flags &= ~(u32)RGFW_windowFullscreen; - RGFW_window_resize(win, win->w, win->h); - RGFW_window_move(win, win->x, win->y); + RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); + RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y)); } } @@ -12077,7 +9592,7 @@ void RGFW_window_maximize(RGFW_window* win) { RGFW_ASSERT(win != NULL); if (RGFW_window_isMaximized(win)) return; - win->internal.flags |= RGFW_windowMaximize; + win->_flags |= RGFW_windowMaximize; objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL); } @@ -12130,75 +9645,81 @@ void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { } #endif -void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { - if (w == 0 && h == 0) { w = 1; h = 1; }; +void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { + if (a.w == 0 && a.h == 0) a = RGFW_AREA(1, 1); ((void (*)(id, SEL, NSSize))objc_msgSend) - ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){(CGFloat)w, (CGFloat)h}); + ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){a.w, a.h}); } -void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { - ((void (*)(id, SEL, NSSize))objc_msgSend) ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){(CGFloat)w, (CGFloat)h}); +void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { + ((void (*)(id, SEL, NSSize))objc_msgSend) + ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h}); } -void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { - if (w == 0 && h == 0) { - RGFW_monitor mon = RGFW_window_getMonitor(win); - w = mon.mode.w; - h = mon.mode.h; +void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { + if (a.w == 0 && a.h == 0) { + a = RGFW_getScreenSize(); } ((void (*)(id, SEL, NSSize))objc_msgSend) - ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){(CGFloat)w, (CGFloat)h}); + ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h}); } -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { +RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, RGFW_area area, i32 channels, u8 type) { RGFW_ASSERT(win != NULL); RGFW_UNUSED(type); if (data == NULL) { - objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), NULL); + objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), NULL); return RGFW_TRUE; } - id representation = NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32); - RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format); + /* code by EimaMei: Make a bitmap representation, then copy the loaded image into it. */ + id representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * (u32)channels, 8 * (u32)channels); + RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * (u32)channels); - id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h})); + /* Add ze representation. */ + id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){area.w, area.h})); objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation); - objc_msgSend_void_id((id)_RGFW->NSApp, sel_registerName("setApplicationIconImage:"), dock_image); - + /* Finally, set the dock image to it. */ + objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image); + /* Free the garbage. */ NSRelease(dock_image); NSRelease(representation); return RGFW_TRUE; } -id NSCursor_arrowStr(const char* str); id NSCursor_arrowStr(const char* str) { void* nclass = objc_getClass("NSCursor"); SEL func = sel_registerName(str); return (id) objc_msgSend_id(nclass, func); } -RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { - if (data == NULL) { +RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { + if (icon == NULL) { objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set")); return NULL; } - id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, w, h, 8, (NSInteger)4, true, false, "NSCalibratedRGBColorSpace", 1 << 1, w * 4, 32); - RGFW_copyImageData(NSBitmapImageRep_bitmapData(representation), w, h, RGFW_formatRGBA8, data, format); + /* NOTE(EimaMei): Code by yours truly. */ + /* Make a bitmap representation, then copy the loaded image into it. */ + id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * (u32)channels, 8 * (u32)channels); + RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), icon, a.w * a.h * (u32)channels); - id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){(CGFloat)w, (CGFloat)h})); + /* Add ze representation. */ + id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){a.w, a.h})); objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation); + /* Finally, set the cursor image. */ id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend) (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0}); + /* Free the garbage. */ NSRelease(cursor_image); NSRelease(representation); @@ -12251,19 +9772,18 @@ void RGFW_releaseCursor(RGFW_window* win) { CGAssociateMouseAndMouseCursorPosition(1); } -void RGFW_captureCursor(RGFW_window* win) { +void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); - CGWarpMouseCursorPosition((CGPoint){(CGFloat)(win->x + (win->w / 2)), (CGFloat)(win->y + (win->h / 2))}); + CGWarpMouseCursorPosition((CGPoint){r.x + (r.w / 2), r.y + (r.h / 2)}); CGAssociateMouseAndMouseCursorPosition(0); } -void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { +void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); - win->internal.lastMouseX = x - win->x; - win->internal.lastMouseY = y - win->y; - CGWarpMouseCursorPosition((CGPoint){(CGFloat)x, (CGFloat)y}); + win->_lastMousePoint = RGFW_POINT(v.x - win->r.x, v.y - win->r.y); + CGWarpMouseCursorPosition((CGPoint){v.x, v.y}); } @@ -12272,7 +9792,7 @@ void RGFW_window_hide(RGFW_window* win) { } void RGFW_window_show(RGFW_window* win) { - if (win->internal.flags & RGFW_windowFocusOnShow) + if (win->_flags & RGFW_windowFocusOnShow) ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL); @@ -12298,7 +9818,6 @@ RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { return b; } -id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display); id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) { Class NSScreenClass = objc_getClass("NSScreen"); @@ -12320,7 +9839,8 @@ id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) { return NULL; } -u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode); +u32 RGFW_osx_getFallbackRefreshRate(CGDirectDisplayID displayID); + u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) { if (mode) { u32 refreshRate = (u32)CGDisplayModeGetRefreshRate(mode); @@ -12336,7 +9856,6 @@ u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) { return 60; } -RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen); RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { RGFW_monitor monitor; @@ -12346,8 +9865,7 @@ RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { CGRect bounds = CGDisplayBounds(display); monitor.x = (i32)bounds.origin.x; monitor.y = (i32)bounds.origin.y; - monitor.mode.w = (i32) bounds.size.width; - monitor.mode.h = (i32) bounds.size.height; + monitor.mode.area = RGFW_AREA((int) bounds.size.width, (int) bounds.size.height); monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8; @@ -12359,8 +9877,8 @@ RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { monitor.physW = (float)screenSizeMM.width / 25.4f; monitor.physH = (float)screenSizeMM.height / 25.4f; - float ppi_width = (monitor.mode.w/monitor.physW); - float ppi_height = (monitor.mode.h/monitor.physH); + float ppi_width = (monitor.mode.area.w/monitor.physW); + float ppi_height = (monitor.mode.area.h/monitor.physH); monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor")); float dpi = 96.0f * monitor.pixelRatio; @@ -12368,7 +9886,7 @@ RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) { monitor.scaleX = ((i32)(((float) (ppi_width) / dpi) * 10.0f)) / 10.0f; monitor.scaleY = ((i32)(((float) (ppi_height) / dpi) * 10.0f)) / 10.0f; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, "monitor found"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found"); return monitor; } @@ -12393,10 +9911,10 @@ RGFW_monitor* RGFW_getMonitors(size_t* len) { } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { - CGPoint point = { (CGFloat)mon.x, (CGFloat)mon.y }; + CGPoint point = { mon.x, mon.y }; CGDirectDisplayID display; - u32 displayCount = 0; + uint32_t displayCount = 0; CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount); if (err != kCGErrorSuccess || displayCount != 1) return RGFW_FALSE; @@ -12411,8 +9929,7 @@ RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i); RGFW_monitorMode foundMode; - foundMode.w = (i32)CGDisplayModeGetWidth(cmode); - foundMode.h = (i32)CGDisplayModeGetHeight(cmode); + foundMode.area = RGFW_AREA(CGDisplayModeGetWidth(cmode), CGDisplayModeGetHeight(cmode)); foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode); foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8; @@ -12471,203 +9988,104 @@ void RGFW_writeClipboard(const char* text, u32 textLen) { SEL func = sel_registerName("setString:forType:"); ((bool (*)(id, SEL, id, id))objc_msgSend) - (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String((const char*)NSPasteboardTypeString)); + (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String(NSPasteboardTypeString)); } -#ifdef RGFW_OPENGL -void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param); -void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) { - ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend) - (context, sel_registerName("setValues:forParameter:"), vals, param); -} - - -/* MacOS OpenGL API spares us yet again (there are no extensions) */ -RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char * extension, size_t len) { RGFW_UNUSED(extension); RGFW_UNUSED(len); return RGFW_FALSE; } - -RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { - static CFBundleRef RGFWnsglFramework = NULL; - if (RGFWnsglFramework == NULL) - RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - - CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII); - - RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName); - - CFRelease(symbolName); - - return symbol; -} - -RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { - win->src.ctx.native = ctx; - win->src.gfxType = RGFW_gfxNativeOpenGL; - - i32 attribs[40]; - size_t render_type_index = 0; - { - RGFW_attribStack stack; - RGFW_attribStack_init(&stack, attribs, 40); - - i32 colorBits = (i32)(hints->red + hints->green + hints->blue + hints->alpha) / 4; - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAColorSize, colorBits); - - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAlphaSize, hints->alpha); - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFADepthSize, hints->depth); - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAStencilSize, hints->stencil); - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAuxBuffers, hints->auxBuffers); - RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAClosestPolicy); - if (hints->samples) { - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 1); - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASamples, hints->samples); - } else RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFASampleBuffers, 0); - - if (hints->doubleBuffer) - RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFADoubleBuffer); - - #ifdef RGFW_COCOA_GRAPHICS_SWITCHING - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAllowOfflineRenderers, kCGLPFASupportsAutomaticGraphicsSwitching) - #endif - #if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 - if (hints->stereo]) RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAStereo); - #endif - - /* macOS has the surface attribs and the OpenGL attribs connected for some reason maybe this is to give macOS more control to limit openGL/the OpenGL version? */ - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAOpenGLProfile, - (hints->major >= 4) ? NSOpenGLProfileVersion4_1Core : (hints->major >= 3) ? - NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy); - - if (hints->major <= 2) { - i32 accumSize = (i32)(hints->accumRed + hints->accumGreen + hints->accumBlue + hints->accumAlpha) / 4; - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFAAccumSize, accumSize); - } - - if (hints->renderer == RGFW_glSoftware) { - RGFW_attribStack_pushAttribs(&stack, NSOpenGLPFARendererID, kCGLRendererGenericFloatID); - } else { - RGFW_attribStack_pushAttrib(&stack, NSOpenGLPFAAccelerated); - } - render_type_index = stack.count - 1; - - RGFW_attribStack_pushAttribs(&stack, 0, 0); - } - - void* format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs); - if (format == NULL) { - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "Failed to load pixel format for OpenGL"); - - assert(render_type_index + 3 < (sizeof(attribs) / sizeof(attribs[0]))); - attribs[render_type_index] = NSOpenGLPFARendererID; - attribs[render_type_index + 1] = kCGLRendererGenericFloatID; - attribs[render_type_index + 3] = 0; - - format = (void*) ((id(*)(id, SEL, const u32*))objc_msgSend) (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), (u32*)attribs); - if (format == NULL) - RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenGLContext, "and loading software rendering OpenGL failed"); + #ifdef RGFW_OPENGL + void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { + if (win != NULL) + objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); else - RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, "Switching to software rendering"); + objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext")); + } + void* RGFW_getCurrent_OpenGL(void) { + return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext")); } - /* the pixel format can be passed directly to OpenGL context creation to create a context - this is because the format also includes information about the OpenGL version (which may be a bad thing) */ + void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { + objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer")); + } + #endif - if (win->src.view) - NSRelease(win->src.view); - win->src.view = (id) ((id(*)(id, SEL, NSRect, u32*))objc_msgSend) (NSAlloc(_RGFW->customViewClasses[1]), - sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {(double)win->w, (double)win->h}}, (u32*)format); + #if !defined(RGFW_EGL) - id share = NULL; - if (hints->share) { - share = (id)hints->share->ctx; + void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { + RGFW_ASSERT(win != NULL); + #if defined(RGFW_OPENGL) + + NSOpenGLContext_setValues((id)win->src.ctx, &swapInterval, 222); + #else + RGFW_UNUSED(swapInterval); + #endif } - win->src.ctx.native->ctx = ((id (*)(id, SEL, id, id))objc_msgSend)(NSAlloc(objc_getClass("NSOpenGLContext")), - sel_registerName("initWithFormat:shareContext:"), - (id)format, share); + #endif - objc_msgSend_void_id(win->src.view, sel_registerName("setOpenGLContext:"), win->src.ctx.native->ctx); - if (win->internal.flags & RGFW_windowTransparent) { - i32 opacity = 0; - #define NSOpenGLCPSurfaceOpacity 236 - NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &opacity, (NSOpenGLContextParameter)NSOpenGLCPSurfaceOpacity); +void RGFW_window_swapBuffers_software(RGFW_window* win) { +#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + RGFW_RGB_to_BGR(win, win->buffer); + i32 channels = 4; + id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc")); + NSSize size = (NSSize){win->bufferSize.w, win->bufferSize.h}; + image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size); - } + id rep = NSBitmapImageRep_initWithBitmapData(&win->buffer, win->r.w, win->r.h , 8, channels, (channels == 4), false, + "NSDeviceRGBColorSpace", 1 << 1, (u32)win->bufferSize.w * (u32)channels, 8 * (u32)channels); + ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep); - objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext")); + id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView")); + ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES); + id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer")); - objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view); - objc_msgSend_void_bool(win->src.view, sel_registerName("setWantsLayer:"), true); - objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4); + ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image); + ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); - return RGFW_TRUE; -} - -void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { - objc_msgSend_void(ctx->ctx, sel_registerName("release")); - win->src.ctx.native->ctx = NULL; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); -} - -void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { - if (win) RGFW_ASSERT(win->src.ctx.native); - if (win != NULL) - objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("makeCurrentContext")); - else - objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext")); -} -void* RGFW_getCurrentContext_OpenGL(void) { - return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext")); -} - -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { - RGFW_ASSERT(win && win->src.ctx.native); - objc_msgSend_void(win->src.ctx.native->ctx, sel_registerName("flushBuffer")); -} -void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { - RGFW_ASSERT(win != NULL && win->src.ctx.native != NULL); - NSOpenGLContext_setValues((id)win->src.ctx.native->ctx, &swapInterval, (NSOpenGLContextParameter)222); -} -#endif - -void RGFW_deinitPlatform(void) { } - -void RGFW_window_closePlatform(RGFW_window* win) { - NSRelease(win->src.view); -} - -#ifdef RGFW_WEBGPU -WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { - WGPUSurfaceDescriptor surfaceDesc = {0}; - id* nsView = (id*)window->src.view; - if (!nsView) { - fprintf(stderr, "RGFW Error: NSView is NULL for macOS window.\n"); - return NULL; - } - - ((void (*)(id, SEL, BOOL))objc_msgSend)(nsView, sel_registerName("setWantsLayer:"), YES); - id layer = ((id (*)(id, SEL))objc_msgSend)(nsView, sel_registerName("layer")); - - void* metalLayer = RGFW_getLayer_OSX(); - if (metalLayer == NULL) { - return NULL; - } - ((void (*)(id, SEL, id))objc_msgSend)((id)nsView, sel_registerName("setLayer:"), metalLayer); - layer = metalLayer; /* Use the newly created layer */ - - /* At this point, 'layer' should be a valid CAMetalLayer* */ - WGPUSurfaceSourceMetalLayer fromMetal = {0}; - fromMetal.chain.sType = WGPUSType_SurfaceSourceMetalLayer; -#ifdef __OBJC__ - fromMetal.layer = (__bridge CAMetalLayer*)layer; /* Use __bridge for ARC compatibility if mixing C/Obj-C */ + NSRelease(rep); + NSRelease(image); #else - fromMetal.layer = layer; + RGFW_UNUSED(win); #endif - - surfaceDesc.nextInChain = (WGPUChainedStruct*)&fromMetal.chain; - return wgpuInstanceCreateSurface(instance, &surfaceDesc); } -#endif + +void RGFW_deinit(void) { + _RGFW.windowCount = -1; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); +} + +void RGFW_window_close(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + NSRelease(win->src.view); + if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); + + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if ((win->_flags & RGFW_BUFFER_ALLOC)) + RGFW_FREE(win->buffer); + #endif + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); + _RGFW.windowCount--; + if (_RGFW.windowCount == 0) RGFW_deinit(); + + RGFW_clipboard_switch(NULL); + RGFW_FREE(win->event.droppedFiles); + if ((win->_flags & RGFW_WINDOW_ALLOC)) { + RGFW_FREE(win); + win = NULL; + } +} + +u64 RGFW_getTimerFreq(void) { + static u64 freq = 0; + if (freq == 0) { + mach_timebase_info_data_t info; + mach_timebase_info(&info); + freq = (u64)((info.denom * 1e9) / info.numer); + } + + return freq; +} + +u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); } #endif /* RGFW_MACOS */ @@ -12683,40 +10101,33 @@ WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance i EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE; - - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = _RGFW->root); - RGFW_windowResizedCallback(_RGFW->root, E->windowInnerWidth, E->windowInnerHeight); + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root); + RGFW_windowResizedCallback(_RGFW.root, RGFW_RECT(0, 0, E->windowInnerWidth, E->windowInnerHeight)); return EM_TRUE; } EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - if (!(_RGFW->root->internal.enabledEvents & RGFW_windowResizedFlag)) return EM_TRUE; - static u8 fullscreen = RGFW_FALSE; - static i32 originalW, originalH; + static RGFW_rect ogRect; if (fullscreen == RGFW_FALSE) { - originalW = _RGFW->root->w; - originalH = _RGFW->root->h; + ogRect = _RGFW.root->r; } fullscreen = !fullscreen; - RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e.common.win = _RGFW->root); - _RGFW->root->w = E->screenWidth; - _RGFW->root->h = E->screenHeight; + RGFW_eventQueuePushEx(e.type = RGFW_windowResized; e._win = _RGFW.root); + _RGFW.root->r = RGFW_RECT(0, 0, E->screenWidth, E->screenHeight); EM_ASM("Module.canvas.focus();"); if (fullscreen == RGFW_FALSE) { - _RGFW->root->w = originalW; - _RGFW->root->h = originalH; + _RGFW.root->r = RGFW_RECT(0, 0, ogRect.w, ogRect.h); + /* emscripten_request_fullscreen("#canvas", 0); */ } else { #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0 EmscriptenFullscreenStrategy FSStrat = {0}; - FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; + FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; /* EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; */ FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF; FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat); @@ -12725,111 +10136,97 @@ EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreen #endif } - emscripten_set_canvas_element_size("#canvas", _RGFW->root->w, _RGFW->root->h); - RGFW_windowResizedCallback(_RGFW->root, _RGFW->root->w, _RGFW->root->h); + emscripten_set_canvas_element_size("#canvas", _RGFW.root->r.w, _RGFW.root->r.h); + + RGFW_windowResizedCallback(_RGFW.root, _RGFW.root->r); return EM_TRUE; } + + EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E); - if (!(_RGFW->root->internal.enabledEvents & RGFW_focusInFlag)) return EM_TRUE; + RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e._win = _RGFW.root); + _RGFW.root->_flags |= RGFW_windowFocus; + RGFW_focusCallback(_RGFW.root, 1); - RGFW_eventQueuePushEx(e.type = RGFW_focusIn; e.common.win = _RGFW->root); - _RGFW->root->internal.inFocus = RGFW_TRUE; - RGFW_focusCallback(_RGFW->root, 1); - - if ((_RGFW->root->internal.holdMouse)) RGFW_window_holdMouse(_RGFW->root); + if ((_RGFW.root->_flags & RGFW_HOLD_MOUSE)) RGFW_window_mouseHold(_RGFW.root, RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h)); return EM_TRUE; } EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(E); - if (!(_RGFW->root->internal.enabledEvents & RGFW_focusOutFlag)) return EM_TRUE; - - RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e.common.win = _RGFW->root); - RGFW_window_focusLost(_RGFW->root); - RGFW_focusCallback(_RGFW->root, 0); + RGFW_eventQueuePushEx(e.type = RGFW_focusOut; e._win = _RGFW.root); + RGFW_window_focusLost(_RGFW.root); + RGFW_focusCallback(_RGFW.root, 0); return EM_TRUE; } EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - - if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE; - RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.mouse.x = E->targetX; e.mouse.y = E->targetY; - e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; - e.common.win = _RGFW->root); + e.point = RGFW_POINT(E->targetX, E->targetY); + e.vector = RGFW_POINT(E->movementX, E->movementY); + e._win = _RGFW.root); - _RGFW->vectorX = E->movementX; - _RGFW->vectorY = E->movementY; - _RGFW->root->internal.lastMouseX = E->targetX; - _RGFW->root->internal.lastMouseY = E->targetY; - RGFW_mousePosCallback(_RGFW->root, E->targetX, E->targetY, E->movementX, E->movementY); + _RGFW.root->_lastMousePoint = RGFW_POINT(E->targetX, E->targetY); + RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->targetX, E->targetY), RGFW_POINT(E->movementX, E->movementY)); return EM_TRUE; } EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE; - int button = E->button; if (button > 2) button += 2; RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.mouse.x = E->targetX; e.mouse.y = E->targetY; - e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; - e.button.value = (u8)button; - e.common.win = _RGFW->root); - _RGFW->vectorX = E->movementX; - _RGFW->vectorY = E->movementY; - _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current; - _RGFW->mouseButtons[button].current = 1; + e.point = RGFW_POINT(E->targetX, E->targetY); + e.vector = RGFW_POINT(E->movementX, E->movementY); + e.button = (u8)button; + e.scroll = 0; + e._win = _RGFW.root); + RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; + RGFW_mouseButtons[button].current = 1; - RGFW_mouseButtonCallback(_RGFW->root, button, 1); + RGFW_mouseButtonCallback(_RGFW.root, button, 0, 1); return EM_TRUE; } EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE; - int button = E->button; if (button > 2) button += 2; RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased; - e.mouse.x = E->targetX; e.mouse.y = E->targetY; - e.mouse.vecX = E->movementX; e.mouse.vecY = E->movementY; - e.button.value = (u8)button; - e.common.win = _RGFW->root); - _RGFW->vectorX = E->movementX; - _RGFW->vectorY = E->movementY; - _RGFW->mouseButtons[button].prev = _RGFW->mouseButtons[button].current; - _RGFW->mouseButtons[button].current = 0; + e.point = RGFW_POINT(E->targetX, E->targetY); + e.vector = RGFW_POINT(E->movementX, E->movementY); + e.button = (u8)button; + e.scroll = 0; + e._win = _RGFW.root); + RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; + RGFW_mouseButtons[button].current = 0; - RGFW_mouseButtonCallback(_RGFW->root, button, 0); + RGFW_mouseButtonCallback(_RGFW.root, button, 0, 0); return EM_TRUE; } EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseScrollFlag)) return EM_TRUE; - - _RGFW->scrollX = E->deltaX; - _RGFW->scrollY = E->deltaY; + int button = RGFW_mouseScrollUp + (E->deltaY < 0); RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.scroll.x = E->deltaX; - e.scroll.y = E->deltaY; - ); - RGFW_mouseScrollCallback(_RGFW->root, E->deltaX, E->deltaY); + e.button = (u8)button; + e.scroll = (double)(E->deltaY < 0 ? 1 : -1); + e._win = _RGFW.root); + RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current; + RGFW_mouseButtons[button].current = 1; + RGFW_mouseButtonCallback(_RGFW.root, button, E->deltaY < 0 ? 1 : -1, 1); return EM_TRUE; } @@ -12837,44 +10234,35 @@ EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* E, void* EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonPressedFlag)) return EM_TRUE; - size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonPressed; - e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; - e.button.value = RGFW_mouseLeft; - e.common.win = _RGFW->root); + e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); + e.button = RGFW_mouseLeft; + e._win = _RGFW.root); - _RGFW->mouseButtons[RGFW_mouseLeft].prev = _RGFW->mouseButtons[RGFW_mouseLeft].current; - _RGFW->mouseButtons[RGFW_mouseLeft].current = 1; + RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current; + RGFW_mouseButtons[RGFW_mouseLeft].current = 1; - _RGFW->root->internal.lastMouseX = E->touches[i].targetX; - _RGFW->root->internal.lastMouseX = E->touches[i].targetY; - RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); - RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 1); + _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); + RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); + RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 1); } return EM_TRUE; } - EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - if (!(_RGFW->root->internal.enabledEvents & RGFW_mousePosChangedFlag)) return EM_TRUE; - size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mousePosChanged; - e.mouse.x = E->touches[i].targetX; - e.mouse.y = E->touches[i].targetY; - e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; - e.button.value = RGFW_mouseLeft; - e.common.win = _RGFW->root); + e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); + e.button = RGFW_mouseLeft; + e._win = _RGFW.root); - _RGFW->root->internal.lastMouseX = E->touches[i].targetX; - _RGFW->root->internal.lastMouseX = E->touches[i].targetY; - RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); + _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); + RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); } return EM_TRUE; } @@ -12882,563 +10270,60 @@ EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* E, vo EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); - if (!(_RGFW->root->internal.enabledEvents & RGFW_mouseButtonReleasedFlag)) return EM_TRUE; - size_t i; for (i = 0; i < (size_t)E->numTouches; i++) { RGFW_eventQueuePushEx(e.type = RGFW_mouseButtonReleased; - e.mouse.x = E->touches[i].targetX; e.mouse.y = E->touches[i].targetY; - e.button.value = RGFW_mouseLeft; - e.common.win = _RGFW->root); + e.point = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); + e.button = RGFW_mouseLeft; + e._win = _RGFW.root); - _RGFW->mouseButtons[RGFW_mouseLeft].prev = _RGFW->mouseButtons[RGFW_mouseLeft].current; - _RGFW->mouseButtons[RGFW_mouseLeft].current = 0; + RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current; + RGFW_mouseButtons[RGFW_mouseLeft].current = 0; - _RGFW->root->internal.lastMouseX = E->touches[i].targetX; - _RGFW->root->internal.lastMouseY = E->touches[i].targetY; - RGFW_mousePosCallback(_RGFW->root, E->touches[i].targetX, E->touches[i].targetY, 0, 0); - RGFW_mouseButtonCallback(_RGFW->root, RGFW_mouseLeft, 0); + _RGFW.root->_lastMousePoint = RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY); + RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(E->touches[i].targetX, E->touches[i].targetY), _RGFW.root->event.vector); + RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 0); } return EM_TRUE; } EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* E, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); return EM_TRUE; } -u32 RGFW_WASMPhysicalToRGFW(u32 hash); +EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) { + RGFW_UNUSED(eventType); RGFW_UNUSED(userData); -void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) { - const char* iCode = code; + if (gamepadEvent->index >= 4) + return 0; - u32 hash = 0; - while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++; - - u32 physicalKey = RGFW_WASMPhysicalToRGFW(hash); - - u8 mappedKey = (u8)(*((u32*)key)); - - if (*((u16*)key) != mappedKey) { - mappedKey = 0; - if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab; + size_t i = gamepadEvent->index; + if (gamepadEvent->connected) { + RGFW_STRNCPY(RGFW_gamepads_name[gamepadEvent->index], gamepadEvent->id, sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1); + RGFW_gamepads_name[gamepadEvent->index][sizeof(RGFW_gamepads_name[gamepadEvent->index]) - 1] = '\0'; + RGFW_gamepads_type[i] = RGFW_gamepadUnknown; + if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box")) + RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft; + else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5")) + RGFW_gamepads_type[i] = RGFW_gamepadSony; + else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo")) + RGFW_gamepads_type[i] = RGFW_gamepadNintendo; + else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech")) + RGFW_gamepads_type[i] = RGFW_gamepadLogitech; + RGFW_gamepadCount++; + } else { + RGFW_gamepadCount--; } - if (!(press ? (_RGFW->root->internal.enabledEvents & RGFW_keyPressedFlag) : (_RGFW->root->internal.enabledEvents & RGFW_keyReleasedFlag))) return; + RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(gamepadEvent->connected ? RGFW_gamepadConnected : RGFW_gamepadConnected); + e.gamepad = (u16)gamepadEvent->index; + e._win = _RGFW.root); - RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased); - e.key.value = (u8)physicalKey; - e.key.sym = (u8)mappedKey; - e.key.mod = _RGFW->root->internal.mod; - e.key.repeat = RGFW_window_isKeyDown(_RGFW->root, (u8)physicalKey); - e.common.win = _RGFW->root); + RGFW_gamepadCallback(_RGFW.root, gamepadEvent->index, gamepadEvent->connected); + RGFW_gamepads[gamepadEvent->index] = gamepadEvent->connected; - _RGFW->keyboard[physicalKey].prev = _RGFW->keyboard[physicalKey].current; - _RGFW->keyboard[physicalKey].current = press; - - RGFW_keyCallback(_RGFW->root, physicalKey, mappedKey, _RGFW->root->internal.mod, RGFW_window_isKeyDown(_RGFW->root, (u8)physicalKey), press); + return 1; /* The event was consumed by the callback handler */ } -void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { - RGFW_updateKeyModsEx(_RGFW->root, capital, numlock, control, alt, shift, super, scroll); -} - -void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { - if (!(_RGFW->root->internal.flags & RGFW_windowAllowDND)) - return; - - if (!(_RGFW->root->internal.enabledEvents & RGFW_dataDropFlag)) return; - - RGFW_eventQueuePushEx(e.type = RGFW_dataDrop; - e.drop.count = count; - e.common.win = _RGFW->root); - - _RGFW->windowState.win = _RGFW->root; - _RGFW->windowState.dataDrop = RGFW_TRUE; - _RGFW->windowState.filesCount = count; - RGFW_dataDropCallback(_RGFW->root, _RGFW->files, count); -} - -void RGFW_stopCheckEvents(void) { - _RGFW->stopCheckEvents_bool = RGFW_TRUE; -} - -RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { - surface->data = data; - surface->w = w; - surface->h = h; - surface->format = format; - return RGFW_TRUE; -} - -void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { - /* TODO: Needs fixing. */ - RGFW_copyImageData(surface->data, surface->w, RGFW_MIN(win->h, surface->h), RGFW_formatRGBA8, surface->data, surface->format); - EM_ASM_({ - var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); - let context = document.getElementById("canvas").getContext("2d"); - let image = context.getImageData(0, 0, $1, $2); - image.data.set(data); - context.putImageData(image, 0, $4 - $2); - }, surface->data, surface->w, surface->h, RGFW_MIN(win->h, surface->w), RGFW_MIN(win->h, surface->h)); -} - -void RGFW_surface_freePtr(RGFW_surface* surface) { } - -void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) { - /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */ - /* TODO: find a better way to do this - */ - RGFW_STRNCPY((char*)_RGFW->files[index], file, RGFW_MAX_PATH - 1); - _RGFW->files[index][RGFW_MAX_PATH - 1] = '\0'; -} - -#include -#include -#include -#include - -void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); } - -void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) { - FILE* file = fopen(path, "w+"); - if (file == NULL) - return; - - fwrite(data, sizeof(char), len, file); - fclose(file); -} - -void RGFW_initKeycodesPlatform(void) { - _RGFW->keycodes[DOM_VK_BACK_QUOTE] = RGFW_backtick; - _RGFW->keycodes[DOM_VK_0] = RGFW_0; - _RGFW->keycodes[DOM_VK_1] = RGFW_1; - _RGFW->keycodes[DOM_VK_2] = RGFW_2; - _RGFW->keycodes[DOM_VK_3] = RGFW_3; - _RGFW->keycodes[DOM_VK_4] = RGFW_4; - _RGFW->keycodes[DOM_VK_5] = RGFW_5; - _RGFW->keycodes[DOM_VK_6] = RGFW_6; - _RGFW->keycodes[DOM_VK_7] = RGFW_7; - _RGFW->keycodes[DOM_VK_8] = RGFW_8; - _RGFW->keycodes[DOM_VK_9] = RGFW_9; - _RGFW->keycodes[DOM_VK_SPACE] = RGFW_space; - _RGFW->keycodes[DOM_VK_A] = RGFW_a; - _RGFW->keycodes[DOM_VK_B] = RGFW_b; - _RGFW->keycodes[DOM_VK_C] = RGFW_c; - _RGFW->keycodes[DOM_VK_D] = RGFW_d; - _RGFW->keycodes[DOM_VK_E] = RGFW_e; - _RGFW->keycodes[DOM_VK_F] = RGFW_f; - _RGFW->keycodes[DOM_VK_G] = RGFW_g; - _RGFW->keycodes[DOM_VK_H] = RGFW_h; - _RGFW->keycodes[DOM_VK_I] = RGFW_i; - _RGFW->keycodes[DOM_VK_J] = RGFW_j; - _RGFW->keycodes[DOM_VK_K] = RGFW_k; - _RGFW->keycodes[DOM_VK_L] = RGFW_l; - _RGFW->keycodes[DOM_VK_M] = RGFW_m; - _RGFW->keycodes[DOM_VK_N] = RGFW_n; - _RGFW->keycodes[DOM_VK_O] = RGFW_o; - _RGFW->keycodes[DOM_VK_P] = RGFW_p; - _RGFW->keycodes[DOM_VK_Q] = RGFW_q; - _RGFW->keycodes[DOM_VK_R] = RGFW_r; - _RGFW->keycodes[DOM_VK_S] = RGFW_s; - _RGFW->keycodes[DOM_VK_T] = RGFW_t; - _RGFW->keycodes[DOM_VK_U] = RGFW_u; - _RGFW->keycodes[DOM_VK_V] = RGFW_v; - _RGFW->keycodes[DOM_VK_W] = RGFW_w; - _RGFW->keycodes[DOM_VK_X] = RGFW_x; - _RGFW->keycodes[DOM_VK_Y] = RGFW_y; - _RGFW->keycodes[DOM_VK_Z] = RGFW_z; - _RGFW->keycodes[DOM_VK_PERIOD] = RGFW_period; - _RGFW->keycodes[DOM_VK_COMMA] = RGFW_comma; - _RGFW->keycodes[DOM_VK_SLASH] = RGFW_slash; - _RGFW->keycodes[DOM_VK_OPEN_BRACKET] = RGFW_bracket; - _RGFW->keycodes[DOM_VK_CLOSE_BRACKET] = RGFW_closeBracket; - _RGFW->keycodes[DOM_VK_SEMICOLON] = RGFW_semicolon; - _RGFW->keycodes[DOM_VK_QUOTE] = RGFW_apostrophe; - _RGFW->keycodes[DOM_VK_BACK_SLASH] = RGFW_backSlash; - _RGFW->keycodes[DOM_VK_RETURN] = RGFW_return; - _RGFW->keycodes[DOM_VK_DELETE] = RGFW_delete; - _RGFW->keycodes[DOM_VK_NUM_LOCK] = RGFW_numLock; - _RGFW->keycodes[DOM_VK_DIVIDE] = RGFW_kpSlash; - _RGFW->keycodes[DOM_VK_MULTIPLY] = RGFW_kpMultiply; - _RGFW->keycodes[DOM_VK_SUBTRACT] = RGFW_kpMinus; - _RGFW->keycodes[DOM_VK_NUMPAD1] = RGFW_kp1; - _RGFW->keycodes[DOM_VK_NUMPAD2] = RGFW_kp2; - _RGFW->keycodes[DOM_VK_NUMPAD3] = RGFW_kp3; - _RGFW->keycodes[DOM_VK_NUMPAD4] = RGFW_kp4; - _RGFW->keycodes[DOM_VK_NUMPAD5] = RGFW_kp5; - _RGFW->keycodes[DOM_VK_NUMPAD6] = RGFW_kp6; - _RGFW->keycodes[DOM_VK_NUMPAD9] = RGFW_kp9; - _RGFW->keycodes[DOM_VK_NUMPAD0] = RGFW_kp0; - _RGFW->keycodes[DOM_VK_DECIMAL] = RGFW_kpPeriod; - _RGFW->keycodes[DOM_VK_RETURN] = RGFW_kpReturn; - _RGFW->keycodes[DOM_VK_HYPHEN_MINUS] = RGFW_minus; - _RGFW->keycodes[DOM_VK_EQUALS] = RGFW_equals; - _RGFW->keycodes[DOM_VK_BACK_SPACE] = RGFW_backSpace; - _RGFW->keycodes[DOM_VK_TAB] = RGFW_tab; - _RGFW->keycodes[DOM_VK_CAPS_LOCK] = RGFW_capsLock; - _RGFW->keycodes[DOM_VK_SHIFT] = RGFW_shiftL; - _RGFW->keycodes[DOM_VK_CONTROL] = RGFW_controlL; - _RGFW->keycodes[DOM_VK_ALT] = RGFW_altL; - _RGFW->keycodes[DOM_VK_META] = RGFW_superL; - _RGFW->keycodes[DOM_VK_F1] = RGFW_F1; - _RGFW->keycodes[DOM_VK_F2] = RGFW_F2; - _RGFW->keycodes[DOM_VK_F3] = RGFW_F3; - _RGFW->keycodes[DOM_VK_F4] = RGFW_F4; - _RGFW->keycodes[DOM_VK_F5] = RGFW_F5; - _RGFW->keycodes[DOM_VK_F6] = RGFW_F6; - _RGFW->keycodes[DOM_VK_F7] = RGFW_F7; - _RGFW->keycodes[DOM_VK_F8] = RGFW_F8; - _RGFW->keycodes[DOM_VK_F9] = RGFW_F9; - _RGFW->keycodes[DOM_VK_F10] = RGFW_F10; - _RGFW->keycodes[DOM_VK_F11] = RGFW_F11; - _RGFW->keycodes[DOM_VK_F12] = RGFW_F12; - _RGFW->keycodes[DOM_VK_UP] = RGFW_up; - _RGFW->keycodes[DOM_VK_DOWN] = RGFW_down; - _RGFW->keycodes[DOM_VK_LEFT] = RGFW_left; - _RGFW->keycodes[DOM_VK_RIGHT] = RGFW_right; - _RGFW->keycodes[DOM_VK_INSERT] = RGFW_insert; - _RGFW->keycodes[DOM_VK_END] = RGFW_end; - _RGFW->keycodes[DOM_VK_PAGE_UP] = RGFW_pageUp; - _RGFW->keycodes[DOM_VK_PAGE_DOWN] = RGFW_pageDown; - _RGFW->keycodes[DOM_VK_ESCAPE] = RGFW_escape; - _RGFW->keycodes[DOM_VK_HOME] = RGFW_home; - _RGFW->keycodes[DOM_VK_SCROLL_LOCK] = RGFW_scrollLock; - _RGFW->keycodes[DOM_VK_PRINTSCREEN] = RGFW_printScreen; - _RGFW->keycodes[DOM_VK_PAUSE] = RGFW_pause; - _RGFW->keycodes[DOM_VK_F13] = RGFW_F13; - _RGFW->keycodes[DOM_VK_F14] = RGFW_F14; - _RGFW->keycodes[DOM_VK_F15] = RGFW_F15; - _RGFW->keycodes[DOM_VK_F16] = RGFW_F16; - _RGFW->keycodes[DOM_VK_F17] = RGFW_F17; - _RGFW->keycodes[DOM_VK_F18] = RGFW_F18; - _RGFW->keycodes[DOM_VK_F19] = RGFW_F19; - _RGFW->keycodes[DOM_VK_F20] = RGFW_F20; - _RGFW->keycodes[DOM_VK_F21] = RGFW_F21; - _RGFW->keycodes[DOM_VK_F22] = RGFW_F22; - _RGFW->keycodes[DOM_VK_F23] = RGFW_F23; - _RGFW->keycodes[DOM_VK_F24] = RGFW_F24; -} - -i32 RGFW_initPlatform(void) { return 0; } - -RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { - emscripten_set_canvas_element_size("#canvas", win->w, win->h); - emscripten_set_window_title(name); - - /* load callbacks */ - 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); - emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart); - emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend); - emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove); - emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel); - emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown); - emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup); - emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel); - emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin); - emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout); - - if (flags & RGFW_windowAllowDND) { - win->internal.flags |= RGFW_windowAllowDND; - } - - EM_ASM({ - window.addEventListener("keydown", - (event) => { - var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); - Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); - Module._RGFW_handleKeyEvent(key, code, 1); - _free(key); _free(code); - }, - true); - window.addEventListener("keyup", - (event) => { - var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); - Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); - Module._RGFW_handleKeyEvent(key, code, 0); - _free(key); _free(code); - }, - true); - }); - - EM_ASM({ - var canvas = document.getElementById('canvas'); - canvas.addEventListener('drop', function(e) { - e.preventDefault(); - if (e.dataTransfer.file < 0) - return; - - var filenamesArray = []; - var count = e.dataTransfer.files.length; - - /* Read and save the files to emscripten's files */ - var drop_dir = '.rgfw_dropped_files'; - Module._RGFW_mkdir(drop_dir); - - for (var i = 0; i < count; i++) { - var file = e.dataTransfer.files[i]; - - var path = '/' + drop_dir + '/' + file.name.replace("//", '_'); - var reader = new FileReader(); - - reader.onloadend = (e) => { - if (reader.readyState != 2) { - out('failed to read dropped file: '+file.name+': '+reader.error); - } - else { - var data = e.target.result; - - Module._RGFW_writeFile(path, new Uint8Array(data), file.size); - } - }; - - reader.readAsArrayBuffer(file); - /* This works weird on modern OpenGL */ - var filename = stringToNewUTF8(path); - - filenamesArray.push(filename); - - Module._RGFW_makeSetValue(i, filename); - } - - Module._Emscripten_onDrop(count); - - for (var i = 0; i < count; ++i) { - _free(filenamesArray[i]); - } - }, true); - - canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true); - }); - - return win; -} - -u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { - return (u8)rgfw_keycode; /* TODO */ -} - -void RGFW_pollEvents(void) { - emscripten_sleep(0); - RGFW_resetPrevState(); -} - -void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { - RGFW_UNUSED(win); - emscripten_set_canvas_element_size("#canvas", w, h); -} - -/* NOTE: I don't know if this is possible */ -void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); } -/* this one might be possible but it looks iffy */ -RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); return NULL; } - -void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); } -void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); } - -RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { - static const char cursors[16][16] = { - "default", "default", "text", "crosshair", - "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize", - "move", "not-allowed" - }; - - RGFW_UNUSED(win); - EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]); - return RGFW_TRUE; -} - -RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { - return RGFW_window_setMouseStandard(win, RGFW_mouseNormal); -} - -void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { - RGFW_window_showMouseFlags(win, show); - if (show) - RGFW_window_setMouseDefault(win); - else - EM_ASM(document.getElementById('canvas').style.cursor = 'none';); -} - -RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { - if(x) *x = EM_ASM_INT({ - return window.mouseX || 0; - }); - if (y) *y = EM_ASM_INT({ - return window.mouseY || 0; - }); - return RGFW_TRUE; -} - -void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { - RGFW_UNUSED(win); - - EM_ASM_({ - var canvas = document.getElementById('canvas'); - if ($0) { - canvas.style.pointerEvents = 'none'; - } else { - canvas.style.pointerEvents = 'auto'; - } - }, passthrough); -} - -void RGFW_writeClipboard(const char* text, u32 textLen) { - RGFW_UNUSED(textLen); - EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text); -} - - -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { - RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); - /* - placeholder code for later - I'm not sure if this is possible do the the async stuff - */ - return 0; -} - -#ifdef RGFW_OPENGL -RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { - win->src.ctx.native = ctx; - win->src.gfxType = RGFW_gfxNativeOpenGL; - - EmscriptenWebGLContextAttributes attrs; - attrs.alpha = hints->alpha; - attrs.depth = hints->depth; - attrs.stencil = hints->stencil; - attrs.antialias = hints->samples; - attrs.premultipliedAlpha = EM_TRUE; - attrs.preserveDrawingBuffer = EM_FALSE; - - if (hints->doubleBuffer == 0) - attrs.renderViaOffscreenBackBuffer = 0; - else - attrs.renderViaOffscreenBackBuffer = hints->auxBuffers; - - attrs.failIfMajorPerformanceCaveat = EM_FALSE; - attrs.majorVersion = (hints->major == 0) ? 1 : hints->major; - attrs.minorVersion = hints->minor; - - attrs.enableExtensionsByDefault = EM_TRUE; - attrs.explicitSwapControl = EM_TRUE; - - emscripten_webgl_init_context_attributes(&attrs); - win->src.ctx.native->ctx = emscripten_webgl_create_context("#canvas", &attrs); - emscripten_webgl_make_context_current(win->src.ctx.native->ctx); - - #ifdef LEGACY_GL_EMULATION - EM_ASM("Module.useWebGL = true; GLImmediate.init();"); - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context initalized."); - #endif - return RGFW_TRUE; -} - -void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { - emscripten_webgl_destroy_context(ctx->ctx); - win->src.ctx.native->ctx = 0; - RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, "OpenGL context freed."); -} - -void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { - if (win) RGFW_ASSERT(win->src.ctx.native); - if (win == NULL) - emscripten_webgl_make_context_current(0); - else - emscripten_webgl_make_context_current(win->src.ctx.native->ctx); -} - -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { - RGFW_ASSERT(win && win->src.ctx.native); - emscripten_webgl_commit_frame(); -} -void* RGFW_getCurrentContext_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); } - -RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) { - return EM_ASM_INT({ - var ext = UTF8ToString($0, $1); - var canvas = document.querySelector('canvas'); - var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - if (!gl) return 0; - - var supported = gl.getSupportedExtensions(); - return supported && supported.includes(ext) ? 1 : 0; - }, extension, len); - return RGFW_FALSE; -} - -RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { - return (RGFW_proc)emscripten_webgl_get_proc_address(procname); - return NULL; -} - -#endif - -void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } - -void RGFW_deinitPlatform(void) { } - -void RGFW_window_closePlatform(RGFW_window* win) { } - -int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); } -int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); } - -void RGFW_releaseCursor(RGFW_window* win) { - RGFW_UNUSED(win); - emscripten_exit_pointerlock(); -} - -void RGFW_captureCursor(RGFW_window* win) { - RGFW_UNUSED(win); - emscripten_request_pointerlock("#canvas", 1); -} - - -void RGFW_window_setName(RGFW_window* win, const char* name) { - RGFW_UNUSED(win); - emscripten_set_window_title(name); -} - -void RGFW_window_maximize(RGFW_window* win) { - RGFW_ASSERT(win != NULL); - - RGFW_monitor mon = RGFW_window_getMonitor(win); - RGFW_window_move(win, 0, 0); - RGFW_window_resize(win, mon.mode.w, mon.mode.h); -} - -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { - RGFW_ASSERT(win != NULL); - if (fullscreen) { - win->internal.flags |= RGFW_windowFullscreen; - EM_ASM( Module.requestFullscreen(false, true); ); - return; - } - win->internal.flags &= ~(u32)RGFW_windowFullscreen; - EM_ASM( Module.exitFullscreen(false, true); ); -} - -void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { - RGFW_UNUSED(win); - EM_ASM({ - var element = document.getElementById("canvas"); - if (element) - element.style.opacity = $1; - }, "elementId", opacity); -} - -#ifdef RGFW_WEBGPU -WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { - WGPUSurfaceDescriptor surfaceDesc = {0}; - WGPUEmscriptenSurfaceSourceCanvasHTMLSelector canvasDesc = {0}; - canvasDesc.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector; - canvasDesc.selector = (WGPUStringView){.data = "#canvas", .length = 7}; - - surfaceDesc.nextInChain = &canvasDesc.chain; - return wgpuInstanceCreateSurface(instance, &surfaceDesc); -} -#endif - -u32 RGFW_WASMPhysicalToRGFW(u32 hash) { +u32 RGFW_wASMPhysicalToRGFW(u32 hash) { switch(hash) { /* 0x0000 */ case 0x67243A2DU /* Escape */: return RGFW_escape; /* 0x0001 */ case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */ @@ -13493,7 +10378,7 @@ u32 RGFW_WASMPhysicalToRGFW(u32 hash) { 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_kpMultiply; + 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 */ @@ -13507,32 +10392,21 @@ u32 RGFW_WASMPhysicalToRGFW(u32 hash) { 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_kpMultiply; /* 0x0047 */ - case 0xC925FCD0U /* Numpad8 */: return RGFW_kp8; /* 0x0048 */ - case 0xC925FCD1U /* Numpad9 */: return RGFW_kp9; /* 0x0049 */ + 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_kp4; /* 0x004B */ - case 0xC925FCDDU /* Numpad5 */: return RGFW_kp5; /* 0x004C */ - case 0xC925FCDEU /* Numpad6 */: return RGFW_kp6; /* 0x004D */ - case 0xC925FCD9U /* Numpad1 */: return RGFW_kp1; /* 0x004F */ - case 0xC925FCDAU /* Numpad2 */: return RGFW_kp2; /* 0x0050 */ - case 0xC925FCDBU /* Numpad3 */: return RGFW_kp3; /* 0x0051 */ - case 0xC925FCD8U /* Numpad0 */: return RGFW_kp0; /* 0x0052 */ + 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_period; /* 0x0053 */ case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */ case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */ - case 0x7B8E57B3U /* F13 */: return DOM_PK_F13; /* 0x0064 */ - case 0x7B8E57B4U /* F14 */: return DOM_PK_F14; /* 0x0065 */ - case 0x7B8E57B5U /* F15 */: return DOM_PK_F15; /* 0x0066 */ - case 0x7B8E57B6U /* F16 */: return DOM_PK_F16; /* 0x0067 */ - case 0x7B8E57B7U /* F17 */: return DOM_PK_F17; /* 0x0068 */ - case 0x7B8E57B8U /* F18 */: return DOM_PK_F18; /* 0x0069 */ - case 0x7B8E57B9U /* F19 */: return DOM_PK_F19; /* 0x006A */ - case 0x7B8E57A8U /* F20 */: return DOM_PK_F20; /* 0x006B */ - case 0x7B8E57A9U /* F21 */: return DOM_PK_F21; /* 0x006C */ - case 0x7B8E57AAU /* F22 */: return DOM_PK_F22; /* 0x006D */ - case 0x7B8E57ABU /* F23 */: return DOM_PK_F23; /* 0x006E */ - case 0x7393FBACU /* NumpadEqual */: return RGFW_kpReturn; + 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 */ @@ -13547,28 +10421,602 @@ u32 RGFW_WASMPhysicalToRGFW(u32 hash) { case 0x6725C50DU /* Delete */: return RGFW_delete; /* 0xE053 */ case 0x6723658CU /* OSLeft */: return RGFW_superL; /* 0xE05B */ case 0x39643F7CU /* MetaRight */: return RGFW_superR; /* 0xE05C */ - case 0x380B9C8CU /* NumpadAdd */: return DOM_PK_NUMPAD_ADD; /* 0x004E */ - default: return DOM_PK_UNKNOWN; } return 0; } +void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) { + const char* iCode = code; + + u32 hash = 0; + while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++; + + u32 physicalKey = RGFW_wASMPhysicalToRGFW(hash); + + u8 mappedKey = (u8)(*((u32*)key)); + + if (*((u16*)key) != mappedKey) { + mappedKey = 0; + if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab; + } + + RGFW_eventQueuePushEx(e.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased); + e.key = (u8)physicalKey; + e.keyChar = (u8)mappedKey; + e.keyMod = _RGFW.root->event.keyMod; + e._win = _RGFW.root); + + RGFW_keyboard[physicalKey].prev = RGFW_keyboard[physicalKey].current; + RGFW_keyboard[physicalKey].current = press; + + RGFW_keyCallback(_RGFW.root, physicalKey, mappedKey, _RGFW.root->event.keyMod, press); +} + +void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) { + RGFW_updateKeyModsPro(_RGFW.root, capital, numlock, control, alt, shift, super, scroll); +} + +void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { + if (!(_RGFW.root->_flags & RGFW_windowAllowDND)) + return; + + _RGFW.root->event.droppedFilesCount = count; + RGFW_eventQueuePushEx(e.type = RGFW_DND; + e.droppedFilesCount = count; + e._win = _RGFW.root); + RGFW_dndCallback(_RGFW.root, _RGFW.root->event.droppedFiles, count); +} + +RGFW_bool RGFW_stopCheckEvents_bool = RGFW_FALSE; +void RGFW_stopCheckEvents(void) { + RGFW_stopCheckEvents_bool = RGFW_TRUE; +} + +void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { + RGFW_UNUSED(win); + if (waitMS == 0) return; + + u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6); + + while ((_RGFW.eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && (RGFW_getTimeNS() / 1e+6) - start < waitMS) + emscripten_sleep(0); + + RGFW_stopCheckEvents_bool = RGFW_FALSE; +} + +void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){ + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + win->buffer = buffer; + win->bufferSize = area; + #ifdef RGFW_OSMESA + win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); + OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h); + OSMesaPixelStore(OSMESA_Y_UP, 0); + #endif + #else + RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */ + #endif +} + +void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) { + /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */ + /* TODO: find a better way to do this + */ + RGFW_STRNCPY((char*)_RGFW.root->event.droppedFiles[index], file, RGFW_MAX_PATH - 1); + _RGFW.root->event.droppedFiles[index][RGFW_MAX_PATH - 1] = '\0'; +} + +#include +#include +#include +#include + +void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); } + +void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) { + FILE* file = fopen(path, "w+"); + if (file == NULL) + return; + + fwrite(data, sizeof(char), len, file); + fclose(file); +} + +void RGFW_window_initOpenGL(RGFW_window* win) { +#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_BUFFER) + EmscriptenWebGLContextAttributes attrs; + attrs.alpha = RGFW_GL_HINTS[RGFW_glDepth]; + attrs.depth = RGFW_GL_HINTS[RGFW_glAlpha]; + attrs.stencil = RGFW_GL_HINTS[RGFW_glStencil]; + attrs.antialias = RGFW_GL_HINTS[RGFW_glSamples]; + attrs.premultipliedAlpha = EM_TRUE; + attrs.preserveDrawingBuffer = EM_FALSE; + + if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0) + attrs.renderViaOffscreenBackBuffer = 0; + else + attrs.renderViaOffscreenBackBuffer = RGFW_GL_HINTS[RGFW_glAuxBuffers]; + + attrs.failIfMajorPerformanceCaveat = EM_FALSE; + attrs.majorVersion = (RGFW_GL_HINTS[RGFW_glMajor] == 0) ? 1 : RGFW_GL_HINTS[RGFW_glMajor]; + attrs.minorVersion = RGFW_GL_HINTS[RGFW_glMinor]; + + attrs.enableExtensionsByDefault = EM_TRUE; + attrs.explicitSwapControl = EM_TRUE; + + emscripten_webgl_init_context_attributes(&attrs); + win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs); + emscripten_webgl_make_context_current(win->src.ctx); + + #ifdef LEGACY_GL_EMULATION + EM_ASM("Module.useWebGL = true; GLImmediate.init();"); + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized"); + #endif + glViewport(0, 0, win->r.w, win->r.h); +#endif +} + +void RGFW_window_freeOpenGL(RGFW_window* win) { +#if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_OSMESA) + if (win->src.ctx == 0) return; + emscripten_webgl_destroy_context(win->src.ctx); + win->src.ctx = 0; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed"); +#elif defined(RGFW_OPENGL) && defined(RGFW_OSMESA) + if(win->src.ctx == 0) return; + OSMesaDestroyContext(win->src.ctx); + win->src.ctx = 0; +#else + RGFW_UNUSED(win); +#endif +} + +i32 RGFW_init(void) { +#if defined(RGFW_C89) || defined(__cplusplus) + if (_RGFW_init) return 0; + _RGFW_init = RGFW_TRUE; + _RGFW.root = NULL; _RGFW.current = NULL; _RGFW.windowCount = -2; _RGFW.eventLen = 0; _RGFW.eventIndex = 0; +#endif + + _RGFW.windowCount = 0; + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context initialized"); + return 0; +} + +RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) { + RGFW_window_basic_init(win, rect, flags); + RGFW_window_initOpenGL(win); + + #if defined(RGFW_WEBGPU) + win->src.ctx = wgpuCreateInstance(NULL); + win->src.device = emscripten_webgpu_get_device(); + win->src.queue = wgpuDeviceGetQueue(win->src.device); + #endif + + emscripten_set_canvas_element_size("#canvas", rect.w, rect.h); + emscripten_set_window_title(name); + + /* load callbacks */ + 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); + emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart); + emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend); + emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove); + emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel); + emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown); + emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup); + emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel); + emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin); + emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout); + emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad); + emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad); + + if (flags & RGFW_windowAllowDND) { + win->_flags |= RGFW_windowAllowDND; + } + + EM_ASM({ + window.addEventListener("keydown", + (event) => { + var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); + Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); + Module._RGFW_handleKeyEvent(key, code, 1); + _free(key); _free(code); + }, + true); + window.addEventListener("keyup", + (event) => { + var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code); + Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock")); + Module._RGFW_handleKeyEvent(key, code, 0); + _free(key); _free(code); + }, + true); + }); + + EM_ASM({ + var canvas = document.getElementById('canvas'); + canvas.addEventListener('drop', function(e) { + e.preventDefault(); + if (e.dataTransfer.file < 0) + return; + + var filenamesArray = []; + var count = e.dataTransfer.files.length; + + /* Read and save the files to emscripten's files */ + var drop_dir = '.rgfw_dropped_files'; + Module._RGFW_mkdir(drop_dir); + + for (var i = 0; i < count; i++) { + var file = e.dataTransfer.files[i]; + + var path = '/' + drop_dir + '/' + file.name.replace("//", '_'); + var reader = new FileReader(); + + reader.onloadend = (e) => { + if (reader.readyState != 2) { + out('failed to read dropped file: '+file.name+': '+reader.error); + } + else { + var data = e.target.result; + + _RGFW_writeFile(path, new Uint8Array(data), file.size); + } + }; + + reader.readAsArrayBuffer(file); + /* This works weird on modern opengl */ + var filename = stringToNewUTF8(path); + + filenamesArray.push(filename); + + Module._RGFW_makeSetValue(i, filename); + } + + Module._Emscripten_onDrop(count); + + for (var i = 0; i < count; ++i) { + _free(filenamesArray[i]); + } + }, true); + + canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true); + }); + + RGFW_window_setFlags(win, flags); + + if ((flags & RGFW_windowNoInitAPI) == 0) { + RGFW_window_initBuffer(win); + } + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created"); + return win; +} + +u8 RGFW_rgfwToKeyChar(u32 rgfw_keycode) { + return (u8)rgfw_keycode; /* TODO */ +} + +RGFW_event* RGFW_window_checkEvent(RGFW_window* win) { + if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL; + RGFW_event* ev = RGFW_window_checkEventCore(win); + if (ev) return ev; + + emscripten_sample_gamepad_data(); + /* check gamepads */ + int i; + for (i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) { + if (RGFW_gamepads[i] == 0) + continue; + EmscriptenGamepadEvent gamepadState; + + if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS) + break; + + /* Register buttons data for every connected gamepad */ + int j; + for (j = 0; (j < gamepadState.numButtons) && (j < 16); j++) { + u32 map[] = { + RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, + RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2, + RGFW_gamepadSelect, RGFW_gamepadStart, + RGFW_gamepadL3, RGFW_gamepadR3, + RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, RGFW_gamepadHome + }; + + + u32 button = map[j]; + if (button == 404) + continue; + + if (RGFW_gamepadPressed[i][button].current != gamepadState.digitalButton[j]) { + if (gamepadState.digitalButton[j]) + win->event.type = RGFW_gamepadButtonPressed; + else + win->event.type = RGFW_gamepadButtonReleased; + + win->event.gamepad = i; + win->event.button = map[j]; + + RGFW_gamepadPressed[i][button].prev = RGFW_gamepadPressed[i][button].current; + RGFW_gamepadPressed[i][button].current = gamepadState.digitalButton[j]; + + RGFW_gamepadButtonCallback(win, win->event.gamepad, win->event.button, gamepadState.digitalButton[j]); + return &win->event; + } + } + + for (j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) { + win->event.axisesCount = gamepadState.numAxes / 2; + if (RGFW_gamepadAxes[i][(size_t)(j / 2)].x != (i8)(gamepadState.axis[j] * 100.0f) || + RGFW_gamepadAxes[i][(size_t)(j / 2)].y != (i8)(gamepadState.axis[j + 1] * 100.0f) + ) { + + RGFW_gamepadAxes[i][(size_t)(j / 2)].x = (i8)(gamepadState.axis[j] * 100.0f); + RGFW_gamepadAxes[i][(size_t)(j / 2)].y = (i8)(gamepadState.axis[j + 1] * 100.0f); + win->event.axis[(size_t)(j / 2)] = RGFW_gamepadAxes[i][(size_t)(j / 2)]; + + win->event.type = RGFW_gamepadAxisMove; + win->event.gamepad = i; + win->event.whichAxis = j / 2; + + RGFW_gamepadAxisCallback(win, win->event.gamepad, win->event.axis, win->event.axisesCount, win->event.whichAxis); + return &win->event; + } + } + } + + return NULL; +} + +void RGFW_window_resize(RGFW_window* win, RGFW_area a) { + RGFW_UNUSED(win); + emscripten_set_canvas_element_size("#canvas", a.w, a.h); +} + +/* NOTE: I don't know if this is possible */ +void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } +/* this one might be possible but it looks iffy */ +RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(channels); RGFW_UNUSED(a); RGFW_UNUSED(icon); return NULL; } + +void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); } +void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); } + +RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { + static const char cursors[16][16] = { + "default", "default", "text", "crosshair", + "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize", + "move", "not-allowed" + }; + + RGFW_UNUSED(win); + EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]); + return RGFW_TRUE; +} + +RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { + return RGFW_window_setMouseStandard(win, RGFW_mouseNormal); +} + +void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) { + RGFW_window_showMouseFlags(win, show); + if (show) + RGFW_window_setMouseDefault(win); + else + EM_ASM(document.getElementById('canvas').style.cursor = 'none';); +} + +RGFW_point RGFW_getGlobalMousePoint(void) { + RGFW_point point; + point.x = EM_ASM_INT({ + return window.mouseX || 0; + }); + point.y = EM_ASM_INT({ + return window.mouseY || 0; + }); + return point; +} + +void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { + RGFW_UNUSED(win); + + EM_ASM_({ + var canvas = document.getElementById('canvas'); + if ($0) { + canvas.style.pointerEvents = 'none'; + } else { + canvas.style.pointerEvents = 'auto'; + } + }, passthrough); +} + +void RGFW_writeClipboard(const char* text, u32 textLen) { + RGFW_UNUSED(textLen); + EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text); +} + + +RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { + RGFW_UNUSED(str); RGFW_UNUSED(strCapacity); + /* + placeholder code for later + I'm not sure if this is possible do the the async stuff + */ + return 0; +} + +void RGFW_window_swapBuffers_software(RGFW_window* win) { +#if defined(RGFW_OSMESA) + EM_ASM_({ + var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); + let context = document.getElementById("canvas").getContext("2d"); + let image = context.getImageData(0, 0, $1, $2); + image.data.set(data); + context.putImageData(image, 0, $4 - $2); + }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h); +#elif defined(RGFW_BUFFER) + EM_ASM_({ + var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4); + let context = document.getElementById("canvas").getContext("2d"); + let image = context.getImageData(0, 0, $1, $2); + image.data.set(data); + context.putImageData(image, 0, 0); + }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h); + emscripten_sleep(0); +#else + RGFW_UNUSED(win); +#endif +} + +void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { +#if !defined(RGFW_WEBGPU) && !(defined(RGFW_OSMESA) || defined(RGFW_BUFFER)) + if (win == NULL) + emscripten_webgl_make_context_current(0); + else + emscripten_webgl_make_context_current(win->src.ctx); +#endif +} + + +void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { +#ifndef RGFW_WEBGPU + emscripten_webgl_commit_frame(); + +#endif + emscripten_sleep(0); +} + +#ifndef RGFW_WEBGPU +void* RGFW_getCurrent_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); } +#endif + +#ifndef RGFW_EGL +void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } +#endif + +void RGFW_deinit(void) { _RGFW.windowCount = -1; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, RGFW_DEBUG_CTX(NULL, 0), "global context deinitialized"); } + +void RGFW_window_close(RGFW_window* win) { + if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win); + + #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) + if ((win->_flags & RGFW_BUFFER_ALLOC)) + RGFW_FREE(win->buffer); + #endif + + RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed"); + _RGFW.windowCount--; + if (_RGFW.windowCount == 0) RGFW_deinit(); + + RGFW_clipboard_switch(NULL); + RGFW_FREE(win->event.droppedFiles); + if ((win->_flags & RGFW_WINDOW_ALLOC)) { + RGFW_FREE(win); + win = NULL; + } +} + +int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); } +int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); } + +RGFW_area RGFW_getScreenSize(void) { + return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight()); +} + +RGFW_bool RGFW_extensionSupportedPlatform(const char* extension, size_t len) { +#ifdef RGFW_OPENGL + return EM_ASM_INT({ + var ext = UTF8ToString($0, $1); + var canvas = document.querySelector('canvas'); + var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); + if (!gl) return 0; + + var supported = gl.getSupportedExtensions(); + return supported && supported.includes(ext) ? 1 : 0; + }, extension, len); +#else + return RGFW_FALSE; +#endif +} + +RGFW_proc RGFW_getProcAddress(const char* procname) { +#ifdef RGFW_OPENGL + return (RGFW_proc)emscripten_webgl_get_proc_address(procname); +#else + return NULL +#endif +} + +void RGFW_sleep(u64 milisecond) { + emscripten_sleep(milisecond); +} + +u64 RGFW_getTimerFreq(void) { return (u64)1000; } +u64 RGFW_getTimerValue(void) { return emscripten_get_now() * 1e+6; } + +void RGFW_releaseCursor(RGFW_window* win) { + RGFW_UNUSED(win); + emscripten_exit_pointerlock(); +} + +void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { + RGFW_UNUSED(win); RGFW_UNUSED(r); + + emscripten_request_pointerlock("#canvas", 1); +} + + +void RGFW_window_setName(RGFW_window* win, const char* name) { + RGFW_UNUSED(win); + emscripten_set_window_title(name); +} + +void RGFW_window_maximize(RGFW_window* win) { + RGFW_ASSERT(win != NULL); + + RGFW_area screen = RGFW_getScreenSize(); + RGFW_window_move(win, RGFW_POINT(0, 0)); + RGFW_window_resize(win, screen); +} + +void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { + RGFW_ASSERT(win != NULL); + if (fullscreen) { + win->_flags |= RGFW_windowFullscreen; + EM_ASM( Module.requestFullscreen(false, true); ); + return; + } + win->_flags &= ~(u32)RGFW_windowFullscreen; + EM_ASM( Module.exitFullscreen(false, true); ); +} + +void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { + RGFW_UNUSED(win); + EM_ASM({ + var element = document.getElementById("canvas"); + if (element) + element.style.opacity = $1; + }, "elementId", opacity); +} + /* unsupported functions */ void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); } RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; } RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_UNUSED(len); return NULL; } RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; } -void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_UNUSED(win); RGFW_UNUSED(x); RGFW_UNUSED(y); } -void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } -void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } -void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_UNUSED(win); RGFW_UNUSED(w); RGFW_UNUSED(h); } +void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } +void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } +void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } +void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); } void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); } void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); } -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, RGFW_icon type) { RGFW_UNUSED(win); RGFW_UNUSED(data); RGFW_UNUSED(w); RGFW_UNUSED(h); RGFW_UNUSED(format); RGFW_UNUSED(type); return RGFW_FALSE; } +RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); return RGFW_FALSE; } void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); } void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); } RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } @@ -13576,338 +11024,43 @@ RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return R RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; } RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return (RGFW_monitor){}; } -void RGFW_waitForEvent(i32 waitMS) { RGFW_UNUSED(waitMS); } #endif /* end of web asm defines */ -/* - * RGFW function pointer backend, made to allow you to compile for Wayland but fallback to X11 -*/ -#ifdef RGFW_DYNAMIC -typedef RGFW_window* (*RGFW_createWindowPlatform_ptr)(const char* name, RGFW_windowFlags flags, RGFW_window* win); -typedef RGFW_bool (*RGFW_getMouse_ptr)(i32* x, i32* y); -typedef u8 (*RGFW_rgfwToKeyChar_ptr)(u32 key); -typedef void (*RGFW_pollEvents_ptr)(void); -typedef void (*RGFW_window_move_ptr)(RGFW_window* win, i32 x, i32 y); -typedef void (*RGFW_window_resize_ptr)(RGFW_window* win, i32 w, i32 h); -typedef void (*RGFW_window_setAspectRatio_ptr)(RGFW_window* win, i32 w, i32 h); -typedef void (*RGFW_window_setMinSize_ptr)(RGFW_window* win, i32 w, i32 h); -typedef void (*RGFW_window_setMaxSize_ptr)(RGFW_window* win, i32 w, i32 h); -typedef void (*RGFW_window_maximize_ptr)(RGFW_window* win); -typedef void (*RGFW_window_focus_ptr)(RGFW_window* win); -typedef void (*RGFW_window_raise_ptr)(RGFW_window* win); -typedef void (*RGFW_window_setFullscreen_ptr)(RGFW_window* win, RGFW_bool fullscreen); -typedef void (*RGFW_window_setFloating_ptr)(RGFW_window* win, RGFW_bool floating); -typedef void (*RGFW_window_setOpacity_ptr)(RGFW_window* win, u8 opacity); -typedef void (*RGFW_window_minimize_ptr)(RGFW_window* win); -typedef void (*RGFW_window_restore_ptr)(RGFW_window* win); -typedef RGFW_bool (*RGFW_window_isFloating_ptr)(RGFW_window* win); -typedef void (*RGFW_window_setName_ptr)(RGFW_window* win, const char* name); -typedef void (*RGFW_window_setMousePassthrough_ptr)(RGFW_window* win, RGFW_bool passthrough); -typedef RGFW_bool (*RGFW_window_setIconEx_ptr)(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type); -typedef RGFW_mouse* (*RGFW_loadMouse_ptr)(u8* data, i32 w, i32 h, RGFW_format format); -typedef void (*RGFW_window_setMouse_ptr)(RGFW_window* win, RGFW_mouse* mouse); -typedef void (*RGFW_window_moveMouse_ptr)(RGFW_window* win, i32 x, i32 y); -typedef RGFW_bool (*RGFW_window_setMouseDefault_ptr)(RGFW_window* win); -typedef RGFW_bool (*RGFW_window_setMouseStandard_ptr)(RGFW_window* win, u8 mouse); -typedef void (*RGFW_window_hide_ptr)(RGFW_window* win); -typedef void (*RGFW_window_show_ptr)(RGFW_window* win); -typedef RGFW_ssize_t (*RGFW_readClipboardPtr_ptr)(char* str, size_t strCapacity); -typedef void (*RGFW_writeClipboard_ptr)(const char* text, u32 textLen); -typedef RGFW_bool (*RGFW_window_isHidden_ptr)(RGFW_window* win); -typedef RGFW_bool (*RGFW_window_isMinimized_ptr)(RGFW_window* win); -typedef RGFW_bool (*RGFW_window_isMaximized_ptr)(RGFW_window* win); -typedef RGFW_monitor* (*RGFW_getMonitors_ptr)(size_t* len); -typedef RGFW_monitor (*RGFW_getPrimaryMonitor_ptr)(void); -typedef RGFW_bool (*RGFW_monitor_requestMode_ptr)(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request); -typedef RGFW_monitor (*RGFW_window_getMonitor_ptr)(RGFW_window* win); -typedef void (*RGFW_window_closePlatform_ptr)(RGFW_window* win); -typedef RGFW_bool (*RGFW_createSurfacePtr_ptr)(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface); -typedef void (*RGFW_window_blitSurface_ptr)(RGFW_window* win, RGFW_surface* surface); -typedef void (*RGFW_surface_freePtr_ptr)(RGFW_surface* surface); -typedef void (*RGFW_freeMouse_ptr)(RGFW_mouse* mouse); -typedef void (*RGFW_window_setBorder_ptr)(RGFW_window* win, RGFW_bool border); -typedef void (*RGFW_releaseCursor_ptr)(RGFW_window* win); -typedef void (*RGFW_captureCursor_ptr)(RGFW_window* win); -#ifdef RGFW_OPENGL -typedef void (*RGFW_window_makeCurrentContext_OpenGL_ptr)(RGFW_window* win); -typedef void* (*RGFW_getCurrentContext_OpenGL_ptr)(void); -typedef void (*RGFW_window_swapBuffers_OpenGL_ptr)(RGFW_window* win); -typedef void (*RGFW_window_swapInterval_OpenGL_ptr)(RGFW_window* win, i32 swapInterval); -typedef RGFW_bool (*RGFW_extensionSupportedPlatform_OpenGL_ptr)(const char* extension, size_t len); -typedef RGFW_proc (*RGFW_getProcAddress_OpenGL_ptr)(const char* procname); -typedef RGFW_bool (*RGFW_window_createContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints); -typedef void (*RGFW_window_deleteContextPtr_OpenGL_ptr)(RGFW_window* win, RGFW_glContext* ctx); -#endif -#ifdef RGFW_WEBGPU -typedef WGPUSurface (*RGFW_window_createSurface_WebGPU_ptr)(RGFW_window* window, WGPUInstance instance); -#endif +/* unix (macOS, linux, web asm) only stuff */ +#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND) +#ifndef RGFW_NO_THREADS +#include -/* Structure to hold all function pointers */ -typedef struct RGFW_FunctionPointers { - RGFW_createSurfacePtr_ptr createSurfacePtr; - RGFW_window_blitSurface_ptr window_blitSurface; - RGFW_surface_freePtr_ptr surface_freePtr; - RGFW_freeMouse_ptr freeMouse; - RGFW_window_setBorder_ptr window_setBorder; - RGFW_releaseCursor_ptr releaseCursor; - RGFW_captureCursor_ptr captureCursor; - RGFW_createWindowPlatform_ptr createWindowPlatform; - RGFW_getMouse_ptr getGlobalMouse; - RGFW_rgfwToKeyChar_ptr rgfwToKeyChar; - RGFW_pollEvents_ptr pollEvents; - RGFW_window_move_ptr window_move; - RGFW_window_resize_ptr window_resize; - RGFW_window_setAspectRatio_ptr window_setAspectRatio; - RGFW_window_setMinSize_ptr window_setMinSize; - RGFW_window_setMaxSize_ptr window_setMaxSize; - RGFW_window_maximize_ptr window_maximize; - RGFW_window_focus_ptr window_focus; - RGFW_window_raise_ptr window_raise; - RGFW_window_setFullscreen_ptr window_setFullscreen; - RGFW_window_setFloating_ptr window_setFloating; - RGFW_window_setOpacity_ptr window_setOpacity; - RGFW_window_minimize_ptr window_minimize; - RGFW_window_restore_ptr window_restore; - RGFW_window_isFloating_ptr window_isFloating; - RGFW_window_setName_ptr window_setName; - RGFW_window_setMousePassthrough_ptr window_setMousePassthrough; - RGFW_window_setIconEx_ptr window_setIconEx; - RGFW_loadMouse_ptr loadMouse; - RGFW_window_setMouse_ptr window_setMouse; - RGFW_window_moveMouse_ptr window_moveMouse; - RGFW_window_setMouseDefault_ptr window_setMouseDefault; - RGFW_window_setMouseStandard_ptr window_setMouseStandard; - RGFW_window_hide_ptr window_hide; - RGFW_window_show_ptr window_show; - RGFW_readClipboardPtr_ptr readClipboardPtr; - RGFW_writeClipboard_ptr writeClipboard; - RGFW_window_isHidden_ptr window_isHidden; - RGFW_window_isMinimized_ptr window_isMinimized; - RGFW_window_isMaximized_ptr window_isMaximized; - RGFW_getMonitors_ptr getMonitors; - RGFW_getPrimaryMonitor_ptr getPrimaryMonitor; - RGFW_monitor_requestMode_ptr monitor_requestMode; - RGFW_window_getMonitor_ptr window_getMonitor; - RGFW_window_closePlatform_ptr window_closePlatform; -#ifdef RGFW_OPENGL - RGFW_extensionSupportedPlatform_OpenGL_ptr extensionSupportedPlatform_OpenGL; - RGFW_getProcAddress_OpenGL_ptr getProcAddress_OpenGL; - RGFW_window_createContextPtr_OpenGL_ptr window_createContextPtr_OpenGL; - RGFW_window_deleteContextPtr_OpenGL_ptr window_deleteContextPtr_OpenGL; - RGFW_window_makeCurrentContext_OpenGL_ptr window_makeCurrentContext_OpenGL; - RGFW_getCurrentContext_OpenGL_ptr getCurrentContext_OpenGL; - RGFW_window_swapBuffers_OpenGL_ptr window_swapBuffers_OpenGL; - RGFW_window_swapInterval_OpenGL_ptr window_swapInterval_OpenGL; -#endif -#ifdef RGFW_WEBGPU - RGFW_window_createSurface_WebGPU_ptr window_createSurface_WebGPU; -#endif -} RGFW_functionPointers; - -RGFW_functionPointers RGFW_api; - -RGFW_bool RGFW_createSurfacePtr(u8* data, i32 w, i32 h, RGFW_format format, RGFW_surface* surface) { return RGFW_api.createSurfacePtr(data, w, h, format, surface); } -void RGFW_surface_freePtr(RGFW_surface* surface) { RGFW_api.surface_freePtr(surface); } -void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_api.freeMouse(mouse); } -void RGFW_window_blitSurface(RGFW_window* win, RGFW_surface* surface) { RGFW_api.window_blitSurface(win, surface); } -void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_api.window_setBorder(win, border); } -void RGFW_releaseCursor(RGFW_window* win) { RGFW_api.releaseCursor(win); } -void RGFW_captureCursor(RGFW_window* win) { RGFW_api.captureCursor(win); } -RGFW_window* RGFW_createWindowPlatform(const char* name, RGFW_windowFlags flags, RGFW_window* win) { RGFW_init(); return RGFW_api.createWindowPlatform(name, flags, win); } -RGFW_bool RGFW_getGlobalMouse(i32* x, i32* y) { return RGFW_api.getGlobalMouse(x, y); } -u8 RGFW_rgfwToKeyChar(u32 key) { return RGFW_api.rgfwToKeyChar(key); } -void RGFW_pollEvents(void) { RGFW_api.pollEvents(); } -void RGFW_window_move(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_move(win, x, y); } -void RGFW_window_resize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_resize(win, w, h); } -void RGFW_window_setAspectRatio(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setAspectRatio(win, w, h); } -void RGFW_window_setMinSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMinSize(win, w, h); } -void RGFW_window_setMaxSize(RGFW_window* win, i32 w, i32 h) { RGFW_api.window_setMaxSize(win, w, h); } -void RGFW_window_maximize(RGFW_window* win) { RGFW_api.window_maximize(win); } -void RGFW_window_focus(RGFW_window* win) { RGFW_api.window_focus(win); } -void RGFW_window_raise(RGFW_window* win) { RGFW_api.window_raise(win); } -void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) { RGFW_api.window_setFullscreen(win, fullscreen); } -void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_api.window_setFloating(win, floating); } -void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) { RGFW_api.window_setOpacity(win, opacity); } -void RGFW_window_minimize(RGFW_window* win) { RGFW_api.window_minimize(win); } -void RGFW_window_restore(RGFW_window* win) { RGFW_api.window_restore(win); } -RGFW_bool RGFW_window_isFloating(RGFW_window* win) { return RGFW_api.window_isFloating(win); } -void RGFW_window_setName(RGFW_window* win, const char* name) { RGFW_api.window_setName(win, name); } - -#ifndef RGFW_NO_PASSTHROUGH -void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) { RGFW_api.window_setMousePassthrough(win, passthrough); } -#endif - -RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, i32 w, i32 h, RGFW_format format, u8 type) { return RGFW_api.window_setIconEx(win, data, w, h, format, type); } -RGFW_mouse* RGFW_loadMouse(u8* data, i32 w, i32 h, RGFW_format format) { return RGFW_api.loadMouse(data, w, h, format); } -void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_api.window_setMouse(win, mouse); } -void RGFW_window_moveMouse(RGFW_window* win, i32 x, i32 y) { RGFW_api.window_moveMouse(win, x, y); } -RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) { return RGFW_api.window_setMouseDefault(win); } -RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { return RGFW_api.window_setMouseStandard(win, mouse); } -void RGFW_window_hide(RGFW_window* win) { RGFW_api.window_hide(win); } -void RGFW_window_show(RGFW_window* win) { RGFW_api.window_show(win); } -RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) { return RGFW_api.readClipboardPtr(str, strCapacity); } -void RGFW_writeClipboard(const char* text, u32 textLen) { RGFW_api.writeClipboard(text, textLen); } -RGFW_bool RGFW_window_isHidden(RGFW_window* win) { return RGFW_api.window_isHidden(win); } -RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { return RGFW_api.window_isMinimized(win); } -RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { return RGFW_api.window_isMaximized(win); } -RGFW_monitor* RGFW_getMonitors(size_t* len) { return RGFW_api.getMonitors(len); } -RGFW_monitor RGFW_getPrimaryMonitor(void) { return RGFW_api.getPrimaryMonitor(); } -RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { return RGFW_api.monitor_requestMode(mon, mode, request); } -RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { return RGFW_api.window_getMonitor(win); } -void RGFW_window_closePlatform(RGFW_window* win) { RGFW_api.window_closePlatform(win); } - -#ifdef RGFW_OPENGL -RGFW_bool RGFW_extensionSupportedPlatform_OpenGL(const char* extension, size_t len) { return RGFW_api.extensionSupportedPlatform_OpenGL(extension, len); } -RGFW_proc RGFW_getProcAddress_OpenGL(const char* procname) { return RGFW_api.getProcAddress_OpenGL(procname); } -RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) { return RGFW_api.window_createContextPtr_OpenGL(win, ctx, hints); } -void RGFW_window_deleteContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx) { RGFW_api.window_deleteContextPtr_OpenGL(win, ctx); } -void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) { RGFW_api.window_makeCurrentContext_OpenGL(win); } -void* RGFW_getCurrentContext_OpenGL(void) { return RGFW_api.getCurrentContext_OpenGL(); } -void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { RGFW_api.window_swapBuffers_OpenGL(win); } -void RGFW_window_swapInterval_OpenGL(RGFW_window* win, i32 swapInterval) { RGFW_api.window_swapInterval_OpenGL(win, swapInterval); } -#endif - -#ifdef RGFW_WEBGPU -WGPUSurface RGFW_window_createSurface_WebGPU(RGFW_window* window, WGPUInstance instance) { return RGFW_api.window_createSurface_WebGPU(window, instance); } -#endif -#endif /* RGFW_DYNAMIC */ - -/* - * start of X11 AND wayland defines - * this allows a single executable to support x11 AND wayland - * falling back to x11 if wayland fails to initalize -*/ -#if defined(RGFW_WAYLAND) && defined(RGFW_X11) -void RGFW_load_X11(void) { - RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_X11; - RGFW_api.window_blitSurface = RGFW_window_blitSurface_X11; - RGFW_api.surface_freePtr = RGFW_surface_freePtr_X11; - RGFW_api.freeMouse = RGFW_freeMouse_X11; - RGFW_api.window_setBorder = RGFW_window_setBorder_X11; - RGFW_api.releaseCursor = RGFW_releaseCursor_X11; - RGFW_api.captureCursor = RGFW_captureCursor_X11; - RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_X11; - RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_X11; - RGFW_api.rgfwToKeyChar = RGFW_rgfwToKeyChar_X11; - RGFW_api.pollEvents = RGFW_pollEvents_X11; - RGFW_api.window_move = RGFW_window_move_X11; - RGFW_api.window_resize = RGFW_window_resize_X11; - RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_X11; - RGFW_api.window_setMinSize = RGFW_window_setMinSize_X11; - RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_X11; - RGFW_api.window_maximize = RGFW_window_maximize_X11; - RGFW_api.window_focus = RGFW_window_focus_X11; - RGFW_api.window_raise = RGFW_window_raise_X11; - RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_X11; - RGFW_api.window_setFloating = RGFW_window_setFloating_X11; - RGFW_api.window_setOpacity = RGFW_window_setOpacity_X11; - RGFW_api.window_minimize = RGFW_window_minimize_X11; - RGFW_api.window_restore = RGFW_window_restore_X11; - RGFW_api.window_isFloating = RGFW_window_isFloating_X11; - RGFW_api.window_setName = RGFW_window_setName_X11; -#ifndef RGFW_NO_PASSTHROUGH - RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_X11; -#endif - RGFW_api.window_setIconEx = RGFW_window_setIconEx_X11; - RGFW_api.loadMouse = RGFW_loadMouse_X11; - RGFW_api.window_setMouse = RGFW_window_setMouse_X11; - RGFW_api.window_moveMouse = RGFW_window_moveMouse_X11; - RGFW_api.window_setMouseDefault = RGFW_window_setMouseDefault_X11; - RGFW_api.window_setMouseStandard = RGFW_window_setMouseStandard_X11; - RGFW_api.window_hide = RGFW_window_hide_X11; - RGFW_api.window_show = RGFW_window_show_X11; - RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_X11; - RGFW_api.writeClipboard = RGFW_writeClipboard_X11; - RGFW_api.window_isHidden = RGFW_window_isHidden_X11; - RGFW_api.window_isMinimized = RGFW_window_isMinimized_X11; - RGFW_api.window_isMaximized = RGFW_window_isMaximized_X11; - RGFW_api.getMonitors = RGFW_getMonitors_X11; - RGFW_api.getPrimaryMonitor = RGFW_getPrimaryMonitor_X11; - RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_X11; - RGFW_api.window_getMonitor = RGFW_window_getMonitor_X11; - RGFW_api.window_closePlatform = RGFW_window_closePlatform_X11; -#ifdef RGFW_OPENGL - RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_X11; - RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_X11; - RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_X11; - RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_X11; - RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_X11; - RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_X11; - RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_X11; - RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_X11; -#endif -#ifdef RGFW_WEBGPU - RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_X11; -#endif +RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { + RGFW_thread t; + pthread_create((pthread_t*) &t, NULL, *ptr, args); + return t; } +void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); } +void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); } -void RGFW_load_Wayland(void) { - RGFW_api.createSurfacePtr = RGFW_createSurfacePtr_Wayland; - RGFW_api.window_blitSurface = RGFW_window_blitSurface_Wayland; - RGFW_api.surface_freePtr = RGFW_surface_freePtr_Wayland; - RGFW_api.freeMouse = RGFW_freeMouse_Wayland; - RGFW_api.window_setBorder = RGFW_window_setBorder_Wayland; - RGFW_api.releaseCursor = RGFW_releaseCursor_Wayland; - RGFW_api.captureCursor = RGFW_captureCursor_Wayland; - RGFW_api.createWindowPlatform = RGFW_createWindowPlatform_Wayland; - RGFW_api.getGlobalMouse = RGFW_getGlobalMouse_Wayland; - RGFW_api.rgfwToKeyChar = RGFW_rgfwToKeyChar_Wayland; - RGFW_api.pollEvents = RGFW_pollEvents_Wayland; - RGFW_api.window_move = RGFW_window_move_Wayland; - RGFW_api.window_resize = RGFW_window_resize_Wayland; - RGFW_api.window_setAspectRatio = RGFW_window_setAspectRatio_Wayland; - RGFW_api.window_setMinSize = RGFW_window_setMinSize_Wayland; - RGFW_api.window_setMaxSize = RGFW_window_setMaxSize_Wayland; - RGFW_api.window_maximize = RGFW_window_maximize_Wayland; - RGFW_api.window_focus = RGFW_window_focus_Wayland; - RGFW_api.window_raise = RGFW_window_raise_Wayland; - RGFW_api.window_setFullscreen = RGFW_window_setFullscreen_Wayland; - RGFW_api.window_setFloating = RGFW_window_setFloating_Wayland; - RGFW_api.window_setOpacity = RGFW_window_setOpacity_Wayland; - RGFW_api.window_minimize = RGFW_window_minimize_Wayland; - RGFW_api.window_restore = RGFW_window_restore_Wayland; - RGFW_api.window_isFloating = RGFW_window_isFloating_Wayland; - RGFW_api.window_setName = RGFW_window_setName_Wayland; -#ifndef RGFW_NO_PASSTHROUGH - RGFW_api.window_setMousePassthrough = RGFW_window_setMousePassthrough_Wayland; +#if defined(__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 - RGFW_api.window_setIconEx = RGFW_window_setIconEx_Wayland; - RGFW_api.loadMouse = RGFW_loadMouse_Wayland; - RGFW_api.window_setMouse = RGFW_window_setMouse_Wayland; - RGFW_api.window_moveMouse = RGFW_window_moveMouse_Wayland; - RGFW_api.window_setMouseDefault = RGFW_window_setMouseDefault_Wayland; - RGFW_api.window_setMouseStandard = RGFW_window_setMouseStandard_Wayland; - RGFW_api.window_hide = RGFW_window_hide_Wayland; - RGFW_api.window_show = RGFW_window_show_Wayland; - RGFW_api.readClipboardPtr = RGFW_readClipboardPtr_Wayland; - RGFW_api.writeClipboard = RGFW_writeClipboard_Wayland; - RGFW_api.window_isHidden = RGFW_window_isHidden_Wayland; - RGFW_api.window_isMinimized = RGFW_window_isMinimized_Wayland; - RGFW_api.window_isMaximized = RGFW_window_isMaximized_Wayland; - RGFW_api.getMonitors = RGFW_getMonitors_Wayland; - RGFW_api.getPrimaryMonitor = RGFW_getPrimaryMonitor_Wayland; - RGFW_api.monitor_requestMode = RGFW_monitor_requestMode_Wayland; - RGFW_api.window_getMonitor = RGFW_window_getMonitor_Wayland; - RGFW_api.window_closePlatform = RGFW_window_closePlatform_Wayland; -#ifdef RGFW_OPENGL - RGFW_api.extensionSupportedPlatform_OpenGL = RGFW_extensionSupportedPlatform_OpenGL_Wayland; - RGFW_api.getProcAddress_OpenGL = RGFW_getProcAddress_OpenGL_Wayland; - RGFW_api.window_createContextPtr_OpenGL = RGFW_window_createContextPtr_OpenGL_Wayland; - RGFW_api.window_deleteContextPtr_OpenGL = RGFW_window_deleteContextPtr_OpenGL_Wayland; - RGFW_api.window_makeCurrentContext_OpenGL = RGFW_window_makeCurrentContext_OpenGL_Wayland; - RGFW_api.getCurrentContext_OpenGL = RGFW_getCurrentContext_OpenGL_Wayland; - RGFW_api.window_swapBuffers_OpenGL = RGFW_window_swapBuffers_OpenGL_Wayland; - RGFW_api.window_swapInterval_OpenGL = RGFW_window_swapInterval_OpenGL_Wayland; -#endif -#ifdef RGFW_WEBGPU - RGFW_api.window_createSurface_WebGPU = RGFW_window_createSurface_WebGPU_Wayland; #endif + +#ifndef RGFW_WASM +void RGFW_sleep(u64 ms) { + struct timespec time; + time.tv_sec = 0; + time.tv_nsec = (long int)((double)ms * 1e+6); + + #ifndef RGFW_NO_UNIX_CLOCK + nanosleep(&time, NULL); + #endif } -#endif /* wayland AND x11 */ -/* end of X11 AND wayland defines */ +#endif +#endif /* end of unix / mac stuff */ #endif /* RGFW_IMPLEMENTATION */ #if defined(__cplusplus) && !defined(__EMSCRIPTEN__) @@ -13917,4 +11070,3 @@ void RGFW_load_Wayland(void) { #if _MSC_VER #pragma warning( pop ) #endif - diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 2671538d8..a1b13856b 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -48,6 +48,11 @@ * **********************************************************************************************/ +#ifndef RAYLIB_H /* this should never actually happen, it's only here for IDEs */ +#include "raylib.h" +#include "../rcore.c" +#endif + #if defined(PLATFORM_WEB_RGFW) #define RGFW_NO_GL_HEADER #endif From f031b2f4f4c343871f6fca812677b918cd2c157b Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Dec 2025 18:20:02 +0100 Subject: [PATCH 37/57] Alignment with other platform backends, avoid unneeded includes --- src/platforms/rcore_desktop_rgfw.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index a1b13856b..2671538d8 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -48,11 +48,6 @@ * **********************************************************************************************/ -#ifndef RAYLIB_H /* this should never actually happen, it's only here for IDEs */ -#include "raylib.h" -#include "../rcore.c" -#endif - #if defined(PLATFORM_WEB_RGFW) #define RGFW_NO_GL_HEADER #endif From 33adda198366e560afa59a806dd8db2609261e40 Mon Sep 17 00:00:00 2001 From: dtasada <83500532+dtasada@users.noreply.github.com> Date: Tue, 16 Dec 2025 18:24:53 +0100 Subject: [PATCH 38/57] fixed build errors with zig. now compatible with zig master 0.16.0-dev.1593+c13857e50. still backwards compatible with 0.15.1 (#5415) --- build.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.zig b/build.zig index 5d2902111..239b10f9e 100644 --- a/build.zig +++ b/build.zig @@ -106,9 +106,9 @@ const config_h_flags = outer: { if (std.mem.startsWith(u8, line, "//")) continue; if (std.mem.startsWith(u8, line, "#if")) continue; - var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace + var flag = std.mem.trimStart(u8, line, " \t"); // Trim whitespace flag = flag["#define ".len - 1 ..]; // Remove #define - flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace + flag = std.mem.trimStart(u8, flag, " \t"); // Trim whitespace flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space flag = "-D" ++ flag; // Prepend with -D @@ -193,7 +193,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. // No GLFW required on PLATFORM_DRM if (options.platform != .drm) { - raylib.addIncludePath(b.path("src/external/glfw/include")); + raylib.root_module.addIncludePath(b.path("src/external/glfw/include")); } var c_source_files: std.ArrayList([]const u8) = try .initCapacity(b.allocator, 2); @@ -224,7 +224,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. raylib.root_module.addCMacro(options.opengl_version.toCMacroStr(), ""); } - raylib.addIncludePath(b.path("src/platforms")); + raylib.root_module.addIncludePath(b.path("src/platforms")); switch (target.result.os.tag) { .windows => { switch (options.platform) { From 1c94e948733b69e857f1f7014e72ca331c99e089 Mon Sep 17 00:00:00 2001 From: caszu <109808097+caszuu@users.noreply.github.com> Date: Tue, 16 Dec 2025 18:26:20 +0100 Subject: [PATCH 39/57] [rcore] Implement `FLAG_WINDOW_ALWAYS_RUN` on Android (#5414) --- src/platforms/rcore_android.c | 126 ++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 4 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index bc8a25f8f..575807b9a 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -357,13 +357,125 @@ void RestoreWindow(void) // Set window configuration state using flags void SetWindowState(unsigned int flags) { - TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform"); + if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead"); + + // State change: FLAG_WINDOW_ALWAYS_RUN + if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) + { + FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN); + } + + // Setting other window flags is not supported on android + + if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_VSYNC_HINT) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_BORDERLESS_WINDOWED_MODE) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_FULLSCREEN_MODE) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_UNDECORATED) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_HIDDEN) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MAXIMIZED) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MINIMIZED) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_TRANSPARENT) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_HIGHDPI) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MOUSE_PASSTHROUGH) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_MSAA_4X_HINT) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT)) + { + TRACELOG(LOG_WARNING, "SetWindowState(FLAG_INTERLACED_HINT) not available on target platform"); + } } // Clear window configuration state flags void ClearWindowState(unsigned int flags) { - TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform"); + // State change: FLAG_WINDOW_ALWAYS_RUN + if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) + { + FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN); + } + + // Clearing other window flags is not supported on android + + if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_VSYNC_HINT) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_BORDERLESS_WINDOWED_MODE) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_FULLSCREEN_MODE) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_UNDECORATED) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_HIDDEN) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MAXIMIZED) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MINIMIZED) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_TRANSPARENT) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_HIGHDPI) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MOUSE_PASSTHROUGH) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_MSAA_4X_HINT) not available on target platform"); + } + if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT)) + { + TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_INTERLACED_HINT) not available on target platform"); + } } // Set icon for window @@ -601,6 +713,12 @@ void DisableCursor(void) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { + if (platform.surface == EGL_NO_SURFACE) + { + TRACELOG(LOG_WARNING, "SwapScreenBuffer() called with no window, skipping frame"); + return; + } + eglSwapBuffers(platform.device, platform.surface); } @@ -740,8 +858,8 @@ void PollInputEvents(void) int pollEvents = 0; // Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll - // NOTE: Activity is paused if not enabled (platform.appEnabled) - while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT)) + // NOTE: Activity is paused if not enabled (platform.appEnabled) and always run flag is not set (FLAG_WINDOW_ALWAYS_RUN) + while ((pollResult = ALooper_pollOnce((platform.appEnabled || FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN))? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT)) { // Process this event if (platform.source != NULL) platform.source->process(platform.app, platform.source); From 7a5e8aa3a5a95d99e242791b6cda2839281b23d5 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Dec 2025 18:30:33 +0100 Subject: [PATCH 40/57] Update rcore_android.c --- src/platforms/rcore_android.c | 122 ++-------------------------------- 1 file changed, 4 insertions(+), 118 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 575807b9a..7b8d3e052 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -358,124 +358,16 @@ void RestoreWindow(void) void SetWindowState(unsigned int flags) { if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead"); - + // State change: FLAG_WINDOW_ALWAYS_RUN - if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) - { - FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN); - } - - // Setting other window flags is not supported on android - - if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_VSYNC_HINT) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_BORDERLESS_WINDOWED_MODE) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_FULLSCREEN_MODE) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_UNDECORATED) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_HIDDEN) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MAXIMIZED) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MINIMIZED) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_TRANSPARENT) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_HIGHDPI) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MOUSE_PASSTHROUGH) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_MSAA_4X_HINT) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT)) - { - TRACELOG(LOG_WARNING, "SetWindowState(FLAG_INTERLACED_HINT) not available on target platform"); - } + if (!FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN); } // Clear window configuration state flags void ClearWindowState(unsigned int flags) { // State change: FLAG_WINDOW_ALWAYS_RUN - if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) - { - FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN); - } - - // Clearing other window flags is not supported on android - - if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_VSYNC_HINT) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_BORDERLESS_WINDOWED_MODE) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_FULLSCREEN_MODE) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_UNDECORATED) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_HIDDEN) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MAXIMIZED) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MINIMIZED) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_TRANSPARENT) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_HIGHDPI) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MOUSE_PASSTHROUGH) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_MSAA_4X_HINT) not available on target platform"); - } - if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT)) - { - TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_INTERLACED_HINT) not available on target platform"); - } + if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN); } // Set icon for window @@ -713,13 +605,7 @@ void DisableCursor(void) // Swap back buffer with front buffer (screen drawing) void SwapScreenBuffer(void) { - if (platform.surface == EGL_NO_SURFACE) - { - TRACELOG(LOG_WARNING, "SwapScreenBuffer() called with no window, skipping frame"); - return; - } - - eglSwapBuffers(platform.device, platform.surface); + if (platform.surface != EGL_NO_SURFACE) eglSwapBuffers(platform.device, platform.surface); } //---------------------------------------------------------------------------------- From 80ad96acc2837f26d2b40a52ce4d6bbfc1c28cd1 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Dec 2025 18:33:07 +0100 Subject: [PATCH 41/57] Fix #5413 --- examples/text/text_strings_management.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/text/text_strings_management.c b/examples/text/text_strings_management.c index 6c110e6ef..d2e349279 100644 --- a/examples/text/text_strings_management.c +++ b/examples/text/text_strings_management.c @@ -316,7 +316,7 @@ void SliceTextParticle(TextParticle *tp, int particlePos, int sliceLength, TextP void SliceTextParticleByChar(TextParticle *tp, char charToSlice, TextParticle *tps, int *particleCount) { int tokenCount = 0; - const char **tokens = TextSplit(tp->text, charToSlice, &tokenCount); + char **tokens = TextSplit(tp->text, charToSlice, &tokenCount); if (tokenCount > 1) { From 7553e9d58640ba0c3a2fc185a9cb458f00fae06e Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Dec 2025 19:36:01 +0100 Subject: [PATCH 42/57] REVIEWED: Gamepads on latest `SDL2 2.32.8` and `SDL3 3.3.6` #5403 --- .gitignore | 4 ++ src/platforms/rcore_desktop_sdl.c | 85 +++++++++++++++++-------------- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index e5f6faf4d..f7b2cccf6 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,10 @@ packages/ *.h.pch ./*.obj +# Ignore SDL libs for testing +src/external/SDL2 +src/external/SDL3 + # Emscripten emsdk diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 995336ec0..7316f3c14 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -57,7 +57,7 @@ // SDL base library (window/rendered, input, timing... functionality) #ifdef USING_SDL3_PROJECT #include "SDL3/SDL.h" -#elif USING_SDL2_PROJECT +#elif defined(USING_SDL2_PROJECT) #include "SDL2/SDL.h" #else #include "SDL.h" @@ -71,7 +71,7 @@ // SDL OpenGL functionality (if required, instead of internal renderer) #ifdef USING_SDL3_PROJECT #include "SDL3/SDL_opengl.h" - #elif USING_SDL2_PROJECT + #elif defined(USING_SDL2_PROJECT) #include "SDL2/SDL_opengl.h" #else #include "SDL_opengl.h" @@ -1041,7 +1041,7 @@ int GetMonitorPhysicalWidth(int monitor) SDL_DisplayMode mode; SDL_GetCurrentDisplayMode(monitor, &mode); // Calculate size on inches, then convert to millimeter - if (ddpi > 0.0f) width = (mode.w/ddpi)*25.4f; + if (ddpi > 0.0f) width = (int)((mode.w/ddpi)*25.4f); } else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); @@ -1065,7 +1065,7 @@ int GetMonitorPhysicalHeight(int monitor) SDL_DisplayMode mode; SDL_GetCurrentDisplayMode(monitor, &mode); // Calculate size on inches, then convert to millimeter - if (ddpi > 0.0f) height = (mode.h/ddpi)*25.4f; + if (ddpi > 0.0f) height = (int)((mode.h/ddpi)*25.4f); } else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor"); @@ -1127,14 +1127,15 @@ Vector2 GetWindowScaleDPI(void) { Vector2 scale = { 1.0f, 1.0f }; -#ifndef USING_VERSION_SDL3 - // NOTE: SDL_GetWindowDisplayScale was only added on SDL3 +#if defined(USING_VERSION_SDL3) + // NOTE: SDL_GetWindowDisplayScale added on SDL3 // REF: https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale - // TODO: Implement the window scale factor calculation manually - TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform"); -#else scale.x = SDL_GetWindowDisplayScale(platform.window); scale.y = scale.x; +#else + // NOTE: SDL_GetWindowDisplayScale not available on SDL2 + // TODO: Implement the window scale factor calculation manually + TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform"); #endif return scale; @@ -1195,7 +1196,7 @@ Image GetClipboardImage(void) if (fileData) { - image = LoadImageFromMemory(imageExtensions[i], fileData, dataSize); + image = LoadImageFromMemory(imageExtensions[i], fileData, (int)dataSize); if (IsImageValid(image)) { TRACELOG(LOG_INFO, "Clipboard: Got image from clipboard successfully: %s", imageExtensions[i]); @@ -1454,7 +1455,7 @@ void PollInputEvents(void) } break; - // Window events are also polled (Minimized, maximized, close...) + // Window events are also polled (minimized, maximized, close...) #ifndef USING_VERSION_SDL3 // SDL3 states: @@ -1488,7 +1489,8 @@ void PollInputEvents(void) CORE.Window.resizedLastFrame = true; #ifndef USING_VERSION_SDL3 - // Manually detect if the window was maximized (due to SDL2 restore being unreliable on some platforms) to remove the FLAG_WINDOW_MAXIMIZED accordingly + // Manually detect if the window was maximized (due to SDL2 restore being unreliable on some platforms) + // to remove the FLAG_WINDOW_MAXIMIZED accordingly if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) { int borderTop = 0; @@ -1504,14 +1506,8 @@ void PollInputEvents(void) #endif } break; - case SDL_WINDOWEVENT_ENTER: - { - CORE.Input.Mouse.cursorOnScreen = true; - } break; - case SDL_WINDOWEVENT_LEAVE: - { - CORE.Input.Mouse.cursorOnScreen = false; - } break; + case SDL_WINDOWEVENT_ENTER: CORE.Input.Mouse.cursorOnScreen = true; break; + case SDL_WINDOWEVENT_LEAVE: CORE.Input.Mouse.cursorOnScreen = false; break; case SDL_WINDOWEVENT_MINIMIZED: { @@ -1750,7 +1746,11 @@ void PollInputEvents(void) { int button = -1; + #if defined(USING_VERSION_SDL3) switch (event.gbutton.button) + #else + switch (event.jbutton.button) + #endif { case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break; case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break; @@ -1778,7 +1778,11 @@ void PollInputEvents(void) { for (int i = 0; i < MAX_GAMEPADS; i++) { + #if defined(USING_VERSION_SDL3) if (platform.gamepadId[i] == event.gbutton.which) + #else + if (platform.gamepadId[i] == event.jbutton.which) + #endif { CORE.Input.Gamepad.currentButtonState[i][button] = 1; CORE.Input.Gamepad.lastButtonPressed = button; @@ -1791,7 +1795,11 @@ void PollInputEvents(void) { int button = -1; + #if defined(USING_VERSION_SDL3) switch (event.gbutton.button) + #else + switch (event.jbutton.button) + #endif { case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break; case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break; @@ -1819,7 +1827,11 @@ void PollInputEvents(void) { for (int i = 0; i < MAX_GAMEPADS; i++) { + #if defined(USING_VERSION_SDL3) if (platform.gamepadId[i] == event.gbutton.which) + #else + if (platform.gamepadId[i] == event.jbutton.which) + #endif { CORE.Input.Gamepad.currentButtonState[i][button] = 0; if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; @@ -2054,28 +2066,23 @@ int InitPlatform(void) platform.gamepadId[i] = -1; // Set all gamepad initial instance ids as invalid to not conflict with instance id zero } - int numJoysticks = 0; - SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks); // array of joystick IDs, they do not start from 0 + int numJoysticks = SDL_NumJoysticks(); - if (joysticks) + for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++) { - for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++) - { - platform.gamepad[i] = SDL_GameControllerOpen(joysticks[i]); - platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i])); + platform.gamepad[i] = SDL_GameControllerOpen(i); + platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i])); - if (platform.gamepad[i]) - { - CORE.Input.Gamepad.ready[i] = true; - CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i])); - CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f; - CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; - strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1); - CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0'; - } - else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError()); + if (platform.gamepad[i]) + { + CORE.Input.Gamepad.ready[i] = true; + CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i])); + CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f; + CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; + strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1); + CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0'; } - SDL_free(joysticks); + else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError()); } // Disable mouse events being interpreted as touch events @@ -2196,7 +2203,7 @@ static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event) for (int i = 0; i < CORE.Input.Touch.pointCount; i++) { SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i); - CORE.Input.Touch.pointId[i] = finger->id; + CORE.Input.Touch.pointId[i] = (int)finger->id; CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width; CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height; CORE.Input.Touch.currentTouchState[i] = 1; From 6d562e5e87887777f1fedcda5ea481f0e372f0f6 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 17 Dec 2025 19:20:18 +0100 Subject: [PATCH 43/57] REVIEWED: HiggDPI content scaling on changing monitors with different DPI #5335 #5356 Note that high-dpi awareness must be enabled by users and `CORE.Window.render` reports the scaled framebuffer size, while `CORE.Window.screen` reports the logical size. `ToggleBorderlessWindow()` has also been reviewed to be consistent with scaling, if monitor physical display size is reported as 1920x1080 but there is a content scale of 1.5, then the borderless fullscreen window will be 1280x720, with the 1920x1080 framebuffer --- examples/core/core_highdpi_testbed.c | 33 ++++++- src/platforms/rcore_desktop_glfw.c | 131 +++++++++++++++++---------- src/rcore.c | 26 ++---- 3 files changed, 120 insertions(+), 70 deletions(-) diff --git a/examples/core/core_highdpi_testbed.c b/examples/core/core_highdpi_testbed.c index a341d081c..7710e7595 100644 --- a/examples/core/core_highdpi_testbed.c +++ b/examples/core/core_highdpi_testbed.c @@ -30,6 +30,10 @@ int main(void) SetConfigFlags(FLAG_WINDOW_HIGHDPI | FLAG_WINDOW_RESIZABLE); InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi testbed"); + Vector2 scaleDpi = GetWindowScaleDPI(); + Vector2 mousePos = GetMousePosition(); + int currentMonitor = GetCurrentMonitor(); + int gridSpacing = 40; // Grid spacing in pixels SetTargetFPS(60); @@ -40,7 +44,9 @@ int main(void) { // Update //---------------------------------------------------------------------------------- - // TODO: Update variables / Implement example logic at this point + mousePos = GetMousePosition(); + currentMonitor = GetCurrentMonitor(); + scaleDpi = GetWindowScaleDPI(); //---------------------------------------------------------------------------------- // Draw @@ -50,11 +56,30 @@ int main(void) ClearBackground(RAYWHITE); // Draw grid - for (int h = 0; h < 20; h++) DrawLine(0, h*gridSpacing, GetRenderWidth(), h*gridSpacing, LIGHTGRAY); - for (int v = 0; v < 40; v++) DrawLine(v*gridSpacing, 0, v*gridSpacing, GetScreenHeight(), LIGHTGRAY); + for (int h = 0; h < 20; h++) + { + DrawText(TextFormat("%02i", h*gridSpacing), 4, h*gridSpacing - 4, 10, GRAY); + DrawLine(24, h*gridSpacing, GetScreenWidth(), h*gridSpacing, LIGHTGRAY); + } + for (int v = 0; v < 40; v++) + { + DrawText(TextFormat("%02i", v*gridSpacing), v*gridSpacing - 10, 4, 10, GRAY); + DrawLine(v*gridSpacing, 20, v*gridSpacing, GetScreenHeight(), LIGHTGRAY); + } // Draw UI info - DrawText(TextFormat("SCREEN SIZE: %ix%i", GetScreenWidth(), GetScreenHeight()), 10, 10, 20, BLACK); + DrawText(TextFormat("CURRENT MONITOR: %i/%i (%ix%i)", currentMonitor + 1, GetMonitorCount(), + GetMonitorWidth(currentMonitor), GetMonitorHeight(currentMonitor)), 50, 50, 20, DARKGRAY); + DrawText(TextFormat("SCREEN SIZE: %ix%i", GetScreenWidth(), GetScreenHeight()), 50, 90, 20, DARKGRAY); + DrawText(TextFormat("RENDER SIZE: %ix%i", GetRenderWidth(), GetRenderHeight()), 50, 130, 20, DARKGRAY); + DrawText(TextFormat("SCALE FACTOR: %.1fx%.1f", scaleDpi.x, scaleDpi.y), 50, 170, 20, GRAY); + + // Draw mouse position + DrawCircleV(GetMousePosition(), 20, MAROON); + DrawRectangle(mousePos.x - 25, mousePos.y, 50, 2, BLACK); + DrawRectangle(mousePos.x, mousePos.y - 25, 2, 50, BLACK); + DrawText(TextFormat("[%i,%i]", GetMouseX(), GetMouseY()), mousePos.x - 44, + (mousePos.y > GetScreenHeight() - 60)? mousePos.y - 46 : mousePos.y + 30, 20, BLACK); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index d6ed11c2f..5a26a0b6e 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -134,9 +134,10 @@ static void ErrorCallback(int error, const char *description); // Window callbacks events static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized -static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved +static void FramebufferSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 FramebufferSize Callback, runs when window is resized +static void WindowPosCallback(GLFWwindow *window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored -static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized +static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale @@ -205,7 +206,6 @@ void ToggleFullscreen(void) glfwSetWindowMonitor(platform.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE); } - } else { @@ -231,22 +231,22 @@ void ToggleBorderlessWindowed(void) bool wasOnFullscreen = false; if (CORE.Window.fullscreen) { - // fullscreen already saves the previous position so it does not need to be set here again + // Fullscreen already saves the previous position so it does not need to be set here again ToggleFullscreen(); wasOnFullscreen = true; } - const int monitor = GetCurrentMonitor(); - int monitorCount; + int monitorCount = 0; GLFWmonitor **monitors = glfwGetMonitors(&monitorCount); + const int monitor = GetCurrentMonitor(); if ((monitor >= 0) && (monitor < monitorCount)) { const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]); - if (mode) + if (mode != NULL) { - if (!IsWindowState(FLAG_BORDERLESS_WINDOWED_MODE)) + if (!FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) { // Store screen position and size // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here @@ -286,6 +286,14 @@ void ToggleBorderlessWindowed(void) glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE); FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED); + // Make sure to restore size to HighDPI + if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) + { + Vector2 scaleDpi = GetWindowScaleDPI(); + CORE.Window.previousScreen.width *= scaleDpi.x; + CORE.Window.previousScreen.height *= scaleDpi.y; + } + // Return previous screen size and position // NOTE: The order matters here, it must set size first, then set position, otherwise the screen will be positioned incorrectly glfwSetWindowMonitor( @@ -475,13 +483,13 @@ void ClearWindowState(unsigned int flags) // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running if ((FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) && (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))) { - ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function + ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function } // State change: FLAG_FULLSCREEN_MODE if ((FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) && (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))) { - ToggleFullscreen(); // NOTE: Window state flag updated inside function + ToggleFullscreen(); // NOTE: Window state flag updated inside function } // State change: FLAG_WINDOW_RESIZABLE @@ -1329,7 +1337,8 @@ void PollInputEvents(void) CORE.Window.resizedLastFrame = false; - if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN))) + if ((CORE.Window.eventWaiting) || + (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) && !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN))) { glfwWaitEvents(); // Wait for in input events before continue (drawing is paused) CORE.Time.previous = GetTime(); @@ -1436,17 +1445,15 @@ int InitPlatform(void) // HACK: Most of this was written before GLFW_SCALE_FRAMEBUFFER existed and // was enabled by default. Disabling it gets back the old behavior. A - // complete fix will require removing a lot of CORE.Window.render - // manipulation code + // complete fix will require removing a lot of CORE.Window.render manipulation code // NOTE: This currently doesn't work on macOS(see #5185), so we skip it there // when FLAG_WINDOW_HIGHDPI is *unset* #if !defined(__APPLE__) - glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); + glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); #endif if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { - // since we skipped it before, now make sure to set this on macOS #if defined(__APPLE__) glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); #endif @@ -1639,6 +1646,7 @@ int InitPlatform(void) return -1; } + // NOTE: Not considering scale factor now, considered below CORE.Window.render.width = CORE.Window.screen.width; CORE.Window.render.height = CORE.Window.screen.height; } @@ -1666,11 +1674,11 @@ int InitPlatform(void) int fbWidth = CORE.Window.screen.width; int fbHeight = CORE.Window.screen.height; + #if !defined(__APPLE__) if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling - // Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); - #if !defined(__APPLE__) + // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight); // Screen scaling matrix is required in case desired screen area is different from display area @@ -1678,8 +1686,8 @@ int InitPlatform(void) // Mouse input scaling for the new screen size SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight); - #endif } + #endif CORE.Window.render.width = fbWidth; CORE.Window.render.height = fbHeight; @@ -1735,28 +1743,24 @@ int InitPlatform(void) // Initialize input events callbacks //---------------------------------------------------------------------------- // Set window callback events - glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default! + glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing is not enabled by default + glfwSetFramebufferSizeCallback(platform.handle, FramebufferSizeCallback); glfwSetWindowPosCallback(platform.handle, WindowPosCallback); glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback); glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback); glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback); glfwSetDropCallback(platform.handle, WindowDropCallback); - - if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) - { - glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback); - } + if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback); // Set input callback events glfwSetKeyCallback(platform.handle, KeyCallback); glfwSetCharCallback(platform.handle, CharCallback); glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback); - glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes + glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes glfwSetScrollCallback(platform.handle, MouseScrollCallback); glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback); glfwSetJoystickCallback(JoystickCallback); - - glfwSetInputMode(platform.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM) + glfwSetInputMode(platform.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM) // Retrieve gamepad names for (int i = 0; i < MAX_GAMEPADS; i++) @@ -1814,79 +1818,108 @@ void ClosePlatform(void) #endif } -// GLFW3 Error Callback, runs on GLFW3 error +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +// NOTE: Those functions are only required for current platform +//---------------------------------------------------------------------------------- + +// GLFW3: Error callback, runs on GLFW3 error static void ErrorCallback(int error, const char *description) { TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description); } -// GLFW3 WindowSize Callback, runs when window is resizedLastFrame +// GLFW3: Window size change callback, runs when window is resized // NOTE: Window resizing not enabled by default, use SetConfigFlags() static void WindowSizeCallback(GLFWwindow *window, int width, int height) +{ + // Nothing to do for now on window resize... +} + +// GLFW3: Framebuffer size change callback, runs when framebuffer is resized +static void FramebufferSizeCallback(GLFWwindow *window, int width, int height) { // WARNING: On window minimization, callback is called, // but we don't want to change internal screen values, it breaks things if ((width == 0) || (height == 0)) return; // Reset viewport and projection matrix for new size + // NOTE: Stores current render size: CORE.Window.render SetupViewport(width, height); + // Set render size CORE.Window.currentFbo.width = width; CORE.Window.currentFbo.height = height; CORE.Window.resizedLastFrame = true; if (IsWindowFullscreen()) return; - // if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale - if (IsWindowState(FLAG_WINDOW_HIGHDPI)) + // Check if render size was actually scaled for high-dpi + if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { - width = (int)(width/GetWindowScaleDPI().x); - height = (int)(height/GetWindowScaleDPI().y); + Vector2 scaleDpi = GetWindowScaleDPI(); + width = (int)((float)width/scaleDpi.x); + height = (int)((float)height/scaleDpi.y); } - // Set render size - CORE.Window.render.width = width; - CORE.Window.render.height = height; - // Set current screen size CORE.Window.screen.width = width; CORE.Window.screen.height = height; // WARNING: If using a render texture, it is not scaled to new size } -static void WindowPosCallback(GLFWwindow* window, int x, int y) + +// GLFW3: Window position callback, runs when window position changes +static void WindowPosCallback(GLFWwindow *window, int x, int y) { // Set current window position CORE.Window.position.x = x; CORE.Window.position.y = y; } + +// GLFW3: Window content scale callback, runs on monitor content scale change detected static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley) { + float fbWidth = (float)CORE.Window.screen.width*scalex; + float fbHeight = (float)CORE.Window.screen.height*scaley; + +#if !defined(__APPLE__) + // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling + // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f); + + // Mouse input scaling for the new screen size + SetMouseScale(1.0f/scalex, 1.0f/scaley); +#endif + + CORE.Window.render.width = (int)fbWidth; + CORE.Window.render.height = (int)fbHeight; + CORE.Window.currentFbo.width = (int)fbWidth; + CORE.Window.currentFbo.height = (int)fbHeight; } -// GLFW3 WindowIconify Callback, runs when window is minimized/restored +// GLFW3: Window iconify callback, runs when window is minimized/restored static void WindowIconifyCallback(GLFWwindow *window, int iconified) { if (iconified) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was iconified else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was restored } -// GLFW3 WindowMaximize Callback, runs when window is maximized/restored +// GLFW3: Window maximize callback, runs when window is maximized/restored static void WindowMaximizeCallback(GLFWwindow *window, int maximized) { if (maximized) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was maximized else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was restored } -// GLFW3 WindowFocus Callback, runs when window get/lose focus +// GLFW3: Window focus callback, runs when window get/lose focus static void WindowFocusCallback(GLFWwindow *window, int focused) { if (focused) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window was focused else FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window lost focus } -// GLFW3 Window Drop Callback, runs when drop files into window +// GLFW3: Window drop callback, runs when files are dropped into window static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) { if (count > 0) @@ -1914,7 +1947,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths } } -// GLFW3 Keyboard Callback, runs on key pressed +// GLFW3: Keyboard callback, runs on key pressed static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { if (key < 0) return; // Security check, macOS fn key generates -1 @@ -1941,7 +1974,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(platform.handle, GLFW_TRUE); } -// GLFW3 Char Callback, get unicode codepoint value +// GLFW3: Char callback, runs on key pressed to get unicode codepoint value static void CharCallback(GLFWwindow *window, unsigned int codepoint) { // NOTE: Registers any key down considering OS keyboard layout but @@ -1958,7 +1991,7 @@ static void CharCallback(GLFWwindow *window, unsigned int codepoint) } } -// GLFW3 Mouse Button Callback, runs on mouse button pressed +// GLFW3: Mouse button callback, runs on mouse button pressed static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, @@ -1994,7 +2027,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int #endif } -// GLFW3 Cursor Position Callback, runs on mouse move +// GLFW3: Cursor position callback, runs on mouse movement static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) { CORE.Input.Mouse.currentPosition.x = (float)x; @@ -2025,20 +2058,20 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) #endif } -// GLFW3 Scrolling Callback, runs on mouse wheel +// GLFW3: Mouse wheel scroll callback, runs on mouse wheel changes static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) { CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset }; } -// GLFW3 CursorEnter Callback, when cursor enters the window +// GLFW3: Cursor ennter callback, when cursor enters the window static void CursorEnterCallback(GLFWwindow *window, int enter) { if (enter) CORE.Input.Mouse.cursorOnScreen = true; else CORE.Input.Mouse.cursorOnScreen = false; } -// GLFW3 Joystick Connected/Disconnected Callback +// GLFW3: Joystick connected/disconnected callback static void JoystickCallback(int jid, int event) { if (event == GLFW_CONNECTED) diff --git a/src/rcore.c b/src/rcore.c index 19228cc8e..23d125b5a 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -816,30 +816,22 @@ int GetScreenHeight(void) // Get current render width which is equal to screen width*dpi scale int GetRenderWidth(void) { - if (CORE.Window.usingFbo) return CORE.Window.currentFbo.width; - int width = 0; -#if defined(__APPLE__) - Vector2 scale = GetWindowScaleDPI(); - width = (int)((float)CORE.Window.render.width*scale.x); -#else - width = CORE.Window.render.width; -#endif + + if (CORE.Window.usingFbo) return CORE.Window.currentFbo.width; + else width = CORE.Window.render.width; + return width; } // Get current screen height which is equal to screen height*dpi scale int GetRenderHeight(void) { - if (CORE.Window.usingFbo) return CORE.Window.currentFbo.height; - int height = 0; -#if defined(__APPLE__) - Vector2 scale = GetWindowScaleDPI(); - height = (int)((float)CORE.Window.render.height*scale.y); -#else - height = CORE.Window.render.height; -#endif + + if (CORE.Window.usingFbo) return CORE.Window.currentFbo.height; + else height = CORE.Window.render.height; + return height; } @@ -1833,7 +1825,7 @@ void TakeScreenshot(const char *fileName) // Apply a scale if we are doing HIGHDPI auto-scaling Vector2 scale = { 1.0f, 1.0f }; - if (IsWindowState(FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI(); + if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI(); unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y)); Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; From 4b760091da1da052a23f180a7e01c5d763d2875f Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 17 Dec 2025 21:23:25 +0100 Subject: [PATCH 44/57] REVIEWED: Window scaling with HighDPI on macOS #5059 --- examples/core/core_highdpi_testbed.c | 2 ++ src/platforms/rcore_desktop_glfw.c | 26 ++++++++++++-------------- src/rcore.c | 7 ------- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/examples/core/core_highdpi_testbed.c b/examples/core/core_highdpi_testbed.c index 7710e7595..6a036bbfc 100644 --- a/examples/core/core_highdpi_testbed.c +++ b/examples/core/core_highdpi_testbed.c @@ -47,6 +47,8 @@ int main(void) mousePos = GetMousePosition(); currentMonitor = GetCurrentMonitor(); scaleDpi = GetWindowScaleDPI(); + + if (IsKeyPressed(KEY_SPACE)) ToggleBorderlessWindowed(); //---------------------------------------------------------------------------------- // Draw diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 5a26a0b6e..fc839070a 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -246,7 +246,7 @@ void ToggleBorderlessWindowed(void) if (mode != NULL) { - if (!FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) + if (!FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) { // Store screen position and size // NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here @@ -286,6 +286,7 @@ void ToggleBorderlessWindowed(void) glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE); FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED); + #if !defined(__APPLE__) // Make sure to restore size to HighDPI if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { @@ -293,6 +294,7 @@ void ToggleBorderlessWindowed(void) CORE.Window.previousScreen.width *= scaleDpi.x; CORE.Window.previousScreen.height *= scaleDpi.y; } + #endif // Return previous screen size and position // NOTE: The order matters here, it must set size first, then set position, otherwise the screen will be positioned incorrectly @@ -1443,22 +1445,14 @@ int InitPlatform(void) if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer - // HACK: Most of this was written before GLFW_SCALE_FRAMEBUFFER existed and - // was enabled by default. Disabling it gets back the old behavior. A - // complete fix will require removing a lot of CORE.Window.render manipulation code - // NOTE: This currently doesn't work on macOS(see #5185), so we skip it there - // when FLAG_WINDOW_HIGHDPI is *unset* -#if !defined(__APPLE__) - glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); -#endif - if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { #if defined(__APPLE__) glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); #endif // Resize window content area based on the monitor content scale - // NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11 + // NOTE: This hint only has an effect on platforms where screen coordinates and + // pixels always map 1:1 such as Windows and X11 // On platforms like macOS the resolution of the framebuffer is changed independently of the window size glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on #if defined(__APPLE__) @@ -1674,7 +1668,6 @@ int InitPlatform(void) int fbWidth = CORE.Window.screen.width; int fbHeight = CORE.Window.screen.height; - #if !defined(__APPLE__) if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling @@ -1683,11 +1676,11 @@ int InitPlatform(void) // Screen scaling matrix is required in case desired screen area is different from display area CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f); - +#if !defined(__APPLE__) // Mouse input scaling for the new screen size SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight); +#endif } - #endif CORE.Window.render.width = fbWidth; CORE.Window.render.height = fbHeight; @@ -1834,11 +1827,14 @@ static void ErrorCallback(int error, const char *description) static void WindowSizeCallback(GLFWwindow *window, int width, int height) { // Nothing to do for now on window resize... + //TRACELOG(LOG_INFO, "GLFW3: Window size callback called [%i,%i]", width, height); } // GLFW3: Framebuffer size change callback, runs when framebuffer is resized static void FramebufferSizeCallback(GLFWwindow *window, int width, int height) { + //TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height); + // WARNING: On window minimization, callback is called, // but we don't want to change internal screen values, it breaks things if ((width == 0) || (height == 0)) return; @@ -1880,6 +1876,8 @@ static void WindowPosCallback(GLFWwindow *window, int x, int y) // GLFW3: Window content scale callback, runs on monitor content scale change detected static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley) { + TRACELOG(LOG_INFO, "GLFW3: Window content scale changed, scale: [%.2f,%.2f]", scalex, scaley); + float fbWidth = (float)CORE.Window.screen.width*scalex; float fbHeight = (float)CORE.Window.screen.height*scaley; diff --git a/src/rcore.c b/src/rcore.c index 23d125b5a..1f47efcb9 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3815,14 +3815,7 @@ void SetupViewport(int width, int height) CORE.Window.render.height = height; // Set viewport width and height - // NOTE: We consider render size (scaled) and offset in case black bars are required and - // render area does not match full display area (this situation is only applicable on fullscreen mode) -#if defined(__APPLE__) - Vector2 scale = GetWindowScaleDPI(); - rlViewport(CORE.Window.renderOffset.x/2*scale.x, CORE.Window.renderOffset.y/2*scale.y, (CORE.Window.render.width)*scale.x, (CORE.Window.render.height)*scale.y); -#else rlViewport(CORE.Window.renderOffset.x/2, CORE.Window.renderOffset.y/2, CORE.Window.render.width, CORE.Window.render.height); -#endif rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlLoadIdentity(); // Reset current matrix (projection) From ca578b8b08a338722058ca60c675ae6c42497d80 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Dec 2025 17:03:53 +0100 Subject: [PATCH 45/57] Update raylib.sln --- projects/VS2022/raylib.sln | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index f0ff823da..8a6350a36 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -5543,7 +5543,7 @@ Global {19CA0070-B4B2-4394-90B7-D0C259AA35BA} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021} {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A} - {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} + {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021} {A4662163-83E7-4309-8CAA-B0BF13655FE6} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C} {5F4B766F-DD52-4B53-B6C3-BC7611E17F20} = {278D8859-20B1-428F-8448-064F46E1F021} @@ -5559,7 +5559,7 @@ Global {124935CC-73BB-489E-92E8-4F922A85DB5D} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {AC215730-2B5F-4498-B7F5-5DB80AEFCA5F} = {278D8859-20B1-428F-8448-064F46E1F021} {0835E6BF-0170-4E99-A55C-E06E1EF4C3B2} = {278D8859-20B1-428F-8448-064F46E1F021} - {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE} + {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {278D8859-20B1-428F-8448-064F46E1F021} {1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {9DE2FC01-A839-4F89-8319-9071D4C54821} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} {2F578155-D51F-4C03-AB7F-5C5122CA46CC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035} From 720dd22491cdc4a29ec0ea87b572d9380872198c Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 18 Dec 2025 17:04:58 +0100 Subject: [PATCH 46/57] REVIEWED: `rlLoadTexture()`, un complete texture do to issue on mipmap loading #5416 --- src/rlgl.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 97f892eb5..45a68053c 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3353,8 +3353,8 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, mipWidth /= 2; mipHeight /= 2; - mipOffset += mipSize; // Increment offset position to next mipmap - if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap + mipOffset += mipSize; // Increment offset position to next mipmap + if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap // Security check for NPOT textures if (mipWidth < 1) mipWidth = 1; @@ -3392,8 +3392,14 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - // Define thee maximum number of mipmap levels to be used, 0 is default texture size + // Define the maximum number of mipmap levels to be used, 0 is base texture size + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount - 1); + + // Check if the loaded texture with mipmaps is complete, + // uncomplete textures will draw in black if mipmap filtering is required + //GLint complete = 0; + //glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, &complete); } #endif @@ -5232,7 +5238,7 @@ static int rlGetPixelDataSize(int width, int height, int format) // Most compressed formats works on 4x4 blocks, // if texture is smaller, minimum dataSize is 8 or 16 - if ((width < 4) && (height < 4)) + if ((width <= 4) && (height <= 4)) { if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8; else if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; From 66392fe0ae36420a470caacf41778f575a11c8d5 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Dec 2025 00:06:44 +0100 Subject: [PATCH 47/57] REVIEWED: `rlGetPixelDataSize()`, correct compressed data size calculation per blocks #5416 --- src/rlgl.h | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 45a68053c..cda64896c 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -5224,24 +5224,36 @@ static int rlGetPixelDataSize(int width, int height, int format) case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB: case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB: case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB: - case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: // 8 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*8; + } break; case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: - case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; - case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; + case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: // 16 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*16; + } break; + case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*4; + } break; default: break; } - double bytesPerPixel = (double)bpp/8.0; - dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes - - // Most compressed formats works on 4x4 blocks, - // if texture is smaller, minimum dataSize is 8 or 16 - if ((width <= 4) && (height <= 4)) + // Compute dataSize for uncompressed texture data (no blocks) + if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) && + (format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) { - if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8; - else if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; + double bytesPerPixel = (double)bpp/8.0; + dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes } return dataSize; From f16fb065eaa9efbb02fcfc1bc5e43c835792c9da Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Dec 2025 01:15:34 +0100 Subject: [PATCH 48/57] Update rcore_template.c --- src/platforms/rcore_template.c | 89 +++------------------------------- 1 file changed, 8 insertions(+), 81 deletions(-) diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c index bc03a3cdb..1f8c5242b 100644 --- a/src/platforms/rcore_template.c +++ b/src/platforms/rcore_template.c @@ -54,11 +54,6 @@ typedef struct { // TODO: Define the platform specific variables required - // Display data - EGLDisplay device; // Native display device (physical screen connection) - EGLSurface surface; // Surface to draw on, framebuffers (connected to context) - EGLContext context; // Graphic context, mode in which drawing can be done - EGLConfig config; // Graphic config } PlatformData; //---------------------------------------------------------------------------------- @@ -346,10 +341,10 @@ void SwapScreenBuffer(void) double GetTime(void) { double time = 0.0; + struct timespec ts = { 0 }; clock_gettime(CLOCK_MONOTONIC, &ts); unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; - time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer() return time; @@ -366,7 +361,7 @@ void OpenURL(const char *url) if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); else { - // TODO: + // TODO: Load url using default browser } } @@ -462,86 +457,18 @@ int InitPlatform(void) CORE.Window.fullscreen = true; FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE); - EGLint samples = 0; - EGLint sampleBuffer = 0; if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) { - samples = 4; - sampleBuffer = 1; + // TODO: Enable MSAA + TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4"); } - const EGLint framebufferAttribs[] = - { - EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support - EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5) - EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) - EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) - //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI) - EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!) - //EGL_STENCIL_SIZE, 8, // Stencil buffer size - EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA - EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs) - EGL_NONE - }; + // TODO: Init display and graphic device - const EGLint contextAttribs[] = - { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - EGLint numConfigs = 0; - - // Get an EGL device connection - platform.device = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (platform.device == EGL_NO_DISPLAY) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); - return false; - } - - // Initialize the EGL device connection - if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE) - { - // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred. - TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device"); - return false; - } - - // Get an appropriate EGL framebuffer configuration - eglChooseConfig(platform.device, framebufferAttribs, &platform.config, 1, &numConfigs); - - // Set rendering API - eglBindAPI(EGL_OPENGL_ES_API); - - // Create an EGL rendering context - platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs); - if (platform.context == EGL_NO_CONTEXT) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context"); - return -1; - } - - // Create an EGL window surface - EGLint displayFormat = 0; - - // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry() - // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID - eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat); - - // Android specific call - ANativeWindow_setBuffersGeometry(platform.app->window, 0, 0, displayFormat); // Force use of native display size - - platform.surface = eglCreateWindowSurface(platform.device, platform.config, platform.app->window, NULL); - - // There must be at least one frame displayed before the buffers are swapped - eglSwapInterval(platform.device, 1); - - EGLBoolean result = eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context); - - // Check surface and context activation - if (result != EGL_FALSE) + // TODO: Check display, device and context activation + bool result = true; + if (result) { CORE.Window.ready = true; From 13f9112d8c069ed333acf72c2c1b94a0533c6dc1 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Dec 2025 01:16:34 +0100 Subject: [PATCH 49/57] Update rcore_desktop_sdl.c --- src/platforms/rcore_desktop_sdl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 7316f3c14..add1de6ad 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -679,6 +679,7 @@ void ClearWindowState(unsigned int flags) { TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL"); } + if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)) { // NOTE: There also doesn't seem to be a feature to disable high DPI once enabled TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL"); @@ -1474,7 +1475,7 @@ void PollInputEvents(void) const int height = event.window.data2; SetupViewport(width, height); // if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale - if (IsWindowState(FLAG_WINDOW_HIGHDPI)) + if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { CORE.Window.screen.width = (int)(width/GetWindowScaleDPI().x); CORE.Window.screen.height = (int)(height/GetWindowScaleDPI().y); From b9446863d7b75e8b056186e3cca5a4f47837462d Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Dec 2025 22:36:44 +0100 Subject: [PATCH 50/57] REXM: RENAMED: `core_high_dpi` --> `core_highdpi_demo` --- examples/Makefile | 2 +- examples/Makefile.Web | 4 +- examples/README.md | 2 +- .../{core_high_dpi.c => core_highdpi_demo.c} | 4 +- ...ore_high_dpi.png => core_highdpi_demo.png} | Bin examples/examples_list.txt | 2 +- ..._dpi.vcxproj => core_highdpi_demo.vcxproj} | 1138 ++++++++--------- projects/VS2022/raylib.sln | 2 +- 8 files changed, 577 insertions(+), 577 deletions(-) rename examples/core/{core_high_dpi.c => core_highdpi_demo.c} (98%) rename examples/core/{core_high_dpi.png => core_highdpi_demo.png} (100%) rename projects/VS2022/examples/{core_high_dpi.vcxproj => core_highdpi_demo.vcxproj} (97%) diff --git a/examples/Makefile b/examples/Makefile index 06a0c2729..bc2afbb3c 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -531,7 +531,7 @@ CORE = \ core/core_delta_time \ core/core_directory_files \ core/core_drop_files \ - core/core_high_dpi \ + core/core_highdpi_demo \ core/core_highdpi_testbed \ core/core_input_actions \ core/core_input_gamepad \ diff --git a/examples/Makefile.Web b/examples/Makefile.Web index 7101ed7e3..f36113f15 100644 --- a/examples/Makefile.Web +++ b/examples/Makefile.Web @@ -519,7 +519,7 @@ CORE = \ core/core_delta_time \ core/core_directory_files \ core/core_drop_files \ - core/core_high_dpi \ + core/core_highdpi_demo \ core/core_highdpi_testbed \ core/core_input_actions \ core/core_input_gamepad \ @@ -783,7 +783,7 @@ core/core_directory_files: core/core_directory_files.c core/core_drop_files: core/core_drop_files.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) -core/core_high_dpi: core/core_high_dpi.c +core/core_highdpi_demo: core/core_highdpi_demo.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) core/core_highdpi_testbed: core/core_highdpi_testbed.c diff --git a/examples/README.md b/examples/README.md index d64ed7608..367bfa0ab 100644 --- a/examples/README.md +++ b/examples/README.md @@ -61,7 +61,7 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind | [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) | core_smooth_pixelperfect | ⭐⭐⭐☆ | 3.7 | 4.0 | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) | | [core_random_sequence](core/core_random_sequence.c) | core_random_sequence | ⭐☆☆☆ | 5.0 | 5.0 | [Dalton Overmyer](https://github.com/REDl3east) | | [core_automation_events](core/core_automation_events.c) | core_automation_events | ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | -| [core_high_dpi](core/core_high_dpi.c) | core_high_dpi | ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) | +| [core_highdpi_demo](core/core_highdpi_demo.c) | core_highdpi_demo | ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) | | [core_render_texture](core/core_render_texture.c) | core_render_texture | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [core_undo_redo](core/core_undo_redo.c) | core_undo_redo | ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) | | [core_viewport_scaling](core/core_viewport_scaling.c) | core_viewport_scaling | ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) | diff --git a/examples/core/core_high_dpi.c b/examples/core/core_highdpi_demo.c similarity index 98% rename from examples/core/core_high_dpi.c rename to examples/core/core_highdpi_demo.c index 312f0c3e2..b1f706d98 100644 --- a/examples/core/core_high_dpi.c +++ b/examples/core/core_highdpi_demo.c @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raylib [core] example - high dpi +* raylib [core] example - highdpi demo * * Example complexity rating: [★★☆☆] 2/4 * @@ -33,7 +33,7 @@ int main(void) const int screenHeight = 450; SetConfigFlags(FLAG_WINDOW_HIGHDPI | FLAG_WINDOW_RESIZABLE); - InitWindow(screenWidth, screenHeight, "raylib [core] example - high dpi"); + InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi demo"); SetWindowMinSize(450, 450); int logicalGridDescY = 120; diff --git a/examples/core/core_high_dpi.png b/examples/core/core_highdpi_demo.png similarity index 100% rename from examples/core/core_high_dpi.png rename to examples/core/core_highdpi_demo.png diff --git a/examples/examples_list.txt b/examples/examples_list.txt index 925ad9454..3310cf2d2 100644 --- a/examples/examples_list.txt +++ b/examples/examples_list.txt @@ -43,7 +43,7 @@ core;core_custom_frame_control;★★★★;4.0;4.0;2021;2025;"Ramon Santamaria" core;core_smooth_pixelperfect;★★★☆;3.7;4.0;2021;2025;"Giancamillo Alessandroni";@NotManyIdeasDev core;core_random_sequence;★☆☆☆;5.0;5.0;2023;2025;"Dalton Overmyer";@REDl3east core;core_automation_events;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria";@raysan5 -core;core_high_dpi;★★☆☆;5.0;5.5;2025;2025;"Jonathan Marler";@marler8997 +core;core_highdpi_demo;★★☆☆;5.0;5.5;2025;2025;"Jonathan Marler";@marler8997 core;core_render_texture;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5 core;core_undo_redo;★★★☆;5.5;5.6;2025;2025;"Ramon Santamaria";@raysan5 core;core_viewport_scaling;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers diff --git a/projects/VS2022/examples/core_high_dpi.vcxproj b/projects/VS2022/examples/core_highdpi_demo.vcxproj similarity index 97% rename from projects/VS2022/examples/core_high_dpi.vcxproj rename to projects/VS2022/examples/core_highdpi_demo.vcxproj index 11e1b41c0..8a7cdce40 100644 --- a/projects/VS2022/examples/core_high_dpi.vcxproj +++ b/projects/VS2022/examples/core_highdpi_demo.vcxproj @@ -1,569 +1,569 @@ - - - - - Debug.DLL - ARM64 - - - Debug.DLL - Win32 - - - Debug.DLL - x64 - - - Debug - ARM64 - - - Debug - Win32 - - - Debug - x64 - - - Release.DLL - ARM64 - - - Release.DLL - Win32 - - - Release.DLL - x64 - - - Release - ARM64 - - - Release - Win32 - - - Release - x64 - - - - {BCB71111-8505-4B35-8CEF-EC6115DC9D4D} - Win32Proj - core_high_dpi - 10.0 - core_high_dpi - - - - Application - true - $(DefaultPlatformToolset) - Unicode - - - Application - true - $(DefaultPlatformToolset) - Unicode - - - Application - true - $(DefaultPlatformToolset) - Unicode - - - Application - true - $(DefaultPlatformToolset) - Unicode - - - Application - true - $(DefaultPlatformToolset) - Unicode - - - Application - true - $(DefaultPlatformToolset) - Unicode - - - Application - false - $(DefaultPlatformToolset) - true - Unicode - - - Application - false - $(DefaultPlatformToolset) - true - Unicode - - - Application - false - $(DefaultPlatformToolset) - true - Unicode - - - Application - false - $(DefaultPlatformToolset) - true - Unicode - - - Application - false - $(DefaultPlatformToolset) - true - Unicode - - - Application - false - $(DefaultPlatformToolset) - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - true - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - true - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - true - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - true - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - true - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - false - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - false - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - false - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - false - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - false - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - false - $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ - $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - $(SolutionDir)..\..\examples\core - WindowsLocalDebugger - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) - CompileAsC - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - - - Console - true - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) - CompileAsC - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - /FS %(AdditionalOptions) - - - Console - true - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) - CompileAsC - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - /FS %(AdditionalOptions) - - - Console - true - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) - CompileAsC - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - - - Console - true - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" - Copy Debug DLL to output directory - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) - CompileAsC - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - - - Console - true - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" - Copy Debug DLL to output directory - - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) - CompileAsC - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - - - Console - true - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" - Copy Debug DLL to output directory - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsC - true - - - Console - true - true - true - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsC - true - - - Console - true - true - true - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsC - true - - - Console - true - true - true - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsC - true - - - Console - true - true - true - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - - - xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" - - - Copy Release DLL to output directory - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsC - true - - - Console - true - true - true - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - - - xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" - - - Copy Release DLL to output directory - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP - $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) - CompileAsC - true - - - Console - true - true - true - raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ - - - xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" - - - Copy Release DLL to output directory - - - - - - - - - - - {e89d61ac-55de-4482-afd4-df7242ebc859} - - - - - - + + + + + Debug.DLL + ARM64 + + + Debug.DLL + Win32 + + + Debug.DLL + x64 + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release.DLL + ARM64 + + + Release.DLL + Win32 + + + Release.DLL + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {BCB71111-8505-4B35-8CEF-EC6115DC9D4D} + Win32Proj + core_highdpi_demo + 10.0 + core_highdpi_demo + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + true + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\ + $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\ + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + $(SolutionDir)..\..\examples\core + WindowsLocalDebugger + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + /FS %(AdditionalOptions) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions) + CompileAsC + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + + + Console + true + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + Copy Debug DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP + $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories) + CompileAsC + true + + + Console + true + true + true + raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\ + + + xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)" + + + Copy Release DLL to output directory + + + + + + + + + + + {e89d61ac-55de-4482-afd4-df7242ebc859} + + + + + + diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln index 8a6350a36..50fef1cf5 100644 --- a/projects/VS2022/raylib.sln +++ b/projects/VS2022/raylib.sln @@ -57,7 +57,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_custom_logging", "exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_drop_files", "examples\core_drop_files.vcxproj", "{0199E349-0701-40BC-8A7F-06A54FFA3E7C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_high_dpi", "examples\core_high_dpi.vcxproj", "{BCB71111-8505-4B35-8CEF-EC6115DC9D4D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_demo", "examples\core_highdpi_demo.vcxproj", "{BCB71111-8505-4B35-8CEF-EC6115DC9D4D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_input_gamepad", "examples\core_input_gamepad.vcxproj", "{8F19E3DA-8929-4000-87B5-3CA6929636CC}" EndProject From 3212becc915a8a491712c7c7dc81ec5581cca240 Mon Sep 17 00:00:00 2001 From: SabeDoesThings <122580233+SabeDoesThings@users.noreply.github.com> Date: Sun, 21 Dec 2025 13:15:38 -0600 Subject: [PATCH 51/57] Update BINDINGS.md (#5421) --- BINDINGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BINDINGS.md b/BINDINGS.md index 07f590d7d..ee7da46f4 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -76,6 +76,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [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) | **???** | +| [ringraylib5](https://github.com/ring-lang/ring/tree/master/extensions/ringraylib5) | **5.0** | [Ring](https://ring-lang.github.io/) | **???** | | [racket-raylib](https://github.com/eutro/racket-raylib) | **5.5** | [Racket](https://racket-lang.org) | MIT/Apache-2.0 | | [raylib-swift](https://github.com/STREGAsGate/Raylib) | 4.0 | [Swift](https://swift.org) | MIT | | [raylib-scopes](https://github.com/salotz/raylib-scopes) | auto | [Scopes](http://scopes.rocks) | MIT | From 85167509751622bdf6c53ad559b036dcbcba476d Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 22 Dec 2025 20:29:57 +0100 Subject: [PATCH 52/57] Remove internal function --- src/platforms/rcore_desktop_glfw.c | 41 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index fc839070a..4e4e473d3 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -156,8 +156,6 @@ static void *AllocateWrapper(size_t size, void *user); static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_REALLOC macro static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro -static void SetDimensionsFromMonitor(GLFWmonitor *monitor); // Set screen dimensions from monitor/display dimensions - //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- @@ -1535,11 +1533,20 @@ int InitPlatform(void) monitor = glfwGetPrimaryMonitor(); if (!monitor) { - TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor"); - return -1; + TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor"); + return -1; } - SetDimensionsFromMonitor(monitor); + // Set dimensions from monitor + GLFWvidmode *mode = glfwGetVideoMode(monitor); + + // Default display resolution to that of the current mode + CORE.Window.display.width = mode->width; + CORE.Window.display.height = mode->height; + + // Set screen width/height to the display width/height if they are 0 + if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width; + if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height; // Remember center for switching from fullscreen to window if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width)) @@ -1628,7 +1635,15 @@ int InitPlatform(void) if (monitorIndex < monitorCount) { monitor = monitors[monitorIndex]; - SetDimensionsFromMonitor(monitor); + GLFWvidmode *mode = glfwGetVideoMode(monitor); + + // Default display resolution to that of the current mode + CORE.Window.display.width = mode->width; + CORE.Window.display.height = mode->height; + + // Set screen width/height to the display width/height if they are 0 + if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width; + if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height; if (requestWindowedFullscreen) glfwSetWindowSize(platform.handle, CORE.Window.screen.width, CORE.Window.screen.height); } @@ -2085,20 +2100,6 @@ static void JoystickCallback(int jid, int event) } } -// Set screen dimensions from monitor/display dimensions -static void SetDimensionsFromMonitor(GLFWmonitor *monitor) -{ - const GLFWvidmode *mode = glfwGetVideoMode(monitor); - - // Default display resolution to that of the current mode - CORE.Window.display.width = mode->width; - CORE.Window.display.height = mode->height; - - // Set screen width/height to the display width/height if they are 0 - if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width; - if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height; -} - #ifdef _WIN32 # define WIN32_CLIPBOARD_IMPLEMENTATION # include "../external/win32_clipboard.h" From e4baf682abae07ea64d028b66259524834a8d74e Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 22 Dec 2025 20:30:11 +0100 Subject: [PATCH 53/57] Update rtext.c --- src/rtext.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/rtext.c b/src/rtext.c index f04f9ade4..7c25fde0b 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -700,7 +700,11 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz switch (type) { case FONT_DEFAULT: - case FONT_BITMAP: glyphs[k].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, cp, &cpWidth, &cpHeight, &glyphs[k].offsetX, &glyphs[k].offsetY); break; + case FONT_BITMAP: + { + glyphs[k].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, cp, + &cpWidth, &cpHeight, &glyphs[k].offsetX, &glyphs[k].offsetY); + } break; case FONT_SDF: { if (cp != 32) From f27f2d097f92ee38235f88a9fe01829469c5f454 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 22 Dec 2025 22:48:08 +0100 Subject: [PATCH 54/57] REVIEWED: HighDPI support on macOS (when requested by app) Tested on two monitors with different DPI configuration, for HigDPI enabled and not, including window resizing (with framebuffer resizing if required). Verified mouse coordinates follow the requested screen size. --- src/platforms/rcore_desktop_glfw.c | 65 +++++++++++++++++------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 4e4e473d3..8a2abf6c0 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -135,12 +135,12 @@ static void ErrorCallback(int error, const char *description); // Window callbacks events static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized static void FramebufferSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 FramebufferSize Callback, runs when window is resized +static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale static void WindowPosCallback(GLFWwindow *window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window -static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale // Input callbacks events static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed @@ -1024,8 +1024,8 @@ Vector2 GetWindowPosition(void) // Get window scale DPI factor for current monitor Vector2 GetWindowScaleDPI(void) { - Vector2 scale = { 0 }; - glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y); + Vector2 scale = { 1.0f, 1.0f }; + if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y); return scale; } @@ -1452,12 +1452,18 @@ int InitPlatform(void) // NOTE: This hint only has an effect on platforms where screen coordinates and // pixels always map 1:1 such as Windows and X11 // On platforms like macOS the resolution of the framebuffer is changed independently of the window size - glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); #if defined(__APPLE__) glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); #endif } - else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE); + else + { + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE); +#if defined(__APPLE__) + glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); +#endif + } // Mouse passthrough if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE); @@ -1527,9 +1533,7 @@ int InitPlatform(void) GLFWmonitor *monitor = NULL; if (CORE.Window.fullscreen) { - // According to glfwCreateWindow(), if the user does not have a choice, fullscreen applications - // should default to the primary monitor - + // NOTE: Fullscreen applications default to the primary monitor monitor = glfwGetPrimaryMonitor(); if (!monitor) { @@ -1538,7 +1542,7 @@ int InitPlatform(void) } // Set dimensions from monitor - GLFWvidmode *mode = glfwGetVideoMode(monitor); + const GLFWvidmode *mode = glfwGetVideoMode(monitor); // Default display resolution to that of the current mode CORE.Window.display.width = mode->width; @@ -1635,7 +1639,7 @@ int InitPlatform(void) if (monitorIndex < monitorCount) { monitor = monitors[monitorIndex]; - GLFWvidmode *mode = glfwGetVideoMode(monitor); + const GLFWvidmode *mode = glfwGetVideoMode(monitor); // Default display resolution to that of the current mode CORE.Window.display.width = mode->width; @@ -1846,6 +1850,7 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height) } // GLFW3: Framebuffer size change callback, runs when framebuffer is resized +// WARNING: If FLAG_WINDOW_HIGHDPI is set, WindowContentScaleCallback() is called before this function static void FramebufferSizeCallback(GLFWwindow *window, int width, int height) { //TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height); @@ -1863,32 +1868,26 @@ static void FramebufferSizeCallback(GLFWwindow *window, int width, int height) CORE.Window.currentFbo.height = height; CORE.Window.resizedLastFrame = true; - if (IsWindowFullscreen()) return; - // Check if render size was actually scaled for high-dpi if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { + // Set screen size to logical pixel size, considering content scaling Vector2 scaleDpi = GetWindowScaleDPI(); - width = (int)((float)width/scaleDpi.x); - height = (int)((float)height/scaleDpi.y); + CORE.Window.screen.width = (int)((float)width/scaleDpi.x); + CORE.Window.screen.height = (int)((float)height/scaleDpi.y); + } + else + { + // Set screen size to render size (physical pixel size) + CORE.Window.screen.width = width; + CORE.Window.screen.height = height; } - - // Set current screen size - CORE.Window.screen.width = width; - CORE.Window.screen.height = height; // WARNING: If using a render texture, it is not scaled to new size } -// GLFW3: Window position callback, runs when window position changes -static void WindowPosCallback(GLFWwindow *window, int x, int y) -{ - // Set current window position - CORE.Window.position.x = x; - CORE.Window.position.y = y; -} - // GLFW3: Window content scale callback, runs on monitor content scale change detected +// WARNING: If FLAG_WINDOW_HIGHDPI is not set, this function is not called static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley) { TRACELOG(LOG_INFO, "GLFW3: Window content scale changed, scale: [%.2f,%.2f]", scalex, scaley); @@ -1896,13 +1895,13 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s float fbWidth = (float)CORE.Window.screen.width*scalex; float fbHeight = (float)CORE.Window.screen.height*scaley; -#if !defined(__APPLE__) // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f); +#if !defined(__APPLE__) // Mouse input scaling for the new screen size - SetMouseScale(1.0f/scalex, 1.0f/scaley); + SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight); #endif CORE.Window.render.width = (int)fbWidth; @@ -1911,6 +1910,16 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s CORE.Window.currentFbo.height = (int)fbHeight; } +// GLFW3: Window position callback, runs when window position changes +static void WindowPosCallback(GLFWwindow *window, int x, int y) +{ + TRACELOG(LOG_INFO, "GLFW3: Window position changed"); + + // Set current window position + CORE.Window.position.x = x; + CORE.Window.position.y = y; +} + // GLFW3: Window iconify callback, runs when window is minimized/restored static void WindowIconifyCallback(GLFWwindow *window, int iconified) { From aa2884bd7808bc949ec72e6a65db093cc9bf6c24 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 22 Dec 2025 22:50:38 +0100 Subject: [PATCH 55/57] Update rcore_desktop_glfw.c --- src/platforms/rcore_desktop_glfw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 8a2abf6c0..efa146fd0 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1913,8 +1913,6 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s // GLFW3: Window position callback, runs when window position changes static void WindowPosCallback(GLFWwindow *window, int x, int y) { - TRACELOG(LOG_INFO, "GLFW3: Window position changed"); - // Set current window position CORE.Window.position.x = x; CORE.Window.position.y = y; From 6a701b2679883823f04fed10f301fefcca1adaec Mon Sep 17 00:00:00 2001 From: caszu <109808097+caszuu@users.noreply.github.com> Date: Tue, 23 Dec 2025 15:37:08 +0100 Subject: [PATCH 56/57] fix android SetWindowState (#5424) --- src/platforms/rcore_android.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 7b8d3e052..20a85a6a4 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -360,7 +360,7 @@ void SetWindowState(unsigned int flags) if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead"); // State change: FLAG_WINDOW_ALWAYS_RUN - if (!FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN); + if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN); } // Clear window configuration state flags From 0a4583ca5468e48a3e7b7ea9ca4a8055272e524e Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 23 Dec 2025 11:10:55 -0500 Subject: [PATCH 57/57] [rl_gputex.h] Possibly fixed the swizzling in `rl_load_dds_from_memory()` function (#5422) * Possibly fixed the swizzling bug * Removed examples, and generation. --- src/external/rl_gputex.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/external/rl_gputex.h b/src/external/rl_gputex.h index 29500f3cf..78d618db5 100644 --- a/src/external/rl_gputex.h +++ b/src/external/rl_gputex.h @@ -308,7 +308,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ unsigned char alpha = 0; // NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1 - for (int i = 0; i < image_pixel_size; i++) + for (int i = 0; i < data_size/sizeof(unsigned short); i++) { alpha = ((unsigned short *)image_data)[i] >> 15; ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 1; @@ -328,7 +328,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ unsigned char alpha = 0; // NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4 - for (int i = 0; i < image_pixel_size; i++) + for (int i = 0; i < data_size/sizeof(unsigned short); i++) { alpha = ((unsigned short *)image_data)[i] >> 12; ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 4; @@ -362,7 +362,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_ // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment) // DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA // So, we must realign B8G8R8A8 to R8G8B8A8 - for (int i = 0; i < image_pixel_size*4; i += 4) + for (int i = 0; i < data_size; i += 4) { blue = ((unsigned char *)image_data)[i]; ((unsigned char *)image_data)[i] = ((unsigned char *)image_data)[i + 2];