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) | core_smooth_pixelperfect | ⭐⭐⭐☆ | 3.7 | 4.0 | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) | | [core_random_sequence](core/core_random_sequence.c) | core_random_sequence | ⭐☆☆☆ | 5.0 | 5.0 | [Dalton Overmyer](https://github.com/REDl3east) | | [core_automation_events](core/core_automation_events.c) | core_automation_events | ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) | -| [core_high_dpi](core/core_high_dpi.c) | core_high_dpi | ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) | +| [core_highdpi_demo](core/core_highdpi_demo.c) | core_highdpi_demo | ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) | | [core_render_texture](core/core_render_texture.c) | core_render_texture | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [core_undo_redo](core/core_undo_redo.c) | core_undo_redo | ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) | | [core_viewport_scaling](core/core_viewport_scaling.c) | core_viewport_scaling | ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) | @@ -69,11 +69,12 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind | [core_directory_files](core/core_directory_files.c) | core_directory_files | ⭐☆☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) | | [core_highdpi_testbed](core/core_highdpi_testbed.c) | core_highdpi_testbed | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | | [core_screen_recording](core/core_screen_recording.c) | core_screen_recording | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | -| [core_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ananth S](https://github.com/Ananth1839) | +| [core_clipboard_text](core/core_clipboard_text.c) | core_clipboard_text | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ananth S](https://github.com/Ananth1839) | | [core_text_file_loading](core/core_text_file_loading.c) | core_text_file_loading | ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) | | [core_compute_hash](core/core_compute_hash.c) | core_compute_hash | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) | +| [core_keyboard_testbed](core/core_keyboard_testbed.c) | core_keyboard_testbed | ⭐⭐☆☆ | 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) | shapes_rlgl_triangle | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) | | [shapes_ball_physics](shapes/shapes_ball_physics.c) | shapes_ball_physics | ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) | | [shapes_penrose_tile](shapes/shapes_penrose_tile.c) | shapes_penrose_tile | ⭐⭐⭐⭐️ | 5.5 | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) | +| [shapes_hilbert_curve](shapes/shapes_hilbert_curve.c) | shapes_hilbert_curve | ⭐⭐⭐☆ | 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) | textures_textured_curve | ⭐⭐⭐☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) | | [textures_sprite_stacking](textures/textures_sprite_stacking.c) | textures_sprite_stacking | ⭐⭐☆☆ | 5.6-dev | 6.0 | [Robin](https://github.com/RobinsAviary) | | [textures_cellular_automata](textures/textures_cellular_automata.c) | textures_cellular_automata | ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) | +| [textures_framebuffer_rendering](textures/textures_framebuffer_rendering.c) | textures_framebuffer_rendering | ⭐⭐☆☆ | 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");