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/BINDINGS.md b/BINDINGS.md
index 07f590d7d..6ef57035f 100644
--- a/BINDINGS.md
+++ b/BINDINGS.md
@@ -21,6 +21,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [claw-raylib](https://github.com/bohonghuang/claw-raylib) | **auto** | [Common Lisp](https://common-lisp.net) | Apache-2.0 |
| [raylib](https://github.com/fosskers/raylib) | 5.5 | [Common Lisp](https://common-lisp.net) | MPL-2.0 |
| [chez-raylib](https://github.com/Yunoinsky/chez-raylib) | **auto** | [Chez Scheme](https://cisco.github.io/ChezScheme) | GPLv3 |
+| [chicken-raylib](https://github.com/meowstr/chicken-raylib) | 5.5 | [CHICKEN Scheme](https://wiki.call-cc.org) | MIT |
| [CLIPSraylib](https://github.com/mrryanjohnston/CLIPSraylib) | **auto** | [CLIPS](https://www.clipsrules.net/) | MIT |
| [raylib-cr](https://github.com/sol-vin/raylib-cr) | 4.6-dev (5e1a81) | [Crystal](https://crystal-lang.org) | Apache-2.0 |
| [ray-cyber](https://github.com/fubark/ray-cyber) | **5.0** | [Cyber](https://cyberscript.dev) | MIT |
@@ -28,6 +29,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [bindbc-raylib3](https://github.com/o3o/bindbc-raylib3) | **5.0** | [D](https://dlang.org) | BSL-1.0 |
| [dray](https://github.com/redthing1/dray) | **5.0** | [D](https://dlang.org) | Apache-2.0 |
| [raylib-d](https://github.com/schveiguy/raylib-d) | **5.5** | [D](https://dlang.org) | Zlib |
+| [DenoRaylib550](https://github.com/JJLDonley/DenoRaylib550) | **5.5** | [Deno](https://deno.land) | MIT |
| [rayex](https://github.com/shiryel/rayex) | 3.7 | [elixir](https://elixir-lang.org) | Apache-2.0 |
| [raylib-elle](https://github.com/acquitelol/elle/blob/rewrite/std/raylib.le) | **5.5** | [Elle](https://github.com/acquitelol/elle) | GPL-3.0 |
| [raylib-factor](https://github.com/factor/factor/blob/master/extra/raylib/raylib.factor) | 4.5 | [Factor](https://factorcode.org) | BSD |
@@ -76,6 +78,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 |
diff --git a/LICENSE b/LICENSE
index e96f876a2..bc6f4b851 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
This software is provided "as-is", without any express or implied warranty. In no event
will the authors be held liable for any damages arising from the use of this software.
diff --git a/README.md b/README.md
index 875792f18..37e37c7c4 100644
--- a/README.md
+++ b/README.md
@@ -140,7 +140,7 @@ contributors
------------
-
+
license
diff --git a/ROADMAP.md b/ROADMAP.md
index 9a8111133..a49cdbfd7 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -15,13 +15,13 @@ _Current version of raylib is complete and functional but there is always room f
**raylib 5.x**
- [ ] `rcore`: Support additional platforms: iOS, consoles?
- - [ ] `rcore_web`: Avoid GLFW dependency, functionality can be directly implemented using emscripten SDK
+ - [x] `rcore_web`: Avoid GLFW dependency, functionality can be directly implemented using emscripten SDK
- [ ] `rlgl`: Review GLSL shaders naming conventions for consistency
- [ ] `textures`: Improve compressed textures support, loading and saving
- [ ] `rmodels`: Improve 3d objects loading, specially animations (obj, gltf)
- [ ] `raudio`: Implement miniaudio high-level provided features
- - [ ] `examples`: Review all examples, add more and better code explanations
- - [ ] Software renderer backend? Maybe using `Image` provided API
+ - [x] `examples`: Review all examples, add more and better code explanations
+ - [x] Software renderer backend? Maybe using `Image` provided API
**raylib 4.x**
- [x] Split core module into separate platforms?
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..48a825e37
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,18 @@
+# Security Policy
+
+## Supported Versions
+
+Most considerations of errors and defects can be handled using the project Issues and/or Discussions.
+
+| Version | Supported |
+| ------- | ------------------ |
+| 6.0.x | :white_check_mark: |
+| < 5.5 | :x: |
+
+## Reporting a Vulnerability
+
+Discovered vulnerability can be directly reported using the project Issues and/or Discussions.
+
+_TODO: Tell them where to go, how often they can expect to get an update on a
+reported vulnerability, what to expect if the vulnerability is accepted or
+declined, etc._
diff --git a/build.zig b/build.zig
index 239b10f9e..ab98bbe98 100644
--- a/build.zig
+++ b/build.zig
@@ -197,7 +197,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
}
var c_source_files: std.ArrayList([]const u8) = try .initCapacity(b.allocator, 2);
- c_source_files.appendSliceAssumeCapacity(&.{ "src/rcore.c", "src/utils.c" });
+ c_source_files.appendSliceAssumeCapacity(&.{ "src/rcore.c" });
if (options.rshapes) {
try c_source_files.append(b.allocator, "src/rshapes.c");
@@ -348,7 +348,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
}
},
.freebsd, .openbsd, .netbsd, .dragonfly => {
- try c_source_files.append(b.allocator, "rglfw.c");
+ try c_source_files.append(b.allocator, "src/rglfw.c");
raylib.root_module.linkSystemLibrary("GL", .{});
raylib.root_module.linkSystemLibrary("rt", .{});
raylib.root_module.linkSystemLibrary("dl", .{});
diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake
index 96abeea93..9b8fbdb25 100644
--- a/cmake/LibraryConfigurations.cmake
+++ b/cmake/LibraryConfigurations.cmake
@@ -27,6 +27,12 @@ if (${PLATFORM} MATCHES "Desktop")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
find_package(OpenGL QUIET)
set(LIBS_PRIVATE ${OPENGL_LIBRARIES} winmm)
+ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "QNX")
+ set(GRAPHICS "GRAPHICS_API_OPENGL_ES2")
+ find_library(GLESV2 GLESv2)
+ find_library(EGL EGL)
+ set(LIBS_PUBLIC m)
+ set(LIBS_PRIVATE ${GLESV2} ${EGL} atomic pthread dl)
elseif (UNIX)
find_library(pthread NAMES pthread)
find_package(OpenGL QUIET)
diff --git a/examples/Makefile b/examples/Makefile
index 06a0c2729..acfcb0857 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -30,7 +30,7 @@
# > PLATFORM_ANDROID:
# - Android (ARM, ARM64)
#
-# Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+# Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
#
# This software is provided "as-is", without any express or implied warranty. In no event
# will the authors be held liable for any damages arising from the use of this software.
@@ -205,15 +205,17 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
- MAKE = mingw32-make
+ ifeq ($(PLATFORM_OS),WINDOWS)
+ MAKE = mingw32-make
+ endif
endif
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
- ifeq ($(OS),Windows_NT)
+ ifeq ($(PLATFORM_OS),WINDOWS)
MAKE = mingw32-make
else
- EMMAKE != type emmake
+ EMMAKE := $(shell command -v emmake)
ifneq (, $(EMMAKE))
- MAKE = emmake make
+ MAKE = $(EMMAKE) make
else
MAKE = mingw32-make
endif
@@ -531,7 +533,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 \
@@ -542,6 +544,7 @@ CORE = \
core/core_input_mouse_wheel \
core/core_input_multitouch \
core/core_input_virtual_controls \
+ core/core_keyboard_testbed \
core/core_monitor_detector \
core/core_random_sequence \
core/core_random_values \
@@ -575,6 +578,7 @@ SHAPES = \
shapes/shapes_easings_box \
shapes/shapes_easings_rectangles \
shapes/shapes_following_eyes \
+ shapes/shapes_hilbert_curve \
shapes/shapes_kaleidoscope \
shapes/shapes_lines_bezier \
shapes/shapes_lines_drawing \
@@ -605,6 +609,7 @@ TEXTURES = \
textures/textures_bunnymark \
textures/textures_cellular_automata \
textures/textures_fog_of_war \
+ textures/textures_framebuffer_rendering \
textures/textures_gif_player \
textures/textures_image_channel \
textures/textures_image_drawing \
diff --git a/examples/Makefile.Web b/examples/Makefile.Web
index 7101ed7e3..3841dff29 100644
--- a/examples/Makefile.Web
+++ b/examples/Makefile.Web
@@ -30,7 +30,7 @@
# > PLATFORM_ANDROID:
# - Android (ARM, ARM64)
#
-# Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+# Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
#
# This software is provided "as-is", without any express or implied warranty. In no event
# will the authors be held liable for any damages arising from the use of this software.
@@ -208,12 +208,12 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
MAKE = mingw32-make
endif
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
- ifeq ($(OS),Windows_NT)
+ ifeq ($(PLATFORM_OS),WINDOWS)
MAKE = mingw32-make
else
- EMMAKE != type emmake
+ EMMAKE := $(shell command -v emmake)
ifneq (, $(EMMAKE))
- MAKE = emmake make
+ MAKE = $(EMMAKE) make
else
MAKE = mingw32-make
endif
@@ -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 \
@@ -530,6 +530,7 @@ CORE = \
core/core_input_mouse_wheel \
core/core_input_multitouch \
core/core_input_virtual_controls \
+ core/core_keyboard_testbed \
core/core_monitor_detector \
core/core_random_sequence \
core/core_random_values \
@@ -563,6 +564,7 @@ SHAPES = \
shapes/shapes_easings_box \
shapes/shapes_easings_rectangles \
shapes/shapes_following_eyes \
+ shapes/shapes_hilbert_curve \
shapes/shapes_kaleidoscope \
shapes/shapes_lines_bezier \
shapes/shapes_lines_drawing \
@@ -593,6 +595,7 @@ TEXTURES = \
textures/textures_bunnymark \
textures/textures_cellular_automata \
textures/textures_fog_of_war \
+ textures/textures_framebuffer_rendering \
textures/textures_gif_player \
textures/textures_image_channel \
textures/textures_image_drawing \
@@ -783,7 +786,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
@@ -818,6 +821,9 @@ core/core_input_multitouch: core/core_input_multitouch.c
core/core_input_virtual_controls: core/core_input_virtual_controls.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+core/core_keyboard_testbed: core/core_keyboard_testbed.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
core/core_monitor_detector: core/core_monitor_detector.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -914,6 +920,9 @@ shapes/shapes_easings_rectangles: shapes/shapes_easings_rectangles.c
shapes/shapes_following_eyes: shapes/shapes_following_eyes.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+shapes/shapes_hilbert_curve: shapes/shapes_hilbert_curve.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
shapes/shapes_kaleidoscope: shapes/shapes_kaleidoscope.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -1005,6 +1014,9 @@ textures/textures_cellular_automata: textures/textures_cellular_automata.c
textures/textures_fog_of_war: textures/textures_fog_of_war.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+textures/textures_framebuffer_rendering: textures/textures_framebuffer_rendering.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
textures/textures_gif_player: textures/textures_gif_player.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/scarfy_run.gif@resources/scarfy_run.gif
@@ -1367,15 +1379,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/r_pentomino.png@resources/game_of_life/r_pentomino.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/acorn.png@resources/game_of_life/acorn.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 \
--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/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
+ --preload-file shaders/resources/game_of_life/glider_gun.png@resources/game_of_life/glider_gun.png \
+ --preload-file shaders/resources/game_of_life/breeder.png@resources/game_of_life/breeder.png
shaders/shaders_hot_reloading: shaders/shaders_hot_reloading.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
diff --git a/examples/README.md b/examples/README.md
index d64ed7608..6b2c1950b 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -17,9 +17,9 @@ 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: 205]
+## EXAMPLES COLLECTION [TOTAL: 208]
-### category: core [47]
+### category: core [48]
Examples using raylib [core](../src/rcore.c) module platform functionality: window creation, inputs, drawing modes and system functionality.
@@ -61,7 +61,7 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind
| [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) |
| ⭐⭐⭐☆ | 3.7 | 4.0 | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) |
| [core_random_sequence](core/core_random_sequence.c) |
| ⭐☆☆☆ | 5.0 | 5.0 | [Dalton Overmyer](https://github.com/REDl3east) |
| [core_automation_events](core/core_automation_events.c) |
| ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) |
-| [core_high_dpi](core/core_high_dpi.c) |
| ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) |
+| [core_highdpi_demo](core/core_highdpi_demo.c) |
| ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) |
| [core_render_texture](core/core_render_texture.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_undo_redo](core/core_undo_redo.c) |
| ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_viewport_scaling](core/core_viewport_scaling.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) |
@@ -69,11 +69,12 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind
| [core_directory_files](core/core_directory_files.c) |
| ⭐☆☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) |
| [core_highdpi_testbed](core/core_highdpi_testbed.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_screen_recording](core/core_screen_recording.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
-| [core_clipboard_text](core/core_clipboard_text.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ananth S](https://github.com/Ananth1839) |
+| [core_clipboard_text](core/core_clipboard_text.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ananth S](https://github.com/Ananth1839) |
| [core_text_file_loading](core/core_text_file_loading.c) |
| ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) |
| [core_compute_hash](core/core_compute_hash.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
+| [core_keyboard_testbed](core/core_keyboard_testbed.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) |
-### category: shapes [38]
+### category: shapes [39]
Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module.
@@ -117,8 +118,9 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
| [shapes_rlgl_triangle](shapes/shapes_rlgl_triangle.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
| [shapes_ball_physics](shapes/shapes_ball_physics.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) |
| [shapes_penrose_tile](shapes/shapes_penrose_tile.c) |
| ⭐⭐⭐⭐️ | 5.5 | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) |
+| [shapes_hilbert_curve](shapes/shapes_hilbert_curve.c) |
| ⭐⭐⭐☆ | 5.6 | 5.6 | [Hamza RAHAL](https://github.com/hmz-rhl) |
-### category: textures [29]
+### category: textures [30]
Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/rtextures.c) module.
@@ -153,6 +155,7 @@ Examples using raylib textures functionality, including image/textures loading/g
| [textures_textured_curve](textures/textures_textured_curve.c) |
| ⭐⭐⭐☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) |
| [textures_sprite_stacking](textures/textures_sprite_stacking.c) |
| ⭐⭐☆☆ | 5.6-dev | 6.0 | [Robin](https://github.com/RobinsAviary) |
| [textures_cellular_automata](textures/textures_cellular_automata.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
+| [textures_framebuffer_rendering](textures/textures_framebuffer_rendering.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Jack Boakes](https://github.com/jackboakes) |
### category: text [16]
diff --git a/examples/audio/audio_music_stream.c b/examples/audio/audio_music_stream.c
index 05ec1c2d6..6e1dfc8c5 100644
--- a/examples/audio/audio_music_stream.c
+++ b/examples/audio/audio_music_stream.c
@@ -113,7 +113,7 @@ int main(void)
DrawText("LEFT-RIGHT for PAN CONTROL", 320, 74, 10, DARKBLUE);
DrawRectangle(300, 100, 200, 12, LIGHTGRAY);
DrawRectangleLines(300, 100, 200, 12, GRAY);
- DrawRectangle(300 + (pan + 1.0)/2.0f*200 - 5, 92, 10, 28, DARKGRAY);
+ DrawRectangle((int)(300 + (pan + 1.0f)/2.0f*200 - 5), 92, 10, 28, DARKGRAY);
DrawRectangle(200, 200, 400, 12, LIGHTGRAY);
DrawRectangle(200, 200, (int)(timePlayed*400.0f), 12, MAROON);
@@ -125,7 +125,7 @@ int main(void)
DrawText("UP-DOWN for VOLUME CONTROL", 320, 334, 10, DARKGREEN);
DrawRectangle(300, 360, 200, 12, LIGHTGRAY);
DrawRectangleLines(300, 360, 200, 12, GRAY);
- DrawRectangle(300 + volume*200 - 5, 352, 10, 28, DARKGRAY);
+ DrawRectangle((int)(300 + volume*200 - 5), 352, 10, 28, DARKGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
diff --git a/examples/audio/audio_spectrum_visualizer.c b/examples/audio/audio_spectrum_visualizer.c
index f5334c9cc..5cde7e9bd 100644
--- a/examples/audio/audio_spectrum_visualizer.c
+++ b/examples/audio/audio_spectrum_visualizer.c
@@ -115,7 +115,7 @@ int main(void)
.tapbackPos = 0.01f
};
- size_t wavCursor = 0;
+ int wavCursor = 0;
const short *wavPCM16 = wav.data;
short chunkSamples[AUDIO_STREAM_RING_BUFFER_SIZE] = { 0 };
diff --git a/examples/audio/audio_spectrum_visualizer.png b/examples/audio/audio_spectrum_visualizer.png
index c3f1bc8b0..f885927b1 100644
Binary files a/examples/audio/audio_spectrum_visualizer.png and b/examples/audio/audio_spectrum_visualizer.png differ
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/core/core_highdpi_testbed.c b/examples/core/core_highdpi_testbed.c
index a341d081c..a925527db 100644
--- a/examples/core/core_highdpi_testbed.c
+++ b/examples/core/core_highdpi_testbed.c
@@ -27,9 +27,14 @@ int main(void)
const int screenWidth = 800;
const int screenHeight = 450;
- SetConfigFlags(FLAG_WINDOW_HIGHDPI | FLAG_WINDOW_RESIZABLE);
+ SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI);
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi testbed");
+ Vector2 scaleDpi = GetWindowScaleDPI();
+ Vector2 mousePos = GetMousePosition();
+ int currentMonitor = GetCurrentMonitor();
+ Vector2 windowPos = GetWindowPosition();
+
int gridSpacing = 40; // Grid spacing in pixels
SetTargetFPS(60);
@@ -40,7 +45,13 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
- // TODO: Update variables / Implement example logic at this point
+ mousePos = GetMousePosition();
+ currentMonitor = GetCurrentMonitor();
+ scaleDpi = GetWindowScaleDPI();
+ windowPos = GetWindowPosition();
+
+ if (IsKeyPressed(KEY_SPACE)) ToggleBorderlessWindowed();
+ if (IsKeyPressed(KEY_F)) ToggleFullscreen();
//----------------------------------------------------------------------------------
// Draw
@@ -50,11 +61,35 @@ 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 < GetScreenHeight()/gridSpacing + 1; 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 < GetScreenWidth()/gridSpacing + 1; 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("WINDOW POSITION: %ix%i", (int)windowPos.x, (int)windowPos.y), 50, 90, 20, DARKGRAY);
+ DrawText(TextFormat("SCREEN SIZE: %ix%i", GetScreenWidth(), GetScreenHeight()), 50, 130, 20, DARKGRAY);
+ DrawText(TextFormat("RENDER SIZE: %ix%i", GetRenderWidth(), GetRenderHeight()), 50, 170, 20, DARKGRAY);
+ DrawText(TextFormat("SCALE FACTOR: %.1fx%.1f", scaleDpi.x, scaleDpi.y), 50, 210, 20, GRAY);
+
+ // Draw reference rectangles, top-left and bottom-right corners
+ DrawRectangle(0, 0, 30, 60, RED);
+ DrawRectangle(GetScreenWidth() - 30, GetScreenHeight() - 60, 30, 60, BLUE);
+
+ // 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/examples/core/core_highdpi_testbed.png b/examples/core/core_highdpi_testbed.png
index da99bbb0d..a37c82130 100644
Binary files a/examples/core/core_highdpi_testbed.png and b/examples/core/core_highdpi_testbed.png differ
diff --git a/examples/core/core_input_gamepad.c b/examples/core/core_input_gamepad.c
index 3c9454318..a9e0660e0 100644
--- a/examples/core/core_input_gamepad.c
+++ b/examples/core/core_input_gamepad.c
@@ -67,7 +67,7 @@ int main(void)
if (IsKeyPressed(KEY_RIGHT)) gamepad++;
Vector2 mousePosition = GetMousePosition();
- vibrateButton = (Rectangle){ 10, 70 + 20*GetGamepadAxisCount(gamepad) + 20, 75, 24 };
+ vibrateButton = (Rectangle){ 10, 70.0f + 20*GetGamepadAxisCount(gamepad) + 20, 75, 24 };
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mousePosition, vibrateButton)) SetGamepadVibration(gamepad, 1.0, 1.0, 1.0);
//----------------------------------------------------------------------------------
@@ -262,7 +262,7 @@ int main(void)
// Draw vibrate button
DrawRectangleRec(vibrateButton, SKYBLUE);
- DrawText("VIBRATE", vibrateButton.x + 14, vibrateButton.y + 1, 10, DARKGRAY);
+ DrawText("VIBRATE", (int)(vibrateButton.x + 14), (int)(vibrateButton.y + 1), 10, DARKGRAY);
if (GetGamepadButtonPressed() != GAMEPAD_BUTTON_UNKNOWN) DrawText(TextFormat("DETECTED BUTTON: %i", GetGamepadButtonPressed()), 10, 430, 10, RED);
else DrawText("DETECTED BUTTON: NONE", 10, 430, 10, GRAY);
diff --git a/examples/core/core_keyboard_testbed.c b/examples/core/core_keyboard_testbed.c
new file mode 100644
index 000000000..904e9c90a
--- /dev/null
+++ b/examples/core/core_keyboard_testbed.c
@@ -0,0 +1,333 @@
+/*******************************************************************************************
+*
+* raylib [core] example - keyboard testbed
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* NOTE: raylib defined keys refer to ENG-US Keyboard layout,
+* mapping to other layouts is up to the user
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* 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) 2026 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define KEY_REC_SPACING 4 // Space in pixels between key rectangles
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static const char *GetKeyText(int key);
+static void GuiKeyboardKey(Rectangle bounds, int key);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [core] example - keyboard testbed");
+ SetExitKey(KEY_NULL); // Avoid exit on KEY_ESCAPE
+
+ // Keyboard line 01
+ int line01KeyWidths[15] = { 0 };
+ for (int i = 0; i < 15; i++) line01KeyWidths[i] = 45;
+ line01KeyWidths[13] = 62; // PRINTSCREEN
+ int line01Keys[15] = {
+ KEY_ESCAPE, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
+ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11,
+ KEY_F12, KEY_PRINT_SCREEN, KEY_PAUSE
+ };
+
+ // Keyboard line 02
+ int line02KeyWidths[15] = { 0 };
+ for (int i = 0; i < 15; i++) line02KeyWidths[i] = 45;
+ line02KeyWidths[0] = 25; // GRAVE
+ line02KeyWidths[13] = 82; // BACKSPACE
+ int line02Keys[15] = {
+ KEY_GRAVE, KEY_ONE, KEY_TWO, KEY_THREE, KEY_FOUR,
+ KEY_FIVE, KEY_SIX, KEY_SEVEN, KEY_EIGHT, KEY_NINE,
+ KEY_ZERO, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_DELETE };
+
+ // Keyboard line 03
+ int line03KeyWidths[15] = { 0 };
+ for (int i = 0; i < 15; i++) line03KeyWidths[i] = 45;
+ line03KeyWidths[0] = 50; // TAB
+ line03KeyWidths[13] = 57; // BACKSLASH
+ int line03Keys[15] = {
+ KEY_TAB, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y,
+ KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFT_BRACKET,
+ KEY_RIGHT_BRACKET, KEY_BACKSLASH, KEY_INSERT
+ };
+
+ // Keyboard line 04
+ int line04KeyWidths[14] = { 0 };
+ for (int i = 0; i < 14; i++) line04KeyWidths[i] = 45;
+ line04KeyWidths[0] = 68; // CAPS
+ line04KeyWidths[12] = 88; // ENTER
+ int line04Keys[14] = {
+ KEY_CAPS_LOCK, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G,
+ KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON,
+ KEY_APOSTROPHE, KEY_ENTER, KEY_PAGE_UP
+ };
+
+ // Keyboard line 05
+ int line05KeyWidths[14] = { 0 };
+ for (int i = 0; i < 14; i++) line05KeyWidths[i] = 45;
+ line05KeyWidths[0] = 80; // LSHIFT
+ line05KeyWidths[11] = 76; // RSHIFT
+ int line05Keys[14] = {
+ KEY_LEFT_SHIFT, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B,
+ KEY_N, KEY_M, KEY_COMMA, KEY_PERIOD, /*KEY_MINUS*/
+ KEY_SLASH, KEY_RIGHT_SHIFT, KEY_UP, KEY_PAGE_DOWN
+ };
+
+ // Keyboard line 06
+ int line06KeyWidths[11] = { 0 };
+ for (int i = 0; i < 11; i++) line06KeyWidths[i] = 45;
+ line06KeyWidths[0] = 80; // LCTRL
+ line06KeyWidths[3] = 208; // SPACE
+ line06KeyWidths[7] = 60; // RCTRL
+ int line06Keys[11] = {
+ KEY_LEFT_CONTROL, KEY_LEFT_SUPER, KEY_LEFT_ALT,
+ KEY_SPACE, KEY_RIGHT_ALT, 162, KEY_NULL,
+ KEY_RIGHT_CONTROL, KEY_LEFT, KEY_DOWN, KEY_RIGHT
+ };
+
+ Vector2 keyboardOffset = { 26, 80 };
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ int key = GetKeyPressed(); // Get pressed keycode
+ if (key > 0) TraceLog(LOG_INFO, "KEYBOARD TESTBED: KEY PRESSED: %d", key);
+
+ int ch = GetCharPressed(); // Get pressed char for text input, using OS mapping
+ if (ch > 0) TraceLog(LOG_INFO, "KEYBOARD TESTBED: CHAR PRESSED: %c (%d)", ch, ch);
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ DrawText("KEYBOARD LAYOUT: ENG-US", 26, 38, 20, LIGHTGRAY);
+
+ // Keyboard line 01 - 15 keys
+ // ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, IMP, CLOSE
+ for (int i = 0, recOffsetX = 0; i < 15; i++)
+ {
+ GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y, line01KeyWidths[i], 30 }, line01Keys[i]);
+ recOffsetX += line01KeyWidths[i] + KEY_REC_SPACING;
+ }
+
+ // Keyboard line 02 - 15 keys
+ // `, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -, =, BACKSPACE, DEL
+ for (int i = 0, recOffsetX = 0; i < 15; i++)
+ {
+ GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + KEY_REC_SPACING, line02KeyWidths[i], 38 }, line02Keys[i]);
+ recOffsetX += line02KeyWidths[i] + KEY_REC_SPACING;
+ }
+
+ // Keyboard line 03 - 15 keys
+ // TAB, Q, W, E, R, T, Y, U, I, O, P, [, ], \, INS
+ for (int i = 0, recOffsetX = 0; i < 15; i++)
+ {
+ GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38 + KEY_REC_SPACING*2, line03KeyWidths[i], 38 }, line03Keys[i]);
+ recOffsetX += line03KeyWidths[i] + KEY_REC_SPACING;
+ }
+
+ // Keyboard line 04 - 14 keys
+ // MAYUS, A, S, D, F, G, H, J, K, L, ;, ', ENTER, REPAG
+ for (int i = 0, recOffsetX = 0; i < 14; i++)
+ {
+ GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*2 + KEY_REC_SPACING*3, line04KeyWidths[i], 38 }, line04Keys[i]);
+ recOffsetX += line04KeyWidths[i] + KEY_REC_SPACING;
+ }
+
+ // Keyboard line 05 - 14 keys
+ // LSHIFT, Z, X, C, V, B, N, M, ,, ., /, RSHIFT, UP, AVPAG
+ for (int i = 0, recOffsetX = 0; i < 14; i++)
+ {
+ GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*3 + KEY_REC_SPACING*4, line05KeyWidths[i], 38 }, line05Keys[i]);
+ recOffsetX += line05KeyWidths[i] + KEY_REC_SPACING;
+ }
+
+ // Keyboard line 06 - 11 keys
+ // LCTRL, WIN, LALT, SPACE, ALTGR, \, FN, RCTRL, LEFT, DOWN, RIGHT
+ for (int i = 0, recOffsetX = 0; i < 11; i++)
+ {
+ GuiKeyboardKey((Rectangle){ keyboardOffset.x + recOffsetX, keyboardOffset.y + 30 + 38*4 + KEY_REC_SPACING*5, line06KeyWidths[i], 38 }, line06Keys[i]);
+ recOffsetX += line06KeyWidths[i] + KEY_REC_SPACING;
+ }
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------------
+// Module Functions Definition
+//------------------------------------------------------------------------------------
+// Get keyboard keycode as text (US keyboard)
+// NOTE: Mapping for other keyboard layouts can be done here
+static const char *GetKeyText(int key)
+{
+ switch (key)
+ {
+ case KEY_APOSTROPHE : return "'"; // Key: '
+ case KEY_COMMA : return ","; // Key: ,
+ case KEY_MINUS : return "-"; // Key: -
+ case KEY_PERIOD : return "."; // Key: .
+ case KEY_SLASH : return "/"; // Key: /
+ case KEY_ZERO : return "0"; // Key: 0
+ case KEY_ONE : return "1"; // Key: 1
+ case KEY_TWO : return "2"; // Key: 2
+ case KEY_THREE : return "3"; // Key: 3
+ case KEY_FOUR : return "4"; // Key: 4
+ case KEY_FIVE : return "5"; // Key: 5
+ case KEY_SIX : return "6"; // Key: 6
+ case KEY_SEVEN : return "7"; // Key: 7
+ case KEY_EIGHT : return "8"; // Key: 8
+ case KEY_NINE : return "9"; // Key: 9
+ case KEY_SEMICOLON : return ";"; // Key: ;
+ case KEY_EQUAL : return "="; // Key: =
+ case KEY_A : return "A"; // Key: A | a
+ case KEY_B : return "B"; // Key: B | b
+ case KEY_C : return "C"; // Key: C | c
+ case KEY_D : return "D"; // Key: D | d
+ case KEY_E : return "E"; // Key: E | e
+ case KEY_F : return "F"; // Key: F | f
+ case KEY_G : return "G"; // Key: G | g
+ case KEY_H : return "H"; // Key: H | h
+ case KEY_I : return "I"; // Key: I | i
+ case KEY_J : return "J"; // Key: J | j
+ case KEY_K : return "K"; // Key: K | k
+ case KEY_L : return "L"; // Key: L | l
+ case KEY_M : return "M"; // Key: M | m
+ case KEY_N : return "N"; // Key: N | n
+ case KEY_O : return "O"; // Key: O | o
+ case KEY_P : return "P"; // Key: P | p
+ case KEY_Q : return "Q"; // Key: Q | q
+ case KEY_R : return "R"; // Key: R | r
+ case KEY_S : return "S"; // Key: S | s
+ case KEY_T : return "T"; // Key: T | t
+ case KEY_U : return "U"; // Key: U | u
+ case KEY_V : return "V"; // Key: V | v
+ case KEY_W : return "W"; // Key: W | w
+ case KEY_X : return "X"; // Key: X | x
+ case KEY_Y : return "Y"; // Key: Y | y
+ case KEY_Z : return "Z"; // Key: Z | z
+ case KEY_LEFT_BRACKET : return "["; // Key: [
+ case KEY_BACKSLASH : return "\\"; // Key: '\'
+ case KEY_RIGHT_BRACKET : return "]"; // Key: ]
+ case KEY_GRAVE : return "`"; // Key: `
+ case KEY_SPACE : return "SPACE"; // Key: Space
+ case KEY_ESCAPE : return "ESC"; // Key: Esc
+ case KEY_ENTER : return "ENTER"; // Key: Enter
+ case KEY_TAB : return "TAB"; // Key: Tab
+ case KEY_BACKSPACE : return "BACK"; // Key: Backspace
+ case KEY_INSERT : return "INS"; // Key: Ins
+ case KEY_DELETE : return "DEL"; // Key: Del
+ case KEY_RIGHT : return "RIGHT"; // Key: Cursor right
+ case KEY_LEFT : return "LEFT"; // Key: Cursor left
+ case KEY_DOWN : return "DOWN"; // Key: Cursor down
+ case KEY_UP : return "UP"; // Key: Cursor up
+ case KEY_PAGE_UP : return "PGUP"; // Key: Page up
+ case KEY_PAGE_DOWN : return "PGDOWN"; // Key: Page down
+ case KEY_HOME : return "HOME"; // Key: Home
+ case KEY_END : return "END"; // Key: End
+ case KEY_CAPS_LOCK : return "CAPS"; // Key: Caps lock
+ case KEY_SCROLL_LOCK : return "LOCK"; // Key: Scroll down
+ case KEY_NUM_LOCK : return "NUMLOCK"; // Key: Num lock
+ case KEY_PRINT_SCREEN : return "PRINTSCR"; // Key: Print screen
+ case KEY_PAUSE : return "PAUSE"; // Key: Pause
+ case KEY_F1 : return "F1"; // Key: F1
+ case KEY_F2 : return "F2"; // Key: F2
+ case KEY_F3 : return "F3"; // Key: F3
+ case KEY_F4 : return "F4"; // Key: F4
+ case KEY_F5 : return "F5"; // Key: F5
+ case KEY_F6 : return "F6"; // Key: F6
+ case KEY_F7 : return "F7"; // Key: F7
+ case KEY_F8 : return "F8"; // Key: F8
+ case KEY_F9 : return "F9"; // Key: F9
+ case KEY_F10 : return "F10"; // Key: F10
+ case KEY_F11 : return "F11"; // Key: F11
+ case KEY_F12 : return "F12"; // Key: F12
+ case KEY_LEFT_SHIFT : return "LSHIFT"; // Key: Shift left
+ case KEY_LEFT_CONTROL : return "LCTRL"; // Key: Control left
+ case KEY_LEFT_ALT : return "LALT"; // Key: Alt left
+ case KEY_LEFT_SUPER : return "WIN"; // Key: Super left
+ case KEY_RIGHT_SHIFT : return "RSHIFT"; // Key: Shift right
+ case KEY_RIGHT_CONTROL : return "RCTRL"; // Key: Control right
+ case KEY_RIGHT_ALT : return "ALTGR"; // Key: Alt right
+ case KEY_RIGHT_SUPER : return "RSUPER"; // Key: Super right
+ case KEY_KB_MENU : return "KBMENU"; // Key: KB menu
+ case KEY_KP_0 : return "KP0"; // Key: Keypad 0
+ case KEY_KP_1 : return "KP1"; // Key: Keypad 1
+ case KEY_KP_2 : return "KP2"; // Key: Keypad 2
+ case KEY_KP_3 : return "KP3"; // Key: Keypad 3
+ case KEY_KP_4 : return "KP4"; // Key: Keypad 4
+ case KEY_KP_5 : return "KP5"; // Key: Keypad 5
+ case KEY_KP_6 : return "KP6"; // Key: Keypad 6
+ case KEY_KP_7 : return "KP7"; // Key: Keypad 7
+ case KEY_KP_8 : return "KP8"; // Key: Keypad 8
+ case KEY_KP_9 : return "KP9"; // Key: Keypad 9
+ case KEY_KP_DECIMAL : return "KPDEC"; // Key: Keypad .
+ case KEY_KP_DIVIDE : return "KPDIV"; // Key: Keypad /
+ case KEY_KP_MULTIPLY : return "KPMUL"; // Key: Keypad *
+ case KEY_KP_SUBTRACT : return "KPSUB"; // Key: Keypad -
+ case KEY_KP_ADD : return "KPADD"; // Key: Keypad +
+ case KEY_KP_ENTER : return "KPENTER"; // Key: Keypad Enter
+ case KEY_KP_EQUAL : return "KPEQU"; // Key: Keypad =
+ default: return "";
+ }
+}
+
+// Draw keyboard key
+static void GuiKeyboardKey(Rectangle bounds, int key)
+{
+ if (key == KEY_NULL) DrawRectangleLinesEx(bounds, 2.0f, LIGHTGRAY);
+ else
+ {
+ if (IsKeyDown(key))
+ {
+ DrawRectangleLinesEx(bounds, 2.0f, MAROON);
+ DrawText(GetKeyText(key), bounds.x + 4, bounds.y + 4, 10, MAROON);
+ }
+ else
+ {
+ DrawRectangleLinesEx(bounds, 2.0f, DARKGRAY);
+ DrawText(GetKeyText(key), bounds.x + 4, bounds.y + 4, 10, DARKGRAY);
+ }
+ }
+
+ if (CheckCollisionPointRec(GetMousePosition(), bounds))
+ {
+ DrawRectangleRec(bounds, Fade(RED, 0.2f));
+ DrawRectangleLinesEx(bounds, 3.0f, RED);
+ }
+}
\ No newline at end of file
diff --git a/examples/core/core_keyboard_testbed.png b/examples/core/core_keyboard_testbed.png
new file mode 100644
index 000000000..bac0fc29a
Binary files /dev/null and b/examples/core/core_keyboard_testbed.png differ
diff --git a/examples/core/core_viewport_scaling.c b/examples/core/core_viewport_scaling.c
index adcd51ea3..6ff5ac9c4 100644
--- a/examples/core/core_viewport_scaling.c
+++ b/examples/core/core_viewport_scaling.c
@@ -112,16 +112,16 @@ int main(void)
if (CheckCollisionPointRec(mousePosition, decreaseResolutionButton) && mousePressed)
{
resolutionIndex = (resolutionIndex + RESOLUTION_COUNT - 1)%RESOLUTION_COUNT;
- gameWidth = resolutionList[resolutionIndex].x;
- gameHeight = resolutionList[resolutionIndex].y;
+ gameWidth = (int)resolutionList[resolutionIndex].x;
+ gameHeight = (int)resolutionList[resolutionIndex].y;
ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
}
if (CheckCollisionPointRec(mousePosition, increaseResolutionButton) && mousePressed)
{
resolutionIndex = (resolutionIndex + 1)%RESOLUTION_COUNT;
- gameWidth = resolutionList[resolutionIndex].x;
- gameHeight = resolutionList[resolutionIndex].y;
+ gameWidth = (int)resolutionList[resolutionIndex].x;
+ gameHeight = (int)resolutionList[resolutionIndex].y;
ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
}
@@ -145,7 +145,7 @@ int main(void)
// Draw our scene to the render texture
BeginTextureMode(target);
ClearBackground(WHITE);
- DrawCircle(textureMousePosition.x, textureMousePosition.y, 20.0f, LIME);
+ DrawCircleV(textureMousePosition, 20.0f, LIME);
EndTextureMode();
// Draw render texture to main framebuffer
@@ -159,7 +159,7 @@ int main(void)
// Draw info box
Rectangle infoRect = (Rectangle){5, 5, 330, 105};
DrawRectangleRec(infoRect, Fade(LIGHTGRAY, 0.7f));
- DrawRectangleLines(infoRect.x, infoRect.y, infoRect.width, infoRect.height, BLUE);
+ DrawRectangleLinesEx(infoRect, 1, BLUE);
DrawText(TextFormat("Window Resolution: %d x %d", screenWidth, screenHeight), 15, 15, 10, BLACK);
DrawText(TextFormat("Game Resolution: %d x %d", gameWidth, gameHeight), 15, 30, 10, BLACK);
diff --git a/examples/examples_list.txt b/examples/examples_list.txt
index 925ad9454..eda62ee13 100644
--- a/examples/examples_list.txt
+++ b/examples/examples_list.txt
@@ -1,11 +1,13 @@
#
-# raylib examples list used to generate/update collection
-# examples must be provided as: ;;;;;;;"";
+# raylib examples list with available .c example files
+#
+# WARNING: List is not ordered by example name but by the display order on web,
+# so it can not be automatically generated scanning available .c code files, only updated
+# new examples are added at the end of each category; it's up to the user to reorder them as desired
+#
+# examples data is listed as: ;;;;;;;"";
#
# This list is used as the main reference by [rexm] tool for examples collection validation and management
-# New examples must be added to this list and any possible rename must be made on this list first
-#
-# WARNING: List is not ordered by example name but by the display order on web
#
core;core_basic_window;★☆☆☆;1.0;1.0;2013;2025;"Ramon Santamaria";@raysan5
core;core_delta_time;★☆☆☆;5.5;5.6-dev;2025;2025;"Robin";@RobinsAviary
@@ -43,7 +45,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
@@ -54,6 +56,7 @@ core;core_screen_recording;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santama
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
+core;core_keyboard_testbed;★★☆☆;5.6;5.6;2026;2026;"Ramon Santamaria";@raysan5
shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5
shapes;shapes_bouncing_ball;★☆☆☆;2.5;2.5;2013;2025;"Ramon Santamaria";@raysan5
shapes;shapes_bullet_hell;★☆☆☆;5.6;5.6;2025;2025;"Zero";@zerohorsepower
@@ -92,6 +95,7 @@ shapes;shapes_rlgl_color_wheel;★★★☆;5.6-dev;5.6-dev;2025;2025;"Robin";@R
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
+shapes;shapes_hilbert_curve;★★★☆;5.6;5.6;2025;2025;"Hamza RAHAL";@hmz-rhl
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
@@ -121,6 +125,7 @@ textures;textures_screen_buffer;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";
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
+textures;textures_framebuffer_rendering;★★☆☆;5.6;5.6;2026;2026;"Jack Boakes";@jackboakes
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
diff --git a/examples/models/models_decals.c b/examples/models/models_decals.c
index f556139e1..71122dd68 100644
--- a/examples/models/models_decals.c
+++ b/examples/models/models_decals.c
@@ -45,7 +45,7 @@ static void FreeMeshBuilder(MeshBuilder *mb);
static Mesh BuildMesh(MeshBuilder *mb);
static Mesh GenMeshDecal(Model inputModel, Matrix projection, float decalSize, float decalOffset);
static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s);
-#define FreeDecalMeshData() GenMeshDecal((Model){ .meshCount = -1.0f }, (Matrix){ 0 }, 0.0f, 0.0f)
+static void FreeDecalMeshData(void) { GenMeshDecal((Model){ .meshCount = -1 }, (Matrix){ 0 }, 0.0f, 0.0f); }
static bool GuiButton(Rectangle rec, const char *label);
//------------------------------------------------------------------------------------
@@ -198,12 +198,12 @@ int main(void)
EndMode3D();
float yPos = 10;
- float x0 = GetScreenWidth() - 300;
+ float x0 = GetScreenWidth() - 300.0f;
float x1 = x0 + 100;
float x2 = x1 + 100;
- DrawText("Vertices", x1, yPos, 10, LIME);
- DrawText("Triangles", x2, yPos, 10, LIME);
+ DrawText("Vertices", (int)x1, (int)yPos, 10, LIME);
+ DrawText("Triangles", (int)x2, (int)yPos, 10, LIME);
yPos += 15;
int vertexCount = 0;
@@ -215,24 +215,24 @@ int main(void)
triangleCount += model.meshes[i].triangleCount;
}
- DrawText("Main model", x0, yPos, 10, LIME);
- DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME);
- DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME);
+ DrawText("Main model", (int)x0, (int)yPos, 10, LIME);
+ DrawText(TextFormat("%d", vertexCount), (int)x1, (int)yPos, 10, LIME);
+ DrawText(TextFormat("%d", triangleCount), (int)x2, (int)yPos, 10, LIME);
yPos += 15;
for (int i = 0; i < decalCount; i++)
{
if (i == 20)
{
- DrawText("...", x0, yPos, 10, LIME);
+ DrawText("...", (int)x0, (int)yPos, 10, LIME);
yPos += 15;
}
if (i < 20)
{
- DrawText(TextFormat("Decal #%d", i+1), x0, yPos, 10, LIME);
- DrawText(TextFormat("%d", decalModels[i].meshes[0].vertexCount), x1, yPos, 10, LIME);
- DrawText(TextFormat("%d", decalModels[i].meshes[0].triangleCount), x2, yPos, 10, LIME);
+ DrawText(TextFormat("Decal #%d", i+1), (int)x0, (int)yPos, 10, LIME);
+ DrawText(TextFormat("%d", decalModels[i].meshes[0].vertexCount), (int)x1, (int)yPos, 10, LIME);
+ DrawText(TextFormat("%d", decalModels[i].meshes[0].triangleCount), (int)x2, (int)yPos, 10, LIME);
yPos += 15;
}
@@ -240,18 +240,18 @@ int main(void)
triangleCount += decalModels[i].meshes[0].triangleCount;
}
- DrawText("TOTAL", x0, yPos, 10, LIME);
- DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME);
- DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME);
+ DrawText("TOTAL", (int)x0, (int)yPos, 10, LIME);
+ DrawText(TextFormat("%d", vertexCount), (int)x1, (int)yPos, 10, LIME);
+ DrawText(TextFormat("%d", triangleCount), (int)x2, (int)yPos, 10, LIME);
yPos += 15;
DrawText("Hold RMB to move camera", 10, 430, 10, GRAY);
DrawText("(c) Character model and texture from kenney.nl", screenWidth - 260, screenHeight - 20, 10, GRAY);
// UI elements
- if (GuiButton((Rectangle){ 10, screenHeight - 100, 100, 60 }, showModel ? "Hide Model" : "Show Model")) showModel = !showModel;
+ if (GuiButton((Rectangle){ 10, screenHeight - 1000.f, 100, 60 }, showModel ? "Hide Model" : "Show Model")) showModel = !showModel;
- if (GuiButton((Rectangle){ 10 + 110, screenHeight - 100, 100, 60 }, "Clear Decals"))
+ if (GuiButton((Rectangle){ 10 + 110, screenHeight - 100.0f, 100, 60 }, "Clear Decals"))
{
// Clear decals, unload all decal models
for (int i = 0; i < decalCount; i++) UnloadModel(decalModels[i]);
@@ -596,8 +596,8 @@ static bool GuiButton(Rectangle rec, const char *label)
DrawRectangleRec(rec, bgColor);
DrawRectangleLinesEx(rec, 2.0f, DARKGRAY);
- float fontSize = 10.0f;
- float textWidth = MeasureText(label, fontSize);
+ int fontSize = 10;
+ int textWidth = MeasureText(label, fontSize);
DrawText(label, (int)(rec.x + rec.width*0.5f - textWidth*0.5f), (int)(rec.y + rec.height*0.5f - fontSize*0.5f), fontSize, DARKGRAY);
diff --git a/examples/models/models_first_person_maze.c b/examples/models/models_first_person_maze.c
index 43020974f..13b56f4cd 100644
--- a/examples/models/models_first_person_maze.c
+++ b/examples/models/models_first_person_maze.c
@@ -80,18 +80,23 @@ int main(void)
if (playerCellY < 0) playerCellY = 0;
else if (playerCellY >= cubicmap.height) playerCellY = cubicmap.height - 1;
- // Check map collisions using image data and player position
- // TODO: Improvement: Just check player surrounding cells for collision
- for (int y = 0; y < cubicmap.height; y++)
+ // Check map collisions using image data and player position against surrounding cells only
+ for (int y = playerCellY - 1; y <= playerCellY + 1; y++)
{
- for (int x = 0; x < cubicmap.width; x++)
+ // Avoid map accessing out of bounds
+ if ((y >= 0) && (y < cubicmap.height))
{
- if ((mapPixels[y*cubicmap.width + x].r == 255) && // Collision: white pixel, only check R channel
- (CheckCollisionCircleRec(playerPos, playerRadius,
- (Rectangle){ mapPosition.x - 0.5f + x*1.0f, mapPosition.z - 0.5f + y*1.0f, 1.0f, 1.0f })))
+ for (int x = playerCellX - 1; x <= playerCellX + 1; x++)
{
- // Collision detected, reset camera position
- camera.position = oldCamPos;
+ // NOTE: Collision: Only checking R channel for white pixel
+ if (((x >= 0) && (x < cubicmap.width)) &&
+ (mapPixels[y*cubicmap.width + x].r == 255) &&
+ (CheckCollisionCircleRec(playerPos, playerRadius,
+ (Rectangle){ mapPosition.x - 0.5f + x*1.0f, mapPosition.z - 0.5f + y*1.0f, 1.0f, 1.0f })))
+ {
+ // Collision detected, reset camera position
+ camera.position = oldCamPos;
+ }
}
}
}
diff --git a/examples/others/raylib_opengl_interop.c b/examples/others/raylib_opengl_interop.c
index 540a623ab..935eb87f8 100644
--- a/examples/others/raylib_opengl_interop.c
+++ b/examples/others/raylib_opengl_interop.c
@@ -30,6 +30,7 @@
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_DESKTOP_SDL)
#if defined(GRAPHICS_API_OPENGL_ES2)
+ #define GLAD_GLES2_IMPLEMENTATION
#include "glad_gles2.h" // Required for: OpenGL functionality
#define glGenVertexArrays glGenVertexArraysOES
#define glBindVertexArray glBindVertexArrayOES
diff --git a/examples/shaders/shaders_deferred_rendering.c b/examples/shaders/shaders_deferred_rendering.c
index 811566917..4b03b69a4 100644
--- a/examples/shaders/shaders_deferred_rendering.c
+++ b/examples/shaders/shaders_deferred_rendering.c
@@ -40,13 +40,13 @@
//----------------------------------------------------------------------------------
// GBuffer data
typedef struct GBuffer {
- unsigned int framebuffer;
+ unsigned int framebufferId;
- unsigned int positionTexture;
- unsigned int normalTexture;
- unsigned int albedoSpecTexture;
+ unsigned int positionTextureId;
+ unsigned int normalTextureId;
+ unsigned int albedoSpecTextureId;
- unsigned int depthRenderbuffer;
+ unsigned int depthRenderbufferId;
} GBuffer;
// Deferred mode passes
@@ -90,15 +90,10 @@ int main(void)
// Initialize the G-buffer
GBuffer gBuffer = { 0 };
- gBuffer.framebuffer = rlLoadFramebuffer();
+ gBuffer.framebufferId = rlLoadFramebuffer();
+ if (gBuffer.framebufferId == 0) TraceLog(LOG_WARNING, "Failed to create framebufferId");
- if (!gBuffer.framebuffer)
- {
- TraceLog(LOG_WARNING, "Failed to create framebuffer");
- exit(1);
- }
-
- rlEnableFramebuffer(gBuffer.framebuffer);
+ rlEnableFramebuffer(gBuffer.framebufferId);
// NOTE: Vertex positions are stored in a texture for simplicity. A better approach would use a depth texture
// (instead of a detph renderbuffer) to reconstruct world positions in the final render shader via clip-space position,
@@ -107,46 +102,42 @@ int main(void)
// 16-bit precision ensures OpenGL ES 3 compatibility, though it may lack precision for real scenarios
// But as mentioned above, the positions could be reconstructed instead of stored. If not targeting OpenGL ES
// and you wish to maintain this approach, consider using `RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32`
- gBuffer.positionTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, 1);
+ gBuffer.positionTextureId = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, 1);
// Similarly, 16-bit precision is used for normals ensures OpenGL ES 3 compatibility
// This is generally sufficient, but a 16-bit fixed-point format offer a better uniform precision in all orientations
- gBuffer.normalTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, 1);
+ gBuffer.normalTextureId = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, 1);
// Albedo (diffuse color) and specular strength can be combined into one texture
// The color in RGB, and the specular strength in the alpha channel
- gBuffer.albedoSpecTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
+ gBuffer.albedoSpecTextureId = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1);
- // Activate the draw buffers for our framebuffer
+ // Activate the draw buffers for our framebufferId
rlActiveDrawBuffers(3);
- // Now we attach our textures to the framebuffer
- rlFramebufferAttach(gBuffer.framebuffer, gBuffer.positionTexture, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
- rlFramebufferAttach(gBuffer.framebuffer, gBuffer.normalTexture, RL_ATTACHMENT_COLOR_CHANNEL1, RL_ATTACHMENT_TEXTURE2D, 0);
- rlFramebufferAttach(gBuffer.framebuffer, gBuffer.albedoSpecTexture, RL_ATTACHMENT_COLOR_CHANNEL2, RL_ATTACHMENT_TEXTURE2D, 0);
+ // Now we attach our textures to the framebufferId
+ rlFramebufferAttach(gBuffer.framebufferId, gBuffer.positionTextureId, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0);
+ rlFramebufferAttach(gBuffer.framebufferId, gBuffer.normalTextureId, RL_ATTACHMENT_COLOR_CHANNEL1, RL_ATTACHMENT_TEXTURE2D, 0);
+ rlFramebufferAttach(gBuffer.framebufferId, gBuffer.albedoSpecTextureId, RL_ATTACHMENT_COLOR_CHANNEL2, RL_ATTACHMENT_TEXTURE2D, 0);
// Finally we attach the depth buffer
- gBuffer.depthRenderbuffer = rlLoadTextureDepth(screenWidth, screenHeight, true);
- rlFramebufferAttach(gBuffer.framebuffer, gBuffer.depthRenderbuffer, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
+ gBuffer.depthRenderbufferId = rlLoadTextureDepth(screenWidth, screenHeight, true);
+ rlFramebufferAttach(gBuffer.framebufferId, gBuffer.depthRenderbufferId, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0);
- // Make sure our framebuffer is complete
- // NOTE: rlFramebufferComplete() automatically unbinds the framebuffer, so we don't have
- // to rlDisableFramebuffer() here
- if (!rlFramebufferComplete(gBuffer.framebuffer))
- {
- TraceLog(LOG_WARNING, "Framebuffer is not complete");
- }
+ // Make sure our framebufferId is complete
+ // NOTE: rlFramebufferComplete() automatically unbinds the framebufferId, so we don't have to rlDisableFramebuffer() here
+ if (!rlFramebufferComplete(gBuffer.framebufferId)) TraceLog(LOG_WARNING, "Framebuffer is not complete");
// Now we initialize the sampler2D uniform's in the deferred shader
// We do this by setting the uniform's values to the texture units that
// we later bind our g-buffer textures to
rlEnableShader(deferredShader.id);
- int texUnitPosition = 0;
- int texUnitNormal = 1;
- int texUnitAlbedoSpec = 2;
- SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gPosition"), &texUnitPosition, RL_SHADER_UNIFORM_SAMPLER2D);
- SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gNormal"), &texUnitNormal, RL_SHADER_UNIFORM_SAMPLER2D);
- SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gAlbedoSpec"), &texUnitAlbedoSpec, RL_SHADER_UNIFORM_SAMPLER2D);
+ int texUnitPosition = 0;
+ int texUnitNormal = 1;
+ int texUnitAlbedoSpec = 2;
+ SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gPosition"), &texUnitPosition, RL_SHADER_UNIFORM_SAMPLER2D);
+ SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gNormal"), &texUnitNormal, RL_SHADER_UNIFORM_SAMPLER2D);
+ SetShaderValue(deferredShader, rlGetLocationUniform(deferredShader.id, "gAlbedoSpec"), &texUnitAlbedoSpec, RL_SHADER_UNIFORM_SAMPLER2D);
rlDisableShader();
// Assign out lighting shader to model
@@ -176,7 +167,7 @@ int main(void)
cubeRotations[i] = (float)(rand()%360);
}
- DeferredMode mode = DEFERRED_SHADING;
+ int mode = DEFERRED_SHADING;
rlEnableDepthTest();
@@ -215,17 +206,16 @@ int main(void)
BeginDrawing();
// Draw to the geometry buffer by first activating it
- rlEnableFramebuffer(gBuffer.framebuffer);
+ rlEnableFramebuffer(gBuffer.framebufferId);
rlClearColor(0, 0, 0, 0);
rlClearScreenBuffers(); // Clear color and depth buffer
-
rlDisableColorBlend();
+
BeginMode3D(camera);
// NOTE: We have to use rlEnableShader here. `BeginShaderMode` or thus `rlSetShader`
// will not work, as they won't immediately load the shader program
rlEnableShader(gbufferShader.id);
- // When drawing a model here, make sure that the material's shaders
- // are set to the gbuffer shader!
+ // When drawing a model here, make sure that the material's shaders are set to the gbuffer shader!
DrawModel(model, Vector3Zero(), 1.0f, WHITE);
DrawModel(cube, (Vector3) { 0.0, 1.0f, 0.0 }, 1.0f, WHITE);
@@ -234,12 +224,12 @@ int main(void)
Vector3 position = cubePositions[i];
DrawModelEx(cube, position, (Vector3) { 1, 1, 1 }, cubeRotations[i], (Vector3) { CUBE_SCALE, CUBE_SCALE, CUBE_SCALE }, WHITE);
}
-
rlDisableShader();
EndMode3D();
+
rlEnableColorBlend();
- // Go back to the default framebuffer (0) and draw our deferred shading
+ // Go back to the default framebufferId (0) and draw our deferred shading
rlDisableFramebuffer();
rlClearScreenBuffers(); // Clear color & depth buffer
@@ -254,21 +244,21 @@ int main(void)
// We are binding them to locations that we earlier set in sampler2D uniforms `gPosition`, `gNormal`,
// and `gAlbedoSpec`
rlActiveTextureSlot(texUnitPosition);
- rlEnableTexture(gBuffer.positionTexture);
+ rlEnableTexture(gBuffer.positionTextureId);
rlActiveTextureSlot(texUnitNormal);
- rlEnableTexture(gBuffer.normalTexture);
+ rlEnableTexture(gBuffer.normalTextureId);
rlActiveTextureSlot(texUnitAlbedoSpec);
- rlEnableTexture(gBuffer.albedoSpecTexture);
+ rlEnableTexture(gBuffer.albedoSpecTextureId);
- // Finally, we draw a fullscreen quad to our default framebuffer
+ // Finally, we draw a fullscreen quad to our default framebufferId
// This will now be shaded using our deferred shader
rlLoadDrawQuad();
rlDisableShader();
rlEnableColorBlend();
EndMode3D();
- // As a last step, we now copy over the depth buffer from our g-buffer to the default framebuffer
- rlBindFramebuffer(RL_READ_FRAMEBUFFER, gBuffer.framebuffer);
+ // As a last step, we now copy over the depth buffer from our g-buffer to the default framebufferId
+ rlBindFramebuffer(RL_READ_FRAMEBUFFER, gBuffer.framebufferId);
rlBindFramebuffer(RL_DRAW_FRAMEBUFFER, 0);
rlBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, 0x00000100); // GL_DEPTH_BUFFER_BIT
rlDisableFramebuffer();
@@ -290,7 +280,7 @@ int main(void)
case DEFERRED_POSITION:
{
DrawTextureRec((Texture2D){
- .id = gBuffer.positionTexture,
+ .id = gBuffer.positionTextureId,
.width = screenWidth,
.height = screenHeight,
}, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, Vector2Zero(), RAYWHITE);
@@ -300,7 +290,7 @@ int main(void)
case DEFERRED_NORMAL:
{
DrawTextureRec((Texture2D){
- .id = gBuffer.normalTexture,
+ .id = gBuffer.normalTextureId,
.width = screenWidth,
.height = screenHeight,
}, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, Vector2Zero(), RAYWHITE);
@@ -310,7 +300,7 @@ int main(void)
case DEFERRED_ALBEDO:
{
DrawTextureRec((Texture2D){
- .id = gBuffer.albedoSpecTexture,
+ .id = gBuffer.albedoSpecTextureId,
.width = screenWidth,
.height = screenHeight,
}, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, Vector2Zero(), RAYWHITE);
@@ -331,18 +321,20 @@ int main(void)
// De-Initialization
//--------------------------------------------------------------------------------------
- UnloadModel(model); // Unload the models
+ // Unload the models
+ UnloadModel(model);
UnloadModel(cube);
- UnloadShader(deferredShader); // Unload shaders
+ // Unload shaders
+ UnloadShader(deferredShader);
UnloadShader(gbufferShader);
// Unload geometry buffer and all attached textures
- rlUnloadFramebuffer(gBuffer.framebuffer);
- rlUnloadTexture(gBuffer.positionTexture);
- rlUnloadTexture(gBuffer.normalTexture);
- rlUnloadTexture(gBuffer.albedoSpecTexture);
- rlUnloadTexture(gBuffer.depthRenderbuffer);
+ rlUnloadFramebuffer(gBuffer.framebufferId);
+ rlUnloadTexture(gBuffer.positionTextureId);
+ rlUnloadTexture(gBuffer.normalTextureId);
+ rlUnloadTexture(gBuffer.albedoSpecTextureId);
+ rlUnloadTexture(gBuffer.depthRenderbufferId);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/examples/shapes/shapes_ball_physics.c b/examples/shapes/shapes_ball_physics.c
index f9b620d28..0c98ccf9d 100644
--- a/examples/shapes/shapes_ball_physics.c
+++ b/examples/shapes/shapes_ball_physics.c
@@ -46,12 +46,12 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - ball physics");
Ball balls[MAX_BALLS] = {{
- .pos = { GetScreenWidth()/2, GetScreenHeight()/2 },
+ .pos = { GetScreenWidth()/2.0f, GetScreenHeight()/2.0f },
.vel = { 200, 200 },
.ppos = { 0 },
.radius = 40,
- .friction = 0.99,
- .elasticity = 0.9,
+ .friction = 0.99f,
+ .elasticity = 0.9f,
.color = BLUE,
.grabbed = false
}};
@@ -110,11 +110,11 @@ int main(void)
{
balls[ballCount++] = (Ball){
.pos = mousePos,
- .vel = { GetRandomValue(-300, 300), GetRandomValue(-300, 300) },
+ .vel = { (float)GetRandomValue(-300, 300), (float)GetRandomValue(-300, 300) },
.ppos = { 0 },
- .radius = 20 + GetRandomValue(0, 30),
- .friction = 0.99,
- .elasticity = 0.9,
+ .radius = 20.0f + (float)GetRandomValue(0, 30),
+ .friction = 0.99f,
+ .elasticity = 0.9f,
.color = { GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 },
.grabbed = false
};
@@ -126,7 +126,7 @@ int main(void)
{
for (int i = 0; i < ballCount; i++)
{
- if (!balls[i].grabbed) balls[i].vel = (Vector2){ GetRandomValue(-2000, 2000), GetRandomValue(-2000, 2000) };
+ if (!balls[i].grabbed) balls[i].vel = (Vector2){ (float)GetRandomValue(-2000, 2000), (float)GetRandomValue(-2000, 2000) };
}
}
diff --git a/examples/shapes/shapes_hilbert_curve.c b/examples/shapes/shapes_hilbert_curve.c
new file mode 100644
index 000000000..3f368ca03
--- /dev/null
+++ b/examples/shapes/shapes_hilbert_curve.c
@@ -0,0 +1,196 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - hilbert curve
+*
+* Example complexity rating: [★★★☆] 3/4
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* Example contributed by Hamza RAHAL (@hmz-rhl) 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 Hamza RAHAL (@hmz-rhl)
+*
+********************************************************************************************/
+
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+
+#include // Required for: calloc(), free()
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static Vector2 *LoadHilbertPath(int order, float size, int *strokeCount);
+static void UnloadHilbertPath(Vector2 *hilbertPath);
+static Vector2 ComputeHilbertStep(int order, int index);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - hilbert curve");
+
+ int order = 2;
+ float size = GetScreenHeight();
+ int strokeCount = 0;
+ Vector2 *hilbertPath = LoadHilbertPath(order, size, &strokeCount);
+
+ int prevOrder = order;
+ int prevSize = (int)size; // NOTE: Size from slider is float but for comparison we use int
+ int counter = 0;
+ float thick = 2.0f;
+ bool animate = true;
+
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ //--------------------------------------------------------------------------------------
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ // Check if order or size have changed to regenerate
+ // NOTE: Size from slider is float but for comparison we use int
+ if ((prevOrder != order) || (prevSize != (int)size))
+ {
+ UnloadHilbertPath(hilbertPath);
+ hilbertPath = LoadHilbertPath(order, size, &strokeCount);
+
+ if (animate) counter = 0;
+ else counter = strokeCount;
+
+ prevOrder = order;
+ prevSize = size;
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //--------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ if (counter < strokeCount)
+ {
+ // Draw Hilbert path animation, one stroke every frame
+ for (int i = 1; i <= counter; i++)
+ {
+ DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i/strokeCount)*360.0f, 1.0f, 1.0f));
+ }
+
+ counter += 1;
+ }
+ else
+ {
+ // Draw full Hilbert path
+ for (int i = 1; i < strokeCount; i++)
+ {
+ DrawLineEx(hilbertPath[i], hilbertPath[i - 1], thick, ColorFromHSV(((float)i/strokeCount)*360.0f, 1.0f, 1.0f));
+ }
+ }
+
+ // Draw UI using raygui
+ GuiCheckBox((Rectangle){ 450, 50, 20, 20 }, "ANIMATE GENERATION ON CHANGE", &animate);
+ GuiSpinner((Rectangle){ 585, 100, 180, 30 }, "HILBERT CURVE ORDER: ", &order, 2, 8, false);
+ GuiSlider((Rectangle){ 524, 150, 240, 24 }, "THICKNESS: ", NULL, &thick, 1.0f, 10.0f);
+ GuiSlider((Rectangle){ 524, 190, 240, 24 }, "TOTAL SIZE: ", NULL, &size, 10.0f, GetScreenHeight()*1.5f);
+
+ EndDrawing();
+ //--------------------------------------------------------------------------
+ }
+ //--------------------------------------------------------------------------------------
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadHilbertPath(hilbertPath);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+ return 0;
+}
+
+//------------------------------------------------------------------------------------
+// Module Functions Definition
+//------------------------------------------------------------------------------------
+// Load the whole Hilbert Path (including each U and their link)
+static Vector2 *LoadHilbertPath(int order, float size, int *strokeCount)
+{
+ int N = 1 << order;
+ float len = size/N;
+ *strokeCount = N*N;
+
+ Vector2 *hilbertPath = (Vector2 *)RL_CALLOC(*strokeCount, sizeof(Vector2));
+
+ for (int i = 0; i < *strokeCount; i++)
+ {
+ hilbertPath[i] = ComputeHilbertStep(order, i);
+ hilbertPath[i].x = hilbertPath[i].x*len + len/2.0f;
+ hilbertPath[i].y = hilbertPath[i].y*len + len/2.0f;
+ }
+
+ return hilbertPath;
+}
+
+// Unload Hilbert path data
+static void UnloadHilbertPath(Vector2 *hilbertPath)
+{
+ RL_FREE(hilbertPath);
+}
+
+// Compute Hilbert path U positions
+static Vector2 ComputeHilbertStep(int order, int index)
+{
+ // Hilbert points base pattern
+ static const Vector2 hilbertPoints[4] = {
+ [0] = { .x = 0, .y = 0 },
+ [1] = { .x = 0, .y = 1 },
+ [2] = { .x = 1, .y = 1 },
+ [3] = { .x = 1, .y = 0 },
+ };
+
+ int hilbertIndex = index&3;
+ Vector2 vect = hilbertPoints[hilbertIndex];
+ float temp = 0.0f;
+ int len = 0;
+
+ for (int j = 1; j < order; j++)
+ {
+ index = index >> 2;
+ hilbertIndex = index&3;
+ len = 1 << j;
+
+ switch (hilbertIndex)
+ {
+ case 0:
+ {
+ temp = vect.x;
+ vect.x = vect.y;
+ vect.y = temp;
+ } break;
+ case 2: vect.x += len;
+ case 1: vect.y += len; break;
+ case 3:
+ {
+ temp = len - 1 - vect.x;
+ vect.x = 2*len - 1 - vect.y;
+ vect.y = temp;
+ } break;
+ default: break;
+ }
+ }
+
+ return vect;
+}
diff --git a/examples/shapes/shapes_hilbert_curve.png b/examples/shapes/shapes_hilbert_curve.png
new file mode 100644
index 000000000..af99cbc49
Binary files /dev/null and b/examples/shapes/shapes_hilbert_curve.png differ
diff --git a/examples/shapes/shapes_kaleidoscope.c b/examples/shapes/shapes_kaleidoscope.c
index 119fca598..31129a54c 100644
--- a/examples/shapes/shapes_kaleidoscope.c
+++ b/examples/shapes/shapes_kaleidoscope.c
@@ -50,9 +50,9 @@ int main(void)
int symmetry = 6;
float angle = 360.0f/(float)symmetry;
float thickness = 3.0f;
- Rectangle resetButtonRec = { screenWidth - 55, 5, 50, 25 };
- Rectangle backButtonRec = { screenWidth - 55, screenHeight - 30, 25, 25 };
- Rectangle nextButtonRec = { screenWidth - 30, screenHeight - 30, 25, 25 };
+ Rectangle resetButtonRec = { screenWidth - 55.0f, 5.0f, 50, 25 };
+ Rectangle backButtonRec = { screenWidth - 55.0f, screenHeight - 30.0f, 25, 25 };
+ Rectangle nextButtonRec = { screenWidth - 30.0f, screenHeight - 30.0f, 25, 25 };
Vector2 mousePos = { 0 };
Vector2 prevMousePos = { 0 };
Vector2 scaleVector = { 1.0f, -1.0f };
diff --git a/examples/shapes/shapes_penrose_tile.c b/examples/shapes/shapes_penrose_tile.c
index 304dca3cc..cf41852f8 100644
--- a/examples/shapes/shapes_penrose_tile.c
+++ b/examples/shapes/shapes_penrose_tile.c
@@ -185,12 +185,12 @@ static void BuildProductionStep(PenroseLSystem *ls)
char *newProduction = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE);
newProduction[0] = '\0';
- int productionLength = strnlen(ls->production, STR_MAX_SIZE);
+ int productionLength = (int)strnlen(ls->production, STR_MAX_SIZE);
for (int i = 0; i < productionLength; i++)
{
char step = ls->production[i];
- int remainingSpace = STR_MAX_SIZE - strnlen(newProduction, STR_MAX_SIZE) - 1;
+ int remainingSpace = STR_MAX_SIZE - (int)strnlen(newProduction, STR_MAX_SIZE) - 1;
switch (step)
{
case 'W': strncat(newProduction, ls->ruleW, remainingSpace); break;
@@ -201,7 +201,7 @@ static void BuildProductionStep(PenroseLSystem *ls)
{
if (step != 'F')
{
- int t = strnlen(newProduction, STR_MAX_SIZE);
+ int t = (int)strnlen(newProduction, STR_MAX_SIZE);
newProduction[t] = step;
newProduction[t + 1] = '\0';
}
@@ -218,7 +218,7 @@ static void BuildProductionStep(PenroseLSystem *ls)
// Draw penrose tile lines
static void DrawPenroseLSystem(PenroseLSystem *ls)
{
- Vector2 screenCenter = { GetScreenWidth()/2, GetScreenHeight()/2 };
+ Vector2 screenCenter = { GetScreenWidth()/2.0f, GetScreenHeight()/2.0f };
TurtleState turtle = {
.origin = { 0 },
@@ -245,7 +245,7 @@ static void DrawPenroseLSystem(PenroseLSystem *ls)
Vector2 startPosScreen = { startPosWorld.x + screenCenter.x, startPosWorld.y + screenCenter.y };
Vector2 endPosScreen = { turtle.origin.x + screenCenter.x, turtle.origin.y + screenCenter.y };
- DrawLineEx(startPosScreen, endPosScreen, 2, Fade(BLACK, 0.2));
+ DrawLineEx(startPosScreen, endPosScreen, 2, Fade(BLACK, 0.2f));
}
repeats = 1;
diff --git a/examples/text/text_inline_styling.c b/examples/text/text_inline_styling.c
index 8faef30eb..81f8156b6 100644
--- a/examples/text/text_inline_styling.c
+++ b/examples/text/text_inline_styling.c
@@ -178,14 +178,14 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float
// Convert hex color text into actual Color
unsigned int colHexValue = strtoul(colHexText, NULL, 16);
if (text[i - 1] == 'c')
- {
+ {
colFront = GetColor(colHexValue);
- colFront.a *= (float)color.a/255.0f;
+ colFront.a = (unsigned char)(colFront.a * (float)color.a/255.0f);
}
else if (text[i - 1] == 'b')
{
colBack = GetColor(colHexValue);
- colBack.a *= (float)color.a/255.0f;
+ colBack.a *= (unsigned char)(colFront.a * (float)color.a / 255.0f);
}
i += (colHexCount + 1); // Skip color value retrieved and ']'
diff --git a/examples/text/text_strings_management.c b/examples/text/text_strings_management.c
index 6c110e6ef..e4a7ab2af 100644
--- a/examples/text/text_strings_management.c
+++ b/examples/text/text_strings_management.c
@@ -133,7 +133,7 @@ int main(void)
{
for (int i = 0; i < particleCount; i++)
{
- if (!textParticles[i].grabbed) textParticles[i].vel = (Vector2){ GetRandomValue(-2000, 2000), GetRandomValue(-2000, 2000) };
+ if (!textParticles[i].grabbed) textParticles[i].vel = (Vector2){ (float)GetRandomValue(-2000, 2000), (float)GetRandomValue(-2000, 2000) };
}
}
@@ -233,9 +233,9 @@ int main(void)
for (int i = 0; i < particleCount; i++)
{
TextParticle *tp = &textParticles[i];
- DrawRectangle(tp->rect.x-tp->borderWidth, tp->rect.y-tp->borderWidth, tp->rect.width+tp->borderWidth*2, tp->rect.height+tp->borderWidth*2, BLACK);
+ DrawRectangleRec((Rectangle) { tp->rect.x - tp->borderWidth, tp->rect.y - tp->borderWidth, tp->rect.width + tp->borderWidth * 2, tp->rect.height + tp->borderWidth * 2 }, BLACK);
DrawRectangleRec(tp->rect, tp->color);
- DrawText(tp->text, tp->rect.x+tp->padding, tp->rect.y+tp->padding, FONT_SIZE, BLACK);
+ DrawText(tp->text, (int)(tp->rect.x+tp->padding), (int)(tp->rect.y+tp->padding), FONT_SIZE, BLACK);
}
DrawText("grab a text particle by pressing with the mouse and throw it by releasing", 10, 10, 10, DARKGRAY);
@@ -265,8 +265,8 @@ void PrepareFirstTextParticle(const char* text, TextParticle *tps, int *particle
{
tps[0] = CreateTextParticle(
text,
- GetScreenWidth()/2,
- GetScreenHeight()/2,
+ GetScreenWidth()/2.0f,
+ GetScreenHeight()/2.0f,
RAYWHITE
);
*particleCount = 1;
@@ -277,12 +277,12 @@ TextParticle CreateTextParticle(const char *text, float x, float y, Color color)
TextParticle tp = {
.text = "",
.rect = { x, y, 30, 30 },
- .vel = { GetRandomValue(-200, 200), GetRandomValue(-200, 200) },
+ .vel = { (float)GetRandomValue(-200, 200), (float)GetRandomValue(-200, 200) },
.ppos = { 0 },
.padding = 5.0f,
.borderWidth = 5.0f,
- .friction = 0.99,
- .elasticity = 0.9,
+ .friction = 0.99f,
+ .elasticity = 0.9f,
.color = color,
.grabbed = false
};
@@ -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)
{
diff --git a/examples/text/text_words_alignment.c b/examples/text/text_words_alignment.c
index a558d5b11..dbd9cd03e 100644
--- a/examples/text/text_words_alignment.c
+++ b/examples/text/text_words_alignment.c
@@ -19,8 +19,6 @@
#include "raymath.h" // Required for: Lerp()
-#include
-
typedef enum TextAlignment {
TEXT_ALIGN_LEFT = 0,
TEXT_ALIGN_TOP = 0,
diff --git a/examples/textures/textures_framebuffer_rendering.c b/examples/textures/textures_framebuffer_rendering.c
new file mode 100644
index 000000000..484192739
--- /dev/null
+++ b/examples/textures/textures_framebuffer_rendering.c
@@ -0,0 +1,208 @@
+/*******************************************************************************************
+*
+* raylib [textures] example - framebuffer rendering
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* Example contributed by Jack Boakes (@jackboakes) 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) 2026 Jack Boakes (@jackboakes)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h"
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static void DrawCameraPrism(Camera3D camera, float aspect, Color color);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+ const int splitWidth = screenWidth/2;
+
+ InitWindow(screenWidth, screenHeight, "raylib [textures] example - framebuffer rendering");
+
+ // Camera to look at the 3D world
+ Camera3D subjectCamera = { 0 };
+ subjectCamera.position = (Vector3){ 5.0f, 5.0f, 5.0f };
+ subjectCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
+ subjectCamera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+ subjectCamera.fovy = 45.0f;
+ subjectCamera.projection = CAMERA_PERSPECTIVE;
+
+ // Camera to observe the subject camera and 3D world
+ Camera3D observerCamera = { 0 };
+ observerCamera.position = (Vector3){ 10.0f, 10.0f, 10.0f };
+ observerCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
+ observerCamera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
+ observerCamera.fovy = 45.0f;
+ observerCamera.projection = CAMERA_PERSPECTIVE;
+
+ // Set up render textures
+ RenderTexture2D observerTarget = LoadRenderTexture(splitWidth, screenHeight);
+ Rectangle observerSource = { 0.0f, 0.0f, (float)observerTarget.texture.width, -(float)observerTarget.texture.height };
+ Rectangle observerDest = { 0.0f, 0.0f, (float)splitWidth, (float)screenHeight };
+
+ RenderTexture2D subjectTarget = LoadRenderTexture(splitWidth, screenHeight);
+ Rectangle subjectSource = { 0.0f, 0.0f, (float)subjectTarget.texture.width, -(float)subjectTarget.texture.height };
+ Rectangle subjectDest = { (float)splitWidth, 0.0f, (float)splitWidth, (float)screenHeight };
+ const float textureAspectRatio = (float)subjectTarget.texture.width/(float)subjectTarget.texture.height;
+
+ // Rectangles for cropping render texture
+ const float captureSize = 128.0f;
+ Rectangle cropSource = { (subjectTarget.texture.width - captureSize)/2.0f, (subjectTarget.texture.height - captureSize)/2.0f, captureSize, -captureSize };
+ Rectangle cropDest = { splitWidth + 20, 20, captureSize, captureSize};
+
+ SetTargetFPS(60);
+ DisableCursor();
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ UpdateCamera(&observerCamera, CAMERA_FREE);
+ UpdateCamera(&subjectCamera, CAMERA_ORBITAL);
+
+ if (IsKeyPressed(KEY_R)) observerCamera.target = (Vector3){ 0.0f, 0.0f, 0.0f };
+
+ // Build LHS observer view texture
+ BeginTextureMode(observerTarget);
+
+ ClearBackground(RAYWHITE);
+
+ BeginMode3D(observerCamera);
+
+ DrawGrid(10, 1.0f);
+ DrawCube((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, GOLD);
+ DrawCubeWires((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, PINK);
+ DrawCameraPrism(subjectCamera, textureAspectRatio, GREEN);
+
+ EndMode3D();
+
+ DrawText("Observer View", 10, observerTarget.texture.height - 30, 20, BLACK);
+ DrawText("WASD + Mouse to Move", 10, 10, 20, DARKGRAY);
+ DrawText("Scroll to Zoom", 10, 30, 20, DARKGRAY);
+ DrawText("R to Reset Observer Target", 10, 50, 20, DARKGRAY);
+
+ EndTextureMode();
+
+ // Build RHS subject view texture
+ BeginTextureMode(subjectTarget);
+
+ ClearBackground(RAYWHITE);
+
+ BeginMode3D(subjectCamera);
+
+ DrawCube((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, GOLD);
+ DrawCubeWires((Vector3){ 0.0f, 0.0f, 0.0f }, 2.0f, 2.0f, 2.0f, PINK);
+ DrawGrid(10, 1.0f);
+
+ EndMode3D();
+
+ DrawRectangleLines((subjectTarget.texture.width - captureSize)/2, (subjectTarget.texture.height - captureSize)/2, captureSize, captureSize, GREEN);
+ DrawText("Subject View", 10, subjectTarget.texture.height - 30, 20, BLACK);
+
+ EndTextureMode();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(BLACK);
+
+ // Draw observer texture LHS
+ DrawTexturePro(observerTarget.texture, observerSource, observerDest, (Vector2){0.0f, 0.0f }, 0.0f, WHITE);
+
+ // Draw subject texture RHS
+ DrawTexturePro(subjectTarget.texture, subjectSource, subjectDest, (Vector2){ 0.0f, 0.0f }, 0.0f, WHITE);
+
+ // Draw the small crop overlay on top
+ DrawTexturePro(subjectTarget.texture, cropSource, cropDest, (Vector2){ 0.0f, 0.0f }, 0.0f, WHITE);
+ DrawRectangleLinesEx(cropDest, 2, BLACK);
+
+ // Draw split screen divider line
+ DrawLine(splitWidth, 0, splitWidth, screenHeight, BLACK);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadRenderTexture(observerTarget);
+ UnloadRenderTexture(subjectTarget);
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+static void DrawCameraPrism(Camera3D camera, float aspect, Color color)
+{
+ float length = Vector3Distance(camera.position, camera.target);
+ // Define the 4 corners of the camera's prism plane sliced at the target in Normalized Device Coordinates
+ Vector3 planeNDC[4] = {
+ { -1.0f, -1.0f, 1.0f }, // Bottom Left
+ { 1.0f, -1.0f, 1.0f }, // Bottom Right
+ { 1.0f, 1.0f, 1.0f }, // Top Right
+ { -1.0f, 1.0f, 1.0f } // Top Left
+ };
+
+ // Build the matrices
+ Matrix view = GetCameraMatrix(camera);
+ Matrix proj = MatrixPerspective(camera.fovy * DEG2RAD, aspect, 0.05f, length);
+ // Combine view and projection so we can reverse the full camera transform
+ Matrix viewProj = MatrixMultiply(view, proj);
+ // Invert the view-projection matrix to unproject points from NDC space back into world space
+ Matrix inverseViewProj = MatrixInvert(viewProj);
+
+ // Transform the 4 plane corners from NDC into world space
+ Vector3 corners[4];
+ for (int i = 0; i < 4; i++)
+ {
+ float x = planeNDC[i].x;
+ float y = planeNDC[i].y;
+ float z = planeNDC[i].z;
+
+ // Multiply NDC position by the inverse view-projection matrix
+ // This produces a homogeneous (x, y, z, w) position in world space
+ float vx = inverseViewProj.m0*x + inverseViewProj.m4*y + inverseViewProj.m8*z + inverseViewProj.m12;
+ float vy = inverseViewProj.m1*x + inverseViewProj.m5*y + inverseViewProj.m9*z + inverseViewProj.m13;
+ float vz = inverseViewProj.m2*x + inverseViewProj.m6*y + inverseViewProj.m10*z + inverseViewProj.m14;
+ float vw = inverseViewProj.m3*x + inverseViewProj.m7*y + inverseViewProj.m11*z + inverseViewProj.m15;
+
+ corners[i] = (Vector3){ vx/vw, vy/vw, vz/vw };
+ }
+
+ // Draw the far plane sliced at the target
+ DrawLine3D(corners[0], corners[1], color);
+ DrawLine3D(corners[1], corners[2], color);
+ DrawLine3D(corners[2], corners[3], color);
+ DrawLine3D(corners[3], corners[0], color);
+
+ // Draw the prism lines from the far plane to the camera position
+ for (int i = 0; i < 4; i++)
+ {
+ DrawLine3D(camera.position, corners[i], color);
+ }
+}
\ No newline at end of file
diff --git a/examples/textures/textures_framebuffer_rendering.png b/examples/textures/textures_framebuffer_rendering.png
new file mode 100644
index 000000000..e6829f0bd
Binary files /dev/null and b/examples/textures/textures_framebuffer_rendering.png differ
diff --git a/examples/textures/textures_screen_buffer.c b/examples/textures/textures_screen_buffer.c
index e620aab31..503b8d249 100644
--- a/examples/textures/textures_screen_buffer.c
+++ b/examples/textures/textures_screen_buffer.c
@@ -66,7 +66,7 @@ int main(void)
// Grow flameRoot
for (int x = 2; x < flameWidth; x++)
{
- unsigned short flame = flameRootBuffer[x];
+ unsigned char flame = flameRootBuffer[x];
if (flame == 255) continue;
flame += GetRandomValue(0, 2);
if (flame > 255) flame = 255;
diff --git a/examples/textures/textures_textured_curve.c b/examples/textures/textures_textured_curve.c
index abf78c88a..f8d207d83 100644
--- a/examples/textures/textures_textured_curve.c
+++ b/examples/textures/textures_textured_curve.c
@@ -190,7 +190,7 @@ static void DrawTexturedCurve(void)
Vector2 normal = Vector2Normalize((Vector2){ -delta.y, delta.x });
// The v texture coordinate of the segment (add up the length of all the segments so far)
- float v = previousV + Vector2Length(delta);
+ float v = previousV + Vector2Length(delta) / (float)(texRoad.height * 2);
// Make sure the start point has a normal
if (!tangentSet)
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/examples/core_keyboard_testbed.vcxproj b/projects/VS2022/examples/core_keyboard_testbed.vcxproj
new file mode 100644
index 000000000..2278f4ec5
--- /dev/null
+++ b/projects/VS2022/examples/core_keyboard_testbed.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
+
+
+
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}
+ Win32Proj
+ core_keyboard_testbed
+ 10.0
+ core_keyboard_testbed
+
+
+
+ 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}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_hilbert_curve.vcxproj b/projects/VS2022/examples/shapes_hilbert_curve.vcxproj
new file mode 100644
index 000000000..6c60841fb
--- /dev/null
+++ b/projects/VS2022/examples/shapes_hilbert_curve.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
+
+
+
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}
+ Win32Proj
+ shapes_hilbert_curve
+ 10.0
+ shapes_hilbert_curve
+
+
+
+ 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
+ _CRT_SECURE_NO_WARNIGNS;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_WARNIGNS;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
+ _CRT_SECURE_NO_WARNIGNS;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_WARNIGNS;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
+ _CRT_SECURE_NO_WARNIGNS;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_WARNIGNS;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
+ _CRT_SECURE_NO_WARNIGNS;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_WARNIGNS;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/shapes_penrose_tile.vcxproj b/projects/VS2022/examples/shapes_penrose_tile.vcxproj
index bde99f8c1..389bdde36 100644
--- a/projects/VS2022/examples/shapes_penrose_tile.vcxproj
+++ b/projects/VS2022/examples/shapes_penrose_tile.vcxproj
@@ -292,7 +292,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
@@ -309,7 +309,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
/FS %(AdditionalOptions)
@@ -345,7 +345,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
@@ -366,7 +366,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
@@ -410,7 +410,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
CompileAsC
true
@@ -432,7 +432,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
CompileAsC
true
@@ -476,7 +476,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
CompileAsC
true
@@ -504,7 +504,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
CompileAsC
true
diff --git a/projects/VS2022/examples/shapes_rlgl_color_wheel.vcxproj b/projects/VS2022/examples/shapes_rlgl_color_wheel.vcxproj
index b22703577..a02a2d4e2 100644
--- a/projects/VS2022/examples/shapes_rlgl_color_wheel.vcxproj
+++ b/projects/VS2022/examples/shapes_rlgl_color_wheel.vcxproj
@@ -292,7 +292,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNIGNS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
@@ -309,7 +309,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNIGNS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
/FS %(AdditionalOptions)
@@ -345,7 +345,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNIGNS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
@@ -366,7 +366,7 @@
Level3
Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNIGNS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
@@ -410,7 +410,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ _CRT_SECURE_NO_WARNIGNS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
CompileAsC
true
@@ -432,7 +432,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ _CRT_SECURE_NO_WARNIGNS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
CompileAsC
true
@@ -476,7 +476,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ _CRT_SECURE_NO_WARNIGNS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
CompileAsC
true
@@ -504,7 +504,7 @@
MaxSpeed
true
true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ _CRT_SECURE_NO_WARNIGNS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
$(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
CompileAsC
true
diff --git a/projects/VS2022/examples/textures_framebuffer_rendering.vcxproj b/projects/VS2022/examples/textures_framebuffer_rendering.vcxproj
new file mode 100644
index 000000000..3e845545e
--- /dev/null
+++ b/projects/VS2022/examples/textures_framebuffer_rendering.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
+
+
+
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}
+ Win32Proj
+ textures_framebuffer_rendering
+ 10.0
+ textures_framebuffer_rendering
+
+
+
+ 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
diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln
index f0ff823da..47e83ef4c 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
@@ -431,6 +431,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "text_strings_management", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_cellular_automata", "examples\textures_cellular_automata.vcxproj", "{0A0FC982-6E31-401F-BA77-3C5E8AB02C68}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_hilbert_curve", "examples\shapes_hilbert_curve.vcxproj", "{DC163251-16C3-4B72-B965-ACDBA0F02BD1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_keyboard_testbed", "examples\core_keyboard_testbed.vcxproj", "{D35D2FDA-B53F-4F70-81CA-24D95812B89C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_framebuffer_rendering", "examples\textures_framebuffer_rendering.vcxproj", "{F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug.DLL|ARM64 = Debug.DLL|ARM64
@@ -5365,6 +5371,78 @@ Global
{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
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug|ARM64.Build.0 = Debug|ARM64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug|x64.ActiveCfg = Debug|x64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug|x64.Build.0 = Debug|x64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug|x86.ActiveCfg = Debug|Win32
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Debug|x86.Build.0 = Debug|Win32
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release|ARM64.ActiveCfg = Release|ARM64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release|ARM64.Build.0 = Release|ARM64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release|x64.ActiveCfg = Release|x64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release|x64.Build.0 = Release|x64
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release|x86.ActiveCfg = Release|Win32
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1}.Release|x86.Build.0 = Release|Win32
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug|ARM64.Build.0 = Debug|ARM64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug|x64.ActiveCfg = Debug|x64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug|x64.Build.0 = Debug|x64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug|x86.ActiveCfg = Debug|Win32
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Debug|x86.Build.0 = Debug|Win32
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release|ARM64.ActiveCfg = Release|ARM64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release|ARM64.Build.0 = Release|ARM64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release|x64.ActiveCfg = Release|x64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release|x64.Build.0 = Release|x64
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release|x86.ActiveCfg = Release|Win32
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C}.Release|x86.Build.0 = Release|Win32
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug|x64.ActiveCfg = Debug|x64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug|x64.Build.0 = Debug|x64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug|x86.ActiveCfg = Debug|Win32
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Debug|x86.Build.0 = Debug|Win32
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release|ARM64.Build.0 = Release|ARM64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release|x64.ActiveCfg = Release|x64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release|x64.Build.0 = Release|x64
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release|x86.ActiveCfg = Release|Win32
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -5532,7 +5610,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} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
+ {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{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}
@@ -5541,9 +5619,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} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
{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 +5637,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}
@@ -5582,6 +5660,9 @@ Global
{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}
+ {DC163251-16C3-4B72-B965-ACDBA0F02BD1} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {D35D2FDA-B53F-4F70-81CA-24D95812B89C} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {F8DC77C0-556C-4672-B5B3-D2FA4ADC505C} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}
diff --git a/projects/VS2022/raylib/raylib.vcxproj b/projects/VS2022/raylib/raylib.vcxproj
index 3a7082d77..8cc3fae7a 100644
--- a/projects/VS2022/raylib/raylib.vcxproj
+++ b/projects/VS2022/raylib/raylib.vcxproj
@@ -582,7 +582,6 @@
-
@@ -602,7 +601,6 @@
-
diff --git a/projects/VS2022/raylib/raylib.vcxproj.filters b/projects/VS2022/raylib/raylib.vcxproj.filters
index 33030fc9c..75cc28a7e 100644
--- a/projects/VS2022/raylib/raylib.vcxproj.filters
+++ b/projects/VS2022/raylib/raylib.vcxproj.filters
@@ -22,9 +22,6 @@
Source Files
-
- Source Files
-
Source Files\Platform Files
diff --git a/projects/VSCode/main.c b/projects/VSCode/main.c
index ea394de58..7a5d89000 100644
--- a/projects/VSCode/main.c
+++ b/projects/VSCode/main.c
@@ -15,7 +15,7 @@
* This example has been created using raylib 1.0 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 087141447..76c985969 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -36,7 +36,6 @@ set(raylib_sources
rshapes.c
rtext.c
rtextures.c
- utils.c
)
# /cmake/GlfwImport.cmake handles the details around the inclusion of glfw
diff --git a/src/Makefile b/src/Makefile
index bc84abece..459b79f83 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -33,7 +33,7 @@
# Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline.
# Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline.
#
-# Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+# Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
#
# This software is provided "as-is", without any express or implied warranty. In no event
# will the authors be held liable for any damages arising from the use of this software.
@@ -658,8 +658,7 @@ endif
OBJS = rcore.o \
rshapes.o \
rtextures.o \
- rtext.o \
- utils.o
+ rtext.o
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
ifeq ($(USE_EXTERNAL_GLFW),FALSE)
@@ -758,7 +757,7 @@ endif
rcore.o : platforms/*.c
# Compile core module
-rcore.o : rcore.c raylib.h rlgl.h utils.h raymath.h rcamera.h rgestures.h
+rcore.o : rcore.c raylib.h rlgl.h raymath.h rcamera.h rgestures.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
# Compile rglfw module
@@ -770,15 +769,11 @@ rshapes.o : rshapes.c raylib.h rlgl.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
# Compile textures module
-rtextures.o : rtextures.c raylib.h rlgl.h utils.h
+rtextures.o : rtextures.c raylib.h rlgl.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
# Compile text module
-rtext.o : rtext.c raylib.h utils.h
- $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
-
-# Compile utils module
-utils.o : utils.c utils.h
+rtext.o : rtext.c raylib.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
# Compile models module
diff --git a/src/config.h b/src/config.h
index b749f8952..5e7c6f1d2 100644
--- a/src/config.h
+++ b/src/config.h
@@ -6,7 +6,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2018-2025 Ahmad Fatoum & Ramon Santamaria (@raysan5)
+* Copyright (c) 2018-2026 Ahmad Fatoum and Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -30,17 +30,24 @@
//------------------------------------------------------------------------------------
// Module selection - Some modules could be avoided
-// Mandatory modules: rcore, rlgl, utils
+// Mandatory modules: rcore, rlgl
//------------------------------------------------------------------------------------
-#define SUPPORT_MODULE_RSHAPES 1
-#define SUPPORT_MODULE_RTEXTURES 1
-#define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures
-#define SUPPORT_MODULE_RMODELS 1
-#define SUPPORT_MODULE_RAUDIO 1
+#if !defined(EXTERNAL_CONFIG_FLAGS)
+ #define SUPPORT_MODULE_RSHAPES 1
+ #define SUPPORT_MODULE_RTEXTURES 1
+ #define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures
+ #define SUPPORT_MODULE_RMODELS 1
+ #define SUPPORT_MODULE_RAUDIO 1
+#endif
//------------------------------------------------------------------------------------
// Module: rcore - Configuration Flags
//------------------------------------------------------------------------------------
+#if !defined(EXTERNAL_CONFIG_FLAGS)
+// Standard file io library (stdio.h) included
+#define SUPPORT_STANDARD_FILEIO 1
+// Show TRACELOG() output messages
+#define SUPPORT_TRACELOG 1
// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
#define SUPPORT_CAMERA_SYSTEM 1
// Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
@@ -69,10 +76,10 @@
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// Enabling this flag allows manual control of the frame processes, use at your own risk
//#define SUPPORT_CUSTOM_FRAME_CONTROL 1
-
// Support for clipboard image loading
// NOTE: Only working on SDL3, GLFW (Windows) and RGFW (Windows)
-#define SUPPORT_CLIPBOARD_IMAGE 1
+#define SUPPORT_CLIPBOARD_IMAGE 1
+#endif
// NOTE: Clipboard image loading requires support for some image file formats
// TODO: Those defines should probably be removed from here, letting the user manage them
@@ -94,8 +101,15 @@
#endif
#endif
+#if defined(SUPPORT_TRACELOG)
+ #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__)
+#else
+ #define TRACELOG(level, ...) (void)0
+#endif
+
// rcore: Configuration values
//------------------------------------------------------------------------------------
+#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
@@ -105,7 +119,7 @@
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
#define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds
-#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
+#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
@@ -116,7 +130,7 @@
//------------------------------------------------------------------------------------
// Module: rlgl - Configuration values
//------------------------------------------------------------------------------------
-
+#if !defined(EXTERNAL_CONFIG_FLAGS)
// Enable OpenGL Debug Context (only available on OpenGL 4.3)
//#define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT 1
@@ -124,6 +138,7 @@
//#define RLGL_SHOW_GL_DETAILS_INFO 1
#define RL_SUPPORT_MESH_GPU_SKINNING 1 // GPU skinning, comment if your GPU does not support more than 8 VBOs
+#endif
//#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 4096 // Default internal render batch elements limits
#define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
@@ -173,9 +188,11 @@
//------------------------------------------------------------------------------------
// Module: rshapes - Configuration Flags
//------------------------------------------------------------------------------------
+#if !defined(EXTERNAL_CONFIG_FLAGS)
// Use QUADS instead of TRIANGLES for drawing when possible
// Some lines-based shapes could still use lines
#define SUPPORT_QUADS_DRAW_MODE 1
+#endif
// rshapes: Configuration values
//------------------------------------------------------------------------------------
@@ -184,6 +201,7 @@
//------------------------------------------------------------------------------------
// Module: rtextures - Configuration Flags
//------------------------------------------------------------------------------------
+#if !defined(EXTERNAL_CONFIG_FLAGS)
// Selected desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1
@@ -207,10 +225,12 @@
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
#define SUPPORT_IMAGE_MANIPULATION 1
+#endif
//------------------------------------------------------------------------------------
// Module: rtext - Configuration Flags
//------------------------------------------------------------------------------------
+#if !defined(EXTERNAL_CONFIG_FLAGS)
// Default font is loaded on window initialization to be available for the user to render simple text
// NOTE: If enabled, uses external module functions to load default raylib font
#define SUPPORT_DEFAULT_FONT 1
@@ -230,6 +250,7 @@
// Support conservative font atlas size estimation
//#define SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE 1
+#endif
// rtext: Configuration values
//------------------------------------------------------------------------------------
@@ -240,6 +261,7 @@
//------------------------------------------------------------------------------------
// Module: rmodels - Configuration Flags
//------------------------------------------------------------------------------------
+#if !defined(EXTERNAL_CONFIG_FLAGS)
// Selected desired model fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_OBJ 1
#define SUPPORT_FILEFORMAT_MTL 1
@@ -250,6 +272,7 @@
// Support procedural mesh generation functions, uses external par_shapes.h library
// NOTE: Some generated meshes DO NOT include generated texture coordinates
#define SUPPORT_MESH_GENERATION 1
+#endif
// rmodels: Configuration values
//------------------------------------------------------------------------------------
@@ -264,6 +287,7 @@
//------------------------------------------------------------------------------------
// Module: raudio - Configuration Flags
//------------------------------------------------------------------------------------
+#if !defined(EXTERNAL_CONFIG_FLAGS)
// Desired audio fileformats to be supported for loading
#define SUPPORT_FILEFORMAT_WAV 1
#define SUPPORT_FILEFORMAT_OGG 1
@@ -272,6 +296,7 @@
//#define SUPPORT_FILEFORMAT_FLAC 1
#define SUPPORT_FILEFORMAT_XM 1
#define SUPPORT_FILEFORMAT_MOD 1
+#endif
// raudio: Configuration values
//------------------------------------------------------------------------------------
@@ -281,18 +306,4 @@
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Maximum number of audio pool channels
-//------------------------------------------------------------------------------------
-// Module: utils - Configuration Flags
-//------------------------------------------------------------------------------------
-// Standard file io library (stdio.h) included
-#define SUPPORT_STANDARD_FILEIO 1
-// Show TRACELOG() output messages
-// NOTE: By default LOG_DEBUG traces not shown
-#define SUPPORT_TRACELOG 1
-//#define SUPPORT_TRACELOG_DEBUG 1
-
-// utils: Configuration values
-//------------------------------------------------------------------------------------
-#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
-
#endif // CONFIG_H
diff --git a/src/external/RGFW.h b/src/external/RGFW.h
index b913d4f2d..c01ce1177 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,1024 @@ 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 */
+ i32 wOffset; /*!< width offset for window */
+ i32 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 +1338,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 +1409,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 +1442,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 +1468,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 +1483,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 +1530,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 +1590,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 +1644,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 +1855,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 +1935,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 +2112,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 +2269,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 +2293,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 +2419,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 +2487,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 +2508,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 +2559,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 +3017,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 +3047,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 +3055,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 +3076,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 +3110,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 +4497,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 +4517,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 +4547,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 +4568,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 +5130,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 +5192,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 +5288,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 +5301,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 +5528,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 +5593,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 +5614,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 +5624,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 +5655,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 +5716,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 +5729,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 +5751,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 +5773,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 +5813,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 +5863,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 +5874,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 +5893,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 +5920,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 +5984,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 +6137,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 +6354,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 +6366,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 +6389,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 +6426,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 +6458,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 +6487,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 width = (windowRect.right - windowRect.left) - win->src.wOffset;
+ int height = (windowRect.bottom - windowRect.top) - win->src.hOffset;
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 +6538,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((u32)(windowRect.right - windowRect.left) - (u32)win->src.wOffset,
+ (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) - (i32)win->src.wOffset;
+ 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 + win->src.wOffset);
+ 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 + win->src.wOffset);
+ 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 +6590,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 +6601,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 +6632,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 +6693,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 +6709,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 +6726,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 +6734,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 +6903,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 +6951,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 +6960,44 @@ 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.wOffset = (u32)(windowRect.right - windowRect.left) - (u32)(clientRect.right - clientRect.left);
+ win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w + (i32)win->src.wOffset, 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 +7006,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 +7016,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 +7058,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 +7066,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 + (i32)win->src.wOffset, 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 +7114,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 +7274,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 +7548,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 +7560,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 +7570,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 +7640,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 +7657,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 +7665,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 +7685,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 +7707,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 +7715,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 +7729,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 +7741,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 +7760,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 +7790,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 +7830,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 +7852,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 + (i32)win->src.wOffset, win->r.h + (i32)win->src.hOffset, SWP_NOMOVE);
}
@@ -10268,13 +7938,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 +7956,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 +7999,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 +8027,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 +8037,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 +8153,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 +8162,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 +8291,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 +8320,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 +8330,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 +8363,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 +8495,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 +8517,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 +8527,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 +8584,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 +8595,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 +8818,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 +8902,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 +9194,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 +9281,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 +9297,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 +9312,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 +9568,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 +9594,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 +9647,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 +9774,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 +9794,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 +9820,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 +9841,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 +9858,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 +9867,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 +9879,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 +9888,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 +9913,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 +9931,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 +9990,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 +10103,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 +10138,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 +10236,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 +10272,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 +10380,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 +10394,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 +10423,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 +11026,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 +11072,3 @@ void RGFW_load_Wayland(void) {
#if _MSC_VER
#pragma warning( pop )
#endif
-
diff --git a/src/external/rl_gputex.h b/src/external/rl_gputex.h
index 29500f3cf..033045bc8 100644
--- a/src/external/rl_gputex.h
+++ b/src/external/rl_gputex.h
@@ -62,7 +62,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -308,7 +308,7 @@ 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;
@@ -339,7 +339,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
}
}
}
- else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed
+ else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed
{
int data_size = image_pixel_size*3*sizeof(unsigned char);
if (header->mipmap_count > 1) data_size = data_size + data_size/3;
@@ -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];
diff --git a/src/minshell.html b/src/minshell.html
index ec7158841..6e2f137eb 100644
--- a/src/minshell.html
+++ b/src/minshell.html
@@ -54,6 +54,12 @@
// 'Ask where to save each file before downloading' - which you can set true/false.
// If you enable this setting it would always ask you and bring the SaveAsDialog
saveAs(blob, localFSname);
+
+ // Alternative implementation to avoid FileSaver.js
+ //const link = document.createElement("a");
+ //link.href = URL.createObjectURL(blob);
+ //link.download = localFSname;
+ //link.click();
}
diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c
index bc8a25f8f..6122f9a74 100644
--- a/src/platforms/rcore_android.c
+++ b/src/platforms/rcore_android.c
@@ -13,9 +13,6 @@
* - Improvement 01
* - Improvement 02
*
-* ADDITIONAL NOTES:
-* - TRACELOG() function is located in raylib [utils] module
-*
* CONFIGURATION:
* #define RCORE_PLATFORM_CUSTOM_FLAG
* Custom flag for rcore on target platform -not used-
@@ -27,7 +24,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -48,7 +45,11 @@
#include // Required for: android_app struct and activity management
#include // Required for: AWINDOW_FLAG_FULLSCREEN definition and others
+#include // Required for: Android log system: __android_log_vprint()
+#include // Required for: AAssetManager
//#include // Required for: Android sensors functions (accelerometer, gyroscope, light...)
+
+#include // Required for: error types
#include // Required for: JNIEnv and JavaVM [Used in OpenURL() and GetCurrentMonitor()]
#include // Native platform windowing system interface
@@ -267,6 +268,19 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd);
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs
static GamepadButton AndroidTranslateGamepadButton(int button); // Map Android gamepad button to raylib gamepad button
+static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
+
+static int android_read(void *cookie, char *buf, int size);
+static int android_write(void *cookie, const char *buf, int size);
+static fpos_t android_seek(void *cookie, fpos_t offset, int whence);
+static int android_close(void *cookie);
+
+FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
+FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int),
+ fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *));
+
+#define fopen(name, mode) android_fopen(name, mode)
+
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
@@ -357,13 +371,17 @@ 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);
}
// 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);
}
// Set icon for window
@@ -601,7 +619,7 @@ void DisableCursor(void)
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
- eglSwapBuffers(platform.device, platform.surface);
+ if (platform.surface != EGL_NO_SURFACE) eglSwapBuffers(platform.device, platform.surface);
}
//----------------------------------------------------------------------------------
@@ -740,8 +758,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);
@@ -813,8 +831,6 @@ int InitPlatform(void)
// Initialize storage system
//----------------------------------------------------------------------------
- InitAssetManager(platform.app->activity->assetManager, platform.app->activity->internalDataPath); // Initialize assets manager
-
CORE.Storage.basePath = platform.app->activity->internalDataPath; // Define base path for storage
//----------------------------------------------------------------------------
@@ -881,7 +897,6 @@ void ClosePlatform(void)
// NOTE: returns false in case graphic device could not be created
static int InitGraphicsDevice(void)
{
- CORE.Window.fullscreen = true;
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
EGLint samples = 0;
@@ -915,6 +930,7 @@ static int InitGraphicsDevice(void)
// 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");
@@ -1234,8 +1250,11 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
//int32_t AKeyEvent_getMetaState(event);
// Handle gamepad button presses and releases
- if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
- FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
+ // NOTE: Skip gamepad handling if this is a keyboard event, as some devices
+ // report both AINPUT_SOURCE_KEYBOARD and AINPUT_SOURCE_GAMEPAD flags
+ if ((FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
+ FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD)) &&
+ !FLAG_IS_SET(source, AINPUT_SOURCE_KEYBOARD))
{
// For now we'll assume a single gamepad which we "detect" on its input event
CORE.Input.Gamepad.ready[0] = true;
@@ -1328,30 +1347,17 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
}
}
- if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT))
- {
- // One of the touchpoints is released, remove it from touch point arrays
- if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
- {
- // If the touchPoint is hover, remove it from hoverPoints
- for (int i = 0; i < MAX_TOUCH_POINTS; i++)
- {
- if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
- {
- touchRaw.hoverPoints[i] = -1;
- break;
- }
- }
- }
- for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
- {
- touchRaw.pointId[i] = touchRaw.pointId[i+1];
- touchRaw.position[i] = touchRaw.position[i+1];
- }
- touchRaw.pointCount--;
- }
+#if defined(SUPPORT_GESTURES_SYSTEM)
+ GestureEvent gestureEvent = { 0 };
+
+ gestureEvent.pointCount = 0;
+
+ // Register touch actions
+ if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
+ else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_ACTION_UP;
+ else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE;
+ else if (flags == AMOTION_EVENT_ACTION_CANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL;
- int pointCount = 0;
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
{
// If the touchPoint is hover, Ignore it
@@ -1367,35 +1373,62 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
}
if (hover) continue;
- CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i];
- CORE.Input.Touch.position[pointCount] = touchRaw.position[i];
- pointCount++;
- }
- CORE.Input.Touch.pointCount = pointCount;
-
-#if defined(SUPPORT_GESTURES_SYSTEM)
- GestureEvent gestureEvent = { 0 };
-
- gestureEvent.pointCount = CORE.Input.Touch.pointCount;
-
- // Register touch actions
- if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
- else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_ACTION_UP;
- else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE;
- else if (flags == AMOTION_EVENT_ACTION_CANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL;
-
- for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++)
- {
- gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
- gestureEvent.position[i] = CORE.Input.Touch.position[i];
- gestureEvent.position[i].x /= (float)GetScreenWidth();
- gestureEvent.position[i].y /= (float)GetScreenHeight();
+ gestureEvent.pointId[gestureEvent.pointCount] = touchRaw.pointId[i];
+ gestureEvent.position[gestureEvent.pointCount] = touchRaw.position[i];
+ gestureEvent.position[gestureEvent.pointCount].x /= (float)GetScreenWidth();
+ gestureEvent.position[gestureEvent.pointCount].y /= (float)GetScreenHeight();
+ gestureEvent.pointCount++;
}
// Gesture data is sent to gestures system for processing
ProcessGestureEvent(gestureEvent);
#endif
+ if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
+ {
+ // Hover exited. So, remove it from hoverPoints
+ for (int i = 0; i < MAX_TOUCH_POINTS; i++)
+ {
+ if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
+ {
+ touchRaw.hoverPoints[i] = -1;
+ break;
+ }
+ }
+ }
+
+ if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP))
+ {
+ // One of the touchpoints is released, remove it from touch point arrays
+ for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
+ {
+ touchRaw.pointId[i] = touchRaw.pointId[i+1];
+ touchRaw.position[i] = touchRaw.position[i+1];
+ }
+ touchRaw.pointCount--;
+ }
+
+ CORE.Input.Touch.pointCount = 0;
+ for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
+ {
+ // If the touchPoint is hover, Ignore it
+ bool hover = false;
+ for (int j = 0; j < MAX_TOUCH_POINTS; j++)
+ {
+ // Check if the touchPoint is in hoverPointers
+ if (touchRaw.hoverPoints[j] == touchRaw.pointId[i])
+ {
+ hover = true;
+ break;
+ }
+ }
+ if (hover) continue;
+
+ CORE.Input.Touch.pointId[CORE.Input.Touch.pointCount] = touchRaw.pointId[i];
+ CORE.Input.Touch.position[CORE.Input.Touch.pointCount] = touchRaw.position[i];
+ CORE.Input.Touch.pointCount++;
+ }
+
// When all touchpoints are tapped and released really quickly, this event is generated
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
@@ -1413,4 +1446,144 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
return 0;
}
+// Compute framebuffer size relative to screen size and display size
+// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
+static void SetupFramebuffer(int width, int height)
+{
+ // Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
+ if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
+ {
+ TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
+
+ // Downscaling to fit display with border-bars
+ float widthRatio = (float)CORE.Window.display.width/(float)CORE.Window.screen.width;
+ float heightRatio = (float)CORE.Window.display.height/(float)CORE.Window.screen.height;
+
+ if (widthRatio <= heightRatio)
+ {
+ CORE.Window.render.width = CORE.Window.display.width;
+ CORE.Window.render.height = (int)round((float)CORE.Window.screen.height*widthRatio);
+ CORE.Window.renderOffset.x = 0;
+ CORE.Window.renderOffset.y = (CORE.Window.display.height - CORE.Window.render.height);
+ }
+ else
+ {
+ CORE.Window.render.width = (int)round((float)CORE.Window.screen.width*heightRatio);
+ CORE.Window.render.height = CORE.Window.display.height;
+ CORE.Window.renderOffset.x = (CORE.Window.display.width - CORE.Window.render.width);
+ CORE.Window.renderOffset.y = 0;
+ }
+
+ // Screen scaling required
+ float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
+ CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
+
+ // NOTE: We render to full display resolution!
+ // We just need to calculate above parameters for downscale matrix and offsets
+ CORE.Window.render.width = CORE.Window.display.width;
+ CORE.Window.render.height = CORE.Window.display.height;
+
+ TRACELOG(LOG_WARNING, "DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i)", CORE.Window.render.width, CORE.Window.render.height);
+ }
+ else if ((CORE.Window.screen.width < CORE.Window.display.width) || (CORE.Window.screen.height < CORE.Window.display.height))
+ {
+ // Required screen size is smaller than display size
+ TRACELOG(LOG_INFO, "DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
+
+ if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
+ {
+ CORE.Window.screen.width = CORE.Window.display.width;
+ CORE.Window.screen.height = CORE.Window.display.height;
+ }
+
+ // Upscaling to fit display with border-bars
+ float displayRatio = (float)CORE.Window.display.width/(float)CORE.Window.display.height;
+ float screenRatio = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height;
+
+ if (displayRatio <= screenRatio)
+ {
+ CORE.Window.render.width = CORE.Window.screen.width;
+ CORE.Window.render.height = (int)round((float)CORE.Window.screen.width/displayRatio);
+ CORE.Window.renderOffset.x = 0;
+ CORE.Window.renderOffset.y = (CORE.Window.render.height - CORE.Window.screen.height);
+ }
+ else
+ {
+ CORE.Window.render.width = (int)round((float)CORE.Window.screen.height*displayRatio);
+ CORE.Window.render.height = CORE.Window.screen.height;
+ CORE.Window.renderOffset.x = (CORE.Window.render.width - CORE.Window.screen.width);
+ CORE.Window.renderOffset.y = 0;
+ }
+ }
+ else
+ {
+ CORE.Window.render.width = CORE.Window.screen.width;
+ CORE.Window.render.height = CORE.Window.screen.height;
+ CORE.Window.renderOffset.x = 0;
+ CORE.Window.renderOffset.y = 0;
+ }
+}
+
+// Replacement for fopen()
+// REF: https://developer.android.com/ndk/reference/group/asset
+FILE *android_fopen(const char *fileName, const char *mode)
+{
+ FILE *file = NULL;
+
+ if (mode[0] == 'w')
+ {
+ // 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
+ #undef fopen
+ file = fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
+ #define fopen(name, mode) android_fopen(name, mode)
+ }
+ else
+ {
+ // NOTE: AAsset provides access to read-only asset
+ AAsset *asset = AAssetManager_open(platform.app->activity->assetManager, fileName, AASSET_MODE_UNKNOWN);
+
+ if (asset != NULL)
+ {
+ // Get pointer to file in the assets
+ file = funopen(asset, android_read, android_write, android_seek, android_close);
+ }
+ else
+ {
+ #undef fopen
+ // Just do a regular open if file is not found in the assets
+ file = fopen(TextFormat("%s/%s", platform.app->activity->internalDataPath, fileName), mode);
+ if (file == NULL) file = fopen(fileName, mode);
+ #define fopen(name, mode) android_fopen(name, mode)
+ }
+ }
+
+ return file;
+}
+
+static int android_read(void *cookie, char *data, int dataSize)
+{
+ return AAsset_read((AAsset *)cookie, data, dataSize);
+}
+
+static int android_write(void *cookie, const char *data, int dataSize)
+{
+ TRACELOG(LOG_WARNING, "ANDROID: Failed to provide write access to APK");
+
+ return EACCES;
+}
+
+static fpos_t android_seek(void *cookie, fpos_t offset, int whence)
+{
+ return AAsset_seek((AAsset *)cookie, offset, whence);
+}
+
+static int android_close(void *cookie)
+{
+ AAsset_close((AAsset *)cookie);
+ return 0;
+}
+
// EOF
diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c
index d6ed11c2f..f39e256aa 100644
--- a/src/platforms/rcore_desktop_glfw.c
+++ b/src/platforms/rcore_desktop_glfw.c
@@ -16,9 +16,6 @@
* - Improvement 01
* - Improvement 02
*
-* ADDITIONAL NOTES:
-* - TRACELOG() function is located in raylib [utils] module
-*
* CONFIGURATION:
* #define RCORE_PLATFORM_CUSTOM_FLAG
* Custom flag for rcore on target platform -not used-
@@ -30,7 +27,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -134,12 +131,13 @@ 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 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 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
@@ -155,8 +153,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
//----------------------------------------------------------------------------------
@@ -177,46 +173,72 @@ bool WindowShouldClose(void)
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
- if (!CORE.Window.fullscreen)
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
- // Store previous window position (in case we exit fullscreen)
+ // Store previous screen data (in case exiting fullscreen)
CORE.Window.previousPosition = CORE.Window.position;
+ CORE.Window.previousScreen = CORE.Window.screen;
+ // Use current monitor the window is on to get fullscreen required size
int monitorCount = 0;
int monitorIndex = GetCurrentMonitor();
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
-
- // Use current monitor, so we correctly get the display the window is on
GLFWmonitor *monitor = (monitorIndex < monitorCount)? monitors[monitorIndex] : NULL;
- if (monitor == NULL)
+ if (monitor != NULL)
{
- TRACELOG(LOG_WARNING, "GLFW: Failed to get monitor");
+ // Get current monitor video mode
+ const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitorIndex]);
+ CORE.Window.display.width = mode->width;
+ CORE.Window.display.height = mode->height;
- CORE.Window.fullscreen = false;
- FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ CORE.Window.position = (Point){ 0, 0 };
+ CORE.Window.screen = CORE.Window.display;
- glfwSetWindowMonitor(platform.handle, NULL, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
- }
- else
- {
- CORE.Window.fullscreen = true;
+ // Set fullscreen flag to be processed on FramebufferSizeCallback() accordingly
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
+ // NOTE: X11 requires undecorating the window before switching to
+ // fullscreen to avoid issues with framebuffer scaling
+ glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE);
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
+#endif
+ // WARNING: This function launches FramebufferSizeCallback()
glfwSetWindowMonitor(platform.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
}
-
+ else TRACELOG(LOG_WARNING, "GLFW: Failed to get monitor");
}
else
{
- CORE.Window.fullscreen = false;
+ // Restore previous window position and size
+ CORE.Window.position = CORE.Window.previousPosition;
+ CORE.Window.screen = CORE.Window.previousScreen;
+
+ // Set fullscreen flag to be processed on FramebufferSizeCallback() accordingly
+ // and considered by GetWindowScaleDPI()
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
- glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
+#if !defined(__APPLE__)
+ // Make sure to restore render size considering HighDPI scaling
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+ {
+ Vector2 scaleDpi = GetWindowScaleDPI();
+ CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width * scaleDpi.x);
+ CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height * scaleDpi.y);
+ }
+#endif
- // we update the window position right away
- CORE.Window.position.x = CORE.Window.previousPosition.x;
- CORE.Window.position.y = CORE.Window.previousPosition.y;
+ // WARNING: This function launches FramebufferSizeCallback()
+ glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y,
+ CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
+
+#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
+ // NOTE: X11 requires restoring the decorated window after switching from
+ // fullscreen to avoid issues with framebuffer scaling
+ glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
+#endif
}
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
@@ -228,29 +250,24 @@ void ToggleFullscreen(void)
void ToggleBorderlessWindowed(void)
{
// Leave fullscreen before attempting to set borderless windowed mode
- bool wasOnFullscreen = false;
- if (CORE.Window.fullscreen)
- {
- // fullscreen already saves the previous position so it does not need to be set here again
- ToggleFullscreen();
- wasOnFullscreen = true;
- }
+ // NOTE: Fullscreen already saves the previous position so it does not need to be set again later
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) ToggleFullscreen();
- 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
- if (!wasOnFullscreen) CORE.Window.previousPosition = CORE.Window.position;
+ CORE.Window.previousPosition = CORE.Window.position;
CORE.Window.previousScreen = CORE.Window.screen;
// Set undecorated flag
@@ -258,22 +275,13 @@ void ToggleBorderlessWindowed(void)
FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
// Get monitor position and size
- int monitorPosX = 0;
- int monitorPosY = 0;
- glfwGetMonitorPos(monitors[monitor], &monitorPosX, &monitorPosY);
- const int monitorWidth = mode->width;
- const int monitorHeight = mode->height;
+ glfwGetMonitorPos(monitors[monitor], &CORE.Window.position.x, &CORE.Window.position.y);
+ CORE.Window.screen.width = mode->width;
+ CORE.Window.screen.height = mode->height;
// Set screen position and size
- glfwSetWindowMonitor(
- platform.handle,
- monitors[monitor],
- monitorPosX,
- monitorPosY,
- monitorWidth,
- monitorHeight,
- mode->refreshRate
- );
+ glfwSetWindowMonitor(platform.handle, monitors[monitor], CORE.Window.position.x, CORE.Window.position.y,
+ CORE.Window.screen.width, CORE.Window.screen.height, mode->refreshRate);
// Refocus window
glfwFocusWindow(platform.handle);
@@ -282,29 +290,32 @@ void ToggleBorderlessWindowed(void)
}
else
{
+ // Restore previous screen values
+ CORE.Window.position = CORE.Window.previousPosition;
+ CORE.Window.screen = CORE.Window.previousScreen;
+
// Remove undecorated flag
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
- // 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(
- platform.handle,
- NULL,
- CORE.Window.previousPosition.x,
- CORE.Window.previousPosition.y,
- CORE.Window.previousScreen.width,
- CORE.Window.previousScreen.height,
- mode->refreshRate
- );
+ #if !defined(__APPLE__)
+ // Make sure to restore size considering HighDPI scaling
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+ {
+ Vector2 scaleDpi = GetWindowScaleDPI();
+ CORE.Window.screen.width = (unsigned int)(CORE.Window.screen.width * scaleDpi.x);
+ CORE.Window.screen.height = (unsigned int)(CORE.Window.screen.height * scaleDpi.y);
+ }
+ #endif
+
+ // Return to previous screen size and position
+ glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y,
+ CORE.Window.screen.width, CORE.Window.screen.height, mode->refreshRate);
// Refocus window
glfwFocusWindow(platform.handle);
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
-
- CORE.Window.position.x = CORE.Window.previousPosition.x;
- CORE.Window.position.y = CORE.Window.previousPosition.y;
}
}
else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
@@ -475,13 +486,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
@@ -658,7 +669,7 @@ void SetWindowMonitor(int monitor)
if ((monitor >= 0) && (monitor < monitorCount))
{
- if (CORE.Window.fullscreen)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
TRACELOG(LOG_INFO, "GLFW: Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
@@ -894,7 +905,7 @@ Vector2 GetMonitorPosition(int monitor)
if ((monitor >= 0) && (monitor < monitorCount))
{
- int x = 0;
+ int x = 0;
int y = 0;
glfwGetMonitorPos(monitors[monitor], &x, &y);
@@ -1005,19 +1016,15 @@ const char *GetMonitorName(int monitor)
// Get window position XY on monitor
Vector2 GetWindowPosition(void)
{
- int x = 0;
- int y = 0;
-
- glfwGetWindowPos(platform.handle, &x, &y);
-
- return (Vector2){ (float)x, (float)y };
+ return (Vector2){ (float)CORE.Window.position.x, (float)CORE.Window.position.y };
}
// 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) && !FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
+ glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y);
return scale;
}
@@ -1258,7 +1265,13 @@ void PollInputEvents(void)
// Get current gamepad state
// NOTE: There is no callback available, so we get it manually
GLFWgamepadstate state = { 0 };
- glfwGetGamepadState(i, &state); // This remapps all gamepads so they have their buttons mapped like an xbox controller
+ int result = glfwGetGamepadState(i, &state); // This remaps all gamepads so they have their buttons mapped like an xbox controller
+ if (result == GLFW_FALSE) // No joystick is connected, no gamepad mapping or an error occurred
+ {
+ // Setting axes to expected resting value instead of GLFW 0.0f default when gamepad is not connected
+ state.axes[GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
+ state.axes[GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
+ }
const unsigned char *buttons = state.buttons;
@@ -1329,7 +1342,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();
@@ -1347,7 +1361,6 @@ 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
static void *AllocateWrapper(size_t size, void *user)
{
@@ -1407,8 +1420,6 @@ int InitPlatform(void)
unsigned int requestedWindowFlags = CORE.Window.flags;
// Check window creation flags
- if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) CORE.Window.fullscreen = true;
-
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window
else glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); // Window initially hidden
@@ -1434,31 +1445,27 @@ 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))
{
- // since we skipped it before, now make sure to set this on macOS
#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
+ 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);
@@ -1525,91 +1532,61 @@ int InitPlatform(void)
// REF: https://github.com/raysan5/raylib/issues/1554
glfwSetJoystickCallback(NULL);
- 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
+ if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0)) FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
- monitor = glfwGetPrimaryMonitor();
+ // Init window in fullscreen mode if requested
+ // NOTE: Keeping original screen size for toggle
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
+ {
+ // NOTE: Fullscreen applications default to the primary monitor
+ GLFWmonitor *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
+ const GLFWvidmode *mode = glfwGetVideoMode(monitor);
- // 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))
+ // Default display resolution to that of the current mode
+ CORE.Window.display.width = mode->width;
+ CORE.Window.display.height = mode->height;
+
+ // Check if user requested some screen size
+ if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
{
- // If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed
- // Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11
- CORE.Window.position.x = CORE.Window.display.width/4;
- CORE.Window.position.y = CORE.Window.display.height/4;
+ // Set some default screen size in case user decides to exit fullscreen mode
+ CORE.Window.previousScreen.width = 800;
+ CORE.Window.previousScreen.height = 450;
+ CORE.Window.previousPosition.x = CORE.Window.display.width/2 - 800/2;
+ CORE.Window.previousPosition.y = CORE.Window.display.height/2 - 450/2;
+
+ // Set screen width/height to the display width/height
+ 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;
}
else
{
- CORE.Window.position.x = CORE.Window.display.width/2 - CORE.Window.screen.width/2;
- CORE.Window.position.y = CORE.Window.display.height/2 - CORE.Window.screen.height/2;
+ CORE.Window.previousScreen = CORE.Window.screen;
+ CORE.Window.screen = CORE.Window.display;
}
- if (CORE.Window.position.x < 0) CORE.Window.position.x = 0;
- if (CORE.Window.position.y < 0) CORE.Window.position.y = 0;
-
- // Obtain recommended CORE.Window.display.width/CORE.Window.display.height from a valid videomode for the monitor
- int count = 0;
- const GLFWvidmode *modes = glfwGetVideoModes(monitor, &count);
-
- // Get closest video mode to desired CORE.Window.screen.width/CORE.Window.screen.height
- for (int i = 0; i < count; i++)
- {
- if ((unsigned int)modes[i].width >= CORE.Window.screen.width)
- {
- if ((unsigned int)modes[i].height >= CORE.Window.screen.height)
- {
- CORE.Window.display.width = modes[i].width;
- CORE.Window.display.height = modes[i].height;
- break;
- }
- }
- }
-
- TRACELOG(LOG_INFO, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
-
- // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example,
- // for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3),
- // framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched
- // by the sides to fit all monitor space...
-
- // Try to setup the most appropriate fullscreen framebuffer for the requested screenWidth/screenHeight
- // It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset)
- // Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale
- // TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed...
- // HighDPI monitors are properly considered in a following similar function: SetupViewport()
- SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
-
- platform.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", monitor, NULL);
+ platform.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", monitor, NULL);
if (!platform.handle)
{
glfwTerminate();
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
return -1;
}
-
- // NOTE: Full-screen change, not working properly...
- //glfwSetWindowMonitor(platform.handle, glfwGetPrimaryMonitor(), 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
}
else
{
- // No-fullscreen window creation
- bool requestWindowedFullscreen = (CORE.Window.screen.height == 0) && (CORE.Window.screen.width == 0);
-
// Default to at least one pixel in size, as creation with a zero dimension is not allowed
- int creationWidth = (CORE.Window.screen.width != 0)? CORE.Window.screen.width : 1;
- int creationHeight = (CORE.Window.screen.height != 0)? CORE.Window.screen.height : 1;
+ if (CORE.Window.screen.width == 0) CORE.Window.screen.width = 1;
+ if (CORE.Window.screen.height == 0) CORE.Window.screen.height = 1;
- platform.handle = glfwCreateWindow(creationWidth, creationHeight, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL);
+ platform.handle = glfwCreateWindow(CORE.Window.screen.width, CORE.Window.screen.height, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL);
if (!platform.handle)
{
glfwTerminate();
@@ -1618,7 +1595,7 @@ int InitPlatform(void)
}
// After the window was created, determine the monitor that the window manager assigned
- // Derive display sizes, and, if possible, window size in case it was zero at beginning
+ // Derive display sizes and, if possible, window size in case it was zero at beginning
int monitorCount = 0;
int monitorIndex = GetCurrentMonitor();
@@ -1626,10 +1603,18 @@ int InitPlatform(void)
if (monitorIndex < monitorCount)
{
- monitor = monitors[monitorIndex];
- SetDimensionsFromMonitor(monitor);
+ GLFWmonitor *monitor = monitors[monitorIndex];
+ const GLFWvidmode *mode = glfwGetVideoMode(monitor);
- if (requestWindowedFullscreen) glfwSetWindowSize(platform.handle, CORE.Window.screen.width, CORE.Window.screen.height);
+ // 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;
+
+ glfwSetWindowSize(platform.handle, CORE.Window.screen.width, CORE.Window.screen.height);
}
else
{
@@ -1639,19 +1624,20 @@ 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;
}
glfwMakeContextCurrent(platform.handle);
result = glfwGetError(NULL);
+ if ((result != GLFW_NO_WINDOW_CONTEXT) && (result != GLFW_PLATFORM_ERROR)) CORE.Window.ready = true; // Checking context activation
- // Check context activation
- if ((result != GLFW_NO_WINDOW_CONTEXT) && (result != GLFW_PLATFORM_ERROR))
+ if (CORE.Window.ready)
{
- CORE.Window.ready = true;
+ // Setup additional windows configs and register required window size info
- glfwSwapInterval(0); // No V-Sync by default
+ glfwSwapInterval(0); // No V-Sync by default
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
// NOTE: V-Sync can be enabled by graphic driver configuration, it doesn't need
@@ -1669,16 +1655,17 @@ int InitPlatform(void)
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);
+
+ // Get current framebuffer size, on high-dpi it could be bigger than screen size
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
// 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;
@@ -1691,37 +1678,34 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
- }
- else
- {
- TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
- return -1;
- }
- if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
-
- // If graphic device is no properly initialized, we end program
- if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
- else
- {
// Try to center window on screen but avoiding window-bar outside of screen
+ int monitorCount = 0;
+ int monitorIndex = GetCurrentMonitor();
+ GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
+ GLFWmonitor *monitor = monitors[monitorIndex];
+
int monitorX = 0;
int monitorY = 0;
int monitorWidth = 0;
int monitorHeight = 0;
glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
- // Here CORE.Window.render.width/height should be used instead of
+ // TODO: Here CORE.Window.render.width/height should be used instead of
// CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled
- int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2;
- int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2;
- if (posX < monitorX) posX = monitorX;
- if (posY < monitorY) posY = monitorY;
- SetWindowPosition(posX, posY);
+ CORE.Window.position.x = monitorX + (monitorWidth - (int)CORE.Window.screen.width)/2;
+ CORE.Window.position.y = monitorY + (monitorHeight - (int)CORE.Window.screen.height)/2;
+ //if (CORE.Window.position.x < monitorX) CORE.Window.position.x = monitorX;
+ //if (CORE.Window.position.y < monitorY) CORE.Window.position.y = monitorY;
- // Update CORE.Window.position here so it is correct from the start
- CORE.Window.position.x = posX;
- CORE.Window.position.y = posY;
+ SetWindowPosition(CORE.Window.position.x, CORE.Window.position.y);
+
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
+ }
+ else
+ {
+ TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
+ return -1;
}
// Apply window flags requested previous to initialization
@@ -1735,28 +1719,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 +1794,134 @@ 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...
+ //TRACELOG(LOG_INFO, "GLFW3: Window size callback called [%i,%i]", width, 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);
+
// 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))
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
- width = (int)(width/GetWindowScaleDPI().x);
- height = (int)(height/GetWindowScaleDPI().y);
+ // On fullscreen mode, strategy is ignoring high-dpi and
+ // use the all available display size
+
+ // Set screen size to render size (physical pixel size)
+ CORE.Window.screen.width = width;
+ CORE.Window.screen.height = height;
+ CORE.Window.screenScale = MatrixScale(1.0f, 1.0f, 1.0f);
+ SetMouseScale(1.0f, 1.0f);
+ }
+ else // Window mode (including borderless window)
+ {
+ // 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();
+ CORE.Window.screen.width = (int)((float)width/scaleDpi.x);
+ CORE.Window.screen.height = (int)((float)height/scaleDpi.y);
+ CORE.Window.screenScale = MatrixScale(scaleDpi.x, scaleDpi.y, 1.0f);
+#if !defined(__APPLE__)
+ // Mouse input scaling for the new screen size
+ SetMouseScale(1.0f/scaleDpi.x, 1.0f/scaleDpi.y);
+#endif
+ }
+ else
+ {
+ // Set screen size to render size (physical pixel size)
+ CORE.Window.screen.width = width;
+ CORE.Window.screen.height = height;
+ }
}
-
- // 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 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);
+
+ float fbWidth = (float)CORE.Window.screen.width*scalex;
+ float fbHeight = (float)CORE.Window.screen.height*scaley;
+
+ // 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);
+#endif
+
+ CORE.Window.render.width = (int)fbWidth;
+ CORE.Window.render.height = (int)fbHeight;
+ CORE.Window.currentFbo = CORE.Window.render;
+}
+
+// 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;
}
-static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
-{
- CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
-}
-// 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)
@@ -1909,12 +1944,12 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
{
CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
- strcpy(CORE.Window.dropFilepaths[i], paths[i]);
+ strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
}
}
}
-// 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 +1976,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 +1993,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 +2029,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 +2060,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)
@@ -2054,20 +2089,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"
diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c
index 2671538d8..d1518b909 100644
--- a/src/platforms/rcore_desktop_rgfw.c
+++ b/src/platforms/rcore_desktop_rgfw.c
@@ -13,10 +13,7 @@
* - TODO
*
* POSSIBLE IMPROVEMENTS:
-* - TODO
-*
-* ADDITIONAL NOTES:
-* - TRACELOG() function is located in raylib [utils] module
+* - TBD
*
* CONFIGURATION:
* #define RCORE_PLATFORM_RGFW
@@ -29,7 +26,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5), Colleague Riley and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5), Colleague Riley and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -290,14 +287,13 @@ bool WindowShouldClose(void)
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
- if (!CORE.Window.fullscreen)
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
// Store previous window position (in case we exit fullscreen)
CORE.Window.previousPosition = CORE.Window.position;
CORE.Window.previousScreen = CORE.Window.screen;
platform.mon = RGFW_window_getMonitor(platform.window);
- CORE.Window.fullscreen = true;
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
RGFW_monitor_scaleToWindow(platform.mon, platform.window);
@@ -305,7 +301,6 @@ void ToggleFullscreen(void)
}
else
{
- CORE.Window.fullscreen = false;
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
if (platform.mon.mode.area.w)
@@ -331,7 +326,9 @@ void ToggleFullscreen(void)
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
- if (CORE.Window.fullscreen)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) ToggleFullscreen();
+
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
CORE.Window.previousPosition = CORE.Window.position;
CORE.Window.previousScreen = CORE.Window.screen;
@@ -348,8 +345,6 @@ void ToggleBorderlessWindowed(void)
CORE.Window.position = CORE.Window.previousPosition;
RGFW_window_resize(platform.window, RGFW_AREA(CORE.Window.previousScreen.width, CORE.Window.previousScreen.height));
}
-
- CORE.Window.fullscreen = !CORE.Window.fullscreen;
}
// Set window state: maximized, if resizable
@@ -385,7 +380,7 @@ void SetWindowState(unsigned int flags)
}
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
{
- if (!CORE.Window.fullscreen) ToggleFullscreen();
+ ToggleFullscreen();
}
if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
{
@@ -459,7 +454,7 @@ void ClearWindowState(unsigned int flags)
}
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
{
- if (CORE.Window.fullscreen) ToggleFullscreen();
+ ToggleFullscreen();
}
if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
{
@@ -510,7 +505,7 @@ void ClearWindowState(unsigned int flags)
}
if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
- if (CORE.Window.fullscreen) ToggleBorderlessWindowed();
+ ToggleBorderlessWindowed();
}
if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
{
@@ -522,46 +517,15 @@ void ClearWindowState(unsigned int flags)
}
}
-int RGFW_formatToChannels(int format)
-{
- switch (format)
- {
- case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
- case PIXELFORMAT_UNCOMPRESSED_R16: // 16 bpp (1 channel - half float)
- case PIXELFORMAT_UNCOMPRESSED_R32: // 32 bpp (1 channel - float)
- return 1;
- case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: // 8*2 bpp (2 channels)
- case PIXELFORMAT_UNCOMPRESSED_R5G6B5: // 16 bpp
- case PIXELFORMAT_UNCOMPRESSED_R8G8B8: // 24 bpp
- case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: // 16 bpp (1 bit alpha)
- case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: // 16 bpp (4 bit alpha)
- case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: // 32 bpp
- return 2;
- case PIXELFORMAT_UNCOMPRESSED_R32G32B32: // 32*3 bpp (3 channels - float)
- case PIXELFORMAT_UNCOMPRESSED_R16G16B16: // 16*3 bpp (3 channels - half float)
- case PIXELFORMAT_COMPRESSED_DXT1_RGB: // 4 bpp (no alpha)
- case PIXELFORMAT_COMPRESSED_ETC1_RGB: // 4 bpp
- case PIXELFORMAT_COMPRESSED_ETC2_RGB: // 4 bpp
- case PIXELFORMAT_COMPRESSED_PVRT_RGB: // 4 bpp
- return 3;
- case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: // 32*4 bpp (4 channels - float)
- case PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: // 16*4 bpp (4 channels - half float)
- case PIXELFORMAT_COMPRESSED_DXT1_RGBA: // 4 bpp (1 bit alpha)
- case PIXELFORMAT_COMPRESSED_DXT3_RGBA: // 8 bpp
- case PIXELFORMAT_COMPRESSED_DXT5_RGBA: // 8 bpp
- case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: // 8 bpp
- case PIXELFORMAT_COMPRESSED_PVRT_RGBA: // 4 bpp
- case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: // 8 bpp
- case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 2 bpp
- return 4;
- default: return 4;
- }
-}
-
// Set icon for window
void SetWindowIcon(Image image)
{
- RGFW_window_setIcon(platform.window, (u8 *)image.data, RGFW_AREA(image.width, image.height), RGFW_formatToChannels(image.format));
+ if (image.format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+ {
+ TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
+ return;
+ }
+ RGFW_window_setIcon(platform.window, (u8 *)image.data, RGFW_AREA(image.width, image.height), 4);
}
// Set icon for window
@@ -578,12 +542,17 @@ void SetWindowIcons(Image *images, int count)
for (int i = 0; i < count; i++)
{
+ if (images[i].format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+ {
+ TRACELOG(LOG_WARNING, "RGFW: Window icon image must be in R8G8B8A8 pixel format");
+ continue;
+ }
if ((bigIcon == NULL) || ((images[i].width > bigIcon->width) && (images[i].height > bigIcon->height))) bigIcon = &images[i];
if ((smallIcon == NULL) || ((images[i].width < smallIcon->width) && (images[i].height > smallIcon->height))) smallIcon = &images[i];
}
- if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), RGFW_formatToChannels(smallIcon->format), RGFW_iconWindow);
- if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), RGFW_formatToChannels(bigIcon->format), RGFW_iconTaskbar);
+ if (smallIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)smallIcon->data, RGFW_AREA(smallIcon->width, smallIcon->height), 4, RGFW_iconWindow);
+ if (bigIcon != NULL) RGFW_window_setIconEx(platform.window, (u8 *)bigIcon->data, RGFW_AREA(bigIcon->width, bigIcon->height), 4, RGFW_iconTaskbar);
}
}
@@ -1284,13 +1253,11 @@ int InitPlatform(void)
// Check window creation flags
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
- CORE.Window.fullscreen = true;
FLAG_SET(flags, RGFW_windowFullscreen);
}
if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
- CORE.Window.fullscreen = true;
FLAG_SET(flags, RGFW_windowedFullscreen);
}
@@ -1341,10 +1308,6 @@ int InitPlatform(void)
CORE.Window.display.width = CORE.Window.screen.width;
CORE.Window.display.height = CORE.Window.screen.height;
#endif
- // TODO: Is this needed by raylib now?
- // If so, rcore_desktop_sdl should be updated too
- //SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
-
if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval(platform.window, 1);
RGFW_window_makeCurrent(platform.window);
diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c
index 995336ec0..eabea6bfe 100644
--- a/src/platforms/rcore_desktop_sdl.c
+++ b/src/platforms/rcore_desktop_sdl.c
@@ -15,9 +15,6 @@
* - Improvement 01
* - Improvement 02
*
-* ADDITIONAL NOTES:
-* - TRACELOG() function is located in raylib [utils] module
-*
* CONFIGURATION:
* #define RCORE_PLATFORM_CUSTOM_FLAG
* Custom flag for rcore on target platform -not used-
@@ -29,7 +26,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -57,7 +54,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 +68,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"
@@ -472,13 +469,11 @@ void ToggleFullscreen(void)
{
SDL_SetWindowFullscreen(platform.window, 0);
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
- CORE.Window.fullscreen = false;
}
else
{
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
- CORE.Window.fullscreen = true;
}
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
@@ -554,7 +549,7 @@ void SetWindowState(unsigned int flags)
#endif
{
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
- CORE.Window.fullscreen = true;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
}
@@ -644,7 +639,6 @@ void ClearWindowState(unsigned int flags)
if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
{
SDL_SetWindowFullscreen(platform.window, 0);
- CORE.Window.fullscreen = false;
}
if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
{
@@ -679,6 +673,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");
@@ -1041,7 +1036,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 +1060,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 +1122,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 +1191,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]);
@@ -1426,12 +1422,12 @@ void PollInputEvents(void)
#if defined(USING_VERSION_SDL3)
// const char *data; // The text for SDL_EVENT_DROP_TEXT and the file name for SDL_EVENT_DROP_FILE, NULL for other events
- // Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE,
- // and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events,
+ // Event memory is now managed by SDL, so you should not free the data in SDL_EVENT_DROP_FILE,
+ // and if you want to hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events,
// you should make a copy of it. SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed
- strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
+ strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1);
#else
- strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
+ strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1);
SDL_free(event.drop.file);
#endif
@@ -1442,9 +1438,9 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#if defined(USING_VERSION_SDL3)
- strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data);
+ strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1);
#else
- strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
+ strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1);
SDL_free(event.drop.file);
#endif
@@ -1454,7 +1450,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:
@@ -1473,7 +1469,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);
@@ -1488,7 +1484,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 +1501,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 +1741,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 +1773,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 +1790,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 +1822,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;
@@ -1924,11 +1931,7 @@ int InitPlatform(void)
FLAG_SET(flags, SDL_WINDOW_MOUSE_CAPTURE); // Window has mouse captured
// Check window creation flags
- if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
- {
- CORE.Window.fullscreen = true;
- FLAG_SET(flags, SDL_WINDOW_FULLSCREEN);
- }
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) FLAG_SET(flags, SDL_WINDOW_FULLSCREEN);
//if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, SDL_WINDOW_HIDDEN);
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, SDL_WINDOW_BORDERLESS);
@@ -2054,28 +2057,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 +2194,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;
diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c
index 29702921f..9f33dce1b 100644
--- a/src/platforms/rcore_desktop_win32.c
+++ b/src/platforms/rcore_desktop_win32.c
@@ -13,9 +13,6 @@
* - Improvement 01
* - Improvement 02
*
-* ADDITIONAL NOTES:
-* - TRACELOG() function is located in raylib [utils] module
-*
* CONFIGURATION:
* #define RCORE_PLATFORM_CUSTOM_FLAG
* Custom flag for rcore on target platform -not used-
@@ -26,7 +23,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -263,7 +260,7 @@ static bool DecoratedFromStyle(DWORD style)
static DWORD MakeWindowStyle(unsigned flags)
{
// Flag is not needed because there are no child windows,
- // but supposedly it improves efficiency, plus, windows adds this
+ // but supposedly it improves efficiency, plus, windows adds this
// flag automatically anyway so it keeps flags in sync with the OS
DWORD style = WS_CLIPSIBLINGS;
@@ -1877,14 +1874,24 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
} break;
case WM_DPICHANGED:
{
+ // Get current dpi scale factor
+ float scalex = HIWORD(wParam)/96.0f;
+ float scaley = LOWORD(wParam)/96.0f;
+
RECT *suggestedRect = (RECT *)lparam;
// Never set the window size to anything other than the suggested rect here
// Doing so can cause a window to stutter between monitors when transitioning between them
- int result = (int)SetWindowPos(hwnd, NULL, suggestedRect->left, suggestedRect->top,
- suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top, SWP_NOZORDER | SWP_NOACTIVATE);
+ int result = (int)SetWindowPos(hwnd, NULL,
+ suggestedRect->left, suggestedRect->top,
+ suggestedRect->right - suggestedRect->left,
+ suggestedRect->bottom - suggestedRect->top,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+
if (result == 0) TRACELOG(LOG_ERROR, "Failed to set window position [ERROR: %lu]", GetLastError());
+ // TODO: Update screen data, render size, screen scaling, viewport...
+
} break;
case WM_SETCURSOR:
{
@@ -2039,8 +2046,7 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height)
// TODO: Update framebuffer on resize
CORE.Window.currentFbo.width = (int)clientSize.cx;
CORE.Window.currentFbo.height = (int)clientSize.cy;
- //glViewport(0, 0, clientSize.cx, clientSize.cy);
- //SetupFramebuffer(0, 0);
+ //SetupViewport(0, 0, clientSize.cx, clientSize.cy);
SetupViewport(clientSize.cx, clientSize.cy);
CORE.Window.resizedLastFrame = true;
diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c
index 640799b0a..b296e0042 100644
--- a/src/platforms/rcore_drm.c
+++ b/src/platforms/rcore_drm.c
@@ -13,9 +13,6 @@
* - Improvement 01
* - Improvement 02
*
-* ADDITIONAL NOTES:
-* - TRACELOG() function is located in raylib [utils] module
-*
* CONFIGURATION:
* #define SUPPORT_SSH_KEYBOARD_RPI (Raspberry Pi only)
* Reconfigure standard input to receive key inputs, works with SSH connection
@@ -29,7 +26,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -89,6 +86,10 @@
#define EGL_OPENGL_ES3_BIT 0x40
#endif
+#ifndef EGL_PLATFORM_GBM_KHR
+ #define EGL_PLATFORM_GBM_KHR 0x31D7
+#endif
+
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@@ -135,8 +136,12 @@ typedef struct {
char currentButtonStateEvdev[MAX_MOUSE_BUTTONS]; // Holds the new mouse state for the next polling event to grab
bool cursorRelative; // Relative cursor mode
int mouseFd; // File descriptor for the evdev mouse/touch/gestures
+ bool mouseIsTouch; // Check if the current mouse device is actually a touchscreen
Rectangle absRange; // Range of values for absolute pointing devices (touchscreens)
int touchSlot; // Hold the touch slot number of the currently being sent multitouch block
+ bool touchActive[MAX_TOUCH_POINTS]; // Track which touch points are currently active
+ Vector2 touchPosition[MAX_TOUCH_POINTS]; // Track touch positions for each slot
+ int touchId[MAX_TOUCH_POINTS]; // Track touch IDs for each slot
// Gamepad data
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
@@ -265,6 +270,8 @@ static int FindMatchingConnectorMode(const drmModeConnector *connector, const dr
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
static int FindNearestConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search the nearest matching DRM connector mode in connector's list
+static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
+
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
@@ -1113,9 +1120,6 @@ void PollInputEvents(void)
// Register previous touch states
for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
- // Reset touch positions to invalid state
- for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ -1, -1 };
-
// Map touch position to mouse position for convenience
// NOTE: For DRM touchscreen devices, this mapping is disabled to avoid false touch detection
// CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
@@ -1147,7 +1151,6 @@ int InitPlatform(void)
// Initialize graphic device: display/window and graphic context
//----------------------------------------------------------------------------
- CORE.Window.fullscreen = true;
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
@@ -1158,7 +1161,8 @@ int InitPlatform(void)
platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully");
- if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
+ drmModeRes *res = NULL;
+ if ((platform.fd == -1) || ((res = drmModeGetResources(platform.fd)) == NULL))
{
if (platform.fd != -1) close(platform.fd);
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1");
@@ -1166,7 +1170,7 @@ int InitPlatform(void)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully");
}
- if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
+ if ((platform.fd == -1) || ((res = drmModeGetResources(platform.fd)) == NULL))
{
if (platform.fd != -1) close(platform.fd);
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0");
@@ -1174,7 +1178,7 @@ int InitPlatform(void)
if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully");
}
- if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL))
+ if ((platform.fd == -1) || ((res = drmModeGetResources(platform.fd)) == NULL))
{
if (platform.fd != -1) close(platform.fd);
TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card0, trying card2");
@@ -1189,7 +1193,6 @@ int InitPlatform(void)
return -1;
}
- drmModeRes *res = drmModeGetResources(platform.fd);
if (!res)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed get DRM resources");
@@ -1412,9 +1415,27 @@ int InitPlatform(void)
};
EGLint numConfigs = 0;
+ const char *eglClientExtensions = NULL;
// Get an EGL device connection
- platform.device = eglGetDisplay((EGLNativeDisplayType)platform.gbmDevice);
+ // NOTE: eglGetPlatformDisplay() is preferred over eglGetDisplay() legacy call
+ platform.device = EGL_NO_DISPLAY;
+#if defined(EGL_VERSION_1_5)
+ platform.device = eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, platform.gbmDevice, NULL);
+#else
+ // Check if extension is available for eglGetPlatformDisplayEXT()
+ // NOTE: Better compatibility with some drivers (e.g. Mali Midgard)
+ eglClientExtensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ if ((eglClientExtensions != NULL) && (strstr(eglClientExtensions, "EGL_EXT_platform_base") != NULL))
+ {
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
+
+ if (eglGetPlatformDisplayEXT != NULL) platform.device = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, platform.gbmDevice, NULL);
+ }
+
+ // In case extension not found or display could not be retrieved, try useing legacy version
+ if (platform.device == EGL_NO_DISPLAY) platform.device = eglGetDisplay((EGLNativeDisplayType)platform.gbmDevice);
+#endif
if (platform.device == EGL_NO_DISPLAY)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
@@ -1494,8 +1515,21 @@ int InitPlatform(void)
}
// Create an EGL window surface
- platform.surface = eglCreateWindowSurface(platform.device, platform.config, (EGLNativeWindowType)platform.gbmSurface, NULL);
- if (EGL_NO_SURFACE == platform.surface)
+ platform.surface = EGL_NO_SURFACE;
+
+ if ((eglClientExtensions != NULL) && (strstr(eglClientExtensions, "EGL_EXT_platform_base") != NULL))
+ {
+ PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC eglCreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
+
+ if (eglCreatePlatformWindowSurfaceEXT != NULL) platform.surface = eglCreatePlatformWindowSurfaceEXT(platform.device, platform.config, platform.gbmSurface, NULL);
+ }
+
+ if (platform.surface == EGL_NO_SURFACE)
+ {
+ platform.surface = eglCreateWindowSurface(platform.device, platform.config, (EGLNativeWindowType)platform.gbmSurface, NULL);
+ }
+
+ if (platform.surface == EGL_NO_SURFACE)
{
TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL window surface: 0x%04x", eglGetError());
return -1;
@@ -1564,7 +1598,11 @@ int InitPlatform(void)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
// If graphic device is no properly initialized, we end program
- if (!CORE.Window.ready) { TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device"); return -1; }
+ if (!CORE.Window.ready)
+ {
+ TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphic device");
+ return -1;
+ }
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
// Set some default window flags
@@ -1882,8 +1920,15 @@ static void InitEvdevInput(void)
{
CORE.Input.Touch.position[i].x = -1;
CORE.Input.Touch.position[i].y = -1;
+ platform.touchActive[i] = false;
+ platform.touchPosition[i].x = -1;
+ platform.touchPosition[i].y = -1;
+ platform.touchId[i] = -1;
}
+ // Initialize touch slot
+ platform.touchSlot = 0;
+
// Reset keyboard key state
for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
{
@@ -2046,17 +2091,49 @@ static void ConfigureEvdevDevice(char *device)
const char *deviceKindStr = "unknown";
if (isMouse || isTouch)
{
- deviceKindStr = "mouse";
- if (platform.mouseFd != -1) close(platform.mouseFd);
- platform.mouseFd = fd;
+ bool prioritize = false;
- if (absAxisCount > 0)
+ // Priority logic: touchscreens override Mice
+ // 1. No device set yet? Take it
+ if (platform.mouseFd == -1) prioritize = true;
+ // 2. Current is mouse, new is touch? Upgrade to touch
+ else if (isTouch && !platform.mouseIsTouch) prioritize = true;
+ // 3. Current is touch, new is touch? Use the new one (last one found wins, standard behavior)
+ else if (isTouch && platform.mouseIsTouch) prioritize = true;
+ // 4. Current is mouse, new is mouse? Use the new one
+ else if (!isTouch && !platform.mouseIsTouch) prioritize = true;
+ // 5. Current is touch, new is mouse? Ignore the mouse, keep the touchscreen
+ else prioritize = false;
+
+ if (prioritize)
{
- platform.absRange.x = absinfo[ABS_X].info.minimum;
- platform.absRange.width = absinfo[ABS_X].info.maximum - absinfo[ABS_X].info.minimum;
+ deviceKindStr = isTouch? "touchscreen" : "mouse";
- platform.absRange.y = absinfo[ABS_Y].info.minimum;
- platform.absRange.height = absinfo[ABS_Y].info.maximum - absinfo[ABS_Y].info.minimum;
+ if (platform.mouseFd != -1)
+ {
+ TRACELOG(LOG_INFO, "INPUT: Overwriting previous input device with new %s", deviceKindStr);
+ close(platform.mouseFd);
+ }
+
+ platform.mouseFd = fd;
+ platform.mouseIsTouch = isTouch;
+
+ if (absAxisCount > 0)
+ {
+ platform.absRange.x = absinfo[ABS_X].info.minimum;
+ platform.absRange.width = absinfo[ABS_X].info.maximum - absinfo[ABS_X].info.minimum;
+
+ platform.absRange.y = absinfo[ABS_Y].info.minimum;
+ platform.absRange.height = absinfo[ABS_Y].info.maximum - absinfo[ABS_Y].info.minimum;
+ }
+
+ TRACELOG(LOG_INFO, "INPUT: Initialized input device %s as %s", device, deviceKindStr);
+ }
+ else
+ {
+ TRACELOG(LOG_INFO, "INPUT: Ignoring device %s (keeping higher priority %s device)", device, platform.mouseIsTouch ? "touchscreen" : "mouse");
+ close(fd);
+ return;
}
}
else if (isGamepad && !isMouse && !isKeyboard && (platform.gamepadCount < MAX_GAMEPADS))
@@ -2127,18 +2204,15 @@ static void PollKeyboardEvents(void)
// If the event was a key, we know a working keyboard is connected, so disable the SSH keyboard
platform.eventKeyboardMode = true;
#endif
-
// Keyboard keys appear for codes 1 to 255, ignore everthing else
if ((event.code >= 1) && (event.code <= 255))
{
-
// Lookup the scancode in the keymap to get a keycode
keycode = linuxToRaylibMap[event.code];
// Make sure we got a valid keycode
if ((keycode > 0) && (keycode < MAX_KEYBOARD_KEYS))
{
-
// WARNING: https://www.kernel.org/doc/Documentation/input/input.txt
// Event interface: 'value' is the value the event carries. Either a relative change for EV_REL,
// absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat
@@ -2187,16 +2261,15 @@ static void PollGamepadEvents(void)
{
if (event.code < KEYMAP_SIZE)
{
- short keycodeRaylib = linuxToRaylibMap[event.code];
+ short keycode = linuxToRaylibMap[event.code]; // raylib keycode
- TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: KEY_%s Keycode(linux): %4i Keycode(raylib): %4i", i, (event.value == 0)? "UP" : "DOWN", event.code, keycodeRaylib);
+ TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: KEY_%s Keycode(linux): %4i Keycode(raylib): %4i", i, (event.value == 0)? "UP" : "DOWN", event.code, keycode);
- if ((keycodeRaylib != 0) && (keycodeRaylib < MAX_GAMEPAD_BUTTONS))
+ if ((keycode != 0) && (keycode < MAX_GAMEPAD_BUTTONS))
{
// 1 - button pressed, 0 - button released
- CORE.Input.Gamepad.currentButtonState[i][keycodeRaylib] = event.value;
-
- CORE.Input.Gamepad.lastButtonPressed = (event.value == 1)? keycodeRaylib : GAMEPAD_BUTTON_UNKNOWN;
+ CORE.Input.Gamepad.currentButtonState[i][keycode] = event.value;
+ CORE.Input.Gamepad.lastButtonPressed = (event.value == 1)? keycode : GAMEPAD_BUTTON_UNKNOWN;
}
}
}
@@ -2230,6 +2303,7 @@ static void PollMouseEvents(void)
struct input_event event = { 0 };
int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
+ static bool isMultitouch = false; // Detect if device supports MT events
// Try to read data from the mouse/touch/gesture and only continue if successful
while (read(fd, &event, sizeof(event)) == (int)sizeof(event))
@@ -2275,39 +2349,102 @@ static void PollMouseEvents(void)
if (event.code == ABS_X)
{
CORE.Input.Mouse.currentPosition.x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
- CORE.Input.Touch.position[0].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
- touchAction = 2; // TOUCH_ACTION_MOVE
+ // Update single touch position only if it's active and no MT events are being used
+ if (platform.touchActive[0] && !isMultitouch)
+ {
+ platform.touchPosition[0].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width;
+ if (touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
+ }
}
if (event.code == ABS_Y)
{
CORE.Input.Mouse.currentPosition.y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
- CORE.Input.Touch.position[0].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
- touchAction = 2; // TOUCH_ACTION_MOVE
+ // Update single touch position only if it's active and no MT events are being used
+ if (platform.touchActive[0] && !isMultitouch)
+ {
+ platform.touchPosition[0].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height;
+ if (touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
+ }
}
// Multitouch movement
- if (event.code == ABS_MT_SLOT) platform.touchSlot = event.value; // Remember the slot number for the folowing events
+ if (event.code == ABS_MT_SLOT)
+ {
+ platform.touchSlot = event.value;
+ isMultitouch = true;
+ }
if (event.code == ABS_MT_POSITION_X)
{
- if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
+ isMultitouch = true;
+ if (platform.touchSlot < MAX_TOUCH_POINTS)
+ {
+ platform.touchPosition[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width;
+
+ // If this slot is active, it's a move. If not, we are just updating the buffer for when it becomes active.
+ // Only set to MOVE if we haven't already detected a DOWN or UP event this frame
+ if (platform.touchActive[platform.touchSlot] && touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
+ }
}
if (event.code == ABS_MT_POSITION_Y)
{
- if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
+ if (platform.touchSlot < MAX_TOUCH_POINTS)
+ {
+ platform.touchPosition[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height;
+
+ // If this slot is active, it's a move. If not, we are just updating the buffer for when it becomes active.
+ // Only set to MOVE if we haven't already detected a DOWN or UP event this frame
+ if (platform.touchActive[platform.touchSlot] && touchAction == -1) touchAction = 2; // TOUCH_ACTION_MOVE
+ }
}
if (event.code == ABS_MT_TRACKING_ID)
{
- if ((event.value < 0) && (platform.touchSlot < MAX_TOUCH_POINTS))
+ if (platform.touchSlot < MAX_TOUCH_POINTS)
{
- // Touch has ended for this point
- CORE.Input.Touch.position[platform.touchSlot].x = -1;
- CORE.Input.Touch.position[platform.touchSlot].y = -1;
+ if (event.value >= 0)
+ {
+
+ platform.touchActive[platform.touchSlot] = true;
+ platform.touchId[platform.touchSlot] = event.value; // Use Tracking ID for unique IDs
+
+ touchAction = 1; // TOUCH_ACTION_DOWN
+ }
+ else
+ {
+ // Touch has ended for this point
+ platform.touchActive[platform.touchSlot] = false;
+ platform.touchPosition[platform.touchSlot].x = -1;
+ platform.touchPosition[platform.touchSlot].y = -1;
+ platform.touchId[platform.touchSlot] = -1;
+
+ // Force UP action if we haven't already set a DOWN action
+ // (DOWN takes priority over UP if both happen in one frame, though rare)
+ if (touchAction != 1) touchAction = 0; // TOUCH_ACTION_UP
+ }
+ }
+ }
+
+ // Handle ABS_MT_PRESSURE (0x3a) if available, as some devices use it for lift-off
+ #ifndef ABS_MT_PRESSURE
+ #define ABS_MT_PRESSURE 0x3a
+ #endif
+ if (event.code == ABS_MT_PRESSURE)
+ {
+ if (platform.touchSlot < MAX_TOUCH_POINTS)
+ {
+ if (event.value <= 0) // Pressure 0 means lift
+ {
+ platform.touchActive[platform.touchSlot] = false;
+ platform.touchPosition[platform.touchSlot].x = -1;
+ platform.touchPosition[platform.touchSlot].y = -1;
+ platform.touchId[platform.touchSlot] = -1;
+ if (touchAction != 1) touchAction = 0; // TOUCH_ACTION_UP
+ }
}
}
@@ -2319,16 +2456,15 @@ static void PollMouseEvents(void)
if (!event.value && previousMouseLeftButtonState)
{
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
- touchAction = 0; // TOUCH_ACTION_UP
+ if (touchAction != 1) touchAction = 0; // TOUCH_ACTION_UP
}
if (event.value && !previousMouseLeftButtonState)
{
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
- touchAction = 1; // TOUCH_ACTION_DOWN
+ touchAction = 1; // TOUCH_ACTION_DOWN
}
}
-
}
// Button parsing
@@ -2339,8 +2475,43 @@ static void PollMouseEvents(void)
{
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
- if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
- else touchAction = 0; // TOUCH_ACTION_UP
+ if (event.value > 0)
+ {
+ bool activateSlot0 = false;
+
+ if (event.code == BTN_LEFT) activateSlot0 = true; // Mouse click always activates
+ else if (event.code == BTN_TOUCH)
+ {
+ bool anyActive = false;
+ for (int i = 0; i < MAX_TOUCH_POINTS; i++)
+ {
+ if (platform.touchActive[i]) { anyActive = true; break; }
+ }
+
+ if (!anyActive) activateSlot0 = true;
+ }
+
+ if (activateSlot0)
+ {
+ platform.touchActive[0] = true;
+ platform.touchId[0] = 0;
+ }
+
+ touchAction = 1; // TOUCH_ACTION_DOWN
+ }
+ else
+ {
+ // Only clear touch 0 for actual mouse clicks (BTN_LEFT)
+ if (event.code == BTN_LEFT)
+ {
+ platform.touchActive[0] = false;
+ platform.touchPosition[0].x = -1;
+ platform.touchPosition[0].y = -1;
+ }
+ else if (event.code == BTN_TOUCH) platform.touchSlot = 0; // Reset slot index to 0
+
+ touchAction = 0; // TOUCH_ACTION_UP
+ }
}
if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
@@ -2355,24 +2526,40 @@ static void PollMouseEvents(void)
if (!CORE.Input.Mouse.cursorLocked)
{
if (CORE.Input.Mouse.currentPosition.x < 0) CORE.Input.Mouse.currentPosition.x = 0;
- if (CORE.Input.Mouse.currentPosition.x > CORE.Window.screen.width/CORE.Input.Mouse.scale.x) CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/CORE.Input.Mouse.scale.x;
+ if (CORE.Input.Mouse.currentPosition.x > CORE.Window.screen.width/CORE.Input.Mouse.scale.x)
+ CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/CORE.Input.Mouse.scale.x;
if (CORE.Input.Mouse.currentPosition.y < 0) CORE.Input.Mouse.currentPosition.y = 0;
- if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
+ if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y)
+ CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
}
- // Update touch point count
- CORE.Input.Touch.pointCount = 0;
+ // Repack active touches into CORE.Input.Touch
+ int k = 0;
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
{
- if (CORE.Input.Touch.position[i].x >= 0) CORE.Input.Touch.pointCount++;
+ if (platform.touchActive[i])
+ {
+ CORE.Input.Touch.position[k] = platform.touchPosition[i];
+ CORE.Input.Touch.pointId[k] = platform.touchId[i];
+ k++;
+ }
+ }
+
+ CORE.Input.Touch.pointCount = k;
+
+ // Clear remaining slots
+ for (int i = k; i < MAX_TOUCH_POINTS; i++)
+ {
+ CORE.Input.Touch.position[i].x = -1;
+ CORE.Input.Touch.position[i].y = -1;
+ CORE.Input.Touch.pointId[i] = -1;
}
#if defined(SUPPORT_GESTURES_SYSTEM)
if (touchAction > -1)
{
GestureEvent gestureEvent = { 0 };
-
gestureEvent.touchAction = touchAction;
gestureEvent.pointCount = CORE.Input.Touch.pointCount;
@@ -2383,7 +2570,6 @@ static void PollMouseEvents(void)
}
ProcessGestureEvent(gestureEvent);
-
touchAction = -1;
}
#endif
@@ -2479,4 +2665,82 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
return nearestIndex;
}
-// EOF
+// Compute framebuffer size relative to screen size and display size
+// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
+static void SetupFramebuffer(int width, int height)
+{
+ // Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
+ if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
+ {
+ TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
+
+ // Downscaling to fit display with border-bars
+ float widthRatio = (float)CORE.Window.display.width/(float)CORE.Window.screen.width;
+ float heightRatio = (float)CORE.Window.display.height/(float)CORE.Window.screen.height;
+
+ if (widthRatio <= heightRatio)
+ {
+ CORE.Window.render.width = CORE.Window.display.width;
+ CORE.Window.render.height = (int)round((float)CORE.Window.screen.height*widthRatio);
+ CORE.Window.renderOffset.x = 0;
+ CORE.Window.renderOffset.y = (CORE.Window.display.height - CORE.Window.render.height);
+ }
+ else
+ {
+ CORE.Window.render.width = (int)round((float)CORE.Window.screen.width*heightRatio);
+ CORE.Window.render.height = CORE.Window.display.height;
+ CORE.Window.renderOffset.x = (CORE.Window.display.width - CORE.Window.render.width);
+ CORE.Window.renderOffset.y = 0;
+ }
+
+ // Screen scaling required
+ float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
+ CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
+
+ // NOTE: We render to full display resolution!
+ // We just need to calculate above parameters for downscale matrix and offsets
+ CORE.Window.render.width = CORE.Window.display.width;
+ CORE.Window.render.height = CORE.Window.display.height;
+
+ TRACELOG(LOG_WARNING, "DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i)", CORE.Window.render.width, CORE.Window.render.height);
+ }
+ else if ((CORE.Window.screen.width < CORE.Window.display.width) || (CORE.Window.screen.height < CORE.Window.display.height))
+ {
+ // Required screen size is smaller than display size
+ TRACELOG(LOG_INFO, "DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
+
+ if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
+ {
+ CORE.Window.screen.width = CORE.Window.display.width;
+ CORE.Window.screen.height = CORE.Window.display.height;
+ }
+
+ // Upscaling to fit display with border-bars
+ float displayRatio = (float)CORE.Window.display.width/(float)CORE.Window.display.height;
+ float screenRatio = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height;
+
+ if (displayRatio <= screenRatio)
+ {
+ CORE.Window.render.width = CORE.Window.screen.width;
+ CORE.Window.render.height = (int)round((float)CORE.Window.screen.width/displayRatio);
+ CORE.Window.renderOffset.x = 0;
+ CORE.Window.renderOffset.y = (CORE.Window.render.height - CORE.Window.screen.height);
+ }
+ else
+ {
+ CORE.Window.render.width = (int)round((float)CORE.Window.screen.height*displayRatio);
+ CORE.Window.render.height = CORE.Window.screen.height;
+ CORE.Window.renderOffset.x = (CORE.Window.render.width - CORE.Window.screen.width);
+ CORE.Window.renderOffset.y = 0;
+ }
+ }
+ else
+ {
+ CORE.Window.render.width = CORE.Window.screen.width;
+ CORE.Window.render.height = CORE.Window.screen.height;
+ CORE.Window.renderOffset.x = 0;
+ CORE.Window.renderOffset.y = 0;
+ }
+}
+
+// EOF
\ No newline at end of file
diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c
index 1b7a55fd8..c9409a750 100644
--- a/src/platforms/rcore_memory.c
+++ b/src/platforms/rcore_memory.c
@@ -13,9 +13,6 @@
* - Improvement 01
* - Improvement 02
*
-* ADDITIONAL NOTES:
-* - TRACELOG() function is located in raylib [utils] module
-*
* CONFIGURATION:
* #define RCORE_PLATFORM_CUSTOM_FLAG
* Custom flag for rcore on target platform -not used-
@@ -27,7 +24,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2025-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -472,7 +469,7 @@ void PollInputEvents(void)
}
// TODO: Poll input events for current platform
-
+
// Check for key pressed to exit
if (kbhit())
{
@@ -513,7 +510,7 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
-
+
CORE.Window.ready = true;
// TODO: Load OpenGL extensions
diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c
index bc03a3cdb..87cd2e21e 100644
--- a/src/platforms/rcore_template.c
+++ b/src/platforms/rcore_template.c
@@ -27,7 +27,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -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
}
}
@@ -459,89 +454,20 @@ int InitPlatform(void)
// raylib uses OpenGL so, platform should create that kind of connection
// Below example illustrates that process using EGL library
//----------------------------------------------------------------------------
- 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;
diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c
index 934f778c3..f1922600f 100644
--- a/src/platforms/rcore_web.c
+++ b/src/platforms/rcore_web.c
@@ -12,9 +12,6 @@
* POSSIBLE IMPROVEMENTS:
* - Replace glfw3 dependency by direct browser API calls (same as library_glfw3.js)
*
-* ADDITIONAL NOTES:
-* - TRACELOG() function is located in raylib [utils] module
-*
* CONFIGURATION:
* #define RCORE_PLATFORM_CUSTOM_FLAG
* Custom flag for rcore on target platform -not used-
@@ -26,7 +23,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -76,10 +73,10 @@ 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
// 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
@@ -204,7 +201,6 @@ void ToggleFullscreen(void)
EM_ASM(document.exitFullscreen(););
- CORE.Window.fullscreen = false;
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
@@ -213,14 +209,12 @@ void ToggleFullscreen(void)
if (enterFullscreen)
{
// NOTE: The setTimeouts handle the browser mode change delay
- EM_ASM
- (
- setTimeout(function()
- {
+ EM_ASM(
+ setTimeout(function(){
Module.requestFullscreen(false, false);
}, 100);
);
- CORE.Window.fullscreen = true;
+
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
@@ -238,7 +232,7 @@ void ToggleFullscreen(void)
*/
// EM_ASM(Module.requestFullscreen(false, false););
/*
- if (!CORE.Window.fullscreen)
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
// Option 1: Request fullscreen for the canvas element
// This option does not seem to work at all:
@@ -274,7 +268,6 @@ void ToggleFullscreen(void)
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
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
else
@@ -286,7 +279,6 @@ void ToggleFullscreen(void)
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
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
*/
@@ -313,7 +305,6 @@ void ToggleBorderlessWindowed(void)
EM_ASM(document.exitFullscreen(););
- CORE.Window.fullscreen = false;
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
@@ -545,7 +536,6 @@ void ClearWindowState(unsigned int flags)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE) || (canvasStyleWidth > canvasWidth)) EM_ASM(document.exitFullscreen(););
}
- CORE.Window.fullscreen = false;
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
@@ -892,7 +882,7 @@ 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;
@@ -1111,7 +1101,7 @@ void PollInputEvents(void)
else CORE.Input.Gamepad.currentButtonState[i][button] = 0;
}
- //TRACELOGD("INPUT: Gamepad %d, button %d: Digital: %d, Analog: %g", gamepadState.index, j, gamepadState.digitalButton[j], gamepadState.analogButton[j]);
+ //TRACELOG(LOG_DEBUG, "INPUT: Gamepad %d, button %d: Digital: %d, Analog: %g", gamepadState.index, j, gamepadState.digitalButton[j], gamepadState.analogButton[j]);
}
// Register axis data for every connected gamepad
@@ -1135,7 +1125,7 @@ void PollInputEvents(void)
int InitPlatform(void)
{
SetCanvasIdJs(platform.canvasId, 64); // Get the current canvas id
-
+
glfwSetErrorCallback(ErrorCallback);
// Initialize GLFW internal global state
@@ -1155,8 +1145,6 @@ int InitPlatform(void)
// glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers
// Check window creation flags
- if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) CORE.Window.fullscreen = true;
-
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window
else glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); // Window initially hidden
@@ -1209,8 +1197,8 @@ int InitPlatform(void)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
// Profiles Hint, only OpenGL 3.3 and above
// Possible values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); // Forward Compatibility Hint: Only 3.3 and above!
// glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context
}
@@ -1245,7 +1233,7 @@ 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);
@@ -1253,14 +1241,14 @@ int InitPlatform(void)
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)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
// remember center for switchinging from fullscreen to window
if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
@@ -1299,18 +1287,6 @@ int InitPlatform(void)
TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
- // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example,
- // for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3),
- // framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched
- // by the sides to fit all monitor space...
-
- // Try to setup the most appropriate fullscreen framebuffer for the requested screenWidth/screenHeight
- // It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset)
- // Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale
- // TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed...
- // HighDPI monitors are properly considered in a following similar function: SetupViewport()
- SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
-
platform.handle = glfwCreateWindow(CORE.Window.display.width, CORE.Window.display.height, (CORE.Window.title != 0)? CORE.Window.title : " ", glfwGetPrimaryMonitor(), NULL);
// NOTE: Full-screen change, not working properly...
@@ -1531,7 +1507,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
{
CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
- strcpy(CORE.Window.dropFilepaths[i], paths[i]);
+ strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
}
}
}
@@ -1716,12 +1692,12 @@ static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPoin
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
{
/*
- TRACELOGD("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"",
+ TRACELOG(LOG_DEBUG, "%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"",
eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
- for (int i = 0; i < gamepadEvent->numAxes; i++) TRACELOGD("Axis %d: %g", i, gamepadEvent->axis[i]);
- for (int i = 0; i < gamepadEvent->numButtons; i++) TRACELOGD("Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
+ for (int i = 0; i < gamepadEvent->numAxes; i++) TRACELOG(LOG_DEBUG, "Axis %d: %g", i, gamepadEvent->axis[i]);
+ for (int i = 0; i < gamepadEvent->numButtons; i++) TRACELOG(LOG_DEBUG, "Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
*/
if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
@@ -1830,7 +1806,6 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
if (!wasFullscreen)
{
- CORE.Window.fullscreen = false;
FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c
new file mode 100644
index 000000000..36b8e964a
--- /dev/null
+++ b/src/platforms/rcore_web_emscripten.c
@@ -0,0 +1,1690 @@
+/**********************************************************************************************
+*
+* rcore_web_emscripten - Functions to manage window, graphics device and inputs
+*
+* PLATFORM: WEB - EMSCRIPTEN
+* - HTML5 (WebAssembly)
+*
+* LIMITATIONS:
+* - TBD
+*
+* POSSIBLE IMPROVEMENTS:
+* - TBD
+*
+* CONFIGURATION:
+* #define RCORE_PLATFORM_CUSTOM_FLAG
+* Custom flag for rcore on target platform -not used-
+*
+* DEPENDENCIES:
+* - emscripten: Allow interaction between browser API and C
+* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
+*
+*
+* LICENSE: zlib/libpng
+*
+* Copyright (c) 2025-2026 Ramon Santamaria (@raysan5) and contributors
+*
+* This software is provided "as-is", without any express or implied warranty. In no event
+* will the authors be held liable for any damages arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose, including commercial
+* applications, and to alter it and redistribute it freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not claim that you
+* wrote the original software. If you use this software in a product, an acknowledgment
+* in the product documentation would be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
+* as being the original software.
+*
+* 3. This notice may not be removed or altered from any source distribution.
+*
+**********************************************************************************************/
+
+#include // Emscripten functionality for C
+#include // Emscripten HTML5 library
+
+#include // Required for: timespec, nanosleep(), select() - POSIX
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#if (_POSIX_C_SOURCE < 199309L)
+ #undef _POSIX_C_SOURCE
+ #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext.
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct {
+ char canvasId[64]; // Current canvas id
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE glContext; // OpenGL context
+ unsigned int *pixels; // Pointer to pixel data buffer (RGBA 32bit format)
+} PlatformData;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+extern CoreData CORE; // Global CORE state context
+
+static PlatformData platform = { 0 }; // Platform specific data
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static const char cursorLUT[11][12] = {
+ "default", // 0 MOUSE_CURSOR_DEFAULT
+ "default", // 1 MOUSE_CURSOR_ARROW
+ "text", // 2 MOUSE_CURSOR_IBEAM
+ "crosshair", // 3 MOUSE_CURSOR_CROSSHAIR
+ "pointer", // 4 MOUSE_CURSOR_POINTING_HAND
+ "ew-resize", // 5 MOUSE_CURSOR_RESIZE_EW
+ "ns-resize", // 6 MOUSE_CURSOR_RESIZE_NS
+ "nwse-resize", // 7 MOUSE_CURSOR_RESIZE_NWSE
+ "nesw-resize", // 8 MOUSE_CURSOR_RESIZE_NESW
+ "move", // 9 MOUSE_CURSOR_RESIZE_ALL
+ "not-allowed" // 10 MOUSE_CURSOR_NOT_ALLOWED
+};
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+int InitPlatform(void); // Initialize platform (graphics, inputs and more)
+void ClosePlatform(void); // Close platform
+
+// Emscripten window callback events
+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);
+static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
+// TODO: Implement GLFW3 alternative for drop callback, runs when drop files into browser/canvas
+//static void WindowDropCallback(GLFWwindow *window, int count, const char **paths);
+
+// Emscripten input callback events
+static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData);
+static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
+static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
+static EM_BOOL EmscriptenMouseWheelCallback(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData);
+static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData);
+static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
+static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
+
+// 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
+//----------------------------------------------------------------------------------
+// NOTE: Functions declaration is provided by raylib.h
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Window and Graphics Device
+//----------------------------------------------------------------------------------
+
+// Check if application should close
+// This will always return false on a web-build as web builds have no control over this functionality
+// Sleep is handled in EndDrawing() for synchronous code
+bool WindowShouldClose(void)
+{
+ // Emscripten Asyncify is required to run synchronous code in asynchronous JS
+ // 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,
+ // allowing the browser to manage execution asynchronously
+
+ // Optionally we can manage the time we give-control-back-to-browser if required,
+ // but it seems below line could generate stuttering on some browsers
+ emscripten_sleep(12);
+
+ return false;
+}
+
+// Toggle fullscreen mode
+void ToggleFullscreen(void)
+{
+ bool enterFullscreen = false;
+
+ const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
+ if (wasFullscreen)
+ {
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) enterFullscreen = false;
+ else if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) enterFullscreen = true;
+ else
+ {
+ const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
+ const int canvasStyleWidth = EM_ASM_INT( { return parseInt(Module.canvas.style.width); }, 0);
+ if (canvasStyleWidth > canvasWidth) enterFullscreen = false;
+ else enterFullscreen = true;
+ }
+
+ EM_ASM(document.exitFullscreen(););
+
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
+ }
+ else enterFullscreen = true;
+
+ if (enterFullscreen)
+ {
+ // NOTE: The setTimeouts handle the browser mode change delay
+ EM_ASM
+ (
+ setTimeout(function()
+ {
+ Module.requestFullscreen(false, false);
+ }, 100);
+ );
+
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ }
+
+ // NOTE: Old notes below:
+ /*
+ EM_ASM
+ (
+ // This strategy works well while using raylib minimal web shell for emscripten,
+ // it re-scales the canvas to fullscreen using monitor resolution, for tools this
+ // is a good strategy but maybe games prefer to keep current canvas resolution and
+ // display it in fullscreen, adjusting monitor resolution if possible
+ if (document.fullscreenElement) document.exitFullscreen();
+ else Module.requestFullscreen(true, true); //false, true);
+ );
+ */
+ // EM_ASM(Module.requestFullscreen(false, false););
+ /*
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
+ {
+ // Option 1: Request fullscreen for the canvas element
+ // 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);
+
+ // 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
+ // EmscriptenFullscreenStrategy strategy = {
+ // .scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH, //EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT,
+ // .canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF,
+ // .filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT,
+ // .canvasResizedCallback = EmscriptenWindowResizedCallback,
+ // .canvasResizedCallbackUserData = NULL
+ // };
+ //emscripten_request_fullscreen_strategy("#canvas", EM_FALSE, &strategy);
+
+ // Option 3: Request fullscreen for the canvas element with strategy
+ // It works as expected but only inside the browser (client area)
+ EmscriptenFullscreenStrategy strategy = {
+ .scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT,
+ .canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF,
+ .filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT,
+ .canvasResizedCallback = EmscriptenWindowResizedCallback,
+ .canvasResizedCallbackUserData = NULL
+ };
+ emscripten_enter_soft_fullscreen("#canvas", &strategy);
+
+ int width = 0;
+ int height = 0;
+ emscripten_get_canvas_element_size("#canvas", &width, &height);
+ TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height);
+
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ }
+ else
+ {
+ //emscripten_exit_fullscreen();
+ //emscripten_exit_soft_fullscreen();
+
+ int width, height;
+ emscripten_get_canvas_element_size("#canvas", &width, &height);
+ TRACELOG(LOG_WARNING, "Emscripten: Exit fullscreen: Canvas size: %i x %i", width, height);
+
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ }
+ */
+}
+
+// Toggle borderless windowed mode
+void ToggleBorderlessWindowed(void)
+{
+ bool enterBorderless = false;
+
+ const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
+ if (wasFullscreen)
+ {
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) enterBorderless = false;
+ else if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) enterBorderless = true;
+ else
+ {
+ const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
+ const int screenWidth = EM_ASM_INT( { return screen.width; }, 0);
+ if (screenWidth == canvasWidth) enterBorderless = false;
+ else enterBorderless = true;
+ }
+
+ EM_ASM(document.exitFullscreen(););
+
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
+ }
+ else enterBorderless = true;
+
+ if (enterBorderless)
+ {
+ // 1. The setTimeouts handle the browser mode change delay
+ // 2. The style unset handles the possibility of a width="value%" like on the default shell.html file
+ EM_ASM
+ (
+ setTimeout(function()
+ {
+ Module.requestFullscreen(false, true);
+ setTimeout(function()
+ {
+ canvas.style.width="unset";
+ }, 100);
+ }, 100);
+ );
+ FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
+ }
+}
+
+// Set window state: maximized, if resizable
+void MaximizeWindow(void)
+{
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) && !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED))
+ {
+ const int tabWidth = EM_ASM_INT( return window.innerWidth; );
+ const int tabHeight = EM_ASM_INT( return window.innerHeight; );
+
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
+ }
+}
+
+// Set window state: minimized
+void MinimizeWindow(void)
+{
+ TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform");
+}
+
+// Restore window from being minimized/maximized
+void RestoreWindow(void)
+{
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) && FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED))
+ {
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
+ }
+}
+
+// Set window configuration state using flags
+void SetWindowState(unsigned int flags)
+{
+ if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
+
+ // Check previous state and requested state to apply required changes
+ // NOTE: In most cases the functions already change the flags internally
+
+ // State change: FLAG_VSYNC_HINT
+ if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_VSYNC_HINT) not available on target platform");
+ }
+
+ // State change: FLAG_BORDERLESS_WINDOWED_MODE
+ if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
+ {
+ // NOTE: Window state flag updated inside ToggleBorderlessWindowed() function
+ const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
+ if (wasFullscreen)
+ {
+ const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
+ const int canvasStyleWidth = EM_ASM_INT( { return parseInt(Module.canvas.style.width); }, 0);
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) || canvasStyleWidth > canvasWidth) ToggleBorderlessWindowed();
+ }
+ else ToggleBorderlessWindowed();
+ }
+
+ // State change: FLAG_FULLSCREEN_MODE
+ if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
+ {
+ // NOTE: Window state flag updated inside ToggleFullscreen() function
+ const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
+ if (wasFullscreen)
+ {
+ const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
+ const int screenWidth = EM_ASM_INT( { return screen.width; }, 0);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE) || (screenWidth == canvasWidth)) ToggleFullscreen();
+ }
+ else ToggleFullscreen();
+ }
+
+ // State change: FLAG_WINDOW_RESIZABLE
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)) && FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
+ {
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
+ }
+
+ // State change: FLAG_WINDOW_UNDECORATED
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_UNDECORATED) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_HIDDEN
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_HIDDEN) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_MINIMIZED
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MINIMIZED) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_MAXIMIZED
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED) != FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)) && FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
+ {
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE))
+ {
+ const int tabWidth = EM_ASM_INT( return window.innerWidth; );
+ const int tabHeight = EM_ASM_INT( return window.innerHeight; );
+
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
+ }
+ }
+
+ // State change: FLAG_WINDOW_UNFOCUSED
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_UNFOCUSED) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_TOPMOST
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_TOPMOST) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_ALWAYS_RUN
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_ALWAYS_RUN) not available on target platform");
+ }
+
+ // The following states can not be changed after window creation
+ // NOTE: Review for PLATFORM_WEB
+
+ // State change: FLAG_WINDOW_TRANSPARENT
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_TRANSPARENT) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_HIGHDPI
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_HIGHDPI) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MOUSE_PASSTHROUGH) not available on target platform");
+ }
+
+ // State change: FLAG_MSAA_4X_HINT
+ if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
+ {
+ TRACELOG(LOG_WARNING, "SetWindowState(FLAG_MSAA_4X_HINT) not available on target platform");
+ }
+
+ // State change: FLAG_INTERLACED_HINT
+ 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)
+{
+ // Check previous state and requested state to apply required changes
+ // NOTE: In most cases the functions already change the flags internally
+
+ // State change: FLAG_VSYNC_HINT
+ if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_VSYNC_HINT) not available on target platform");
+ }
+
+ // State change: FLAG_BORDERLESS_WINDOWED_MODE
+ if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
+ {
+ const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
+ if (wasFullscreen)
+ {
+ const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
+ const int screenWidth = EM_ASM_INT( { return screen.width; }, 0);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE) || (screenWidth == canvasWidth)) EM_ASM(document.exitFullscreen(););
+ }
+
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
+ }
+
+ // State change: FLAG_FULLSCREEN_MODE
+ if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
+ {
+ const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
+ if (wasFullscreen)
+ {
+ const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
+ const int canvasStyleWidth = EM_ASM_INT( { return parseInt(Module.canvas.style.width); }, 0);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE) || (canvasStyleWidth > canvasWidth)) EM_ASM(document.exitFullscreen(););
+ }
+
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ }
+
+ // State change: FLAG_WINDOW_RESIZABLE
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) && FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
+ {
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
+ }
+
+ // State change: FLAG_WINDOW_HIDDEN
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_HIDDEN) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_MINIMIZED
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MINIMIZED) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_MAXIMIZED
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED) && FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
+ {
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE))
+ {
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
+ }
+ }
+
+ // State change: FLAG_WINDOW_UNDECORATED
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_UNDECORATED) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_UNFOCUSED
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_UNFOCUSED) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_TOPMOST
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_TOPMOST) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_ALWAYS_RUN
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_ALWAYS_RUN) not available on target platform");
+ }
+
+ // The following states can not be changed after window creation
+ // NOTE: Review for PLATFORM_WEB
+
+ // State change: FLAG_WINDOW_TRANSPARENT
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_TRANSPARENT) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_HIGHDPI
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_HIGHDPI) not available on target platform");
+ }
+
+ // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MOUSE_PASSTHROUGH) not available on target platform");
+ }
+
+ // State change: FLAG_MSAA_4X_HINT
+ if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_MSAA_4X_HINT) not available on target platform");
+ }
+
+ // State change: FLAG_INTERLACED_HINT
+ if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
+ {
+ TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_INTERLACED_HINT) not available on target platform");
+ }
+}
+
+// Set icon for window
+void SetWindowIcon(Image image)
+{
+ TRACELOG(LOG_WARNING, "SetWindowIcon() not available on target platform");
+}
+
+// Set icon for window, multiple images
+void SetWindowIcons(Image *images, int count)
+{
+ TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform");
+}
+
+// Set title for window
+void SetWindowTitle(const char *title)
+{
+ CORE.Window.title = title;
+ emscripten_set_window_title(title);
+}
+
+// Set window position on screen (windowed mode)
+void SetWindowPosition(int x, int y)
+{
+ TRACELOG(LOG_WARNING, "SetWindowPosition() not available on target platform");
+}
+
+// Set monitor for the current window
+void SetWindowMonitor(int monitor)
+{
+ TRACELOG(LOG_WARNING, "SetWindowMonitor() not available on target platform");
+}
+
+// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
+void SetWindowMinSize(int width, int height)
+{
+ CORE.Window.screenMin.width = width;
+ CORE.Window.screenMin.height = height;
+
+ // Trigger the resize event once to update the window minimum width and height
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
+}
+
+// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
+void SetWindowMaxSize(int width, int height)
+{
+ CORE.Window.screenMax.width = width;
+ CORE.Window.screenMax.height = height;
+
+ // Trigger the resize event once to update the window maximum width and height
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
+}
+
+// Set window dimensions
+void SetWindowSize(int width, int height)
+{
+ // When resizing the canvas, several elements must be considered:
+ // - CSS canvas size: Web layout size, logical pixels
+ // - Canvas contained framebuffer resolution
+ // * Browser monitor, device pixel ratio (HighDPI)
+
+ double canvasCssWidth = 0.0;
+ double canvasCssHeight = 0.0;
+ emscripten_get_element_css_size(platform.canvasId, &canvasCssWidth, &canvasCssHeight);
+
+ // NOTE: emscripten_get_canvas_element_size() returns canvas framebuffer size, not CSS canvas size
+
+ // Get device pixel ratio
+ // TODO: Should DPI be considered at this point?
+ double dpr = emscripten_get_device_pixel_ratio();
+
+ // Set canvas framebuffer size
+ emscripten_set_canvas_element_size(platform.canvasId, width*dpr, height*dpr);
+
+ // Set canvas CSS size
+ // TODO: Consider canvas CSS style if already scaled 100%
+ EM_ASM({ Module.canvas.style.width = $0; }, width*dpr);
+ EM_ASM({ Module.canvas.style.height = $0; }, height*dpr);
+
+ SetupViewport(width*dpr, height*dpr); // Reset viewport and projection matrix for new size
+}
+
+// Set window opacity, value opacity is between 0.0 and 1.0
+void SetWindowOpacity(float opacity)
+{
+ if (opacity >= 1.0f) opacity = 1.0f;
+ else if (opacity <= 0.0f) opacity = 0.0f;
+
+ EM_ASM({ Module.canvas.style.opacity = $0; }, opacity);
+}
+
+// Set window focused
+void SetWindowFocused(void)
+{
+ TRACELOG(LOG_WARNING, "SetWindowFocused() not available on target platform");
+}
+
+// Get native window handle
+void *GetWindowHandle(void)
+{
+ TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform");
+ return NULL;
+}
+
+// Get number of monitors
+int GetMonitorCount(void)
+{
+ TRACELOG(LOG_WARNING, "GetMonitorCount() not implemented on target platform");
+ return 1;
+}
+
+// Get current monitor where window is placed
+int GetCurrentMonitor(void)
+{
+ TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform");
+ return 0;
+}
+
+// Get selected monitor position
+Vector2 GetMonitorPosition(int monitor)
+{
+ TRACELOG(LOG_WARNING, "GetMonitorPosition() not implemented on target platform");
+ return (Vector2){ 0, 0 };
+}
+
+// Get selected monitor width (currently used by monitor)
+int GetMonitorWidth(int monitor)
+{
+ // Get the width of the user's entire screen in CSS logical pixels,
+ // no physical pixels, it would require multiplying by device pixel ratio
+ // NOTE: Returned value is limited to the current monitor where the browser window is located
+ int width = 0;
+ width = EM_ASM_INT( { return window.screen.width; }, 0);
+ return width;
+}
+
+// Get selected monitor height (currently used by monitor)
+int GetMonitorHeight(int monitor)
+{
+ // Get the height of the user's entire screen in CSS logical pixels,
+ // no physical pixels, it would require multiplying by device pixel ratio
+ // NOTE: Returned value is limited to the current monitor where the browser window is located
+ int height = 0;
+ height = EM_ASM_INT( { return window.screen.height; }, 0);
+ return height;
+}
+
+// Get selected monitor physical width in millimetres
+int GetMonitorPhysicalWidth(int monitor)
+{
+ TRACELOG(LOG_WARNING, "GetMonitorPhysicalWidth() not implemented on target platform");
+ return 0;
+}
+
+// Get selected monitor physical height in millimetres
+int GetMonitorPhysicalHeight(int monitor)
+{
+ TRACELOG(LOG_WARNING, "GetMonitorPhysicalHeight() not implemented on target platform");
+ return 0;
+}
+
+// Get selected monitor refresh rate
+int GetMonitorRefreshRate(int monitor)
+{
+ TRACELOG(LOG_WARNING, "GetMonitorRefreshRate() not implemented on target platform");
+ return 0;
+}
+
+// Get the human-readable, UTF-8 encoded name of the selected monitor
+const char *GetMonitorName(int monitor)
+{
+ TRACELOG(LOG_WARNING, "GetMonitorName() not implemented on target platform");
+ return "";
+}
+
+// Get window position XY on monitor
+Vector2 GetWindowPosition(void)
+{
+ // Browser window position, top-left corner relative to the physical screen origin, expressed in CSS logical pixels
+ // NOTE: Returned position is relative to the current monitor where the browser window is located
+ Vector2 position = { 0, 0 };
+ position.x = (float)EM_ASM_INT( { return window.screenX; }, 0);
+ position.y = (float)EM_ASM_INT( { return window.screenY; }, 0);
+ return position;
+}
+
+// Get current monitor device pixel ratio
+Vector2 GetWindowScaleDPI(void)
+{
+ // Get device pixel ratio
+ // NOTE: Returned scale is relative to the current monitor where the browser window is located
+ Vector2 scale = { 1.0f, 1.0f };
+ scale.x = (float)EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
+ scale.y = scale.x;
+ return scale;
+}
+
+// Set clipboard text content
+void SetClipboardText(const char *text)
+{
+ // Security check to (partially) avoid malicious code
+ if (strchr(text, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided Clipboard could be potentially malicious, avoid [\'] character");
+ else EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
+}
+
+// Get clipboard text content
+// NOTE: returned string is allocated and freed by GLFW
+const char *GetClipboardText(void)
+{
+/*
+ // Accessing clipboard data from browser is tricky due to security reasons
+ // The method to use is navigator.clipboard.readText() but this is an asynchronous method
+ // that will return at some moment after the function is called with the required data
+ emscripten_run_script_string("navigator.clipboard.readText() \
+ .then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
+ .catch(err => { console.error('Failed to read clipboard contents: ', err); });"
+ );
+
+ // The main issue is getting that data, one approach could be using ASYNCIFY and wait
+ // for the data but it requires adding Asyncify emscripten library on compilation
+
+ // Another approach could be just copy the data in a HTML text field and try to retrieve it
+ // later on if available... and clean it for future accesses
+*/
+ return NULL;
+}
+
+// Get clipboard image
+Image GetClipboardImage(void)
+{
+ Image image = { 0 };
+
+ // NOTE: In theory, the new navigator.clipboard.read() can be used to return arbitrary data from clipboard (2024)
+ // REF: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/read
+ TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
+
+ return image;
+}
+
+// Show mouse cursor
+void ShowCursor(void)
+{
+ if (CORE.Input.Mouse.cursorHidden)
+ {
+ EM_ASM( { Module.canvas.style.cursor = UTF8ToString($0); }, cursorLUT[CORE.Input.Mouse.cursor]);
+
+ CORE.Input.Mouse.cursorHidden = false;
+ }
+}
+
+// Hides mouse cursor
+void HideCursor(void)
+{
+ if (!CORE.Input.Mouse.cursorHidden)
+ {
+ EM_ASM(Module.canvas.style.cursor = 'none';);
+
+ CORE.Input.Mouse.cursorHidden = true;
+ }
+}
+
+// Enables cursor (unlock cursor)
+void EnableCursor(void)
+{
+ emscripten_exit_pointerlock();
+
+ // Set cursor position in the middle
+ SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
+
+ // NOTE: CORE.Input.Mouse.cursorLocked handled by EmscriptenPointerlockCallback()
+}
+
+// Disables cursor (lock cursor)
+void DisableCursor(void)
+{
+ emscripten_request_pointerlock(platform.canvasId, 1);
+
+ // Set cursor position in the middle
+ SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
+
+ // NOTE: CORE.Input.Mouse.cursorLocked handled by EmscriptenPointerlockCallback()
+}
+
+// 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 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);
+#endif
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Misc
+//----------------------------------------------------------------------------------
+
+// Get elapsed time measure in seconds since InitTimer()
+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()
+ */
+ time = emscripten_get_now()*1000.0;
+
+ return time;
+}
+
+// Open URL with default system browser (if available)
+// 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
+void OpenURL(const char *url)
+{
+ // Security check to (partially) avoid malicious code on target platform
+ if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
+ else emscripten_run_script(TextFormat("window.open('%s', '_blank')", url));
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Inputs
+//----------------------------------------------------------------------------------
+
+// Set internal gamepad mappings
+int SetGamepadMappings(const char *mappings)
+{
+ TRACELOG(LOG_INFO, "SetGamepadMappings not implemented in rcore_web.c");
+
+ return 0;
+}
+
+// Set gamepad vibration
+void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
+{
+ if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (duration > 0.0f))
+ {
+ if (leftMotor < 0.0f) leftMotor = 0.0f;
+ if (leftMotor > 1.0f) leftMotor = 1.0f;
+ if (rightMotor < 0.0f) rightMotor = 0.0f;
+ if (rightMotor > 1.0f) rightMotor = 1.0f;
+ if (duration > MAX_GAMEPAD_VIBRATION_TIME) duration = MAX_GAMEPAD_VIBRATION_TIME;
+ duration *= 1000.0f; // Convert duration to ms
+
+ // NOTE: [2024.10.21] Current browser support:
+ // - vibrationActuator API: Chrome, Edge, Opera, Safari, Android Chrome, Android Webview
+ // - hapticActuators API: Firefox
+ EM_ASM({
+ try { navigator.getGamepads()[$0].vibrationActuator.playEffect('dual-rumble', { startDelay: 0, duration: $3, weakMagnitude: $1, strongMagnitude: $2 }); }
+ catch (e)
+ {
+ try { navigator.getGamepads()[$0].hapticActuators[0].pulse($2, $3); }
+ catch (e) { }
+ }
+ }, gamepad, leftMotor, rightMotor, duration);
+ }
+}
+
+// Set mouse position XY
+void SetMousePosition(int x, int y)
+{
+ // WARNING: Not supported by browser for security reasons
+}
+
+// Set mouse cursor
+void SetMouseCursor(int cursor)
+{
+ if (CORE.Input.Mouse.cursor != cursor)
+ {
+ if (!CORE.Input.Mouse.cursorLocked) EM_ASM( { Module.canvas.style.cursor = UTF8ToString($0); }, cursorLUT[cursor]);
+ CORE.Input.Mouse.cursor = cursor;
+ }
+}
+
+// Get physical key name
+const char *GetKeyName(int key)
+{
+ // TODO: Browser can definitely provide a key name e->key
+ TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
+ return "";
+}
+
+// Register all input events
+void PollInputEvents(void)
+{
+#if defined(SUPPORT_GESTURES_SYSTEM)
+ // NOTE: Gestures update must be called every frame to reset gestures correctly
+ // because ProcessGestureEvent() is just called on an event, not every frame
+ UpdateGestures();
+#endif
+
+ // Reset keys/chars pressed registered
+ CORE.Input.Keyboard.keyPressedQueueCount = 0;
+ CORE.Input.Keyboard.charPressedQueueCount = 0;
+
+ // Reset last gamepad button/axis registered state
+ CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
+ //CORE.Input.Gamepad.axisCount = 0;
+
+ // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback)
+
+ // Register previous keys states
+ for (int i = 0; i < MAX_KEYBOARD_KEYS; i++)
+ {
+ CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
+ CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
+ }
+
+ // Register previous mouse states
+ for (int i = 0; i < MAX_MOUSE_BUTTONS; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i];
+
+ // Register previous mouse wheel state
+ CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove;
+ CORE.Input.Mouse.currentWheelMove = (Vector2){ 0.0f, 0.0f };
+
+ // Register previous mouse position
+ CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+
+ // Register previous touch states
+ for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i];
+
+ // Reset touch positions
+ // TODO: It resets on target platform the mouse position and not filled again until a move-event,
+ // so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed!
+ //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 };
+
+ // Get number of gamepads connected
+ int numGamepads = 0;
+ if (emscripten_sample_gamepad_data() == EMSCRIPTEN_RESULT_SUCCESS) numGamepads = emscripten_get_num_gamepads();
+
+ for (int i = 0; (i < numGamepads) && (i < MAX_GAMEPADS); i++)
+ {
+ // Register previous gamepad button states
+ for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
+
+ EmscriptenGamepadEvent gamepadState = { 0 };
+ int result = emscripten_get_gamepad_status(i, &gamepadState);
+
+ if (result == EMSCRIPTEN_RESULT_SUCCESS)
+ {
+ // Register buttons data for every connected gamepad
+ for (int j = 0; (j < gamepadState.numButtons) && (j < MAX_GAMEPAD_BUTTONS); j++)
+ {
+ GamepadButton button = -1;
+
+ // Gamepad Buttons reference: https://www.w3.org/TR/gamepad/#gamepad-interface
+ switch (j)
+ {
+ case 0: button = GAMEPAD_BUTTON_RIGHT_FACE_DOWN; break;
+ case 1: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
+ case 2: button = GAMEPAD_BUTTON_RIGHT_FACE_LEFT; break;
+ case 3: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
+ case 4: button = GAMEPAD_BUTTON_LEFT_TRIGGER_1; break;
+ case 5: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_1; break;
+ case 6: button = GAMEPAD_BUTTON_LEFT_TRIGGER_2; break;
+ case 7: button = GAMEPAD_BUTTON_RIGHT_TRIGGER_2; break;
+ case 8: button = GAMEPAD_BUTTON_MIDDLE_LEFT; break;
+ case 9: button = GAMEPAD_BUTTON_MIDDLE_RIGHT; break;
+ case 10: button = GAMEPAD_BUTTON_LEFT_THUMB; break;
+ case 11: button = GAMEPAD_BUTTON_RIGHT_THUMB; break;
+ case 12: button = GAMEPAD_BUTTON_LEFT_FACE_UP; break;
+ case 13: button = GAMEPAD_BUTTON_LEFT_FACE_DOWN; break;
+ case 14: button = GAMEPAD_BUTTON_LEFT_FACE_LEFT; break;
+ case 15: button = GAMEPAD_BUTTON_LEFT_FACE_RIGHT; break;
+ default: break;
+ }
+
+ if (button + 1 != 0) // Check for valid button
+ {
+ if (gamepadState.digitalButton[j] == 1)
+ {
+ CORE.Input.Gamepad.currentButtonState[i][button] = 1;
+ CORE.Input.Gamepad.lastButtonPressed = button;
+ }
+ else CORE.Input.Gamepad.currentButtonState[i][button] = 0;
+ }
+
+ //TRACELOG(LOG_DEBUG, "INPUT: Gamepad %d, button %d: Digital: %d, Analog: %g", gamepadState.index, j, gamepadState.digitalButton[j], gamepadState.analogButton[j]);
+ }
+
+ // Register axis data for every connected gamepad
+ for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXES); j++)
+ {
+ CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j];
+ }
+
+ CORE.Input.Gamepad.axisCount[i] = gamepadState.numAxes;
+ }
+ }
+
+ CORE.Window.resizedLastFrame = false;
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+
+// Initialize platform: graphics, inputs and more
+int InitPlatform(void)
+{
+ SetCanvasIdJs(platform.canvasId, 64); // Get the current canvas id
+
+ // Initialize graphic device: display/window and graphic context
+ //----------------------------------------------------------------------------
+ emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height);
+ EmscriptenWebGLContextAttributes attribs = { 0 };
+ emscripten_webgl_init_context_attributes(&attribs);
+ attribs.alpha = EM_TRUE;
+ attribs.depth = EM_TRUE;
+ attribs.stencil = EM_FALSE;
+ attribs.antialias = EM_FALSE;
+
+ // Check window creation flags
+ // Disable FLAG_WINDOW_MINIMIZED, not supported
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
+
+ // Disable FLAG_WINDOW_MAXIMIZED, not supported
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
+
+ // Disable FLAG_WINDOW_TOPMOST, not supported
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_TOPMOST);
+
+ // NOTE: Some other flags are not supported on HTML5
+
+ // TODO: Scale content area based on the monitor content scale where window is placed on
+
+ // Request MSAA (usually x4 on WebGL 1.0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) attribs.antialias = EM_TRUE;
+
+ // Check selection OpenGL version
+ if (rlGetVersion() == RL_OPENGL_11_SOFTWARE)
+ {
+ // Avoid creating a WebGL canvas, create 2d canvas for software rendering
+ emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height);
+ EM_ASM({
+ const canvas = document.getElementById(platform.canvasId);
+ Module.canvas = canvas;
+ });
+
+ // Load memory framebuffer with desired screen size
+ platform.pixels = (unsigned int *)RL_CALLOC(CORE.Window.screen.width*CORE.Window.screen.height, sizeof(unsigned int));
+ }
+ else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context --> WebGL 1.0
+ {
+ attribs.majorVersion = 1; // WebGL 1.0 requested
+ attribs.minorVersion = 0;
+
+ // Create WebGL context
+ platform.glContext = emscripten_webgl_create_context(platform.canvasId, &attribs);
+ if (platform.glContext == 0) return 0;
+
+ emscripten_webgl_make_context_current(platform.glContext);
+ }
+ else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context --> WebGL 2.0
+ {
+ attribs.majorVersion = 2; // WebGL 2.0 requested
+ attribs.minorVersion = 0;
+
+ // Create WebGL context
+ platform.glContext = emscripten_webgl_create_context(platform.canvasId, &attribs);
+ if (platform.glContext == 0) return 0;
+
+ emscripten_webgl_make_context_current(platform.glContext);
+ }
+
+ // NOTE: Getting video modes is not implemented in emscripten GLFW3 version
+ CORE.Window.display.width = CORE.Window.screen.width;
+ CORE.Window.display.height = CORE.Window.screen.height;
+ CORE.Window.render.width = CORE.Window.screen.width;
+ CORE.Window.render.height = CORE.Window.screen.height;
+
+ // Set default window title
+ emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " ");
+
+ // Check context activation
+ if ((platform.glContext != 0) || (platform.pixels != NULL))
+ {
+ CORE.Window.ready = true;
+
+ int fbWidth = CORE.Window.screen.width;
+ int fbHeight = CORE.Window.screen.height;
+
+ CORE.Window.render.width = fbWidth;
+ CORE.Window.render.height = fbHeight;
+ CORE.Window.currentFbo.width = fbWidth;
+ CORE.Window.currentFbo.height = fbHeight;
+
+ TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
+ TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
+ TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height);
+ TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
+ TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
+ }
+ else
+ {
+ TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
+ return -1;
+ }
+
+ // Load OpenGL extensions
+ // NOTE: GL procedures address loader is required to load extensions
+ if (platform.glContext != 0) rlLoadExtensions(emscripten_webgl_get_proc_address);
+ //----------------------------------------------------------------------------
+
+ // Initialize events callbacks
+ //----------------------------------------------------------------------------
+ // Setup window/canvas events callbacks
+ emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenFullscreenChangeCallback);
+ emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
+ emscripten_set_blur_callback(platform.canvasId, NULL, 1, EmscriptenFocusCallback);
+ emscripten_set_focus_callback(platform.canvasId, NULL, 1, EmscriptenFocusCallback);
+ emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback);
+
+ // Setup input events
+ emscripten_set_keypress_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback);
+ emscripten_set_keydown_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback);
+ emscripten_set_keyup_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback);
+
+ emscripten_set_click_callback(platform.canvasId, NULL, 1, EmscriptenMouseCallback);
+ //emscripten_set_dblclick_callback(platform.canvasId, NULL, 1, EmscriptenMouseCallback);
+ emscripten_set_mousedown_callback(platform.canvasId, NULL, 1, EmscriptenMouseCallback);
+ emscripten_set_mouseup_callback(platform.canvasId, NULL, 1, EmscriptenMouseCallback);
+ emscripten_set_mousemove_callback(platform.canvasId, NULL, 1, EmscriptenMouseCallback);
+ emscripten_set_mousemove_callback(platform.canvasId, NULL, 1, EmscriptenMouseMoveCallback);
+ emscripten_set_wheel_callback(platform.canvasId, NULL, 1, EmscriptenMouseWheelCallback);
+ emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenPointerlockCallback);
+
+ 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);
+
+ // Trigger resize callback to force initial size
+ EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
+ //----------------------------------------------------------------------------
+
+ // Initialize timing system
+ //----------------------------------------------------------------------------
+ InitTimer();
+ //----------------------------------------------------------------------------
+
+ // Initialize storage system
+ //----------------------------------------------------------------------------
+ CORE.Storage.basePath = GetWorkingDirectory();
+ //----------------------------------------------------------------------------
+
+ TRACELOG(LOG_INFO, "PLATFORM: WEB: Initialized successfully");
+
+ return 0;
+}
+
+// Close platform
+// NOTE: Platform closing is managed by browser, so,
+// this function is actually not required, but still
+// implementing some logic behaviour
+void ClosePlatform(void)
+{
+ if (platform.pixels != NULL) RL_FREE(platform.pixels);
+ if (platform.glContext != 0) emscripten_webgl_destroy_context(platform.glContext);
+}
+
+// Emscripten callback functions, called on specific browser events
+//-------------------------------------------------------------------------------------------------------
+// Emscripten: Called on resize event
+static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
+{
+ // Don't resize non-resizeable windows
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) return 1;
+/*
+ // Set current screen size
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+ {
+ Vector2 windowScaleDPI = GetWindowScaleDPI();
+
+ CORE.Window.screen.width = (unsigned int)(width/windowScaleDPI.x);
+ CORE.Window.screen.height = (unsigned int)(height/windowScaleDPI.y);
+ }
+ else
+ {
+ CORE.Window.screen.width = width;
+ CORE.Window.screen.height = height;
+ }
+*/
+ // This event is called whenever the window changes sizes,
+ // so the size of the canvas object is explicitly retrieved below
+ int width = EM_ASM_INT( return window.innerWidth; );
+ int height = EM_ASM_INT( return window.innerHeight; );
+
+ if (width < (int)CORE.Window.screenMin.width) width = CORE.Window.screenMin.width;
+ else if ((width > (int)CORE.Window.screenMax.width) && (CORE.Window.screenMax.width > 0)) width = CORE.Window.screenMax.width;
+
+ 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(platform.canvasId, width, height);
+
+ SetupViewport(width, height); // Reset viewport and projection matrix for new size
+
+ CORE.Window.currentFbo.width = width;
+ CORE.Window.currentFbo.height = height;
+ CORE.Window.resizedLastFrame = true;
+
+ if (IsWindowFullscreen()) return 1;
+
+ // Set current screen size
+ CORE.Window.screen.width = width;
+ CORE.Window.screen.height = height;
+
+ // NOTE: Postprocessing texture is not scaled to new size
+
+ return 0;
+}
+
+// Emscripten: Called on windows focus change events
+static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)
+{
+ EM_BOOL consumed = 1;
+
+ switch (eventType)
+ {
+ case EMSCRIPTEN_EVENT_BLUR: FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); break; // The canvas lost focus
+ case EMSCRIPTEN_EVENT_FOCUS: FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); break;
+ default: consumed = 0; break;
+ }
+
+ return consumed;
+}
+
+// Emscripten: Called on visibility change events
+static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)
+{
+ if (visibilityChangeEvent->hidden) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // The window was hidden
+ else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // The window was restored
+
+ return 1; // The event was consumed by the callback handler
+}
+
+// Emscripten: Called on fullscreen change events
+// TODO: Review fullscreen strategy
+static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData)
+{
+ // NOTE: Reset the fullscreen flags if the user left fullscreen manually by pressing the Escape key
+ const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
+ if (!wasFullscreen)
+ {
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
+ }
+
+ return 1; // The event was consumed by the callback handler
+}
+
+/*
+// GLFW3: Called on file-drop over the window
+// TODO: Implement Emscripten (or HTML5/JS) alternative
+static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
+{
+ if (count > 0)
+ {
+ // In case previous dropped filepaths have not been freed, we free them
+ if (CORE.Window.dropFileCount > 0)
+ {
+ for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) RL_FREE(CORE.Window.dropFilepaths[i]);
+
+ RL_FREE(CORE.Window.dropFilepaths);
+
+ CORE.Window.dropFileCount = 0;
+ CORE.Window.dropFilepaths = NULL;
+ }
+
+ // WARNING: Paths are freed by GLFW when the callback returns, we must keep an internal copy
+ CORE.Window.dropFileCount = count;
+ CORE.Window.dropFilepaths = (char **)RL_CALLOC(CORE.Window.dropFileCount, sizeof(char *));
+
+ for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++)
+ {
+ CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
+ strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1);
+ }
+ }
+}
+*/
+
+// Emscripten: Called on key events
+// TODO: keyCodes should be mapped to raylib/GLFW3 Key values
+static EM_BOOL EmscriptenKeyboardCallback(int eventType, const EmscriptenKeyboardEvent *keyboardEvent, void *userData)
+{
+ switch (eventType)
+ {
+ case EMSCRIPTEN_EVENT_KEYPRESS:
+ {
+ if (keyboardEvent->repeat) CORE.Input.Keyboard.keyRepeatInFrame[keyboardEvent->keyCode] = 1;
+ } break;
+ case EMSCRIPTEN_EVENT_KEYDOWN:
+ {
+ CORE.Input.Keyboard.currentKeyState[keyboardEvent->keyCode] = 1;
+ } break;
+ case EMSCRIPTEN_EVENT_KEYUP:
+ {
+ CORE.Input.Keyboard.currentKeyState[keyboardEvent->keyCode] = 0;
+ } break;
+ default: break;
+ }
+
+ // TODO: Add char codes
+ //unsigned int charCode
+ // Check if there is space available in the queue for characters to be added
+ /*
+ if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
+ {
+ // Add character to the queue
+ CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = keyboardEvent->charCode;
+ CORE.Input.Keyboard.charPressedQueueCount++;
+ }
+ */
+ /*
+ // Check if there is space available in the key queue
+ if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (eventType == EMSCRIPTEN_EVENT_KEYPRESS))
+ {
+ // Add character to the queue
+ CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keyboardEvent->keyCode;
+ CORE.Input.Keyboard.keyPressedQueueCount++;
+ }
+
+ // Check the exit key to set close window
+ //if ((keyboardEvent->keyCode == CORE.Input.Keyboard.exitKey) && (eventType == EMSCRIPTEN_EVENT_KEYPRESS)) CORE.Window.shouldClose = true;
+ */
+
+ return 1; // The event was consumed by the callback handler
+}
+
+// Emscripten: Called on mouse input events
+static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
+{
+ switch (eventType)
+ {
+ case EMSCRIPTEN_EVENT_MOUSEENTER: CORE.Input.Mouse.cursorOnScreen = true; break;
+ case EMSCRIPTEN_EVENT_MOUSELEAVE: CORE.Input.Mouse.cursorOnScreen = false; break;
+ case EMSCRIPTEN_EVENT_MOUSEDOWN:
+ {
+ // NOTE: Emscripten and raylib buttons indices are not aligned
+ if (mouseEvent->button == 0) CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_LEFT] = 1;
+ else if (mouseEvent->button == 1) CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_MIDDLE] = 1;
+ else if (mouseEvent->button == 2) CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_RIGHT] = 1;
+
+ //CORE.Input.Touch.currentTouchState[button] = action;
+ } break;
+ case EMSCRIPTEN_EVENT_MOUSEUP:
+ {
+ if (mouseEvent->button == 0) CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_LEFT] = 0;
+ else if (mouseEvent->button == 1) CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_MIDDLE] = 0;
+ else if (mouseEvent->button == 2) CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_RIGHT] = 0;
+ } break;
+ default: break;
+ }
+
+#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
+ // Process mouse events as touches to be able to use mouse-gestures
+ GestureEvent gestureEvent = { 0 };
+
+ // Register touch actions
+ if ((CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_LEFT] == 1) && (CORE.Input.Mouse.previousButtonState[MOUSE_BUTTON_LEFT] == 0)) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
+ else if ((CORE.Input.Mouse.currentButtonState[MOUSE_BUTTON_LEFT] == 0) && (CORE.Input.Mouse.previousButtonState[MOUSE_BUTTON_LEFT] == 1)) gestureEvent.touchAction = TOUCH_ACTION_UP;
+
+ // NOTE: TOUCH_ACTION_MOVE event is registered in MouseMoveCallback()
+
+ // Assign a pointer ID
+ gestureEvent.pointId[0] = 0;
+
+ // Register touch points count
+ gestureEvent.pointCount = 1;
+
+ // Register touch points position, only one point registered
+ gestureEvent.position[0] = GetMousePosition();
+
+ // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+
+ // Gesture data is sent to gestures-system for processing
+ // Prevent calling ProcessGestureEvent() when Emscripten is present and there's a touch gesture, so EmscriptenTouchCallback() can handle it itself
+ if (GetMouseX() != 0 || GetMouseY() != 0) ProcessGestureEvent(gestureEvent);
+#endif
+
+ return 1; // The event was consumed by the callback handler
+}
+
+// Emscripten: Called on mouse move events
+static EM_BOOL EmscriptenMouseMoveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
+{
+ if (CORE.Input.Mouse.cursorLocked)
+ {
+ CORE.Input.Mouse.previousPosition.x = CORE.Input.Mouse.lockedPosition.x - mouseEvent->movementX;
+ CORE.Input.Mouse.previousPosition.y = CORE.Input.Mouse.lockedPosition.y - mouseEvent->movementY;
+ }
+ else
+ {
+ // Get mouse position in canvas CSS pixels
+ float mouseCssX = (float)mouseEvent->canvasX;
+ float mouseCssY = (float)mouseEvent->canvasY;
+
+ // Get canvas sizes
+ double cssWidth = 0.0;
+ double cssHeight = 0.0;
+ emscripten_get_element_css_size(platform.canvasId, &cssWidth, &cssHeight);
+
+ int fbWidth = 0;
+ int fbHeight = 0;
+ emscripten_get_canvas_element_size(platform.canvasId, &fbWidth, &fbHeight);
+
+ // Convert CSS to framebuffer coordinates
+ float scaleX = (float)fbWidth/(float)cssWidth;
+ float scaleY = (float)fbHeight/(float)cssHeight;
+
+ int mouseX = (int)(mouseCssX*scaleX);
+ int mouseY = (int)(mouseCssY*scaleY);
+
+ CORE.Input.Mouse.currentPosition.x = mouseX;//(float)mouseEvent->canvasX;
+ CORE.Input.Mouse.currentPosition.y = mouseY;//(float)mouseEvent->canvasY;
+
+ // Shorter alternative:
+ //double dpr = emscripten_get_device_pixel_ratio();
+ //int mouseX = (int)(e->canvasX*dpr);
+ //int mouseY = (int)(e->canvasY*dpr);
+
+ CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
+ }
+
+#if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES)
+ // Process mouse events as touches to be able to use mouse-gestures
+ GestureEvent gestureEvent = { 0 };
+
+ gestureEvent.touchAction = TOUCH_ACTION_MOVE;
+
+ // Assign a pointer ID
+ gestureEvent.pointId[0] = 0;
+
+ // Register touch points count
+ gestureEvent.pointCount = 1;
+
+ // Register touch points position, only one point registered
+ gestureEvent.position[0] = CORE.Input.Touch.position[0];
+
+ // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+
+ // Gesture data is sent to gestures-system for processing
+ ProcessGestureEvent(gestureEvent);
+#endif
+
+ return 1; // The event was consumed by the callback handler
+}
+
+// Emscripten: Called on mouse wheel events
+static EM_BOOL EmscriptenMouseWheelCallback(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
+{
+ if (eventType == EMSCRIPTEN_EVENT_WHEEL)
+ {
+ CORE.Input.Mouse.currentWheelMove.x = (float)wheelEvent->deltaX;
+ CORE.Input.Mouse.currentWheelMove.y = (float)wheelEvent->deltaY;
+ }
+
+ return 1; // The event was consumed by the callback handler
+}
+
+// Emscripten: Called on pointer lock events
+static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData)
+{
+ CORE.Input.Mouse.cursorLocked = EM_ASM_INT( { if (document.pointerLockElement) return 1; }, 0);
+
+ if (CORE.Input.Mouse.cursorLocked)
+ {
+ CORE.Input.Mouse.lockedPosition = CORE.Input.Mouse.currentPosition;
+ CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.lockedPosition;
+ }
+
+ return 1; // The event was consumed by the callback handler
+}
+
+// Emscripten: Called on connect/disconnect gamepads events
+static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
+{
+ /*
+ TRACELOG(LOG_DEBUG, "%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"",
+ eventType != 0? emscripten_event_type_to_string(eventType) : "Gamepad state",
+ gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
+
+ for (int i = 0; i < gamepadEvent->numAxes; i++) TRACELOG(LOG_DEBUG, "Axis %d: %g", i, gamepadEvent->axis[i]);
+ for (int i = 0; i < gamepadEvent->numButtons; i++) TRACELOG(LOG_DEBUG, "Button %d: Digital: %d, Analog: %g", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
+ */
+
+ if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
+ {
+ CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
+ snprintf(CORE.Input.Gamepad.name[gamepadEvent->index], MAX_GAMEPAD_NAME_LENGTH, "%s", gamepadEvent->id);
+ }
+ else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
+
+ return 1; // The event was consumed by the callback handler
+}
+
+// Emscripten: Called on touch input events
+static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
+{
+ // Register touch points count
+ CORE.Input.Touch.pointCount = touchEvent->numTouches;
+
+ double canvasWidth = 0.0;
+ double canvasHeight = 0.0;
+ // NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
+ // we are looking for actual CSS size: canvas.style.width and canvas.style.height
+ // EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
+ emscripten_get_element_css_size(platform.canvasId, &canvasWidth, &canvasHeight);
+
+ for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
+ {
+ // Register touch points id
+ CORE.Input.Touch.pointId[i] = touchEvent->touches[i].identifier;
+
+ // Register touch points position
+ CORE.Input.Touch.position[i] = (Vector2){touchEvent->touches[i].targetX, touchEvent->touches[i].targetY};
+
+ // Normalize gestureEvent.position[x] for CORE.Window.screen.width and CORE.Window.screen.height
+ CORE.Input.Touch.position[i].x *= ((float)GetScreenWidth()/(float)canvasWidth);
+ CORE.Input.Touch.position[i].y *= ((float)GetScreenHeight()/(float)canvasHeight);
+
+ if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1;
+ else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
+ }
+
+ // Update mouse position if we detect a single touch
+ if (CORE.Input.Touch.pointCount == 1)
+ {
+ CORE.Input.Mouse.currentPosition.x = CORE.Input.Touch.position[0].x;
+ CORE.Input.Mouse.currentPosition.y = CORE.Input.Touch.position[0].y;
+ }
+
+#if defined(SUPPORT_GESTURES_SYSTEM)
+ GestureEvent gestureEvent = { 0 };
+ gestureEvent.pointCount = CORE.Input.Touch.pointCount;
+
+ // Register touch actions
+ if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_ACTION_DOWN;
+ else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_ACTION_UP;
+ else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_ACTION_MOVE;
+ else if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) gestureEvent.touchAction = TOUCH_ACTION_CANCEL;
+
+ for (int i = 0; (i < gestureEvent.pointCount) && (i < MAX_TOUCH_POINTS); i++)
+ {
+ gestureEvent.pointId[i] = CORE.Input.Touch.pointId[i];
+ gestureEvent.position[i] = CORE.Input.Touch.position[i];
+
+ // Normalize gestureEvent.position[i]
+ gestureEvent.position[i].x /= (float)GetScreenWidth();
+ gestureEvent.position[i].y /= (float)GetScreenHeight();
+ }
+
+ // Gesture data is sent to gestures system for processing
+ ProcessGestureEvent(gestureEvent);
+#endif
+
+ if (eventType == EMSCRIPTEN_EVENT_TOUCHEND)
+ {
+ // Identify the EMSCRIPTEN_EVENT_TOUCHEND and remove it from the list
+ for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
+ {
+ if (touchEvent->touches[i].isChanged)
+ {
+ // Move all touch points one position up
+ for (int j = i; j < CORE.Input.Touch.pointCount - 1; j++)
+ {
+ CORE.Input.Touch.pointId[j] = CORE.Input.Touch.pointId[j + 1];
+ CORE.Input.Touch.position[j] = CORE.Input.Touch.position[j + 1];
+ }
+ // Decrease touch points count to remove the last one
+ CORE.Input.Touch.pointCount--;
+ break;
+ }
+ }
+ // Clamp pointCount to avoid negative values
+ if (CORE.Input.Touch.pointCount < 0) CORE.Input.Touch.pointCount = 0;
+ }
+
+ return 1; // The event was consumed by the callback handler
+}
+//-------------------------------------------------------------------------------------------------------
+
+// EOF
diff --git a/src/raudio.c b/src/raudio.c
index c65aaa134..18f9e0aad 100644
--- a/src/raudio.c
+++ b/src/raudio.c
@@ -50,7 +50,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -74,11 +74,7 @@
#else
#include "raylib.h" // Declares module functions
- // Check if config flags have been externally provided on compilation line
- #if !defined(EXTERNAL_CONFIG_FLAGS)
- #include "config.h" // Defines module configuration flags
- #endif
- #include "utils.h" // Required for: fopen() Android mapping
+ #include "config.h" // Defines module configuration flags
#endif
#if defined(SUPPORT_MODULE_RAUDIO) || defined(RAUDIO_STANDALONE)
@@ -1134,7 +1130,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
- byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n");
+ byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2026 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
byteCount += sprintf(txtData + byteCount, "//////////////////////////////////////////////////////////////////////////////////\n\n");
@@ -1249,7 +1245,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate);
if (frameCount == 0)
{
- RL_FREE(wave->data);
+ RL_FREE(data);
TRACELOG(LOG_WARNING, "WAVE: Failed format conversion");
return;
}
@@ -2743,9 +2739,9 @@ static const char *GetFileExtension(const char *fileName)
static const char *strprbrk(const char *text, const char *charset)
{
const char *latestMatch = NULL;
-
+
for (; (text != NULL) && (text = strpbrk(text, charset)); latestMatch = text++) { }
-
+
return latestMatch;
}
diff --git a/src/raylib.h b/src/raylib.h
index ba80e40c7..177138dc9 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -62,7 +62,7 @@
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software:
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -570,8 +570,7 @@ typedef enum {
} TraceLogLevel;
// Keyboard keys (US keyboard layout)
-// NOTE: Use GetKeyPressed() to allow redefining
-// required keys for alternative layouts
+// NOTE: Use GetKeyPressed() to allow redefining required keys for alternative layouts
typedef enum {
KEY_NULL = 0, // Key: NULL, used for no key pressed
// Alphanumeric keys
@@ -1075,47 +1074,41 @@ RLAPI Matrix GetCameraMatrix(Camera camera); // Get c
RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix
// Timing-related functions
-RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
-RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time)
-RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow()
-RLAPI int GetFPS(void); // Get current FPS
+RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
+RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time)
+RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow()
+RLAPI int GetFPS(void); // Get current FPS
// Custom frame control functions
// NOTE: Those functions are intended for advanced users that want full control over the frame processing
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
-RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing)
-RLAPI void PollInputEvents(void); // Register all input events
-RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution)
+RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing)
+RLAPI void PollInputEvents(void); // Register all input events
+RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution)
// Random values generation functions
-RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator
-RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included)
+RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator
+RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included)
RLAPI int *LoadRandomSequence(unsigned int count, int min, int max); // Load random values sequence, no values repeated
-RLAPI void UnloadRandomSequence(int *sequence); // Unload random values sequence
+RLAPI void UnloadRandomSequence(int *sequence); // Unload random values sequence
// Misc. functions
-RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format)
-RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS)
-RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available)
+RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format)
+RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS)
+RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available)
-// NOTE: Following functions implemented in module [utils]
-//------------------------------------------------------------------
-RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)
-RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level
-RLAPI void *MemAlloc(unsigned int size); // Internal memory allocator
-RLAPI void *MemRealloc(void *ptr, unsigned int size); // Internal memory reallocator
-RLAPI void MemFree(void *ptr); // Internal memory free
+// Logging system
+RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level
+RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)
+RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log
-// Set custom callbacks
-// WARNING: Callbacks setup is intended for advanced users
-RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log
-RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader
-RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver
-RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader
-RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver
+// Memory management, using internal allocators
+RLAPI void *MemAlloc(unsigned int size); // Internal memory allocator
+RLAPI void *MemRealloc(void *ptr, unsigned int size); // Internal memory reallocator
+RLAPI void MemFree(void *ptr); // Internal memory free
-// Files management functions
+// File system management functions
RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read)
RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success
@@ -1123,9 +1116,14 @@ RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
-//------------------------------------------------------------------
-// File system functions
+// File access custom callbacks
+// WARNING: Callbacks setup is intended for advanced users
+RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader
+RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver
+RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader
+RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver
+
RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists)
RLAPI int FileRemove(const char *fileName); // Remove file (if exists)
RLAPI int FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist
diff --git a/src/raymath.h b/src/raymath.h
index 32dfd2b0a..57e3dac51 100644
--- a/src/raymath.h
+++ b/src/raymath.h
@@ -19,20 +19,25 @@
*
* CONFIGURATION:
* #define RAYMATH_IMPLEMENTATION
-* Generates the implementation of the library into the included file.
+* Generates the implementation of the library into the included file
* If not defined, the library is in header only mode and can be included in other headers
-* or source files without problems. But only ONE file should hold the implementation.
+* or source files without problems. But only ONE file should hold the implementation
*
* #define RAYMATH_STATIC_INLINE
-* Define static inline functions code, so #include header suffices for use.
-* This may use up lots of memory.
+* Define static inline functions code, so #include header suffices for use
+* This may use up lots of memory
*
* #define RAYMATH_DISABLE_CPP_OPERATORS
* Disables C++ operator overloads for raymath types.
*
+* #define RAYMATH_USE_SIMD_INTRINSICS
+* Try to enable SIMD intrinsics for MatrixMultiply()
+* Note that users enabling it must be aware of the target platform where application will
+* run to support the selected SIMD intrinsic, for now, only SSE is supported
+*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2015-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2015-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -79,7 +84,6 @@
#endif
#endif
-
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@@ -170,6 +174,35 @@ typedef struct float16 {
#include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf()
+#if defined(RAYMATH_USE_SIMD_INTRINSICS)
+ // SIMD is used on the most costly raymath function MatrixMultiply()
+ // NOTE: Only SSE intrinsics support implemented
+ // TODO: Consider support for other SIMD instrinsics:
+ // - SSEx, AVX, AVX2, FMA, NEON, RVV
+ /*
+ #if defined(__SSE4_2__)
+ #include
+ #define RAYMATH_SSE42_ENABLED
+ #elif defined(__SSE4_1__)
+ #include
+ #define RAYMATH_SSE41_ENABLED
+ #elif defined(__SSSE3__)
+ #include
+ #define RAYMATH_SSSE3_ENABLED
+ #elif defined(__SSE3__)
+ #include
+ #define RAYMATH_SSE3_ENABLED
+ #elif defined(__SSE2__) || (defined(_M_AMD64) || defined(_M_X64)) // SSE2 x64
+ #include
+ #define RAYMATH_SSE2_ENABLED
+ #endif
+ */
+ #if defined(__SSE__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))
+ #include
+ #define RAYMATH_SSE_ENABLED
+ #endif
+#endif
+
//----------------------------------------------------------------------------------
// Module Functions Definition - Utils math
//----------------------------------------------------------------------------------
@@ -1647,7 +1680,64 @@ RMAPI Matrix MatrixSubtract(Matrix left, Matrix right)
RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)
{
Matrix result = { 0 };
+
+#if defined(RAYMATH_SSE_ENABLED)
+ // Load left side and right side
+ __m128 c0 = _mm_set_ps(right.m12, right.m8, right.m4, right.m0);
+ __m128 c1 = _mm_set_ps(right.m13, right.m9, right.m5, right.m1);
+ __m128 c2 = _mm_set_ps(right.m14, right.m10, right.m6, right.m2);
+ __m128 c3 = _mm_set_ps(right.m15, right.m11, right.m7, right.m3);
+
+ // Transpose so c0..c3 become *rows* of the right matrix in semantic order
+ _MM_TRANSPOSE4_PS(c0, c1, c2, c3);
+ float tmp[4] = { 0 };
+ __m128 row;
+
+ // Row 0 of result: [m0, m1, m2, m3]
+ row = _mm_mul_ps(_mm_set1_ps(left.m0), c0);
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m1), c1));
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m2), c2));
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m3), c3));
+ _mm_storeu_ps(tmp, row);
+ result.m0 = tmp[0];
+ result.m1 = tmp[1];
+ result.m2 = tmp[2];
+ result.m3 = tmp[3];
+
+ // Row 1 of result: [m4, m5, m6, m7]
+ row = _mm_mul_ps(_mm_set1_ps(left.m4), c0);
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m5), c1));
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m6), c2));
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m7), c3));
+ _mm_storeu_ps(tmp, row);
+ result.m4 = tmp[0];
+ result.m5 = tmp[1];
+ result.m6 = tmp[2];
+ result.m7 = tmp[3];
+
+ // Row 2 of result: [m8, m9, m10, m11]
+ row = _mm_mul_ps(_mm_set1_ps(left.m8), c0);
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m9), c1));
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m10), c2));
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m11), c3));
+ _mm_storeu_ps(tmp, row);
+ result.m8 = tmp[0];
+ result.m9 = tmp[1];
+ result.m10 = tmp[2];
+ result.m11 = tmp[3];
+
+ // Row 3 of result: [m12, m13, m14, m15]
+ row = _mm_mul_ps(_mm_set1_ps(left.m12), c0);
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m13), c1));
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m14), c2));
+ row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m15), c3));
+ _mm_storeu_ps(tmp, row);
+ result.m12 = tmp[0];
+ result.m13 = tmp[1];
+ result.m14 = tmp[2];
+ result.m15 = tmp[3];
+#else
result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;
result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;
result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;
@@ -1664,6 +1754,7 @@ RMAPI Matrix MatrixMultiply(Matrix left, Matrix right)
result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;
result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;
result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;
+#endif
return result;
}
diff --git a/src/rcamera.h b/src/rcamera.h
index 3e9f83095..82f14fecd 100644
--- a/src/rcamera.h
+++ b/src/rcamera.h
@@ -20,7 +20,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2022-2025 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5)
+* Copyright (c) 2022-2026 Christoph Wagner (@Crydsch) and Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -50,14 +50,14 @@
// Function specifiers in case library is build/used as a shared library (Windows)
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
#if defined(_WIN32)
-#if defined(BUILD_LIBTYPE_SHARED)
-#if defined(__TINYC__)
-#define __declspec(x) __attribute__((x))
-#endif
-#define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
-#elif defined(USE_LIBTYPE_SHARED)
-#define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
-#endif
+ #if defined(BUILD_LIBTYPE_SHARED)
+ #if defined(__TINYC__)
+ #define __declspec(x) __attribute__((x))
+ #endif
+ #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
+ #elif defined(USE_LIBTYPE_SHARED)
+ #define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
+ #endif
#endif
#ifndef RLAPI
@@ -191,19 +191,21 @@ RLAPI Matrix GetCameraProjectionMatrix(Camera *camera, float aspect);
// IsKeyDown()
// IsKeyPressed()
// GetFrameTime()
+
+#include // Required for: fabsf()
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-#define CAMERA_MOVE_SPEED 5.4f // Units per second
-#define CAMERA_ROTATION_SPEED 0.03f
-#define CAMERA_PAN_SPEED 0.2f
+#define CAMERA_MOVE_SPEED 5.4f // Units per second
+#define CAMERA_ROTATION_SPEED 0.03f
+#define CAMERA_PAN_SPEED 0.2f
// Camera mouse movement sensitivity
-#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
+#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
// Camera orbital speed in CAMERA_ORBITAL mode
-#define CAMERA_ORBITAL_SPEED 0.5f // Radians per second
+#define CAMERA_ORBITAL_SPEED 0.5f // Radians per second
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -252,8 +254,11 @@ void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane)
if (moveInWorldPlane)
{
- // Project vector onto world plane
- forward.y = 0;
+ // Project vector onto world plane (the plane defined by the up vector)
+ if (fabsf(camera->up.z) > 0.7071f) forward.z = 0;
+ else if (fabsf(camera->up.x) > 0.7071f) forward.x = 0;
+ else forward.y = 0;
+
forward = Vector3Normalize(forward);
}
@@ -285,8 +290,11 @@ void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane)
if (moveInWorldPlane)
{
- // Project vector onto world plane
- right.y = 0;
+ // Project vector onto world plane (the plane defined by the up vector)
+ if (fabsf(camera->up.z) > 0.7071f) right.z = 0;
+ else if (fabsf(camera->up.x) > 0.7071f) right.x = 0;
+ else right.y = 0;
+
right = Vector3Normalize(right);
}
@@ -345,7 +353,7 @@ void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget)
// - lockView prevents camera overrotation (aka "somersaults")
// - rotateAroundTarget defines if rotation is around target or around its position
// - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE)
-// NOTE: angle must be provided in radians
+// NOTE: [angle] must be provided in radians
void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp)
{
// Up direction
@@ -382,7 +390,7 @@ void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTa
// Move position relative to target
camera->position = Vector3Subtract(camera->target, targetPosition);
}
- else // rotate around camera.position
+ else // Rotate around camera.position
{
// Move target relative to position
camera->target = Vector3Add(camera->position, targetPosition);
diff --git a/src/rcore.c b/src/rcore.c
index 19228cc8e..1794637bd 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -70,7 +70,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) and contributors
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -104,16 +104,12 @@
#include "raylib.h" // Declares module functions
-// Check if config flags have been externally provided on compilation line
-#if !defined(EXTERNAL_CONFIG_FLAGS)
- #include "config.h" // Defines module configuration flags
-#endif
+#include "config.h" // Defines module configuration flags
-#include "utils.h" // Required for: TRACELOG() macros
-
-#include // Required for: srand(), rand(), atexit()
-#include // Required for: sprintf() [Used in OpenURL()]
-#include // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset()
+#include // Required for: srand(), rand(), atexit(), exit()
+#include // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()]
+#include // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset(), strcat()
+#include // Required for: va_list, va_start(), va_end() [Used in TraceLog()]
#include // Required for: time() [Used in InitTimer()]
#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
@@ -205,16 +201,22 @@
#define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir()
#define CHDIR _chdir
#define MKDIR(dir) _mkdir(dir)
+ #define ACCESS(fn) _access(fn, 0)
#else
#include // Required for: getch(), chdir(), mkdir(), access()
#define GETCWD getcwd
#define CHDIR chdir
#define MKDIR(dir) mkdir(dir, 0777)
+ #define ACCESS(fn) access(fn, F_OK)
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
+#ifndef MAX_TRACELOG_MSG_LENGTH
+ #define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
+#endif
+
#ifndef MAX_FILEPATH_CAPACITY
#define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
#endif
@@ -273,7 +275,7 @@
#define FLAG_SET(n, f) ((n) |= (f))
#define FLAG_CLEAR(n, f) ((n) &= ~(f))
#define FLAG_TOGGLE(n, f) ((n) ^= (f))
-#define FLAG_IS_SET(n, f) (((n) & (f)) > 0)
+#define FLAG_IS_SET(n, f) (((n) & (f)) == (f))
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -287,20 +289,19 @@ typedef struct CoreData {
const char *title; // Window text title const pointer
unsigned int flags; // Configuration flags (bit based), keeps window state
bool ready; // Check if window has been initialized successfully
- bool fullscreen; // Check if fullscreen mode is enabled
bool shouldClose; // Check if window set for closing
bool resizedLastFrame; // Check if window has been resized last frame
bool eventWaiting; // Wait for events before ending frame
bool usingFbo; // Using FBO (RenderTexture) for rendering instead of default framebuffer
- Point position; // Window position (required on fullscreen toggle)
- Point previousPosition; // Window previous position (required on borderless windowed toggle)
Size display; // Display width and height (monitor, device-screen, LCD, ...)
- Size screen; // Screen width and height (used render area)
- Size previousScreen; // Screen previous width and height (required on borderless windowed toggle)
- Size currentFbo; // Current render width and height (depends on active fbo)
- Size render; // Framebuffer width and height (render area, including black bars if required)
- Point renderOffset; // Offset from render area (must be divided by 2)
+ Size screen; // Screen current width and height
+ Point position; // Window current position
+ Size previousScreen; // Screen previous width and height (required on fullscreen/borderless-windowed toggle)
+ Point previousPosition; // Window previous position (required on fullscreeen/borderless-windowed toggle)
+ Size render; // Screen framebuffer width and height
+ Point renderOffset; // Screen framebuffer render offset (Not required anymore?)
+ Size currentFbo; // Current framebuffer render width and height (depends on active render texture)
Size screenMin; // Screen minimum width and height (for resizable window)
Size screenMax; // Screen maximum width and height (for resizable window)
Matrix screenScale; // Matrix to scale screen (framebuffer rendering)
@@ -316,17 +317,17 @@ typedef struct CoreData {
struct {
struct {
int exitKey; // Default exit key
- char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state
- char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state
+ char currentKeyState[MAX_KEYBOARD_KEYS]; // Registers current frame key state
+ char previousKeyState[MAX_KEYBOARD_KEYS]; // Registers previous frame key state
- // NOTE: Since key press logic involves comparing previous vs currrent key state,
+ // NOTE: Since key press logic involves comparing previous vs currrent key state,
// key repeats needs to be handled specially
- char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame
+ char keyRepeatInFrame[MAX_KEYBOARD_KEYS]; // Registers key repeats for current frame
- int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
+ int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
int keyPressedQueueCount; // Input keys queue count
- int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode)
+ int charPressedQueue[MAX_CHAR_PRESSED_QUEUE]; // Input characters queue (unicode)
int charPressedQueueCount; // Input characters queue count
} Keyboard;
@@ -342,18 +343,19 @@ typedef struct CoreData {
bool cursorLocked; // Track if cursor is locked (disabled)
bool cursorOnScreen; // Tracks if cursor is inside client area
- char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state
- char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state
+ char currentButtonState[MAX_MOUSE_BUTTONS]; // Registers current mouse button state
+ char previousButtonState[MAX_MOUSE_BUTTONS]; // Registers previous mouse button state
Vector2 currentWheelMove; // Registers current mouse wheel variation
Vector2 previousWheelMove; // Registers previous mouse wheel variation
} Mouse;
struct {
- int pointCount; // Number of touch points active
- int pointId[MAX_TOUCH_POINTS]; // Point identifiers
- Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
- char currentTouchState[MAX_TOUCH_POINTS]; // Registers current touch state
- char previousTouchState[MAX_TOUCH_POINTS]; // Registers previous touch state
+ int pointCount; // Number of touch points active
+ int pointId[MAX_TOUCH_POINTS]; // Point identifiers
+ Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
+ Vector2 previousPosition[MAX_TOUCH_POINTS]; // Previous touch position on screen
+ char currentTouchState[MAX_TOUCH_POINTS]; // Registers current touch state
+ char previousTouchState[MAX_TOUCH_POINTS]; // Registers previous touch state
} Touch;
struct {
@@ -385,10 +387,18 @@ typedef struct CoreData {
//----------------------------------------------------------------------------------
RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported symbol, required for some bindings
-CoreData CORE = { 0 }; // Global CORE state context
+CoreData CORE = { 0 }; // Global CORE state context
+
+static int logTypeLevel = LOG_INFO; // Minimum log type level
+
+static TraceLogCallback traceLog = NULL; // TraceLog callback function pointer
+static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback function pointer
+static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback function pointer
+static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback function pointer
+static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback function pointer
#if defined(SUPPORT_SCREEN_CAPTURE)
-static int screenshotCounter = 0; // Screenshots counter
+static int screenshotCounter = 0; // Screenshots counter
#endif
#if defined(SUPPORT_AUTOMATION_EVENTS)
@@ -493,7 +503,6 @@ extern int InitPlatform(void); // Initialize platform (graphics, inputs
extern void ClosePlatform(void); // Close platform
static void InitTimer(void); // Initialize timer, hi-resolution if available (required by InitPlatform())
-static void SetupFramebuffer(int width, int height); // Setup main framebuffer (required by InitPlatform())
static void SetupViewport(int width, int height); // Set viewport for a provided width and height
static void ScanDirectoryFiles(const char *basePath, FilePathList *list, const char *filter); // Scan all files and directories in a base path
@@ -762,31 +771,31 @@ bool IsWindowReady(void)
// Check if window is currently fullscreen
bool IsWindowFullscreen(void)
{
- return CORE.Window.fullscreen;
+ return FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
// Check if window is currently hidden
bool IsWindowHidden(void)
{
- return (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN));
+ return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
}
// Check if window has been minimized
bool IsWindowMinimized(void)
{
- return (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED));
+ return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
}
// Check if window has been maximized
bool IsWindowMaximized(void)
{
- return (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED));
+ return FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
// Check if window has the focus
bool IsWindowFocused(void)
{
- return (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED));
+ return !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
}
// Check if window has been resizedLastFrame
@@ -798,7 +807,7 @@ bool IsWindowResized(void)
// Check if one specific window flag is enabled
bool IsWindowState(unsigned int flag)
{
- return (FLAG_IS_SET(CORE.Window.flags, flag));
+ return FLAG_IS_SET(CORE.Window.flags, flag);
}
// Get current screen width
@@ -816,30 +825,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;
}
@@ -1108,7 +1109,7 @@ void BeginScissorMode(int x, int y, int width, int height)
rlScissor((int)(x*scale.x), (int)(GetScreenHeight()*scale.y - (((y + height)*scale.y))), (int)(width*scale.x), (int)(height*scale.y));
}
#else
- if (!CORE.Window.usingFbo && (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)))
+ if (!CORE.Window.usingFbo && FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
Vector2 scale = GetWindowScaleDPI();
rlScissor((int)(x*scale.x), (int)(CORE.Window.currentFbo.height - (y + height)*scale.y), (int)(width*scale.x), (int)(height*scale.y));
@@ -1743,7 +1744,7 @@ 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
@@ -1833,7 +1834,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 };
@@ -1864,9 +1865,389 @@ void SetConfigFlags(unsigned int flags)
FLAG_SET(CORE.Window.flags, flags);
}
+// void OpenURL(const char *url); // Defined per platform
+
//----------------------------------------------------------------------------------
-// Module Functions Definition: File system
+// Module Functions Definition: Logging system
//----------------------------------------------------------------------------------
+// Set the current threshold (minimum) log level
+void SetTraceLogLevel(int logType) { logTypeLevel = logType; }
+
+// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
+void TraceLog(int logType, const char *text, ...)
+{
+#if defined(SUPPORT_TRACELOG)
+ // Message has level below current threshold, don't emit
+ if ((logType < logTypeLevel) || (text == NULL)) return;
+
+ va_list args;
+ va_start(args, text);
+
+ if (traceLog)
+ {
+ traceLog(logType, text, args);
+ va_end(args);
+ return;
+ }
+
+#if defined(PLATFORM_ANDROID)
+ switch (logType)
+ {
+ case LOG_TRACE: __android_log_vprint(ANDROID_LOG_VERBOSE, "raylib", text, args); break;
+ case LOG_DEBUG: __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", text, args); break;
+ case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", text, args); break;
+ case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", text, args); break;
+ case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", text, args); break;
+ case LOG_FATAL: __android_log_vprint(ANDROID_LOG_FATAL, "raylib", text, args); break;
+ default: break;
+ }
+#else
+ char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 };
+
+ switch (logType)
+ {
+ case LOG_TRACE: strncpy(buffer, "TRACE: ", 8); break;
+ case LOG_DEBUG: strncpy(buffer, "DEBUG: ", 8); break;
+ case LOG_INFO: strncpy(buffer, "INFO: ", 7); break;
+ case LOG_WARNING: strncpy(buffer, "WARNING: ", 10); break;
+ case LOG_ERROR: strncpy(buffer, "ERROR: ", 8); break;
+ case LOG_FATAL: strncpy(buffer, "FATAL: ", 8); break;
+ default: break;
+ }
+
+ 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);
+#endif
+
+ va_end(args);
+
+ if (logType == LOG_FATAL) exit(EXIT_FAILURE); // If fatal logging, exit program
+
+#endif // SUPPORT_TRACELOG
+}
+
+// Set custom trace log
+void SetTraceLogCallback(TraceLogCallback callback)
+{
+ traceLog = callback;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Memory management
+//----------------------------------------------------------------------------------
+// Internal memory allocator
+// NOTE: Initializes to zero by default
+void *MemAlloc(unsigned int size)
+{
+ void *ptr = RL_CALLOC(size, 1);
+ return ptr;
+}
+
+// Internal memory reallocator
+void *MemRealloc(void *ptr, unsigned int size)
+{
+ void *ret = RL_REALLOC(ptr, size);
+ return ret;
+}
+
+// Internal memory free
+void MemFree(void *ptr)
+{
+ RL_FREE(ptr);
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: File System management
+//----------------------------------------------------------------------------------
+// Load data from file into a buffer
+unsigned char *LoadFileData(const char *fileName, int *dataSize)
+{
+ unsigned char *data = NULL;
+ *dataSize = 0;
+
+ if (fileName != NULL)
+ {
+ if (loadFileData)
+ {
+ data = loadFileData(fileName, dataSize);
+ return data;
+ }
+#if defined(SUPPORT_STANDARD_FILEIO)
+ FILE *file = fopen(fileName, "rb");
+
+ if (file != NULL)
+ {
+ // WARNING: On binary streams SEEK_END could not be found,
+ // using fseek() and ftell() could not work in some (rare) cases
+ fseek(file, 0, SEEK_END);
+ int size = ftell(file); // WARNING: ftell() returns 'long int', maximum size returned is INT_MAX (2147483647 bytes)
+ fseek(file, 0, SEEK_SET);
+
+ if (size > 0)
+ {
+ data = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char));
+
+ if (data != NULL)
+ {
+ // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
+ size_t count = fread(data, sizeof(unsigned char), size, file);
+
+ // WARNING: fread() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
+ // dataSize is unified along raylib as a 'int' type, so, for file-sizes > INT_MAX (2147483647 bytes) we have a limitation
+ if (count > 2147483647)
+ {
+ TRACELOG(LOG_WARNING, "FILEIO: [%s] File is bigger than 2147483647 bytes, avoid using LoadFileData()", fileName);
+
+ RL_FREE(data);
+ data = NULL;
+ }
+ else
+ {
+ *dataSize = (int)count;
+
+ if ((*dataSize) != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded (%i bytes out of %i)", fileName, dataSize, count);
+ else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName);
+ }
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName);
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName);
+
+ fclose(file);
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
+#else
+ TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
+#endif
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
+
+ return data;
+}
+
+// Unload file data allocated by LoadFileData()
+void UnloadFileData(unsigned char *data)
+{
+ RL_FREE(data);
+}
+
+// Save data to file from buffer
+bool SaveFileData(const char *fileName, void *data, int dataSize)
+{
+ bool success = false;
+
+ if (fileName != NULL)
+ {
+ if (saveFileData)
+ {
+ return saveFileData(fileName, data, dataSize);
+ }
+#if defined(SUPPORT_STANDARD_FILEIO)
+ FILE *file = fopen(fileName, "wb");
+
+ if (file != NULL)
+ {
+ // WARNING: fwrite() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
+ // and expects a size_t input value but as dataSize is limited to INT_MAX (2147483647 bytes), there shouldn't be a problem
+ int count = (int)fwrite(data, sizeof(unsigned char), dataSize, file);
+
+ if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
+ else if (count != dataSize) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
+ else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName);
+
+ int result = fclose(file);
+ if (result == 0) success = true;
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
+#else
+ TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
+#endif
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
+
+ return success;
+}
+
+// Export data to code (.h), returns true on success
+bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName)
+{
+ bool success = false;
+
+#ifndef TEXT_BYTES_PER_LINE
+ #define TEXT_BYTES_PER_LINE 20
+#endif
+
+ // NOTE: Text data buffer size is estimated considering raw data size in bytes
+ // and requiring 6 char bytes for every byte: "0x00, "
+ char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char));
+
+ int byteCount = 0;
+ byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
+ byteCount += sprintf(txtData + byteCount, "// //\n");
+ byteCount += sprintf(txtData + byteCount, "// DataAsCode exporter v1.0 - Raw data exported as an array of bytes //\n");
+ byteCount += sprintf(txtData + byteCount, "// //\n");
+ byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
+ byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
+ byteCount += sprintf(txtData + byteCount, "// //\n");
+ byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2026 Ramon Santamaria (@raysan5) //\n");
+ byteCount += sprintf(txtData + byteCount, "// //\n");
+ byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
+
+ // Get file name from path
+ char varFileName[256] = { 0 };
+ strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
+ for (int i = 0; varFileName[i] != '\0'; i++)
+ {
+ // Convert variable name to uppercase
+ if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
+ // Replace non valid character for C identifier with '_'
+ else if (varFileName[i] == '.' || varFileName[i] == '-' || varFileName[i] == '?' || varFileName[i] == '!' || varFileName[i] == '+') { varFileName[i] = '_'; }
+ }
+
+ byteCount += sprintf(txtData + byteCount, "#define %s_DATA_SIZE %i\n\n", varFileName, dataSize);
+
+ byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%s_DATA_SIZE] = { ", varFileName, varFileName);
+ for (int i = 0; i < (dataSize - 1); i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), data[i]);
+ byteCount += sprintf(txtData + byteCount, "0x%x };\n", data[dataSize - 1]);
+
+ // NOTE: Text data size exported is determined by '\0' (NULL) character
+ success = SaveFileText(fileName, txtData);
+
+ RL_FREE(txtData);
+
+ if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName);
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export data as code", fileName);
+
+ return success;
+}
+
+// Load text data from file, returns a '\0' terminated string
+// NOTE: text chars array should be freed manually
+char *LoadFileText(const char *fileName)
+{
+ char *text = NULL;
+
+ if (fileName != NULL)
+ {
+ if (loadFileText)
+ {
+ text = loadFileText(fileName);
+ return text;
+ }
+#if defined(SUPPORT_STANDARD_FILEIO)
+ FILE *file = fopen(fileName, "rt");
+
+ if (file != NULL)
+ {
+ // WARNING: When reading a file as 'text' file,
+ // text mode causes carriage return-linefeed translation...
+ // ...but using fseek() should return correct byte-offset
+ fseek(file, 0, SEEK_END);
+ unsigned int size = (unsigned int)ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ if (size > 0)
+ {
+ text = (char *)RL_CALLOC(size + 1, sizeof(char));
+
+ if (text != NULL)
+ {
+ unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
+
+ // WARNING: \r\n is converted to \n on reading, so,
+ // read bytes count gets reduced by the number of lines
+ if (count < size) text = (char *)RL_REALLOC(text, count + 1);
+
+ // Zero-terminate the string
+ text[count] = '\0';
+
+ TRACELOG(LOG_INFO, "FILEIO: [%s] Text file loaded successfully", fileName);
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName);
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read text file", fileName);
+
+ fclose(file);
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
+#else
+ TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
+#endif
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
+
+ return text;
+}
+
+// Unload file text data allocated by LoadFileText()
+void UnloadFileText(char *text)
+{
+ RL_FREE(text);
+}
+
+// Save text data to file (write), string must be '\0' terminated
+bool SaveFileText(const char *fileName, const char *text)
+{
+ bool success = false;
+
+ if (fileName != NULL)
+ {
+ if (saveFileText)
+ {
+ return saveFileText(fileName, text);
+ }
+#if defined(SUPPORT_STANDARD_FILEIO)
+ FILE *file = fopen(fileName, "wt");
+
+ if (file != NULL)
+ {
+ int 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);
+
+ int result = fclose(file);
+ if (result == 0) success = true;
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
+#else
+ TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
+#endif
+ }
+ else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
+
+ return success;
+}
+
+// File access custom callbacks
+// WARNING: Callbacks setup is intended for advanced users
+
+// Set custom file binary data loader
+void SetLoadFileDataCallback(LoadFileDataCallback callback)
+{
+ loadFileData = callback;
+}
+
+// Set custom file binary data saver
+void SetSaveFileDataCallback(SaveFileDataCallback callback)
+{
+ saveFileData = callback;
+}
+
+// Set custom file text data loader
+void SetLoadFileTextCallback(LoadFileTextCallback callback)
+{
+ loadFileText = callback;
+}
+
+// Set custom file text data saver
+void SetSaveFileTextCallback(SaveFileTextCallback callback)
+{
+ saveFileText = callback;
+}
// Rename file (if exists)
// NOTE: Only rename file name required, not full path
@@ -1982,11 +2363,7 @@ bool FileExists(const char *fileName)
{
bool result = false;
-#if defined(_WIN32)
- if (_access(fileName, 0) != -1) result = true;
-#else
- if (access(fileName, F_OK) != -1) result = true;
-#endif
+ if (ACCESS(fileName) != -1) result = true;
// NOTE: Alternatively, stat() can be used instead of access()
//#include
@@ -2269,7 +2646,7 @@ const char *GetApplicationDirectory(void)
#if defined(_WIN32)
int len = 0;
-
+
#if defined(UNICODE)
unsigned short widePath[MAX_PATH];
len = GetModuleFileNameW(NULL, (wchar_t *)widePath, MAX_PATH);
@@ -2277,7 +2654,7 @@ const char *GetApplicationDirectory(void)
#else
len = GetModuleFileNameA(NULL, appDir, MAX_PATH);
#endif
-
+
if (len > 0)
{
for (int i = len; i >= 0; --i)
@@ -2294,7 +2671,7 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '\\';
}
-
+
#elif defined(__linux__)
unsigned int size = sizeof(appDir);
@@ -2316,7 +2693,7 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '/';
}
-
+
#elif defined(__APPLE__)
uint32_t size = sizeof(appDir);
@@ -2338,7 +2715,7 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '/';
}
-
+
#elif defined(__FreeBSD__)
size_t size = sizeof(appDir);
@@ -2361,6 +2738,10 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '/';
}
+
+#elif defined(__wasm__)
+
+ appDir[0] = '/';
#endif
return appDir;
@@ -2709,7 +3090,7 @@ 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;
@@ -3241,14 +3622,23 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
#if defined(SUPPORT_AUTOMATION_EVENTS)
// Export events as binary file
- // TODO: Save to memory buffer and SaveFileData()
+ // NOTE: Code not used, only for reference if required in the future
/*
- unsigned char fileId[4] = "rAE ";
- FILE *raeFile = fopen(fileName, "wb");
- fwrite(fileId, sizeof(unsigned char), 4, raeFile);
- fwrite(&eventCount, sizeof(int), 1, raeFile);
- fwrite(events, sizeof(AutomationEvent), eventCount, raeFile);
- fclose(raeFile);
+ if (list.count > 0)
+ {
+ int binarySize = 4 + sizeof(int) + sizeof(AutomationEvent)*list.count;
+ unsigned char *binBuffer = (unsigned char *)RL_CALLOC(binarySize, 1);
+ int offset = 0;
+ memcpy(binBuffer + offset, "rAE ", 4);
+ offset += 4;
+ memcpy(binBuffer + offset, &list.count, sizeof(int));
+ offset += sizeof(int);
+ memcpy(binBuffer + offset, list.events, sizeof(AutomationEvent)*list.count);
+ offset += sizeof(AutomationEvent)*list.count;
+
+ success = SaveFileData(TextFormat("%s.rae",fileName), binBuffer, binarySize);
+ RL_FREE(binBuffer);
+ }
*/
// Export events as text
@@ -3265,7 +3655,7 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
byteCount += sprintf(txtData + byteCount, "# more info and bugs-report: github.com/raysan5/raylib\n");
byteCount += sprintf(txtData + byteCount, "# feedback and support: ray[at]raylib.com\n");
byteCount += sprintf(txtData + byteCount, "#\n");
- byteCount += sprintf(txtData + byteCount, "# Copyright (c) 2023-2025 Ramon Santamaria (@raysan5)\n");
+ byteCount += sprintf(txtData + byteCount, "# Copyright (c) 2023-2026 Ramon Santamaria (@raysan5)\n");
byteCount += sprintf(txtData + byteCount, "#\n\n");
// Add events data
@@ -3823,14 +4213,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)
@@ -3843,84 +4226,6 @@ void SetupViewport(int width, int height)
rlLoadIdentity(); // Reset current matrix (modelview)
}
-// Compute framebuffer size relative to screen size and display size
-// NOTE: Global variables CORE.Window.render.width/CORE.Window.render.height and CORE.Window.renderOffset.x/CORE.Window.renderOffset.y can be modified
-void SetupFramebuffer(int width, int height)
-{
- // Calculate CORE.Window.render.width and CORE.Window.render.height, we have the display size (input params) and the desired screen size (global var)
- if ((CORE.Window.screen.width > CORE.Window.display.width) || (CORE.Window.screen.height > CORE.Window.display.height))
- {
- TRACELOG(LOG_WARNING, "DISPLAY: Downscaling required: Screen size (%ix%i) is bigger than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
-
- // Downscaling to fit display with border-bars
- float widthRatio = (float)CORE.Window.display.width/(float)CORE.Window.screen.width;
- float heightRatio = (float)CORE.Window.display.height/(float)CORE.Window.screen.height;
-
- if (widthRatio <= heightRatio)
- {
- CORE.Window.render.width = CORE.Window.display.width;
- CORE.Window.render.height = (int)round((float)CORE.Window.screen.height*widthRatio);
- CORE.Window.renderOffset.x = 0;
- CORE.Window.renderOffset.y = (CORE.Window.display.height - CORE.Window.render.height);
- }
- else
- {
- CORE.Window.render.width = (int)round((float)CORE.Window.screen.width*heightRatio);
- CORE.Window.render.height = CORE.Window.display.height;
- CORE.Window.renderOffset.x = (CORE.Window.display.width - CORE.Window.render.width);
- CORE.Window.renderOffset.y = 0;
- }
-
- // Screen scaling required
- float scaleRatio = (float)CORE.Window.render.width/(float)CORE.Window.screen.width;
- CORE.Window.screenScale = MatrixScale(scaleRatio, scaleRatio, 1.0f);
-
- // NOTE: We render to full display resolution!
- // We just need to calculate above parameters for downscale matrix and offsets
- CORE.Window.render.width = CORE.Window.display.width;
- CORE.Window.render.height = CORE.Window.display.height;
-
- TRACELOG(LOG_WARNING, "DISPLAY: Downscale matrix generated, content will be rendered at (%ix%i)", CORE.Window.render.width, CORE.Window.render.height);
- }
- else if ((CORE.Window.screen.width < CORE.Window.display.width) || (CORE.Window.screen.height < CORE.Window.display.height))
- {
- // Required screen size is smaller than display size
- TRACELOG(LOG_INFO, "DISPLAY: Upscaling required: Screen size (%ix%i) smaller than display size (%ix%i)", CORE.Window.screen.width, CORE.Window.screen.height, CORE.Window.display.width, CORE.Window.display.height);
-
- if ((CORE.Window.screen.width == 0) || (CORE.Window.screen.height == 0))
- {
- CORE.Window.screen.width = CORE.Window.display.width;
- CORE.Window.screen.height = CORE.Window.display.height;
- }
-
- // Upscaling to fit display with border-bars
- float displayRatio = (float)CORE.Window.display.width/(float)CORE.Window.display.height;
- float screenRatio = (float)CORE.Window.screen.width/(float)CORE.Window.screen.height;
-
- if (displayRatio <= screenRatio)
- {
- CORE.Window.render.width = CORE.Window.screen.width;
- CORE.Window.render.height = (int)round((float)CORE.Window.screen.width/displayRatio);
- CORE.Window.renderOffset.x = 0;
- CORE.Window.renderOffset.y = (CORE.Window.render.height - CORE.Window.screen.height);
- }
- else
- {
- CORE.Window.render.width = (int)round((float)CORE.Window.screen.height*displayRatio);
- CORE.Window.render.height = CORE.Window.screen.height;
- CORE.Window.renderOffset.x = (CORE.Window.render.width - CORE.Window.screen.width);
- CORE.Window.renderOffset.y = 0;
- }
- }
- else
- {
- CORE.Window.render.width = CORE.Window.screen.width;
- CORE.Window.render.height = CORE.Window.screen.height;
- CORE.Window.renderOffset.x = 0;
- CORE.Window.renderOffset.y = 0;
- }
-}
-
// Scan all files and directories in a base path
// WARNING: files.paths[] must be previously allocated and
// contain enough space to store all required paths
@@ -4201,22 +4506,20 @@ static void RecordAutomationEvent(void)
if (currentEventList->count == currentEventList->capacity) return; // Security check
- // Event type: INPUT_TOUCH_POSITION
- // TODO: It requires the id!
- /*
- if (((int)CORE.Input.Touch.currentPosition[id].x != (int)CORE.Input.Touch.previousPosition[id].x) ||
- ((int)CORE.Input.Touch.currentPosition[id].y != (int)CORE.Input.Touch.previousPosition[id].y))
+ // Event type: INPUT_TOUCH_POSITION
+ if (((int)CORE.Input.Touch.position[id].x != (int)CORE.Input.Touch.previousPosition[id].x) ||
+ ((int)CORE.Input.Touch.position[id].y != (int)CORE.Input.Touch.previousPosition[id].y))
{
currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
currentEventList->events[currentEventList->count].type = INPUT_TOUCH_POSITION;
currentEventList->events[currentEventList->count].params[0] = id;
- currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Touch.currentPosition[id].x;
- currentEventList->events[currentEventList->count].params[2] = (int)CORE.Input.Touch.currentPosition[id].y;
+ currentEventList->events[currentEventList->count].params[1] = (int)CORE.Input.Touch.position[id].x;
+ currentEventList->events[currentEventList->count].params[2] = (int)CORE.Input.Touch.position[id].y;
TRACELOG(LOG_INFO, "AUTOMATION: Frame: %i | Event type: INPUT_TOUCH_POSITION | Event parameters: %i, %i, %i", currentEventList->events[currentEventList->count].frame, currentEventList->events[currentEventList->count].params[0], currentEventList->events[currentEventList->count].params[1], currentEventList->events[currentEventList->count].params[2]);
currentEventList->count++;
}
- */
+
if (currentEventList->count == currentEventList->capacity) return; // Security check
}
@@ -4338,7 +4641,7 @@ const char *TextFormat(const char *text, ...)
char *currentBuffer = buffers[index];
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
-
+
if (text != NULL)
{
va_list args;
diff --git a/src/rgestures.h b/src/rgestures.h
index f601a4790..e6cb86300 100644
--- a/src/rgestures.h
+++ b/src/rgestures.h
@@ -21,7 +21,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2014-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
diff --git a/src/rglfw.c b/src/rglfw.c
index b167955bc..53399aa13 100644
--- a/src/rglfw.c
+++ b/src/rglfw.c
@@ -7,7 +7,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2017-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2017-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
diff --git a/src/rlgl.h b/src/rlgl.h
index 97f892eb5..8b264343a 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -37,10 +37,6 @@
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation
*
-* #define RLGL_RENDER_TEXTURES_HINT
-* Enable framebuffer objects (fbo) support (enabled by default)
-* Some GPUs could not support them despite the OpenGL version
-*
* #define RLGL_SHOW_GL_DETAILS_INFO
* Show OpenGL extensions and capabilities detailed logs on init
*
@@ -89,7 +85,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2014-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -132,7 +128,6 @@
// Support TRACELOG macros
#ifndef TRACELOG
#define TRACELOG(level, ...) (void)0
- #define TRACELOGD(...) (void)0
#endif
// Allow custom memory allocators
@@ -197,10 +192,6 @@
#define GRAPHICS_API_OPENGL_ES2
#endif
-// Support framebuffer objects by default
-// NOTE: Some driver implementation do not support it, despite they should
-#define RLGL_RENDER_TEXTURES_HINT
-
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@@ -1864,7 +1855,7 @@ void rlDisableShader(void)
// Enable rendering to texture (fbo)
void rlEnableFramebuffer(unsigned int id)
{
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
glBindFramebuffer(GL_FRAMEBUFFER, id);
#endif
}
@@ -1873,7 +1864,7 @@ void rlEnableFramebuffer(unsigned int id)
unsigned int rlGetActiveFramebuffer(void)
{
GLint fboId = 0;
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3))
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboId);
#endif
return fboId;
@@ -1882,7 +1873,7 @@ unsigned int rlGetActiveFramebuffer(void)
// Disable rendering to texture
void rlDisableFramebuffer(void)
{
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif
}
@@ -1890,7 +1881,7 @@ void rlDisableFramebuffer(void)
// Blit active framebuffer to main framebuffer
void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, int bufferMask)
{
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3))
glBlitFramebuffer(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask, GL_NEAREST);
#endif
}
@@ -1898,7 +1889,7 @@ void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX
// Bind framebuffer object (fbo)
void rlBindFramebuffer(unsigned int target, unsigned int framebuffer)
{
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
glBindFramebuffer(target, framebuffer);
#endif
}
@@ -1907,7 +1898,7 @@ void rlBindFramebuffer(unsigned int target, unsigned int framebuffer)
// NOTE: One color buffer is always active by default
void rlActiveDrawBuffers(int count)
{
-#if ((defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT))
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3))
// NOTE: Maximum number of draw buffers supported is implementation dependant,
// it can be queried with glGet*() but it must be at least 8
//GLint maxDrawBuffers = 0;
@@ -3324,7 +3315,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
unsigned int glInternalFormat, glFormat, glType;
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
- TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset);
+ TRACELOG(RL_LOG_DEBUG, "TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset);
if (glInternalFormat != 0)
{
@@ -3353,8 +3344,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;
@@ -3391,9 +3382,15 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
// 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);
-
- // 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
@@ -3821,7 +3818,7 @@ 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)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
glGenFramebuffers(1, &fboId); // Create the framebuffer object
glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer
#endif
@@ -3833,7 +3830,7 @@ unsigned int rlLoadFramebuffer(void)
// NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture
void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel)
{
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
switch (attachType)
@@ -3873,7 +3870,7 @@ bool rlFramebufferComplete(unsigned int id)
{
bool result = false;
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
glBindFramebuffer(GL_FRAMEBUFFER, id);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -3904,7 +3901,7 @@ bool rlFramebufferComplete(unsigned int id)
// NOTE: All attached textures/cubemaps/renderbuffers are also deleted
void rlUnloadFramebuffer(unsigned int id)
{
-#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
+#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2))
// Query depth attachment to automatically delete texture/renderbuffer
int depthType = 0, depthId = 0;
glBindFramebuffer(GL_FRAMEBUFFER, id); // Bind framebuffer to query depth texture type
@@ -4240,7 +4237,7 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name);
name[namelen] = 0;
- TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name));
+ TRACELOG(RL_LOG_DEBUG, "SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name));
}
}
*/
@@ -5218,24 +5215,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;
diff --git a/src/rmodels.c b/src/rmodels.c
index 40af4afc4..58b08350d 100644
--- a/src/rmodels.c
+++ b/src/rmodels.c
@@ -21,7 +21,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -42,14 +42,10 @@
#include "raylib.h" // Declares module functions
-// Check if config flags have been externally provided on compilation line
-#if !defined(EXTERNAL_CONFIG_FLAGS)
- #include "config.h" // Defines module configuration flags
-#endif
+#include "config.h" // Defines module configuration flags
#if defined(SUPPORT_MODULE_RMODELS)
-#include "utils.h" // Required for: TRACELOG(), LoadFileData(), LoadFileText(), SaveFileText()
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality
@@ -132,7 +128,7 @@
#ifndef MAX_MESH_VERTEX_BUFFERS
#define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh
#endif
-#ifndef MAX_FILEPATH_LENGTH
+#ifndef MAX_FILEPATH_LENGTH
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
#endif
@@ -1762,11 +1758,14 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
instancesVboId = rlLoadVertexBuffer(instanceTransforms, instances*sizeof(float16), false);
// Instances transformation matrices are sent to shader attribute location: SHADER_LOC_VERTEX_INSTANCE_TX
- for (unsigned int i = 0; i < 4; i++)
+ if (material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] != -1)
{
- rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i);
- rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i, 4, RL_FLOAT, 0, sizeof(Matrix), i*sizeof(Vector4));
- rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i, 1);
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i, 4, RL_FLOAT, 0, sizeof(Matrix), i*sizeof(Vector4));
+ rlSetVertexAttributeDivisor(material.shader.locs[SHADER_LOC_VERTEX_INSTANCE_TX] + i, 1);
+ }
}
rlDisableVertexBuffer();
@@ -1987,7 +1986,7 @@ bool ExportMesh(Mesh mesh, const char *fileName)
byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n");
byteCount += sprintf(txtData + byteCount, "# // feedback and support: ray[at]raylib.com //\n");
byteCount += sprintf(txtData + byteCount, "# // //\n");
- byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n");
+ byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2026 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "# // //\n");
byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
byteCount += sprintf(txtData + byteCount, "# Vertex Count: %i\n", mesh.vertexCount);
@@ -4153,7 +4152,7 @@ RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
// Test against all triangles in mesh
for (int i = 0; i < triangleCount; i++)
{
- Vector3 a = { 0 };
+ Vector3 a = { 0 };
Vector3 b = { 0 };
Vector3 c = { 0 };
Vector3 *vertdata = (Vector3 *)mesh.vertices;
@@ -6353,7 +6352,7 @@ static bool GetPoseAtTimeGLTF(cgltf_interpolation_type interpolationType, cgltf_
return true;
}
-#define GLTF_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms)
+#define GLTF_FRAMERATE 60.0f // glTF animation framerate (frames per second)
static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCount)
{
@@ -6473,13 +6472,13 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
if (animData.name != NULL) strncpy(animations[i].name, animData.name, sizeof(animations[i].name) - 1);
- animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY) + 1;
+ animations[i].frameCount = (int)(animDuration*GLTF_FRAMERATE) + 1;
animations[i].framePoses = (Transform **)RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
for (int j = 0; j < animations[i].frameCount; j++)
{
animations[i].framePoses[j] = (Transform *)RL_MALLOC(animations[i].boneCount*sizeof(Transform));
- float time = ((float) j*GLTF_ANIMDELAY)/1000.0f;
+ float time = (float)j / GLTF_FRAMERATE;
for (int k = 0; k < animations[i].boneCount; k++)
{
@@ -7042,8 +7041,8 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i animations, %i bones, %i skins", fileName,
m3d->numaction, m3d->numbone, m3d->numskin);
- // No animation or bone+skin?
- if (!m3d->numaction || !m3d->numbone || !m3d->numskin)
+ // No animation or bones, exit out. skins are not required because some people use one animation for N models
+ if (!m3d->numaction || !m3d->numbone)
{
m3d_free(m3d);
UnloadFileData(fileData);
diff --git a/src/rshapes.c b/src/rshapes.c
index 528a362d5..3f686f21a 100644
--- a/src/rshapes.c
+++ b/src/rshapes.c
@@ -25,7 +25,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -46,10 +46,7 @@
#include "raylib.h" // Declares module functions
-// Check if config flags have been externally provided on compilation line
-#if !defined(EXTERNAL_CONFIG_FLAGS)
- #include "config.h" // Defines module configuration flags
-#endif
+#include "config.h" // Defines module configuration flags
#if defined(SUPPORT_MODULE_RSHAPES)
diff --git a/src/rtext.c b/src/rtext.c
index f04f9ade4..45aa19b13 100644
--- a/src/rtext.c
+++ b/src/rtext.c
@@ -34,7 +34,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -55,14 +55,10 @@
#include "raylib.h" // Declares module functions
-// Check if config flags have been externally provided on compilation line
-#if !defined(EXTERNAL_CONFIG_FLAGS)
- #include "config.h" // Defines module configuration flags
-#endif
+#include "config.h" // Defines module configuration flags
#if defined(SUPPORT_MODULE_RTEXT)
-#include "utils.h" // Required for: LoadFile*()
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro()
#include // Required for: malloc(), free()
@@ -700,7 +696,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)
@@ -738,15 +738,19 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
{
stbtt_GetCodepointHMetrics(&fontInfo, cp, &glyphs[k].advanceX, NULL);
glyphs[k].advanceX = (int)((float)glyphs[k].advanceX*scaleFactor);
-
+
Image imSpace = {
- .data = RL_CALLOC(glyphs[k].advanceX*fontSize, 2),
+ .data = NULL,
.width = glyphs[k].advanceX,
.height = fontSize,
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE
};
+ // Only allocate space image if required
+ if (glyphs[k].advanceX > 0) imSpace.data = RL_CALLOC(glyphs[k].advanceX*fontSize, 1);
+ else glyphs[k].advanceX = 0;
+
glyphs[k].image = imSpace;
}
@@ -849,7 +853,8 @@ Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyp
}
#endif
- atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp)
+ int atlasDataSize = atlas.width*atlas.height; // Save total size for bounds checking
+ atlas.data = (unsigned char *)RL_CALLOC(atlasDataSize, 1); // Create a bitmap to store characters (8 bpp)
atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
atlas.mipmaps = 1;
@@ -894,7 +899,15 @@ Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyp
{
for (int x = 0; x < glyphs[i].image.width; x++)
{
- ((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = ((unsigned char *)glyphs[i].image.data)[y*glyphs[i].image.width + x];
+ int destX = offsetX + x;
+ int destY = offsetY + y;
+
+ // Security: check both lower and upper bounds
+ if ((destX >= 0) && (destX < atlas.width) && (destY >= 0) && (destY < atlas.height))
+ {
+ ((unsigned char *)atlas.data)[destY*atlas.width + destX] =
+ ((unsigned char *)glyphs[i].image.data)[y*glyphs[i].image.width + x];
+ }
}
}
@@ -942,7 +955,15 @@ Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyp
{
for (int x = 0; x < glyphs[i].image.width; x++)
{
- ((unsigned char *)atlas.data)[(rects[i].y + padding + y)*atlas.width + (rects[i].x + padding + x)] = ((unsigned char *)glyphs[i].image.data)[y*glyphs[i].image.width + x];
+ int destX = rects[i].x + padding + x;
+ int destY = rects[i].y + padding + y;
+
+ // Security fix: check both lower and upper bounds
+ if (destX >= 0 && destX < atlas.width && destY >= 0 && destY < atlas.height)
+ {
+ ((unsigned char *)atlas.data)[destY * atlas.width + destX] =
+ ((unsigned char *)glyphs[i].image.data)[y * glyphs[i].image.width + x];
+ }
}
}
}
@@ -956,14 +977,17 @@ Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyp
#if defined(SUPPORT_FONT_ATLAS_WHITE_REC)
// Add a 3x3 white rectangle at the bottom-right corner of the generated atlas,
- // useful to use as the white texture to draw shapes with raylib, using this rectangle
- // shapes and text can be backed into a single draw call: SetShapesTexture()
- for (int i = 0, k = atlas.width*atlas.height - 1; i < 3; i++)
+ // useful to use as the white texture to draw shapes with raylib
+ // Security: ensure the atlas is large enough to hold a 3x3 rectangle
+ if ((atlas.width >= 3) && (atlas.height >= 3))
{
- ((unsigned char *)atlas.data)[k - 0] = 255;
- ((unsigned char *)atlas.data)[k - 1] = 255;
- ((unsigned char *)atlas.data)[k - 2] = 255;
- k -= atlas.width;
+ for (int i = 0, k = atlas.width*atlas.height - 1; i < 3; i++)
+ {
+ ((unsigned char *)atlas.data)[k - 0] = 255;
+ ((unsigned char *)atlas.data)[k - 1] = 255;
+ ((unsigned char *)atlas.data)[k - 2] = 255;
+ k -= atlas.width;
+ }
}
#endif
@@ -1007,7 +1031,7 @@ void UnloadFont(Font font)
UnloadTexture(font.texture);
RL_FREE(font.recs);
- TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
+ TRACELOG(LOG_DEBUG, "FONT: Unloaded font data from RAM and VRAM");
}
}
@@ -1020,15 +1044,26 @@ bool ExportFontAsCode(Font font, const char *fileName)
#define TEXT_BYTES_PER_LINE 20
#endif
- #define MAX_FONT_DATA_SIZE 1024*1024 // 1 MB
-
// Get file name from path
char fileNamePascal[256] = { 0 };
strncpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName)), 256 - 1);
+
+ // Get font atlas image and size, required to estimate code file size
+ // NOTE: This mechanism is highly coupled to raylib
+ Image image = LoadImageFromTexture(font.texture);
+ if (image.format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) TRACELOG(LOG_WARNING, "Font export as code: Font image format is not GRAY+ALPHA!");
+ int imageDataSize = GetPixelDataSize(image.width, image.height, image.format);
- // NOTE: Text data buffer size is estimated considering image data size in bytes
- // and requiring 6 char bytes for every byte: "0x00, "
- char *txtData = (char *)RL_CALLOC(MAX_FONT_DATA_SIZE, sizeof(char));
+ // Image data is usually GRAYSCALE + ALPHA and can be reduced to GRAYSCALE
+ //ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
+
+ // Estimate text code size
+ // - Image data is stored as "0x%02x", so it requires at least 4 char per byte, let's use 6
+ // - font.recs[] data is stored as "{ %1.0f, %1.0f, %1.0f , %1.0f }", let's reserve 64 per rec
+ // - font.glyphs[] data is stored as "{ %i, %i, %i, %i, { 0 }},\n", let's reserve 64 per glyph
+ // - Comments and additional code, let's reserve 32KB
+ int txtDataSize = imageDataSize*6 + font.glyphCount*64 + font.glyphCount*64 + 32768;
+ char *txtData = (char *)RL_CALLOC(txtDataSize, sizeof(char));
int byteCount = 0;
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
@@ -1038,7 +1073,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
- byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n");
+ byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2026 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
@@ -1050,15 +1085,6 @@ bool ExportFontAsCode(Font font, const char *fileName)
byteCount += sprintf(txtData + byteCount, "// //\n");
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
- // Support font export and initialization
- // NOTE: This mechanism is highly coupled to raylib
- Image image = LoadImageFromTexture(font.texture);
- if (image.format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) TRACELOG(LOG_WARNING, "Font export as code: Font image format is not GRAY+ALPHA!");
- int imageDataSize = GetPixelDataSize(image.width, image.height, image.format);
-
- // Image data is usually GRAYSCALE + ALPHA and can be reduced to GRAYSCALE
- //ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
-
#define SUPPORT_COMPRESSED_FONT_ATLAS
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
// WARNING: Data is compressed using raylib CompressData() DEFLATE,
@@ -1096,8 +1122,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
byteCount += sprintf(txtData + byteCount, "};\n\n");
// Save font glyphs data
- // NOTE: Glyphs image data not saved (grayscale pixels),
- // it could be generated from image and recs
+ // NOTE: Glyphs image data not saved (grayscale pixels), it could be generated from image and recs
byteCount += sprintf(txtData + byteCount, "// Font glyphs info data\n");
byteCount += sprintf(txtData + byteCount, "// NOTE: No glyphs.image data provided\n");
byteCount += sprintf(txtData + byteCount, "static GlyphInfo fontGlyphs_%s[%i] = {\n", fileNamePascal, font.glyphCount);
@@ -1128,8 +1153,8 @@ bool ExportFontAsCode(Font font, const char *fileName)
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n");
#endif
- // We have two possible mechanisms to assign font.recs and font.glyphs data,
- // that data is already available as global arrays, we two options to assign that data:
+ // There are two possible mechanisms to assign font.recs and font.glyphs data,
+ // that data is already available as global arrays, two options to assign that data:
// - 1. Data copy. This option consumes more memory and Font MUST be unloaded by user, requiring additional code
// - 2. Data assignment. This option consumes less memory and Font MUST NOT be unloaded by user because data is on protected DATA segment
//#define SUPPORT_FONT_DATA_COPY
@@ -1514,7 +1539,7 @@ const char *TextFormat(const char *text, ...)
char *currentBuffer = buffers[index];
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
-
+
if (text != NULL)
{
va_list args;
@@ -1593,14 +1618,13 @@ float TextToFloat(const char *text)
#if defined(SUPPORT_TEXT_MANIPULATION)
// Copy one string to another, returns bytes copied
+// NOTE: Alternative implementation to strcpy(dst, src) from C standard library
int TextCopy(char *dst, const char *src)
{
int bytes = 0;
if ((src != NULL) && (dst != NULL))
{
- // NOTE: Alternative: use strcpy(dst, src)
-
while (*src != '\0')
{
*dst = *src;
@@ -1713,11 +1737,13 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
{
char *insertPoint = NULL; // Next insert point
char *temp = NULL; // Temp pointer
+ int textLen = 0; // Text string length
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
+ textLen = TextLength(text);
searchLen = TextLength(search);
if (searchLen == 0) return NULL; // Empty search causes infinite loop during count
@@ -1728,7 +1754,8 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
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);
+ int tempLen = textLen + (replaceLen - searchLen)*count + 1;
+ temp = result = (char *)RL_MALLOC(tempLen);
if (!result) return NULL; // Memory could not be allocated
@@ -1740,13 +1767,23 @@ char *TextReplace(const char *text, const char *search, const char *replacement)
{
insertPoint = (char *)strstr(text, search);
lastReplacePos = (int)(insertPoint - text);
+
+ // TODO: Review logic to avoid strcpy()
+ // OK - Those lines work
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
temp = strcpy(temp, replacement) + replaceLen;
+ // WRONG - But not those ones
+ //temp = strncpy(temp, text, tempLen - 1) + lastReplacePos;
+ //tempLen -= lastReplacePos;
+ //temp = strncpy(temp, replacement, tempLen - 1) + replaceLen;
+ //tempLen -= 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);
+ strcpy(temp, text); // OK
+ //strncpy(temp, text, tempLen - 1); // WRONG
}
return result;
@@ -2043,7 +2080,7 @@ char *TextToCamel(const char *text)
char *LoadUTF8(const int *codepoints, int length)
{
char *text = NULL;
-
+
if ((codepoints != NULL) && (length > 0))
{
// We allocate enough memory to fit all possible codepoints
@@ -2080,13 +2117,13 @@ int *LoadCodepoints(const char *text, int *count)
{
int *codepoints = NULL;
int codepointCount = 0;
-
+
if (text != NULL)
{
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));
+ codepoints = (int *)RL_CALLOC(textLength, sizeof(int));
int codepointSize = 0;
for (int i = 0; i < textLength; codepointCount++)
@@ -2193,7 +2230,7 @@ int GetCodepoint(const char *text, int *codepointSize)
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
-
+
int codepoint = 0x3f; // Codepoint (defaults to '?')
*codepointSize = 1;
if (text == NULL) return codepoint;
@@ -2488,7 +2525,7 @@ static Font LoadBMFont(const char *fileName)
int charId = 0;
int charX = 0;
int charY = 0;
- int charWidth = 0;
+ int charWidth = 0;
int charHeight = 0;
int charOffsetX = 0;
int charOffsetY = 0;
diff --git a/src/rtextures.c b/src/rtextures.c
index 4208b40bd..a20b5e516 100644
--- a/src/rtextures.c
+++ b/src/rtextures.c
@@ -42,7 +42,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -63,14 +63,10 @@
#include "raylib.h" // Declares module functions
-// Check if config flags have been externally provided on compilation line
-#if !defined(EXTERNAL_CONFIG_FLAGS)
- #include "config.h" // Defines module configuration flags
-#endif
+#include "config.h" // Defines module configuration flags
#if defined(SUPPORT_MODULE_RTEXTURES)
-#include "utils.h" // Required for: TRACELOG()
#include "rlgl.h" // OpenGL abstraction layer to multiple versions
#include // Required for: malloc(), calloc(), free()
@@ -765,7 +761,7 @@ bool ExportImageAsCode(Image image, const char *fileName)
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
- byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2025 Ramon Santamaria (@raysan5) //\n");
+ byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2026 Ramon Santamaria (@raysan5) //\n");
byteCount += sprintf(txtData + byteCount, "// //\n");
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
@@ -1125,7 +1121,7 @@ Image GenImageCellular(int width, int height, int tileSize)
Image GenImageText(int width, int height, const char *text)
{
Image image = { 0 };
-
+
int imageSize = width*height;
image.width = width;
image.height = height;
@@ -1487,7 +1483,7 @@ 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 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')
@@ -2395,7 +2391,7 @@ void ImageMipmaps(Image *image)
if (mipWidth < 1) mipWidth = 1;
if (mipHeight < 1) mipHeight = 1;
- TRACELOGD("IMAGE: Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize);
+ TRACELOG(LOG_DEBUG, "IMAGE: Next mipmap level: %i x %i - current size %i", mipWidth, mipHeight, mipSize);
mipCount++;
mipSize += GetPixelDataSize(mipWidth, mipHeight, image->format); // Add mipmap size (in bytes)
@@ -2432,7 +2428,7 @@ void ImageMipmaps(Image *image)
if (i < image->mipmaps) continue;
- TRACELOGD("IMAGE: Generating mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip);
+ TRACELOG(LOG_DEBUG, "IMAGE: Generating mipmap level: %i (%i x %i) - size: %i - offset: 0x%x", i, mipWidth, mipHeight, mipSize, nextmip);
ImageResize(&imCopy, mipWidth, mipHeight); // Uses internally Mitchell cubic downscale filter
memcpy(nextmip, imCopy.data, mipSize);
}
diff --git a/src/shell.html b/src/shell.html
index e6c80a39b..e5e26a3b1 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -179,7 +179,7 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
-
+
diff --git a/src/utils.c b/src/utils.c
deleted file mode 100644
index 09158893a..000000000
--- a/src/utils.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/**********************************************************************************************
-*
-* raylib.utils - Some common utility functions
-*
-* CONFIGURATION:
-* #define SUPPORT_TRACELOG
-* Show TraceLog() output messages
-* NOTE: By default LOG_DEBUG traces not shown
-*
-*
-* LICENSE: zlib/libpng
-*
-* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
-*
-* This software is provided "as-is", without any express or implied warranty. In no event
-* will the authors be held liable for any damages arising from the use of this software.
-*
-* Permission is granted to anyone to use this software for any purpose, including commercial
-* applications, and to alter it and redistribute it freely, subject to the following restrictions:
-*
-* 1. The origin of this software must not be misrepresented; you must not claim that you
-* wrote the original software. If you use this software in a product, an acknowledgment
-* in the product documentation would be appreciated but is not required.
-*
-* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
-* as being the original software.
-*
-* 3. This notice may not be removed or altered from any source distribution.
-*
-**********************************************************************************************/
-
-#include "raylib.h" // WARNING: Required for: LogType enum
-
-// Check if config flags have been externally provided on compilation line
-#if !defined(EXTERNAL_CONFIG_FLAGS)
- #include "config.h" // Defines module configuration flags
-#endif
-
-#include "utils.h"
-
-#if defined(PLATFORM_ANDROID)
- #include // Required for: Android error types
- #include // Required for: Android log system: __android_log_vprint()
- #include // Required for: Android assets manager: AAsset, AAssetManager_open()...
-#endif
-
-#include // Required for: exit()
-#include // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose()
-#include // Required for: va_list, va_start(), va_end()
-#include // Required for: strcpy(), strcat()
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#ifndef MAX_TRACELOG_MSG_LENGTH
- #define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
-#endif
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-static int logTypeLevel = LOG_INFO; // Minimum log type level
-
-static TraceLogCallback traceLog = NULL; // TraceLog callback function pointer
-static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback function pointer
-static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback function pointer
-static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback function pointer
-static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback function pointer
-
-//----------------------------------------------------------------------------------
-// Functions to set internal callbacks
-//----------------------------------------------------------------------------------
-void SetTraceLogCallback(TraceLogCallback callback) { traceLog = callback; } // Set custom trace log
-void SetLoadFileDataCallback(LoadFileDataCallback callback) { loadFileData = callback; } // Set custom file data loader
-void SetSaveFileDataCallback(SaveFileDataCallback callback) { saveFileData = callback; } // Set custom file data saver
-void SetLoadFileTextCallback(LoadFileTextCallback callback) { loadFileText = callback; } // Set custom file text loader
-void SetSaveFileTextCallback(SaveFileTextCallback callback) { saveFileText = callback; } // Set custom file text saver
-
-#if defined(PLATFORM_ANDROID)
-static AAssetManager *assetManager = NULL; // Android assets manager pointer
-static const char *internalDataPath = NULL; // Android internal data path
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Declaration
-//----------------------------------------------------------------------------------
-#if defined(PLATFORM_ANDROID)
-FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int),
- fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *));
-
-static int android_read(void *cookie, char *buf, int size);
-static int android_write(void *cookie, const char *buf, int size);
-static fpos_t android_seek(void *cookie, fpos_t offset, int whence);
-static int android_close(void *cookie);
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-// Set the current threshold (minimum) log level
-void SetTraceLogLevel(int logType) { logTypeLevel = logType; }
-
-// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
-void TraceLog(int logType, const char *text, ...)
-{
-#if defined(SUPPORT_TRACELOG)
- // Message has level below current threshold, don't emit
- if ((logType < logTypeLevel) || (text == NULL)) return;
-
- va_list args;
- va_start(args, text);
-
- if (traceLog)
- {
- traceLog(logType, text, args);
- va_end(args);
- return;
- }
-
-#if defined(PLATFORM_ANDROID)
- switch (logType)
- {
- case LOG_TRACE: __android_log_vprint(ANDROID_LOG_VERBOSE, "raylib", text, args); break;
- case LOG_DEBUG: __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", text, args); break;
- case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", text, args); break;
- case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", text, args); break;
- case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", text, args); break;
- case LOG_FATAL: __android_log_vprint(ANDROID_LOG_FATAL, "raylib", text, args); break;
- default: break;
- }
-#else
- char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 };
-
- switch (logType)
- {
- case LOG_TRACE: strcpy(buffer, "TRACE: "); break;
- case LOG_DEBUG: strcpy(buffer, "DEBUG: "); break;
- case LOG_INFO: strcpy(buffer, "INFO: "); break;
- case LOG_WARNING: strcpy(buffer, "WARNING: "); break;
- case LOG_ERROR: strcpy(buffer, "ERROR: "); break;
- case LOG_FATAL: strcpy(buffer, "FATAL: "); break;
- default: break;
- }
-
- 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);
-#endif
-
- va_end(args);
-
- if (logType == LOG_FATAL) exit(EXIT_FAILURE); // If fatal logging, exit program
-
-#endif // SUPPORT_TRACELOG
-}
-
-// Internal memory allocator
-// NOTE: Initializes to zero by default
-void *MemAlloc(unsigned int size)
-{
- void *ptr = RL_CALLOC(size, 1);
- return ptr;
-}
-
-// Internal memory reallocator
-void *MemRealloc(void *ptr, unsigned int size)
-{
- void *ret = RL_REALLOC(ptr, size);
- return ret;
-}
-
-// Internal memory free
-void MemFree(void *ptr)
-{
- RL_FREE(ptr);
-}
-
-// Load data from file into a buffer
-unsigned char *LoadFileData(const char *fileName, int *dataSize)
-{
- unsigned char *data = NULL;
- *dataSize = 0;
-
- if (fileName != NULL)
- {
- if (loadFileData)
- {
- data = loadFileData(fileName, dataSize);
- return data;
- }
-#if defined(SUPPORT_STANDARD_FILEIO)
- FILE *file = fopen(fileName, "rb");
-
- if (file != NULL)
- {
- // WARNING: On binary streams SEEK_END could not be found,
- // using fseek() and ftell() could not work in some (rare) cases
- fseek(file, 0, SEEK_END);
- int size = ftell(file); // WARNING: ftell() returns 'long int', maximum size returned is INT_MAX (2147483647 bytes)
- fseek(file, 0, SEEK_SET);
-
- if (size > 0)
- {
- data = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char));
-
- if (data != NULL)
- {
- // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
- size_t count = fread(data, sizeof(unsigned char), size, file);
-
- // WARNING: fread() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
- // dataSize is unified along raylib as a 'int' type, so, for file-sizes > INT_MAX (2147483647 bytes) we have a limitation
- if (count > 2147483647)
- {
- TRACELOG(LOG_WARNING, "FILEIO: [%s] File is bigger than 2147483647 bytes, avoid using LoadFileData()", fileName);
-
- RL_FREE(data);
- data = NULL;
- }
- else
- {
- *dataSize = (int)count;
-
- if ((*dataSize) != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded (%i bytes out of %i)", fileName, dataSize, count);
- else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName);
- }
- }
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName);
- }
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName);
-
- fclose(file);
- }
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
-#else
- TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
-#endif
- }
- else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-
- return data;
-}
-
-// Unload file data allocated by LoadFileData()
-void UnloadFileData(unsigned char *data)
-{
- RL_FREE(data);
-}
-
-// Save data to file from buffer
-bool SaveFileData(const char *fileName, void *data, int dataSize)
-{
- bool success = false;
-
- if (fileName != NULL)
- {
- if (saveFileData)
- {
- return saveFileData(fileName, data, dataSize);
- }
-#if defined(SUPPORT_STANDARD_FILEIO)
- FILE *file = fopen(fileName, "wb");
-
- if (file != NULL)
- {
- // WARNING: fwrite() returns a size_t value, usually 'unsigned int' (32bit compilation) and 'unsigned long long' (64bit compilation)
- // and expects a size_t input value but as dataSize is limited to INT_MAX (2147483647 bytes), there shouldn't be a problem
- int count = (int)fwrite(data, sizeof(unsigned char), dataSize, file);
-
- if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
- else if (count != dataSize) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
- else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName);
-
- int result = fclose(file);
- if (result == 0) success = true;
- }
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
-#else
- TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
-#endif
- }
- else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-
- return success;
-}
-
-// Export data to code (.h), returns true on success
-bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName)
-{
- bool success = false;
-
-#ifndef TEXT_BYTES_PER_LINE
- #define TEXT_BYTES_PER_LINE 20
-#endif
-
- // NOTE: Text data buffer size is estimated considering raw data size in bytes
- // and requiring 6 char bytes for every byte: "0x00, "
- char *txtData = (char *)RL_CALLOC(dataSize*6 + 2000, sizeof(char));
-
- int byteCount = 0;
- byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
- byteCount += sprintf(txtData + byteCount, "// //\n");
- byteCount += sprintf(txtData + byteCount, "// DataAsCode exporter v1.0 - Raw data exported as an array of bytes //\n");
- byteCount += sprintf(txtData + byteCount, "// //\n");
- byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
- byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
- byteCount += sprintf(txtData + byteCount, "// //\n");
- byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022-2025 Ramon Santamaria (@raysan5) //\n");
- byteCount += sprintf(txtData + byteCount, "// //\n");
- byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
-
- // Get file name from path
- char varFileName[256] = { 0 };
- strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
- for (int i = 0; varFileName[i] != '\0'; i++)
- {
- // Convert variable name to uppercase
- if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
- // Replace non valid character for C identifier with '_'
- else if (varFileName[i] == '.' || varFileName[i] == '-' || varFileName[i] == '?' || varFileName[i] == '!' || varFileName[i] == '+') { varFileName[i] = '_'; }
- }
-
- byteCount += sprintf(txtData + byteCount, "#define %s_DATA_SIZE %i\n\n", varFileName, dataSize);
-
- byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%s_DATA_SIZE] = { ", varFileName, varFileName);
- for (int i = 0; i < (dataSize - 1); i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), data[i]);
- byteCount += sprintf(txtData + byteCount, "0x%x };\n", data[dataSize - 1]);
-
- // NOTE: Text data size exported is determined by '\0' (NULL) character
- success = SaveFileText(fileName, txtData);
-
- RL_FREE(txtData);
-
- if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName);
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export data as code", fileName);
-
- return success;
-}
-
-// Load text data from file, returns a '\0' terminated string
-// NOTE: text chars array should be freed manually
-char *LoadFileText(const char *fileName)
-{
- char *text = NULL;
-
- if (fileName != NULL)
- {
- if (loadFileText)
- {
- text = loadFileText(fileName);
- return text;
- }
-#if defined(SUPPORT_STANDARD_FILEIO)
- FILE *file = fopen(fileName, "rt");
-
- if (file != NULL)
- {
- // WARNING: When reading a file as 'text' file,
- // text mode causes carriage return-linefeed translation...
- // ...but using fseek() should return correct byte-offset
- fseek(file, 0, SEEK_END);
- unsigned int size = (unsigned int)ftell(file);
- fseek(file, 0, SEEK_SET);
-
- if (size > 0)
- {
- text = (char *)RL_CALLOC(size + 1, sizeof(char));
-
- if (text != NULL)
- {
- unsigned int count = (unsigned int)fread(text, sizeof(char), size, file);
-
- // WARNING: \r\n is converted to \n on reading, so,
- // read bytes count gets reduced by the number of lines
- if (count < size) text = (char *)RL_REALLOC(text, count + 1);
-
- // Zero-terminate the string
- text[count] = '\0';
-
- TRACELOG(LOG_INFO, "FILEIO: [%s] Text file loaded successfully", fileName);
- }
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to allocated memory for file reading", fileName);
- }
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read text file", fileName);
-
- fclose(file);
- }
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
-#else
- TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
-#endif
- }
- else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-
- return text;
-}
-
-// Unload file text data allocated by LoadFileText()
-void UnloadFileText(char *text)
-{
- RL_FREE(text);
-}
-
-// Save text data to file (write), string must be '\0' terminated
-bool SaveFileText(const char *fileName, const char *text)
-{
- bool success = false;
-
- if (fileName != NULL)
- {
- if (saveFileText)
- {
- return saveFileText(fileName, text);
- }
-#if defined(SUPPORT_STANDARD_FILEIO)
- FILE *file = fopen(fileName, "wt");
-
- if (file != NULL)
- {
- int 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);
-
- int result = fclose(file);
- if (result == 0) success = true;
- }
- else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
-#else
- TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback");
-#endif
- }
- else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
-
- return success;
-}
-
-#if defined(PLATFORM_ANDROID)
-// Initialize asset manager from android app
-void InitAssetManager(AAssetManager *manager, const char *dataPath)
-{
- assetManager = manager;
- internalDataPath = dataPath;
-}
-
-// Replacement for fopen()
-// REF: https://developer.android.com/ndk/reference/group/asset
-FILE *android_fopen(const char *fileName, const char *mode)
-{
- if (mode[0] == 'w')
- {
- // 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
- #undef fopen
- return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode);
- #define fopen(name, mode) android_fopen(name, mode)
- }
- else
- {
- // NOTE: AAsset provides access to read-only asset
- AAsset *asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN);
-
- if (asset != NULL)
- {
- // Get pointer to file in the assets
- return funopen(asset, android_read, android_write, android_seek, android_close);
- }
- else
- {
- #undef fopen
- // Just do a regular open if file is not found in the assets
- return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode);
- #define fopen(name, mode) android_fopen(name, mode)
- }
- }
-}
-#endif // PLATFORM_ANDROID
-
-//----------------------------------------------------------------------------------
-// Module Internal Functions Definition
-//----------------------------------------------------------------------------------
-#if defined(PLATFORM_ANDROID)
-static int android_read(void *cookie, char *data, int dataSize)
-{
- return AAsset_read((AAsset *)cookie, data, dataSize);
-}
-
-static int android_write(void *cookie, const char *data, int dataSize)
-{
- TRACELOG(LOG_WARNING, "ANDROID: Failed to provide write access to APK");
-
- return EACCES;
-}
-
-static fpos_t android_seek(void *cookie, fpos_t offset, int whence)
-{
- return AAsset_seek((AAsset *)cookie, offset, whence);
-}
-
-static int android_close(void *cookie)
-{
- AAsset_close((AAsset *)cookie);
- return 0;
-}
-#endif // PLATFORM_ANDROID
diff --git a/src/utils.h b/src/utils.h
deleted file mode 100644
index 271d0d2c7..000000000
--- a/src/utils.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/**********************************************************************************************
-*
-* raylib.utils - Some common utility functions
-*
-*
-* LICENSE: zlib/libpng
-*
-* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
-*
-* This software is provided "as-is", without any express or implied warranty. In no event
-* will the authors be held liable for any damages arising from the use of this software.
-*
-* Permission is granted to anyone to use this software for any purpose, including commercial
-* applications, and to alter it and redistribute it freely, subject to the following restrictions:
-*
-* 1. The origin of this software must not be misrepresented; you must not claim that you
-* wrote the original software. If you use this software in a product, an acknowledgment
-* in the product documentation would be appreciated but is not required.
-*
-* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
-* as being the original software.
-*
-* 3. This notice may not be removed or altered from any source distribution.
-*
-**********************************************************************************************/
-
-#ifndef UTILS_H
-#define UTILS_H
-
-#if defined(PLATFORM_ANDROID)
- #include // Required for: FILE
- #include // Required for: AAssetManager
-#endif
-
-#if defined(SUPPORT_TRACELOG)
- #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__)
-
- #if defined(SUPPORT_TRACELOG_DEBUG)
- #define TRACELOGD(...) TraceLog(LOG_DEBUG, __VA_ARGS__)
- #else
- #define TRACELOGD(...) (void)0
- #endif
-#else
- #define TRACELOG(level, ...) (void)0
- #define TRACELOGD(...) (void)0
-#endif
-
-//----------------------------------------------------------------------------------
-// Some basic Defines
-//----------------------------------------------------------------------------------
-#if defined(PLATFORM_ANDROID)
- #define fopen(name, mode) android_fopen(name, mode)
-#endif
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-//...
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-// Nop...
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-#if defined(__cplusplus)
-extern "C" { // Prevents name mangling of functions
-#endif
-
-#if defined(PLATFORM_ANDROID)
-void InitAssetManager(AAssetManager *manager, const char *dataPath); // Initialize asset manager from android app
-FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
-#endif
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif // UTILS_H
diff --git a/tools/rexm/README.md b/tools/rexm/README.md
index 232ef51d6..14704b5ea 100644
--- a/tools/rexm/README.md
+++ b/tools/rexm/README.md
@@ -102,4 +102,4 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c
`rexm` is an **open source** project, licensed under an unmodified [zlib/libpng license](LICENSE)
-*Copyright (c) 2025 Ramon Santamaria ([@raysan5](https://github.com/raysan5))*
+*Copyright (c) 2025-2026 Ramon Santamaria ([@raysan5](https://github.com/raysan5))*
diff --git a/tools/rexm/VS2022/raylib/raylib.vcxproj b/tools/rexm/VS2022/raylib/raylib.vcxproj
index df2831b33..dbc6272ed 100644
--- a/tools/rexm/VS2022/raylib/raylib.vcxproj
+++ b/tools/rexm/VS2022/raylib/raylib.vcxproj
@@ -312,7 +312,6 @@
-
@@ -320,7 +319,6 @@
-
diff --git a/tools/rexm/VS2022/raylib/raylib.vcxproj.filters b/tools/rexm/VS2022/raylib/raylib.vcxproj.filters
index b5f5536dc..5914ba240 100644
--- a/tools/rexm/VS2022/raylib/raylib.vcxproj.filters
+++ b/tools/rexm/VS2022/raylib/raylib.vcxproj.filters
@@ -8,7 +8,6 @@
-
@@ -16,7 +15,6 @@
-
external
diff --git a/tools/rexm/reports/examples_issues.md b/tools/rexm/reports/examples_issues.md
index 14e7a61c5..081170806 100644
--- a/tools/rexm/reports/examples_issues.md
+++ b/tools/rexm/reports/examples_issues.md
@@ -21,10 +21,9 @@ Example elements validated:
| **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|[WMETA]|
|:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|:-----:|
| core_highdpi_testbed | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ |
-| rlgl_standalone | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
-| rlgl_compute_shader | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
-| easings_testbed | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ |
-| embedded_files_loading | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
-| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| 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 45c195415..d8f4a9521 100644
--- a/tools/rexm/reports/examples_validation.md
+++ b/tools/rexm/reports/examples_validation.md
@@ -56,7 +56,7 @@ Example elements validated:
| core_smooth_pixelperfect | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_random_sequence | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_automation_events | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| core_high_dpi | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| core_highdpi_demo | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_render_texture | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_undo_redo | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_viewport_scaling | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -67,6 +67,7 @@ Example elements validated:
| core_clipboard_text | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_text_file_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_compute_hash | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| core_keyboard_testbed | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_bullet_hell | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -105,6 +106,7 @@ Example elements validated:
| shapes_rlgl_triangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_ball_physics | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_penrose_tile | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_hilbert_curve | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -134,6 +136,7 @@ Example elements validated:
| textures_textured_curve | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_sprite_stacking | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_cellular_automata | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| textures_framebuffer_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_sprite_fonts | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_font_spritefont | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_font_filters | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -209,7 +212,7 @@ Example elements validated:
| shaders_lightmap_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_rounded_rectangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_depth_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ |
+| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_module_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_music_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_raw_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -219,9 +222,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 | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| rlgl_standalone | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| rlgl_compute_shader | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
+| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c
index aa491ff23..ad9bcbed0 100644
--- a/tools/rexm/rexm.c
+++ b/tools/rexm/rexm.c
@@ -30,7 +30,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2025 Ramon Santamaria (@raysan5)
+* Copyright (c) 2025-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -207,8 +207,8 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf
// Update generated Web example .html file metadata
static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath);
-// Check if text string is a list of strings
-static bool TextInList(const char *text, const char **list, int listCount);
+// Check if text string is in a list of strings and get index, -1 if not found
+static int GetTextListIndex(const char *text, const char **list, int listCount);
//------------------------------------------------------------------------------------
// Program main entry point
@@ -570,7 +570,7 @@ int main(int argc, char *argv[])
// -----------------------------------------------------------------------------------------
// Add example to the collection list, if not already there
- // NOTE: Required format: shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ray";@raysan5
+ // NOTE: Required format: shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2026;"Ray";@raysan5
//------------------------------------------------------------------------------------------------
char *exCollectionList = LoadFileText(exCollectionFilePath);
if (TextFindIndex(exCollectionList, exName) == -1) // Example not found
@@ -660,7 +660,8 @@ int main(int argc, char *argv[])
// we must store provided file paths because pointers will be overwriten
// TODO: It seems projects are added to solution BUT not to required solution folder,
// that process still requires to be done manually
- LOG("INFO: [%s] Adding project to raylib solution (.sln)\n", TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
+ LOG("INFO: [%s] Adding project to raylib solution (.sln)\n",
+ TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
AddVSProjectToSolution(exVSProjectSolutionFile,
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), exCategory);
//------------------------------------------------------------------------------------------------
@@ -1003,6 +1004,9 @@ int main(int argc, char *argv[])
VALID_INVALID_CATEGORY
*/
+ // Validate and update examples collection list
+ // NOTE: New .c examples found are added at the end of its category
+ //---------------------------------------------------------------------------------------------------
// Scan available example .c files and add to collection missing ones
// NOTE: Source of truth is what we have in the examples directories (on validation/update)
LOG("INFO: Scanning available example (.c) files to be added to collection...\n");
@@ -1010,14 +1014,66 @@ int main(int argc, char *argv[])
// Load examples collection list file (raylib/examples/examples_list.txt)
char *exList = LoadFileText(exCollectionFilePath);
+ int exListLen = (int)strlen(exList);
+
char *exListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
bool listUpdated = false;
- int exListLen = (int)strlen(exList);
- strcpy(exListUpdated, exList);
+ // Add new examples to the collection list if not found
+ // WARNING: Added to the end of category, order defines place on raylib webpage
+ for (unsigned int i = 0; i < clist.count; i++)
+ {
+ // NOTE: Skipping "examples_template" from checks
+ if (!TextIsEqual(GetFileNameWithoutExt(clist.paths[i]), "examples_template") &&
+ (TextFindIndex(exList, GetFileNameWithoutExt(clist.paths[i])) == -1))
+ {
+ // Get new example data
+ rlExampleInfo *exInfo = LoadExampleInfo(clist.paths[i]);
- // Copy examples list into an update list
- // NOTE: Checking and removing duplicate entries
+ // Get example category, -1 if not found in list
+ int catIndex = GetTextListIndex(exInfo->category, exCategories, REXM_MAX_EXAMPLE_CATEGORIES);
+
+ if (catIndex > -1)
+ {
+ int nextCatIndex = catIndex + 1;
+ if (nextCatIndex > (REXM_MAX_EXAMPLE_CATEGORIES - 1)) nextCatIndex = -1; // EOF
+
+ // Find position to add new example on list, just before the following category
+ // Category order: core, shapes, textures, text, models, shaders, audio, [others]
+ int exListNextCatIndex = -1;
+ if (nextCatIndex != -1) exListNextCatIndex = TextFindIndex(exList, exCategories[nextCatIndex]);
+ else exListNextCatIndex = exListLen; // EOF
+
+ strncpy(exListUpdated, exList, exListNextCatIndex);
+
+ // Get example difficulty stars
+ char starsText[16] = { 0 };
+ for (int s = 0; s < 4; s++)
+ {
+ // NOTE: Every UTF-8 star are 3 bytes
+ if (s < exInfo->stars) strcpy(starsText + 3*s, "★");
+ else strcpy(starsText + 3*s, "☆");
+ }
+
+ // Add new example to the list
+ int exListNewExLen = sprintf(exListUpdated + exListNextCatIndex,
+ TextFormat("%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n",
+ exInfo->category, exInfo->name, starsText, exInfo->verCreated,
+ exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed,
+ exInfo->author, exInfo->authorGitHub));
+
+ // Add the following examples to the end of collection list
+ strncpy(exListUpdated + exListNextCatIndex + exListNewExLen, exList + exListNextCatIndex, exListLen - exListNextCatIndex);
+
+ listUpdated = true;
+ }
+
+ UnloadExampleInfo(exInfo);
+ }
+ }
+
+ /*
+ // Check and remove duplicate example entries
int lineCount = 0;
char **exListLines = LoadTextLines(exList, &lineCount);
int exListUpdatedOffset = 0;
@@ -1031,46 +1087,7 @@ int main(int argc, char *argv[])
}
UnloadTextLines(exListLines, lineCount);
-
- for (unsigned int i = 0; i < clist.count; i++)
- {
- // NOTE: Skipping "examples_template" from checks
- if (!TextIsEqual(GetFileNameWithoutExt(clist.paths[i]), "examples_template") &&
- (TextFindIndex(exList, GetFileNameWithoutExt(clist.paths[i])) == -1))
- {
- // TODO: Examples to be added in the list should be added at the end of their categories,
- // not at the end of the file...
-
- // Add example to the examples collection list
- // WARNING: Added to the end of the list, order must be set by users and
- // defines placement on raylib webpage
- rlExampleInfo *exInfo = LoadExampleInfo(clist.paths[i]);
-
- // Validate example category
- // TODO: Should [others] category be considered?
- if (TextInList(exInfo->category, exCategories, REXM_MAX_EXAMPLE_CATEGORIES))// && !TextIsEqual(exInfo->category, "others"))
- {
- // Get example difficulty stars
- char starsText[16] = { 0 };
- for (int s = 0; s < 4; s++)
- {
- // NOTE: Every UTF-8 star are 3 bytes
- if (s < exInfo->stars) strcpy(starsText + 3*s, "★");
- else strcpy(starsText + 3*s, "☆");
- }
-
- exListLen += sprintf(exListUpdated + exListLen,
- TextFormat("%s;%s;%s;%s;%s;%i;%i;\"%s\";@%s\n",
- exInfo->category, exInfo->name, starsText, exInfo->verCreated,
- exInfo->verUpdated, exInfo->yearCreated, exInfo->yearReviewed,
- exInfo->author, exInfo->authorGitHub));
-
- listUpdated = true;
- }
-
- UnloadExampleInfo(exInfo);
- }
- }
+ */
if (listUpdated) SaveFileText(exCollectionFilePath, exListUpdated);
@@ -1078,6 +1095,7 @@ int main(int argc, char *argv[])
RL_FREE(exListUpdated);
UnloadDirectoryFiles(clist);
+ //---------------------------------------------------------------------------------------------------
// Check all examples in collection [examples_list.txt] -> Source of truth!
LOG("INFO: Validating examples in collection...\n");
@@ -1226,6 +1244,18 @@ int main(int argc, char *argv[])
// Actions to fix/review anything possible from validation results
//------------------------------------------------------------------------------------------------
+ // Update files: Makefile, Makefile.Web, README.md, examples.js
+ // Solves: VALID_NOT_IN_MAKEFILE, VALID_NOT_IN_MAKEFILE_WEB, VALID_NOT_IN_README, VALID_NOT_IN_JS
+ // WARNING: Makefile.Web needs to be updated before trying to rebuild web example!
+ UpdateRequiredFiles();
+ for (int i = 0; i < exCollectionCount; i++)
+ {
+ exCollection[i].status &= ~VALID_NOT_IN_MAKEFILE;
+ exCollection[i].status &= ~VALID_NOT_IN_MAKEFILE_WEB;
+ exCollection[i].status &= ~VALID_NOT_IN_README;
+ exCollection[i].status &= ~VALID_NOT_IN_JS;
+ }
+
// Check examples "status" information
for (int i = 0; i < exCollectionCount; i++)
{
@@ -1325,17 +1355,6 @@ int main(int argc, char *argv[])
}
}
}
-
- // Update files: Makefile, Makefile.Web, README.md, examples.js
- // Solves: VALID_NOT_IN_MAKEFILE, VALID_NOT_IN_MAKEFILE_WEB, VALID_NOT_IN_README, VALID_NOT_IN_JS
- UpdateRequiredFiles();
- for (int i = 0; i < exCollectionCount; i++)
- {
- exCollection[i].status &= ~VALID_NOT_IN_MAKEFILE;
- exCollection[i].status &= ~VALID_NOT_IN_MAKEFILE_WEB;
- exCollection[i].status &= ~VALID_NOT_IN_README;
- exCollection[i].status &= ~VALID_NOT_IN_JS;
- }
//------------------------------------------------------------------------------------------------
}
@@ -1591,11 +1610,16 @@ int main(int argc, char *argv[])
FileRemove(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
// STEP 3: Run example on browser
- // WARNING: Example download is asynchronous so reading fails on next step
- // when looking for a file that could not have been downloaded yet
- ChangeDirectory(TextFormat("%s", exBasePath));
- if (i == 0) system("start python -m http.server 8080"); // Init localhost just once
- system(TextFormat("start explorer \"http:\\localhost:8080/%s/%s.html", exCategory, exName));
+ if (FileExists(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName)) &&
+ FileExists(TextFormat("%s/%s/%s.wasm", exBasePath, exCategory, exName)) &&
+ FileExists(TextFormat("%s/%s/%s.js", exBasePath, exCategory, exName)))
+ {
+ // WARNING: Example download is asynchronous so reading fails on next step
+ // when looking for a file that could not have been downloaded yet
+ ChangeDirectory(TextFormat("%s", exBasePath));
+ if (i == 0) system("start python -m http.server 8080"); // Init localhost just once
+ system(TextFormat("start explorer \"http:\\localhost:8080/%s/%s.html", exCategory, exName));
+ }
// NOTE: Example .log is automatically downloaded into system Downloads directory on browser-example exectution
@@ -1858,7 +1882,7 @@ int main(int argc, char *argv[])
printf("// rexm [raylib examples manager] - A simple command-line tool to manage raylib examples //\n");
printf("// powered by raylib v5.6-dev //\n");
printf("// //\n");
- printf("// Copyright (c) 2025 Ramon Santamaria (@raysan5) //\n");
+ printf("// Copyright (c) 2025-2026 Ramon Santamaria (@raysan5) //\n");
printf("// //\n");
printf("////////////////////////////////////////////////////////////////////////////////////////////\n\n");
@@ -2417,7 +2441,7 @@ static void UnloadExampleInfo(rlExampleInfo *exInfo)
}
// raylib example line info parser
-// Parses following line format: core;core_basic_window;★☆☆☆;1.0;1.0;2013;2025;"Ray";@raysan5
+// Parses following line format: core;core_basic_window;★☆☆☆;1.0;1.0;2013;2026;"Ray";@raysan5
static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry)
{
#define MAX_EXAMPLE_INFO_LINE_LEN 512
@@ -2429,7 +2453,10 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry)
int tokenCount = 0;
char **tokens = TextSplit(line, ';', &tokenCount);
- if (tokenCount != 9) LOG("REXM: WARNING: Example collection line contains invalid number of tokens: %i\n", tokenCount);
+ if (tokenCount != 9)
+ {
+ LOG("REXM: WARNING: Example collection line contains invalid number of tokens: %i\n", tokenCount);
+ }
// Get category and name
strcpy(entry->category, tokens[0]);
@@ -2587,7 +2614,7 @@ static int AddVSProjectToSolution(const char *slnFile, const char *projFile, con
int result = 0;
// WARNING: Function uses extensively TextFormat(),
- // *projFile ptr will be overwriten after a while
+ // *projFile ptr could be overwriten after a while -> Use copied string
// Generate unique UUID
const char *uuid = GenerateUUIDv4();
@@ -2671,14 +2698,22 @@ static int AddVSProjectToSolution(const char *slnFile, const char *projFile, con
// Add project folder line
// NOTE: Folder uuid depends on category
- if (strcmp(category, "core") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}\n", uuid));
- else if (strcmp(category, "shapes") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s} = {278D8859-20B1-428F-8448-064F46E1F021}\n", uuid));
- else if (strcmp(category, "textures") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}\n", uuid));
- else if (strcmp(category, "text") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}\n", uuid));
- else if (strcmp(category, "models") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}\n", uuid));
- else if (strcmp(category, "shaders") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}\n", uuid));
- else if (strcmp(category, "audio") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}\n", uuid));
- else if (strcmp(category, "other") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s} = {E9D708A5-9C1F-4B84-A795-C5F191801762}\n", uuid));
+ if (strcmp(category, "core") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
+ TextFormat("\t\t{%s} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}\n", uuid));
+ else if (strcmp(category, "shapes") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
+ TextFormat("\t\t{%s} = {278D8859-20B1-428F-8448-064F46E1F021}\n", uuid));
+ else if (strcmp(category, "textures") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
+ TextFormat("\t\t{%s} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}\n", uuid));
+ else if (strcmp(category, "text") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
+ TextFormat("\t\t{%s} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}\n", uuid));
+ else if (strcmp(category, "models") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
+ TextFormat("\t\t{%s} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}\n", uuid));
+ else if (strcmp(category, "shaders") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
+ TextFormat("\t\t{%s} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}\n", uuid));
+ else if (strcmp(category, "audio") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
+ TextFormat("\t\t{%s} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}\n", uuid));
+ else if (strcmp(category, "other") == 0) offsetIndex += sprintf(slnTextUpdated + offsetIndex,
+ TextFormat("\t\t{%s} = {E9D708A5-9C1F-4B84-A795-C5F191801762}\n", uuid));
else LOG("WARNING: Provided category is not valid: %s\n", category);
//----------------------------------------------------------------------------------------
@@ -2817,7 +2852,7 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf
if (exTextUpdated[2] != NULL) exTextUpdatedPtr = exTextUpdated[2];
// Update copyright message
- // String: "* Copyright (c) 2019-2025 Contributor Name (@github_user) and Ramon Santamaria (@raysan5)"
+ // String: "* Copyright (c) 2019-2026 Contributor Name (@github_user) and Ramon Santamaria (@raysan5)"
if (info->yearCreated == info->yearReviewed)
{
exTextUpdated[3] = TextReplaceBetween(exTextUpdatedPtr, "Copyright (c) ", ")",
@@ -2871,8 +2906,8 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath)
// Get example name: replace underscore by spaces
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] = ' '; }
+ strcpy(exTitle, exName);
+ for (int i = 0; (i < 64) && (exTitle[i] != '\0'); i++) { if (exTitle[i] == '_') exTitle[i] = ' '; }
// Get example category from exName: copy until first underscore
for (int i = 0; (exName[i] != '_'); i++) exCategory[i] = exName[i];
@@ -2912,13 +2947,13 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath)
}
// Check if text string is a list of strings
-static bool TextInList(const char *text, const char **list, int listCount)
+static int GetTextListIndex(const char *text, const char **list, int listCount)
{
- bool result = false;
+ int result = -1;
for (int i = 0; i < listCount; i++)
{
- if (TextIsEqual(text, list[i])) { result = true; break; }
+ if (TextIsEqual(text, list[i])) { result = i; break; }
}
return result;
diff --git a/tools/rlparser/LICENSE b/tools/rlparser/LICENSE
index 7ed4b8722..4ce3bbb8d 100644
--- a/tools/rlparser/LICENSE
+++ b/tools/rlparser/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2021-2025 Ramon Santamaria (@raysan5)
+Copyright (c) 2021-2026 Ramon Santamaria (@raysan5)
This software is provided "as-is", without any express or implied warranty. In no event
will the authors be held liable for any damages arising from the use of this software.
diff --git a/tools/rlparser/README.md b/tools/rlparser/README.md
index 0e4f9b739..cf009a891 100644
--- a/tools/rlparser/README.md
+++ b/tools/rlparser/README.md
@@ -19,7 +19,7 @@ Check `rlparser.c` for details about those structs.
// //
// more info and bugs-report: github.com/raysan5/raylib/tools/rlparser //
// //
-// Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) //
+// Copyright (c) 2021-2026 Ramon Santamaria (@raysan5) //
// //
//////////////////////////////////////////////////////////////////////////////////
diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json
index 66d8e9f30..185516563 100644
--- a/tools/rlparser/output/raylib_api.json
+++ b/tools/rlparser/output/raylib_api.json
@@ -4191,6 +4191,17 @@
}
]
},
+ {
+ "name": "SetTraceLogLevel",
+ "description": "Set the current threshold (minimum) log level",
+ "returnType": "void",
+ "params": [
+ {
+ "type": "int",
+ "name": "logLevel"
+ }
+ ]
+ },
{
"name": "TraceLog",
"description": "Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)",
@@ -4211,13 +4222,13 @@
]
},
{
- "name": "SetTraceLogLevel",
- "description": "Set the current threshold (minimum) log level",
+ "name": "SetTraceLogCallback",
+ "description": "Set custom trace log",
"returnType": "void",
"params": [
{
- "type": "int",
- "name": "logLevel"
+ "type": "TraceLogCallback",
+ "name": "callback"
}
]
},
@@ -4258,61 +4269,6 @@
}
]
},
- {
- "name": "SetTraceLogCallback",
- "description": "Set custom trace log",
- "returnType": "void",
- "params": [
- {
- "type": "TraceLogCallback",
- "name": "callback"
- }
- ]
- },
- {
- "name": "SetLoadFileDataCallback",
- "description": "Set custom file binary data loader",
- "returnType": "void",
- "params": [
- {
- "type": "LoadFileDataCallback",
- "name": "callback"
- }
- ]
- },
- {
- "name": "SetSaveFileDataCallback",
- "description": "Set custom file binary data saver",
- "returnType": "void",
- "params": [
- {
- "type": "SaveFileDataCallback",
- "name": "callback"
- }
- ]
- },
- {
- "name": "SetLoadFileTextCallback",
- "description": "Set custom file text data loader",
- "returnType": "void",
- "params": [
- {
- "type": "LoadFileTextCallback",
- "name": "callback"
- }
- ]
- },
- {
- "name": "SetSaveFileTextCallback",
- "description": "Set custom file text data saver",
- "returnType": "void",
- "params": [
- {
- "type": "SaveFileTextCallback",
- "name": "callback"
- }
- ]
- },
{
"name": "LoadFileData",
"description": "Load file data as byte array (read)",
@@ -4414,6 +4370,50 @@
}
]
},
+ {
+ "name": "SetLoadFileDataCallback",
+ "description": "Set custom file binary data loader",
+ "returnType": "void",
+ "params": [
+ {
+ "type": "LoadFileDataCallback",
+ "name": "callback"
+ }
+ ]
+ },
+ {
+ "name": "SetSaveFileDataCallback",
+ "description": "Set custom file binary data saver",
+ "returnType": "void",
+ "params": [
+ {
+ "type": "SaveFileDataCallback",
+ "name": "callback"
+ }
+ ]
+ },
+ {
+ "name": "SetLoadFileTextCallback",
+ "description": "Set custom file text data loader",
+ "returnType": "void",
+ "params": [
+ {
+ "type": "LoadFileTextCallback",
+ "name": "callback"
+ }
+ ]
+ },
+ {
+ "name": "SetSaveFileTextCallback",
+ "description": "Set custom file text data saver",
+ "returnType": "void",
+ "params": [
+ {
+ "type": "SaveFileTextCallback",
+ "name": "callback"
+ }
+ ]
+ },
{
"name": "FileRename",
"description": "Rename file (if exists)",
diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua
index 192ad963a..f2836e1ff 100644
--- a/tools/rlparser/output/raylib_api.lua
+++ b/tools/rlparser/output/raylib_api.lua
@@ -3864,6 +3864,14 @@ return {
{type = "const char *", name = "url"}
}
},
+ {
+ name = "SetTraceLogLevel",
+ description = "Set the current threshold (minimum) log level",
+ returnType = "void",
+ params = {
+ {type = "int", name = "logLevel"}
+ }
+ },
{
name = "TraceLog",
description = "Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)",
@@ -3875,11 +3883,11 @@ return {
}
},
{
- name = "SetTraceLogLevel",
- description = "Set the current threshold (minimum) log level",
+ name = "SetTraceLogCallback",
+ description = "Set custom trace log",
returnType = "void",
params = {
- {type = "int", name = "logLevel"}
+ {type = "TraceLogCallback", name = "callback"}
}
},
{
@@ -3907,46 +3915,6 @@ return {
{type = "void *", name = "ptr"}
}
},
- {
- name = "SetTraceLogCallback",
- description = "Set custom trace log",
- returnType = "void",
- params = {
- {type = "TraceLogCallback", name = "callback"}
- }
- },
- {
- name = "SetLoadFileDataCallback",
- description = "Set custom file binary data loader",
- returnType = "void",
- params = {
- {type = "LoadFileDataCallback", name = "callback"}
- }
- },
- {
- name = "SetSaveFileDataCallback",
- description = "Set custom file binary data saver",
- returnType = "void",
- params = {
- {type = "SaveFileDataCallback", name = "callback"}
- }
- },
- {
- name = "SetLoadFileTextCallback",
- description = "Set custom file text data loader",
- returnType = "void",
- params = {
- {type = "LoadFileTextCallback", name = "callback"}
- }
- },
- {
- name = "SetSaveFileTextCallback",
- description = "Set custom file text data saver",
- returnType = "void",
- params = {
- {type = "SaveFileTextCallback", name = "callback"}
- }
- },
{
name = "LoadFileData",
description = "Load file data as byte array (read)",
@@ -4009,6 +3977,38 @@ return {
{type = "const char *", name = "text"}
}
},
+ {
+ name = "SetLoadFileDataCallback",
+ description = "Set custom file binary data loader",
+ returnType = "void",
+ params = {
+ {type = "LoadFileDataCallback", name = "callback"}
+ }
+ },
+ {
+ name = "SetSaveFileDataCallback",
+ description = "Set custom file binary data saver",
+ returnType = "void",
+ params = {
+ {type = "SaveFileDataCallback", name = "callback"}
+ }
+ },
+ {
+ name = "SetLoadFileTextCallback",
+ description = "Set custom file text data loader",
+ returnType = "void",
+ params = {
+ {type = "LoadFileTextCallback", name = "callback"}
+ }
+ },
+ {
+ name = "SetSaveFileTextCallback",
+ description = "Set custom file text data saver",
+ returnType = "void",
+ params = {
+ {type = "SaveFileTextCallback", name = "callback"}
+ }
+ },
{
name = "FileRename",
description = "Rename file (if exists)",
diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt
index f60f8fc81..0676b8138 100644
--- a/tools/rlparser/output/raylib_api.txt
+++ b/tools/rlparser/output/raylib_api.txt
@@ -1563,100 +1563,100 @@ Function 106: OpenURL() (1 input parameters)
Return type: void
Description: Open URL with default system browser (if available)
Param[1]: url (type: const char *)
-Function 107: TraceLog() (3 input parameters)
+Function 107: SetTraceLogLevel() (1 input parameters)
+ Name: SetTraceLogLevel
+ Return type: void
+ Description: Set the current threshold (minimum) log level
+ Param[1]: logLevel (type: int)
+Function 108: TraceLog() (3 input parameters)
Name: TraceLog
Return type: void
Description: Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)
Param[1]: logLevel (type: int)
Param[2]: text (type: const char *)
Param[3]: args (type: ...)
-Function 108: SetTraceLogLevel() (1 input parameters)
- Name: SetTraceLogLevel
+Function 109: SetTraceLogCallback() (1 input parameters)
+ Name: SetTraceLogCallback
Return type: void
- Description: Set the current threshold (minimum) log level
- Param[1]: logLevel (type: int)
-Function 109: MemAlloc() (1 input parameters)
+ Description: Set custom trace log
+ Param[1]: callback (type: TraceLogCallback)
+Function 110: MemAlloc() (1 input parameters)
Name: MemAlloc
Return type: void *
Description: Internal memory allocator
Param[1]: size (type: unsigned int)
-Function 110: MemRealloc() (2 input parameters)
+Function 111: MemRealloc() (2 input parameters)
Name: MemRealloc
Return type: void *
Description: Internal memory reallocator
Param[1]: ptr (type: void *)
Param[2]: size (type: unsigned int)
-Function 111: MemFree() (1 input parameters)
+Function 112: MemFree() (1 input parameters)
Name: MemFree
Return type: void
Description: Internal memory free
Param[1]: ptr (type: void *)
-Function 112: SetTraceLogCallback() (1 input parameters)
- Name: SetTraceLogCallback
- Return type: void
- Description: Set custom trace log
- Param[1]: callback (type: TraceLogCallback)
-Function 113: SetLoadFileDataCallback() (1 input parameters)
- Name: SetLoadFileDataCallback
- Return type: void
- Description: Set custom file binary data loader
- Param[1]: callback (type: LoadFileDataCallback)
-Function 114: SetSaveFileDataCallback() (1 input parameters)
- Name: SetSaveFileDataCallback
- Return type: void
- Description: Set custom file binary data saver
- Param[1]: callback (type: SaveFileDataCallback)
-Function 115: SetLoadFileTextCallback() (1 input parameters)
- Name: SetLoadFileTextCallback
- Return type: void
- Description: Set custom file text data loader
- Param[1]: callback (type: LoadFileTextCallback)
-Function 116: SetSaveFileTextCallback() (1 input parameters)
- Name: SetSaveFileTextCallback
- Return type: void
- Description: Set custom file text data saver
- Param[1]: callback (type: SaveFileTextCallback)
-Function 117: LoadFileData() (2 input parameters)
+Function 113: LoadFileData() (2 input parameters)
Name: LoadFileData
Return type: unsigned char *
Description: Load file data as byte array (read)
Param[1]: fileName (type: const char *)
Param[2]: dataSize (type: int *)
-Function 118: UnloadFileData() (1 input parameters)
+Function 114: UnloadFileData() (1 input parameters)
Name: UnloadFileData
Return type: void
Description: Unload file data allocated by LoadFileData()
Param[1]: data (type: unsigned char *)
-Function 119: SaveFileData() (3 input parameters)
+Function 115: SaveFileData() (3 input parameters)
Name: SaveFileData
Return type: bool
Description: Save data to file from byte array (write), returns true on success
Param[1]: fileName (type: const char *)
Param[2]: data (type: void *)
Param[3]: dataSize (type: int)
-Function 120: ExportDataAsCode() (3 input parameters)
+Function 116: ExportDataAsCode() (3 input parameters)
Name: ExportDataAsCode
Return type: bool
Description: Export data to code (.h), returns true on success
Param[1]: data (type: const unsigned char *)
Param[2]: dataSize (type: int)
Param[3]: fileName (type: const char *)
-Function 121: LoadFileText() (1 input parameters)
+Function 117: LoadFileText() (1 input parameters)
Name: LoadFileText
Return type: char *
Description: Load text data from file (read), returns a '\0' terminated string
Param[1]: fileName (type: const char *)
-Function 122: UnloadFileText() (1 input parameters)
+Function 118: UnloadFileText() (1 input parameters)
Name: UnloadFileText
Return type: void
Description: Unload file text data allocated by LoadFileText()
Param[1]: text (type: char *)
-Function 123: SaveFileText() (2 input parameters)
+Function 119: SaveFileText() (2 input parameters)
Name: SaveFileText
Return type: bool
Description: Save text data to file (write), string must be '\0' terminated, returns true on success
Param[1]: fileName (type: const char *)
Param[2]: text (type: const char *)
+Function 120: SetLoadFileDataCallback() (1 input parameters)
+ Name: SetLoadFileDataCallback
+ Return type: void
+ Description: Set custom file binary data loader
+ Param[1]: callback (type: LoadFileDataCallback)
+Function 121: SetSaveFileDataCallback() (1 input parameters)
+ Name: SetSaveFileDataCallback
+ Return type: void
+ Description: Set custom file binary data saver
+ Param[1]: callback (type: SaveFileDataCallback)
+Function 122: SetLoadFileTextCallback() (1 input parameters)
+ Name: SetLoadFileTextCallback
+ Return type: void
+ Description: Set custom file text data loader
+ Param[1]: callback (type: LoadFileTextCallback)
+Function 123: SetSaveFileTextCallback() (1 input parameters)
+ Name: SetSaveFileTextCallback
+ Return type: void
+ Description: Set custom file text data saver
+ Param[1]: callback (type: SaveFileTextCallback)
Function 124: FileRename() (2 input parameters)
Name: FileRename
Return type: int
diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml
index 1bbeb175c..3853ac74f 100644
--- a/tools/rlparser/output/raylib_api.xml
+++ b/tools/rlparser/output/raylib_api.xml
@@ -988,13 +988,16 @@
+
+
+
-
-
+
+
@@ -1006,21 +1009,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1048,6 +1036,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/rlparser/rlparser.c b/tools/rlparser/rlparser.c
index d5b03fa01..c291c3038 100644
--- a/tools/rlparser/rlparser.c
+++ b/tools/rlparser/rlparser.c
@@ -52,7 +52,7 @@
raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
BSD-like license that allows static linking with closed source software:
- Copyright (c) 2021-2025 Ramon Santamaria (@raysan5)
+ Copyright (c) 2021-2026 Ramon Santamaria (@raysan5)
**********************************************************************************************/
@@ -1084,7 +1084,7 @@ static void ShowCommandLineInfo(void)
printf("// //\n");
printf("// more info and bugs-report: github.com/raysan5/raylib/tools/rlparser //\n");
printf("// //\n");
- printf("// Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) //\n");
+ printf("// Copyright (c) 2021-2026 Ramon Santamaria (@raysan5) //\n");
printf("// //\n");
printf("//////////////////////////////////////////////////////////////////////////////////\n\n");